diff mbox series

fec: Allow changing the PPS channel

Message ID 20220808131556.163207-1-csokas.bence@prolan.hu (mailing list archive)
State Rejected
Delegated to: Netdev Maintainers
Headers show
Series fec: Allow changing the PPS channel | expand

Checks

Context Check Description
netdev/tree_selection success Guessing tree name failed - patch did not apply

Commit Message

Csókás Bence Aug. 8, 2022, 1:15 p.m. UTC
Makes the PPS channel configurable via the Device Tree (on startup) and sysfs (run-time)

Signed-off-by: Csókás Bence <csokas.bence@prolan.hu>
---
 drivers/net/ethernet/freescale/fec_main.c | 37 +++++++++++++++++++++++
 drivers/net/ethernet/freescale/fec_ptp.c  |  3 --
 2 files changed, 37 insertions(+), 3 deletions(-)

Comments

Richard Cochran Aug. 8, 2022, 2:12 p.m. UTC | #1
On Mon, Aug 08, 2022 at 03:15:57PM +0200, Csókás Bence wrote:
> +static ssize_t pps_ch_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
> +{
> +	struct device *dev = container_of(kobj, struct device, kobj);
> +	struct net_device *ndev = to_net_dev(dev);
> +	struct fec_enet_private *fep = netdev_priv(ndev);
> +	int enable = fep->pps_enable;
> +	struct ptp_clock_request ptp_rq = { .type = PTP_CLK_REQ_PPS };
> +
> +	if (enable)
> +		fep->ptp_caps.enable(&fep->ptp_caps, &ptp_rq, 0);
> +
> +	kstrtoint(buf, 0, &fep->pps_channel);
> +
> +	if (enable)
> +		fep->ptp_caps.enable(&fep->ptp_caps, &ptp_rq, 1);

NAK.

Don't use a private, custom sysfs knob.  The core PTP layer provides
an API for that already.

Thanks,
Richard

> +
> +	return count;
> +}
Csókás Bence Aug. 9, 2022, 7:36 a.m. UTC | #2
Hi!

>On Mon, Aug 08, 2022 at 03:15:57PM +0200, Csókás Bence wrote:
>> +static ssize_t pps_ch_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
>> +{
>> +     struct device *dev = container_of(kobj, struct device, kobj);
>> +     struct net_device *ndev = to_net_dev(dev);
>> +     struct fec_enet_private *fep = netdev_priv(ndev);
>> +     int enable = fep->pps_enable;
>> +     struct ptp_clock_request ptp_rq = { .type = PTP_CLK_REQ_PPS };
>> +
>> +     if (enable)
>> +             fep->ptp_caps.enable(&fep->ptp_caps, &ptp_rq, 0);
>> +
>> +     kstrtoint(buf, 0, &fep->pps_channel);
>> +
>> +     if (enable)
>> +             fep->ptp_caps.enable(&fep->ptp_caps, &ptp_rq, 1);
>
> NAK.
>
> Don't use a private, custom sysfs knob.  The core PTP layer provides
> an API for that already.

Does it? I seem to have missed it. Can you point me at some docs?
Also, does it have support for setting pulse mode (i.e. high, low, toggle)?

> Thanks,
> Richard

Thanks,
Bence

>
>> +
>> +     return count;
>> +}
Richard Cochran Aug. 9, 2022, 8:52 p.m. UTC | #3
On Tue, Aug 09, 2022 at 07:36:55AM +0000, Csókás Bence wrote:
> > Don't use a private, custom sysfs knob.  The core PTP layer provides
> > an API for that already.
> 
> Does it? I seem to have missed it. Can you point me at some docs?

See include/uapi/linux/ptp_clock.h:

/*
 * Bits of the ptp_perout_request.flags field:
 */
#define PTP_PEROUT_ONE_SHOT		(1<<0)
#define PTP_PEROUT_DUTY_CYCLE		(1<<1)
#define PTP_PEROUT_PHASE		(1<<2)

/*
 * flag fields valid for the new PTP_PEROUT_REQUEST2 ioctl.
 */
#define PTP_PEROUT_VALID_FLAGS		(PTP_PEROUT_ONE_SHOT | \
					 PTP_PEROUT_DUTY_CYCLE | \
					 PTP_PEROUT_PHASE)

...

