|
|
@@ -440,7 +440,8 @@ static int cpts_proc_pps_ts_events(struct cpts *cpts)
|
|
|
list_for_each_safe(this, next, &cpts->events) {
|
|
|
event = list_entry(this, struct cpts_event, list);
|
|
|
ev = event_type(event);
|
|
|
- if (ev == CPTS_EV_HW && (cpts_event_port(event) == 4)) {
|
|
|
+ if (ev == CPTS_EV_HW &&
|
|
|
+ (cpts_event_port(event) == (cpts->pps_hw_index + 1))) {
|
|
|
list_del_init(&event->list);
|
|
|
list_add(&event->list, &cpts->pool);
|
|
|
/* record the timestamp only */
|
|
|
@@ -498,9 +499,11 @@ static int cpts_pps_enable(struct cpts *cpts, int on)
|
|
|
if (!on)
|
|
|
return 0;
|
|
|
|
|
|
- spin_lock_bh(&cpts->bc_mux_lock);
|
|
|
- gpio_set_value(cpts->pps_enable_gpio, 1);
|
|
|
- spin_unlock_bh(&cpts->bc_mux_lock);
|
|
|
+ if (cpts->pps_enable_gpio >= 0) {
|
|
|
+ spin_lock_bh(&cpts->bc_mux_lock);
|
|
|
+ gpio_set_value(cpts->pps_enable_gpio, 1);
|
|
|
+ spin_unlock_bh(&cpts->bc_mux_lock);
|
|
|
+ }
|
|
|
|
|
|
if (cpts->ref_enable == -1) {
|
|
|
cpts_pps_start(cpts);
|
|
|
@@ -542,24 +545,31 @@ static int cpts_pps_init(struct cpts *cpts)
|
|
|
cpts->ref_enable = -1;
|
|
|
cpts->pps_offset = 0;
|
|
|
|
|
|
- spin_lock_init(&cpts->bc_mux_lock);
|
|
|
+ if (cpts->use_1pps_gen) {
|
|
|
+ spin_lock_init(&cpts->bc_mux_lock);
|
|
|
|
|
|
#ifdef CONFIG_OMAP_DM_TIMER
|
|
|
- omap_dm_timer_enable(cpts->odt);
|
|
|
- omap_dm_timer_enable(cpts->odt2);
|
|
|
+ omap_dm_timer_enable(cpts->odt);
|
|
|
#endif
|
|
|
- cpts_tmr_init(cpts);
|
|
|
|
|
|
- kthread_init_delayed_work(&cpts->pps_work, cpts_pps_kworker);
|
|
|
- cpts->pps_kworker = kthread_create_worker(0, "pps0");
|
|
|
+ kthread_init_delayed_work(&cpts->pps_work, cpts_pps_kworker);
|
|
|
+ cpts->pps_kworker = kthread_create_worker(0, "pps0");
|
|
|
|
|
|
- if (IS_ERR(cpts->pps_kworker)) {
|
|
|
- err = PTR_ERR(cpts->pps_kworker);
|
|
|
- pr_err("failed to create cpts pps worker %d\n", err);
|
|
|
- // TBD:add error handling
|
|
|
- return -1;
|
|
|
+ if (IS_ERR(cpts->pps_kworker)) {
|
|
|
+ err = PTR_ERR(cpts->pps_kworker);
|
|
|
+ pr_err("failed to create cpts pps worker %d\n", err);
|
|
|
+ // TBD:add error handling
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_OMAP_DM_TIMER
|
|
|
+ if (cpts->use_1pps_latch)
|
|
|
+ omap_dm_timer_enable(cpts->odt2);
|
|
|
+#endif
|
|
|
+
|
|
|
+ cpts_tmr_init(cpts);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
@@ -578,9 +588,11 @@ static void cpts_pps_schedule(struct cpts *cpts)
|
|
|
cpts->pps_enable = -1;
|
|
|
pinctrl_select_state(cpts->pins,
|
|
|
cpts->pin_state_pwm_off);
|
|
|
- spin_lock_bh(&cpts->bc_mux_lock);
|
|
|
- gpio_set_value(cpts->pps_enable_gpio, 0);
|
|
|
- spin_unlock_bh(&cpts->bc_mux_lock);
|
|
|
+ if (cpts->pps_enable_gpio >= 0) {
|
|
|
+ spin_lock_bh(&cpts->bc_mux_lock);
|
|
|
+ gpio_set_value(cpts->pps_enable_gpio, 0);
|
|
|
+ spin_unlock_bh(&cpts->bc_mux_lock);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (!cpts->ref_enable) {
|
|
|
@@ -608,7 +620,11 @@ static int cpts_extts_enable(struct cpts *cpts, u32 index, int on)
|
|
|
unsigned long flags;
|
|
|
u32 v;
|
|
|
|
|
|
- if (index >= cpts->info.n_ext_ts)
|
|
|
+#ifdef CONFIG_TI_1PPS_DM_TIMER
|
|
|
+ if (index >= CPTS_MAX_EXT_TS || index == cpts->pps_hw_index)
|
|
|
+#else
|
|
|
+ if (index >= CPTS_MAX_EXT_TS)
|
|
|
+#endif
|
|
|
return -ENXIO;
|
|
|
|
|
|
if (((cpts->hw_ts_enable & BIT(index)) >> index) == on)
|
|
|
@@ -621,13 +637,17 @@ static int cpts_extts_enable(struct cpts *cpts, u32 index, int on)
|
|
|
v |= BIT(8 + index);
|
|
|
cpts->hw_ts_enable |= BIT(index);
|
|
|
#ifdef CONFIG_TI_1PPS_DM_TIMER
|
|
|
- pinctrl_select_state(cpts->pins, cpts->pin_state_latch_on);
|
|
|
+ if (cpts->use_1pps_latch)
|
|
|
+ pinctrl_select_state(cpts->pins,
|
|
|
+ cpts->pin_state_latch_on);
|
|
|
#endif
|
|
|
} else {
|
|
|
v &= ~BIT(8 + index);
|
|
|
cpts->hw_ts_enable &= ~BIT(index);
|
|
|
#ifdef CONFIG_TI_1PPS_DM_TIMER
|
|
|
- pinctrl_select_state(cpts->pins, cpts->pin_state_latch_off);
|
|
|
+ if (cpts->use_1pps_latch)
|
|
|
+ pinctrl_select_state(cpts->pins,
|
|
|
+ cpts->pin_state_latch_off);
|
|
|
#endif
|
|
|
}
|
|
|
cpts_write32(cpts, v, control);
|
|
|
@@ -666,16 +686,22 @@ static int cpts_ptp_enable(struct ptp_clock_info *ptp,
|
|
|
return cpts_extts_enable(cpts, rq->extts.index, on);
|
|
|
#ifdef CONFIG_TI_1PPS_DM_TIMER
|
|
|
case PTP_CLK_REQ_PPS:
|
|
|
- if (cpts->use_1pps) {
|
|
|
+ if (cpts->use_1pps_gen) {
|
|
|
ok = ptp_bc_clock_sync_enable(cpts->bc_clkid, on);
|
|
|
if (!ok) {
|
|
|
pr_info("cpts error: bc clk sync pps enable denied\n");
|
|
|
return -EBUSY;
|
|
|
}
|
|
|
+ return cpts_pps_enable(cpts, on);
|
|
|
+ } else {
|
|
|
+ return -EOPNOTSUPP;
|
|
|
}
|
|
|
- return cpts_pps_enable(cpts, on);
|
|
|
+
|
|
|
case PTP_CLK_REQ_PEROUT:
|
|
|
/* this enables a pps for external measurement */
|
|
|
+ if (!cpts->use_1pps_ref)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
if (rq->perout.index != 0)
|
|
|
return -EINVAL;
|
|
|
|
|
|
@@ -692,7 +718,7 @@ static int cpts_ptp_enable(struct ptp_clock_info *ptp,
|
|
|
|
|
|
return cpts_ref_enable(cpts, on);
|
|
|
case PTP_CLK_REQ_PPS_OFFSET:
|
|
|
- if (cpts->use_1pps)
|
|
|
+ if (cpts->use_1pps_gen)
|
|
|
cpts->pps_offset = on;
|
|
|
return 0;
|
|
|
#endif
|
|
|
@@ -731,7 +757,7 @@ static const struct ptp_clock_info cpts_info = {
|
|
|
.owner = THIS_MODULE,
|
|
|
.name = "CTPS timer",
|
|
|
.max_adj = 1000000,
|
|
|
- .n_ext_ts = 0,
|
|
|
+ .n_ext_ts = CPTS_MAX_EXT_TS,
|
|
|
.n_pins = 0,
|
|
|
.pps = 0,
|
|
|
.adjfreq = cpts_ptp_adjfreq,
|
|
|
@@ -863,6 +889,13 @@ int cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(cpts_tx_timestamp);
|
|
|
|
|
|
+#ifdef CONFIG_TI_1PPS_DM_TIMER
|
|
|
+static u32 cpts_hw_ts_push_en[4] = {HW1_TS_PUSH_EN,
|
|
|
+ HW2_TS_PUSH_EN,
|
|
|
+ HW3_TS_PUSH_EN,
|
|
|
+ HW4_TS_PUSH_EN};
|
|
|
+#endif
|
|
|
+
|
|
|
int cpts_register(struct cpts *cpts)
|
|
|
{
|
|
|
int err, i;
|
|
|
@@ -890,14 +923,15 @@ int cpts_register(struct cpts *cpts)
|
|
|
|
|
|
ptp_schedule_worker(cpts->clock, cpts->ov_check_period);
|
|
|
#ifdef CONFIG_TI_1PPS_DM_TIMER
|
|
|
- cpts_write32(cpts, cpts_read32(cpts, control) |
|
|
|
- HW4_TS_PUSH_EN, control);
|
|
|
-
|
|
|
- if (cpts->use_1pps) {
|
|
|
+ if (cpts->use_1pps_gen) {
|
|
|
cpts->bc_clkid = ptp_bc_clock_register(PTP_BC_CLOCK_TYPE_GMAC);
|
|
|
pr_info("cpts ptp bc clkid %d\n", cpts->bc_clkid);
|
|
|
ptp_bc_mux_ctrl_register((void *)cpts, &cpts->bc_mux_lock,
|
|
|
cpts_bc_mux_ctrl);
|
|
|
+ cpts_write32(cpts, cpts_read32(cpts, control) |
|
|
|
+ cpts_hw_ts_push_en[cpts->pps_hw_index],
|
|
|
+ control);
|
|
|
+
|
|
|
}
|
|
|
#endif
|
|
|
return 0;
|
|
|
@@ -971,46 +1005,32 @@ static void cpts_calc_mult_shift(struct cpts *cpts)
|
|
|
static int cpts_of_1pps_parse(struct cpts *cpts, struct device_node *node)
|
|
|
{
|
|
|
struct device_node *np = NULL;
|
|
|
- struct device_node *np2 = NULL;
|
|
|
int gpio, ret;
|
|
|
+ u32 prop;
|
|
|
|
|
|
- np = of_parse_phandle(node, "timers", 0);
|
|
|
+ np = of_parse_phandle(node, "pps_timer", 0);
|
|
|
if (!np) {
|
|
|
- dev_err(cpts->dev, "device node lookup for pps timer failed\n");
|
|
|
- return -ENXIO;
|
|
|
- }
|
|
|
-
|
|
|
- np2 = of_parse_phandle(node, "timers", 1);
|
|
|
- if (!np2) {
|
|
|
- dev_err(cpts->dev, "device node lookup for pps timer input failed\n");
|
|
|
+ dev_dbg(cpts->dev,
|
|
|
+ "device node lookup for pps timer failed\n");
|
|
|
return -ENXIO;
|
|
|
}
|
|
|
|
|
|
- cpts->pps_tmr_irqn = of_irq_get(np, 0);
|
|
|
- if (!cpts->pps_tmr_irqn)
|
|
|
- dev_err(cpts->dev, "cannot get 1pps timer interrupt number\n");
|
|
|
-
|
|
|
- cpts->pps_latch_irqn = of_irq_get(np2, 0);
|
|
|
- if (!cpts->pps_latch_irqn)
|
|
|
- dev_err(cpts->dev, "cannot get 1pps latch interrupt number\n");
|
|
|
-
|
|
|
#ifdef CONFIG_OMAP_DM_TIMER
|
|
|
cpts->odt = omap_dm_timer_request_by_node(np);
|
|
|
- cpts->odt2 = omap_dm_timer_request_by_node(np2);
|
|
|
#endif
|
|
|
- if (!cpts->odt || !cpts->odt2)
|
|
|
+ if (!cpts->odt)
|
|
|
return -EPROBE_DEFER;
|
|
|
|
|
|
if (IS_ERR(cpts->odt)) {
|
|
|
- dev_err(cpts->dev, "request for 1pps timer failed: %ld\n",
|
|
|
+ dev_err(cpts->dev, "request for 1pps DM timer failed: %ld\n",
|
|
|
PTR_ERR(cpts->odt));
|
|
|
return PTR_ERR(cpts->odt);
|
|
|
}
|
|
|
|
|
|
- if (IS_ERR(cpts->odt2)) {
|
|
|
- dev_err(cpts->dev, "request for 1pps timer input failed: %ld\n",
|
|
|
- PTR_ERR(cpts->odt2));
|
|
|
- return PTR_ERR(cpts->odt2);
|
|
|
+ cpts->pps_tmr_irqn = of_irq_get(np, 0);
|
|
|
+ if (!cpts->pps_tmr_irqn) {
|
|
|
+ dev_err(cpts->dev, "cannot get 1pps timer interrupt number\n");
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
cpts->pins = devm_pinctrl_get(cpts->dev);
|
|
|
@@ -1034,62 +1054,50 @@ static int cpts_of_1pps_parse(struct cpts *cpts, struct device_node *node)
|
|
|
return PTR_ERR(cpts->pin_state_pwm_off);
|
|
|
}
|
|
|
|
|
|
- cpts->pin_state_latch_on = pinctrl_lookup_state(cpts->pins,
|
|
|
- "latch_on");
|
|
|
- if (IS_ERR(cpts->pin_state_latch_on)) {
|
|
|
- dev_err(cpts->dev, "lookup for latch_on pin state failed: %ld\n",
|
|
|
- PTR_ERR(cpts->pin_state_latch_on));
|
|
|
- return PTR_ERR(cpts->pin_state_latch_on);
|
|
|
- }
|
|
|
-
|
|
|
- cpts->pin_state_latch_off = pinctrl_lookup_state(cpts->pins,
|
|
|
- "latch_off");
|
|
|
- if (IS_ERR(cpts->pin_state_latch_off)) {
|
|
|
- dev_err(cpts->dev, "lookup for latch_off pin state failed: %ld\n",
|
|
|
- PTR_ERR(cpts->pin_state_latch_off));
|
|
|
- return PTR_ERR(cpts->pin_state_latch_off);
|
|
|
- }
|
|
|
-
|
|
|
+ /* The 1PPS enable-gpio signal is only optional and therefore it
|
|
|
+ * may not be provided by DTB.
|
|
|
+ */
|
|
|
+ cpts->pps_enable_gpio = -1;
|
|
|
gpio = of_get_named_gpio(node, "pps-enable-gpios", 0);
|
|
|
if (!gpio_is_valid(gpio)) {
|
|
|
- dev_err(cpts->dev, "failed to parse pps-enable gpio\n");
|
|
|
- return gpio;
|
|
|
- }
|
|
|
+ dev_dbg(cpts->dev, "there is no pps-enable gpio\n");
|
|
|
+ } else {
|
|
|
|
|
|
- ret = devm_gpio_request(cpts->dev, gpio, "pps-enable-ctrl");
|
|
|
- if (ret) {
|
|
|
- dev_err(cpts->dev, "failed to acquire pps-enable gpio\n");
|
|
|
- return ret;
|
|
|
+ ret = devm_gpio_request(cpts->dev, gpio, "pps-enable-ctrl");
|
|
|
+ if (ret) {
|
|
|
+ dev_err(cpts->dev,
|
|
|
+ "failed to acquire pps-enable gpio\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ cpts->pps_enable_gpio = gpio;
|
|
|
+ gpio_direction_output(gpio, 0);
|
|
|
}
|
|
|
- cpts->pps_enable_gpio = gpio;
|
|
|
- gpio_direction_output(gpio, 0);
|
|
|
+
|
|
|
+ if (!of_property_read_u32(node, "cpts_pps_hw_event_index", &prop))
|
|
|
+ cpts->pps_hw_index = prop;
|
|
|
+ else
|
|
|
+ cpts->pps_hw_index = CPTS_PPS_HW_INDEX;
|
|
|
+
|
|
|
+ if (cpts->pps_hw_index > CPTS_PPS_HW_INDEX)
|
|
|
+ cpts->pps_hw_index = CPTS_PPS_HW_INDEX;
|
|
|
+
|
|
|
+ dev_dbg(cpts->dev, "cpts pps hw event index = %d\n",
|
|
|
+ cpts->pps_hw_index);
|
|
|
+
|
|
|
+ cpts->use_1pps_gen = true;
|
|
|
|
|
|
/* The 1PPS reference signal is only optional and therefore the
|
|
|
* corresponding pins may not be provided by DTB.
|
|
|
*/
|
|
|
|
|
|
- gpio = of_get_named_gpio(node, "ref-enable-gpios", 0);
|
|
|
- if (!gpio_is_valid(gpio)) {
|
|
|
- cpts->ref_enable_gpio = -1;
|
|
|
+ cpts->pin_state_ref_on = pinctrl_lookup_state(cpts->pins,
|
|
|
+ "ref_on");
|
|
|
+ if (IS_ERR(cpts->pin_state_ref_on)) {
|
|
|
+ dev_notice(cpts->dev,
|
|
|
+ "lookup for ref_on pin state failed: %ld\n",
|
|
|
+ PTR_ERR(cpts->pin_state_ref_on));
|
|
|
+ return PTR_ERR(cpts->pin_state_ref_on);
|
|
|
} else {
|
|
|
- ret = devm_gpio_request(cpts->dev, gpio, "ref-enable-ctrl");
|
|
|
- if (ret) {
|
|
|
- dev_err(cpts->dev,
|
|
|
- "failed to acquire ref-enable gpio\n");
|
|
|
- devm_gpio_free(cpts->dev, cpts->pps_enable_gpio);
|
|
|
- return ret;
|
|
|
- }
|
|
|
- cpts->ref_enable_gpio = gpio;
|
|
|
- gpio_direction_output(gpio, 1);
|
|
|
-
|
|
|
- cpts->pin_state_ref_on = pinctrl_lookup_state(cpts->pins,
|
|
|
- "ref_on");
|
|
|
- if (IS_ERR(cpts->pin_state_ref_on)) {
|
|
|
- dev_err(cpts->dev,
|
|
|
- "lookup for ref_on pin state failed: %ld\n",
|
|
|
- PTR_ERR(cpts->pin_state_ref_on));
|
|
|
- return PTR_ERR(cpts->pin_state_ref_on);
|
|
|
- }
|
|
|
|
|
|
cpts->pin_state_ref_off = pinctrl_lookup_state(cpts->pins,
|
|
|
"ref_off");
|
|
|
@@ -1099,6 +1107,83 @@ static int cpts_of_1pps_parse(struct cpts *cpts, struct device_node *node)
|
|
|
PTR_ERR(cpts->pin_state_ref_off));
|
|
|
return PTR_ERR(cpts->pin_state_ref_off);
|
|
|
}
|
|
|
+
|
|
|
+ /* The 1PPS ref-enable-gpio signal is only optional and
|
|
|
+ * therefore it may not be provided by DTB.
|
|
|
+ */
|
|
|
+ cpts->ref_enable_gpio = -1;
|
|
|
+ gpio = of_get_named_gpio(node, "ref-enable-gpios", 0);
|
|
|
+ if (!gpio_is_valid(gpio)) {
|
|
|
+ dev_dbg(cpts->dev,
|
|
|
+ "there is no ref-enable gpio\n");
|
|
|
+ } else {
|
|
|
+ ret = devm_gpio_request(cpts->dev, gpio,
|
|
|
+ "ref-enable-ctrl");
|
|
|
+ if (ret) {
|
|
|
+ dev_err(cpts->dev,
|
|
|
+ "failed to acquire ref-enable gpio\n");
|
|
|
+ devm_gpio_free(cpts->dev,
|
|
|
+ cpts->pps_enable_gpio);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ cpts->ref_enable_gpio = gpio;
|
|
|
+ gpio_direction_output(gpio, 1);
|
|
|
+ }
|
|
|
+ cpts->use_1pps_ref = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int cpts_of_1pps_latch_parse(struct cpts *cpts, struct device_node *node)
|
|
|
+{
|
|
|
+ struct device_node *np2 = NULL;
|
|
|
+
|
|
|
+ np2 = of_parse_phandle(node, "latch_timer", 0);
|
|
|
+ if (!np2) {
|
|
|
+ dev_dbg(cpts->dev,
|
|
|
+ "device node lookup for latch timer input failed\n");
|
|
|
+ return -ENXIO;
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef CONFIG_OMAP_DM_TIMER
|
|
|
+ cpts->odt2 = omap_dm_timer_request_by_node(np2);
|
|
|
+#endif
|
|
|
+ if (!cpts->odt2)
|
|
|
+ return -EPROBE_DEFER;
|
|
|
+
|
|
|
+ if (IS_ERR(cpts->odt2)) {
|
|
|
+ dev_err(cpts->dev,
|
|
|
+ "request for 1pps latch timer input failed: %ld\n",
|
|
|
+ PTR_ERR(cpts->odt2));
|
|
|
+ return PTR_ERR(cpts->odt2);
|
|
|
+ }
|
|
|
+
|
|
|
+ cpts->pps_latch_irqn = of_irq_get(np2, 0);
|
|
|
+ if (!cpts->pps_latch_irqn)
|
|
|
+ dev_err(cpts->dev, "cannot get 1pps latch interrupt number\n");
|
|
|
+
|
|
|
+ cpts->pins = devm_pinctrl_get(cpts->dev);
|
|
|
+ if (IS_ERR(cpts->pins)) {
|
|
|
+ dev_err(cpts->dev, "request for 1pps pins failed: %ld\n",
|
|
|
+ PTR_ERR(cpts->pins));
|
|
|
+ return PTR_ERR(cpts->pins);
|
|
|
+ }
|
|
|
+
|
|
|
+ cpts->pin_state_latch_on = pinctrl_lookup_state(cpts->pins,
|
|
|
+ "latch_on");
|
|
|
+ if (IS_ERR(cpts->pin_state_latch_on)) {
|
|
|
+ dev_err(cpts->dev, "lookup for latch_on pin state failed: %ld\n",
|
|
|
+ PTR_ERR(cpts->pin_state_latch_on));
|
|
|
+ return PTR_ERR(cpts->pin_state_latch_on);
|
|
|
+ }
|
|
|
+
|
|
|
+ cpts->pin_state_latch_off = pinctrl_lookup_state(cpts->pins,
|
|
|
+ "latch_off");
|
|
|
+ if (IS_ERR(cpts->pin_state_latch_off)) {
|
|
|
+ dev_err(cpts->dev, "lookup for latch_off pin state failed: %ld\n",
|
|
|
+ PTR_ERR(cpts->pin_state_latch_off));
|
|
|
+ return PTR_ERR(cpts->pin_state_latch_off);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
@@ -1138,7 +1223,11 @@ static int cpts_of_parse(struct cpts *cpts, struct device_node *node)
|
|
|
if (ret == -EPROBE_DEFER)
|
|
|
return ret;
|
|
|
|
|
|
- cpts->use_1pps = (ret == 0);
|
|
|
+ ret = cpts_of_1pps_latch_parse(cpts, node);
|
|
|
+ if (ret == -EPROBE_DEFER)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ cpts->use_1pps_latch = (ret == 0);
|
|
|
#endif
|
|
|
|
|
|
return 0;
|
|
|
@@ -1213,7 +1302,7 @@ struct cpts *cpts_create(struct device *dev, void __iomem *regs,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (cpts->use_1pps) {
|
|
|
+ if (cpts->use_1pps_gen || cpts->use_1pps_latch) {
|
|
|
ret = cpts_pps_init(cpts);
|
|
|
|
|
|
if (ret < 0) {
|
|
|
@@ -1223,9 +1312,10 @@ struct cpts *cpts_create(struct device *dev, void __iomem *regs,
|
|
|
}
|
|
|
|
|
|
/* Enable 1PPS related features */
|
|
|
- cpts->info.pps = 1;
|
|
|
- cpts->info.n_ext_ts = CPTS_MAX_LATCH;
|
|
|
- cpts->info.n_per_out = (cpts->ref_enable_gpio >= 0) ? 1 : 0;
|
|
|
+ cpts->info.pps = (cpts->use_1pps_gen) ? 1 : 0;
|
|
|
+ cpts->info.n_ext_ts = (cpts->use_1pps_gen) ?
|
|
|
+ CPTS_MAX_EXT_TS - 1 : CPTS_MAX_EXT_TS;
|
|
|
+ cpts->info.n_per_out = (cpts->use_1pps_ref) ? 1 : 0;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
@@ -1281,6 +1371,9 @@ static void cpts_bc_mux_ctrl(void *ctx, int enable)
|
|
|
struct cpts *cpts = (struct cpts *)ctx;
|
|
|
static int state;
|
|
|
|
|
|
+ if (cpts->pps_enable_gpio < 0)
|
|
|
+ return;
|
|
|
+
|
|
|
if (enable) {
|
|
|
if (!state)
|
|
|
gpio_set_value(cpts->pps_enable_gpio, 0);
|
|
|
@@ -1369,46 +1462,52 @@ static void cpts_tmr_init(struct cpts *cpts)
|
|
|
if (!cpts)
|
|
|
return;
|
|
|
|
|
|
- parent = clk_get(&cpts->odt->pdev->dev, "abe_giclk_div");
|
|
|
- if (IS_ERR(parent)) {
|
|
|
- pr_err("%s: %s not found\n", __func__, "abe_giclk_div");
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (cpts->use_1pps_gen) {
|
|
|
+ parent = clk_get(&cpts->odt->pdev->dev, "abe_giclk_div");
|
|
|
+ if (IS_ERR(parent)) {
|
|
|
+ pr_err("%s: %s not found\n", __func__, "abe_giclk_div");
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- ret = clk_set_parent(cpts->odt->fclk, parent);
|
|
|
- if (ret < 0)
|
|
|
- pr_err("%s: failed to set %s as parent\n", __func__,
|
|
|
- "abe_giclk_div");
|
|
|
+ ret = clk_set_parent(cpts->odt->fclk, parent);
|
|
|
+ if (ret < 0)
|
|
|
+ pr_err("%s: failed to set %s as parent\n", __func__,
|
|
|
+ "abe_giclk_div");
|
|
|
|
|
|
- parent = clk_get(&cpts->odt2->pdev->dev, "abe_giclk_div");
|
|
|
- if (IS_ERR(parent)) {
|
|
|
- pr_err("%s: %s not found\n", __func__, "abe_giclk_div");
|
|
|
- return;
|
|
|
- }
|
|
|
+ /* initialize timer16 for 1pps generator */
|
|
|
+ cpts_tmr_reinit(cpts);
|
|
|
|
|
|
- ret = clk_set_parent(cpts->odt2->fclk, parent);
|
|
|
- if (ret < 0)
|
|
|
- pr_err("%s: failed to set %s as parent\n", __func__,
|
|
|
- "abe_giclk_div");
|
|
|
+ writel_relaxed(OMAP_TIMER_INT_OVERFLOW, cpts->odt->irq_ena);
|
|
|
+ __omap_dm_timer_write(cpts->odt, OMAP_TIMER_WAKEUP_EN_REG,
|
|
|
+ OMAP_TIMER_INT_OVERFLOW, 0);
|
|
|
|
|
|
- /* initialize timer16 for 1pps generator */
|
|
|
- cpts_tmr_reinit(cpts);
|
|
|
+ pinctrl_select_state(cpts->pins, cpts->pin_state_pwm_off);
|
|
|
+ if (cpts->use_1pps_ref)
|
|
|
+ pinctrl_select_state(cpts->pins,
|
|
|
+ cpts->pin_state_ref_off);
|
|
|
+ }
|
|
|
|
|
|
- /* initialize timer15 for 1pps latch */
|
|
|
- cpts_latch_tmr_init(cpts);
|
|
|
+ if (cpts->use_1pps_latch) {
|
|
|
+ parent = clk_get(&cpts->odt2->pdev->dev, "abe_giclk_div");
|
|
|
+ if (IS_ERR(parent)) {
|
|
|
+ pr_err("%s: %s not found\n", __func__, "abe_giclk_div");
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- writel_relaxed(OMAP_TIMER_INT_OVERFLOW, cpts->odt->irq_ena);
|
|
|
- __omap_dm_timer_write(cpts->odt, OMAP_TIMER_WAKEUP_EN_REG,
|
|
|
- OMAP_TIMER_INT_OVERFLOW, 0);
|
|
|
+ ret = clk_set_parent(cpts->odt2->fclk, parent);
|
|
|
+ if (ret < 0)
|
|
|
+ pr_err("%s: failed to set %s as parent\n", __func__,
|
|
|
+ "abe_giclk_div");
|
|
|
|
|
|
- writel_relaxed(OMAP_TIMER_INT_CAPTURE, cpts->odt2->irq_ena);
|
|
|
- __omap_dm_timer_write(cpts->odt2, OMAP_TIMER_WAKEUP_EN_REG,
|
|
|
- OMAP_TIMER_INT_CAPTURE, 0);
|
|
|
+ /* initialize timer15 for 1pps latch */
|
|
|
+ cpts_latch_tmr_init(cpts);
|
|
|
|
|
|
- pinctrl_select_state(cpts->pins, cpts->pin_state_pwm_off);
|
|
|
- if (cpts->ref_enable_gpio >= 0)
|
|
|
- pinctrl_select_state(cpts->pins, cpts->pin_state_ref_off);
|
|
|
- pinctrl_select_state(cpts->pins, cpts->pin_state_latch_off);
|
|
|
+ writel_relaxed(OMAP_TIMER_INT_CAPTURE, cpts->odt2->irq_ena);
|
|
|
+ __omap_dm_timer_write(cpts->odt2, OMAP_TIMER_WAKEUP_EN_REG,
|
|
|
+ OMAP_TIMER_INT_CAPTURE, 0);
|
|
|
+
|
|
|
+ pinctrl_select_state(cpts->pins, cpts->pin_state_latch_off);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static inline void cpts_turn_on_off_1pps_output(struct cpts *cpts, u64 ts)
|
|
|
@@ -1417,15 +1516,18 @@ static inline void cpts_turn_on_off_1pps_output(struct cpts *cpts, u64 ts)
|
|
|
if (cpts->pps_enable == 1) {
|
|
|
pinctrl_select_state(cpts->pins,
|
|
|
cpts->pin_state_pwm_on);
|
|
|
- spin_lock_bh(&cpts->bc_mux_lock);
|
|
|
- gpio_set_value(cpts->pps_enable_gpio, 0);
|
|
|
- spin_unlock_bh(&cpts->bc_mux_lock);
|
|
|
+ if (cpts->pps_enable_gpio >= 0) {
|
|
|
+ spin_lock_bh(&cpts->bc_mux_lock);
|
|
|
+ gpio_set_value(cpts->pps_enable_gpio, 0);
|
|
|
+ spin_unlock_bh(&cpts->bc_mux_lock);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (cpts->ref_enable == 1) {
|
|
|
pinctrl_select_state(cpts->pins,
|
|
|
cpts->pin_state_ref_on);
|
|
|
- gpio_set_value(cpts->ref_enable_gpio, 0);
|
|
|
+ if (cpts->ref_enable_gpio >= 0)
|
|
|
+ gpio_set_value(cpts->ref_enable_gpio, 0);
|
|
|
}
|
|
|
|
|
|
pr_debug("1pps on at %llu\n", ts);
|
|
|
@@ -1433,15 +1535,18 @@ static inline void cpts_turn_on_off_1pps_output(struct cpts *cpts, u64 ts)
|
|
|
if (cpts->pps_enable == 1) {
|
|
|
pinctrl_select_state(cpts->pins,
|
|
|
cpts->pin_state_pwm_off);
|
|
|
- spin_lock_bh(&cpts->bc_mux_lock);
|
|
|
- gpio_set_value(cpts->pps_enable_gpio, 1);
|
|
|
- spin_unlock_bh(&cpts->bc_mux_lock);
|
|
|
+ if (cpts->pps_enable_gpio >= 0) {
|
|
|
+ spin_lock_bh(&cpts->bc_mux_lock);
|
|
|
+ gpio_set_value(cpts->pps_enable_gpio, 1);
|
|
|
+ spin_unlock_bh(&cpts->bc_mux_lock);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (cpts->ref_enable == 1) {
|
|
|
pinctrl_select_state(cpts->pins,
|
|
|
cpts->pin_state_ref_off);
|
|
|
- gpio_set_value(cpts->ref_enable_gpio, 1);
|
|
|
+ if (cpts->ref_enable_gpio >= 0)
|
|
|
+ gpio_set_value(cpts->ref_enable_gpio, 1);
|
|
|
}
|
|
|
}
|
|
|
}
|