Bläddra i källkod

net: ethernet: ti: cpts: enhance pps gen/latch operations

This patch enhances PPS generation/latch operations to cover more use
cases by implementing the following changes:
- break pps_parse routine into pps generation and pps latch portion so
  that they can be independent including breaking the timers list to
  pps_timer and latch_timer
- inport and record the pps hw push event index if available or use
  the default value for backward compatibility
- make pps_enable_gpio and ref_enable_gpio optional
- break the 1pps control flag to 1pps_gen, 1pps_ref and 1pps_latch

Signed-off-by: Eric Ruei <e-ruei1@ti.com>
Eric Ruei 6 år sedan
förälder
incheckning
b2884344cc
2 ändrade filer med 255 tillägg och 148 borttagningar
  1. 249 144
      drivers/net/ethernet/ti/cpts.c
  2. 6 4
      drivers/net/ethernet/ti/cpts.h

+ 249 - 144
drivers/net/ethernet/ti/cpts.c

@@ -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);
 		}
 	}
 }

+ 6 - 4
drivers/net/ethernet/ti/cpts.h

@@ -114,9 +114,8 @@ enum {
 #define CPTS_EVENT_RX_TX_TIMEOUT 20 /* ms */
 #define CPTS_EVENT_HWSTAMP_TIMEOUT 200 /* ms */
 
-#ifdef CONFIG_TI_1PPS_DM_TIMER
-#define CPTS_MAX_LATCH	3
-#endif
+#define CPTS_MAX_EXT_TS 4
+#define CPTS_PPS_HW_INDEX 3
 
 struct cpts_event {
 	struct list_head list;
@@ -152,8 +151,11 @@ struct cpts {
 	u32 caps;
 
 #ifdef CONFIG_TI_1PPS_DM_TIMER
-	u8 use_1pps;
+	u8 use_1pps_gen;
+	u8 use_1pps_latch;
+	u8 use_1pps_ref;
 	u8 pps_latch_receive;
+	int pps_hw_index;
 	int pps_enable;
 	int pps_state;
 	int pps_latch_state;