struct ptp_perout_request {
	union {
		/*
		 * Absolute start time.
		 * Valid only if (flags & PTP_PEROUT_PHASE) is unset.
		 */
		struct ptp_clock_time start;
		/*
		 * Phase offset. The signal should start toggling at an
		 * unspecified integer multiple of the period, plus this value.
		 * The start time should be "as soon as possible".
		 * Valid only if (flags & PTP_PEROUT_PHASE) is set.
		 */
		struct ptp_clock_time phase;
	};
	struct ptp_clock_time period; /* Desired period, zero means disable. */
	unsigned int index;           /* Which channel to configure. */
	unsigned int flags;
	union {
		/*
		 * The "on" time of the signal.
		 * Must be lower than the period.
		 * Valid only if (flags & PTP_PEROUT_DUTY_CYCLE) is set.
		 */
		struct ptp_clock_time on;
		/* Reserved for future use. */
		unsigned int rsv[4];
	};
};


There is also an API to select pins, with ptp_pin_function,
ptp_pin_desc, PTP_PIN_GETFUNC, PTP_PIN_SETFUNC.

> Also, does it have support for setting pulse mode (i.e. high, low, toggle)?

You can produce a signal with any duty cycle that you wish.  No
support for inverted output, but you could add it if it is important
to you.

Thanks,
Richard
diff mbox series

Patch

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 4112c1283c40..0c1c489c3826 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -47,6 +47,7 @@ 
 #include <linux/bitops.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/kobject.h>
 #include <linux/clk.h>
 #include <linux/crc32.h>
 #include <linux/platform_device.h>
@@ -3609,6 +3610,36 @@  static int fec_enet_init_stop_mode(struct fec_enet_private *fep,
 	return ret;
 }
 
+static ssize_t pps_ch_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct net_device *ndev = to_net_dev(dev);
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	return sprintf(buf, "%d", fep->pps_channel);
+}
+
+static ssize_t pps_ch_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct net_device *ndev = to_net_dev(dev);
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	int enable = fep->pps_enable;
+	struct ptp_clock_request ptp_rq = { .type = PTP_CLK_REQ_PPS };
+
+	if (enable)
+		fep->ptp_caps.enable(&fep->ptp_caps, &ptp_rq, 0);
+
+	kstrtoint(buf, 0, &fep->pps_channel);
+
+	if (enable)
+		fep->ptp_caps.enable(&fep->ptp_caps, &ptp_rq, 1);
+
+	return count;
+}
+
+struct kobj_attribute pps_ch_attr = __ATTR(pps_channel, 0660, pps_ch_show, pps_ch_store);
+
 static int
 fec_probe(struct platform_device *pdev)
 {
@@ -3705,6 +3736,9 @@  fec_probe(struct platform_device *pdev)
 		fep->phy_interface = interface;
 	}
 
+	if (of_property_read_u32(np, "fsl,pps-channel", &fep->pps_channel))
+		fep->pps_channel = 0;
+
 	fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
 	if (IS_ERR(fep->clk_ipg)) {
 		ret = PTR_ERR(fep->clk_ipg);
@@ -3817,6 +3851,9 @@  fec_probe(struct platform_device *pdev)
 	if (ret)
 		goto failed_register;
 
+	if (sysfs_create_file(&ndev->dev.kobj, &pps_ch_attr.attr))
+		pr_err("Cannot create pps_channel sysfs file\n");
+
 	device_init_wakeup(&ndev->dev, fep->wol_flag &
 			   FEC_WOL_HAS_MAGIC_PACKET);
 
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index 69dfed4de4ef..a5077eff305b 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -86,8 +86,6 @@ 
 #define FEC_CC_MULT	(1 << 31)
 #define FEC_COUNTER_PERIOD	(1 << 31)
 #define PPS_OUPUT_RELOAD_PERIOD	NSEC_PER_SEC
-#define FEC_CHANNLE_0		0
-#define DEFAULT_PPS_CHANNEL	FEC_CHANNLE_0
 
 /**
  * fec_ptp_enable_pps
@@ -112,7 +110,6 @@  static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable)
 	if (fep->pps_enable == enable)
 		return 0;
 
-	fep->pps_channel = DEFAULT_PPS_CHANNEL;
 	fep->reload_period = PPS_OUPUT_RELOAD_PERIOD;
 
 	spin_lock_irqsave(&fep->tmreg_lock, flags);