ptp: introduce programmable pins.

This patch adds a pair of new ioctls to the PTP Hardware Clock device
interface. Using the ioctls, user space programs can query each pin to
find out its current function and also reprogram a different function
if desired.

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h
index 38a9935..0d8ff3f 100644
--- a/include/linux/ptp_clock_kernel.h
+++ b/include/linux/ptp_clock_kernel.h
@@ -49,7 +49,11 @@
  * @n_alarm:   The number of programmable alarms.
  * @n_ext_ts:  The number of external time stamp channels.
  * @n_per_out: The number of programmable periodic signals.
+ * @n_pins:    The number of programmable pins.
  * @pps:       Indicates whether the clock supports a PPS callback.
+ * @pin_config: Array of length 'n_pins'. If the number of
+ *              programmable pins is nonzero, then drivers must
+ *              allocate and initialize this array.
  *
  * clock operations
  *
@@ -70,6 +74,18 @@
  *            parameter request: Desired resource to enable or disable.
  *            parameter on: Caller passes one to enable or zero to disable.
  *
+ * @verify:   Confirm that a pin can perform a given function. The PTP
+ *            Hardware Clock subsystem maintains the 'pin_config'
+ *            array on behalf of the drivers, but the PHC subsystem
+ *            assumes that every pin can perform every function. This
+ *            hook gives drivers a way of telling the core about
+ *            limitations on specific pins. This function must return
+ *            zero if the function can be assigned to this pin, and
+ *            nonzero otherwise.
+ *            parameter pin: index of the pin in question.
+ *            parameter func: the desired function to use.
+ *            parameter chan: the function channel index to use.
+ *
  * Drivers should embed their ptp_clock_info within a private
  * structure, obtaining a reference to it using container_of().
  *
@@ -83,13 +99,17 @@
 	int n_alarm;
 	int n_ext_ts;
 	int n_per_out;
+	int n_pins;
 	int pps;
+	struct ptp_pin_desc *pin_config;
 	int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta);
 	int (*adjtime)(struct ptp_clock_info *ptp, s64 delta);
 	int (*gettime)(struct ptp_clock_info *ptp, struct timespec *ts);
 	int (*settime)(struct ptp_clock_info *ptp, const struct timespec *ts);
 	int (*enable)(struct ptp_clock_info *ptp,
 		      struct ptp_clock_request *request, int on);
+	int (*verify)(struct ptp_clock_info *ptp, unsigned int pin,
+		      enum ptp_pin_function func, unsigned int chan);
 };
 
 struct ptp_clock;
@@ -156,4 +176,17 @@
 
 extern int ptp_clock_index(struct ptp_clock *ptp);
 
+/**
+ * ptp_find_pin() - obtain the pin index of a given auxiliary function
+ *
+ * @ptp:    The clock obtained from ptp_clock_register().
+ * @func:   One of the ptp_pin_function enumerated values.
+ * @chan:   The particular functional channel to find.
+ * Return:  Pin index in the range of zero to ptp_clock_caps.n_pins - 1,
+ *          or -1 if the auxiliary function cannot be found.
+ */
+
+int ptp_find_pin(struct ptp_clock *ptp,
+		 enum ptp_pin_function func, unsigned int chan);
+
 #endif
diff --git a/include/uapi/linux/ptp_clock.h b/include/uapi/linux/ptp_clock.h
index b65c834..f0b7bfe 100644
--- a/include/uapi/linux/ptp_clock.h
+++ b/include/uapi/linux/ptp_clock.h
@@ -50,7 +50,8 @@
 	int n_ext_ts;  /* Number of external time stamp channels. */
 	int n_per_out; /* Number of programmable periodic signals. */
 	int pps;       /* Whether the clock supports a PPS callback. */
-	int rsv[15];   /* Reserved for future use. */
+	int n_pins;    /* Number of input/output pins. */
+	int rsv[14];   /* Reserved for future use. */
 };
 
 struct ptp_extts_request {
@@ -80,6 +81,40 @@
 	struct ptp_clock_time ts[2 * PTP_MAX_SAMPLES + 1];
 };
 
+enum ptp_pin_function {
+	PTP_PF_NONE,
+	PTP_PF_EXTTS,
+	PTP_PF_PEROUT,
+	PTP_PF_PHYSYNC,
+};
+
+struct ptp_pin_desc {
+	/*
+	 * Hardware specific human readable pin name. This field is
+	 * set by the kernel during the PTP_PIN_GETFUNC ioctl and is
+	 * ignored for the PTP_PIN_SETFUNC ioctl.
+	 */
+	char name[64];
+	/*
+	 * Pin index in the range of zero to ptp_clock_caps.n_pins - 1.
+	 */
+	unsigned int index;
+	/*
+	 * Which of the PTP_PF_xxx functions to use on this pin.
+	 */
+	unsigned int func;
+	/*
+	 * The specific channel to use for this function.
+	 * This corresponds to the 'index' field of the
+	 * PTP_EXTTS_REQUEST and PTP_PEROUT_REQUEST ioctls.
+	 */
+	unsigned int chan;
+	/*
+	 * Reserved for future use.
+	 */
+	unsigned int rsv[5];
+};
+
 #define PTP_CLK_MAGIC '='
 
 #define PTP_CLOCK_GETCAPS  _IOR(PTP_CLK_MAGIC, 1, struct ptp_clock_caps)
@@ -87,6 +122,8 @@
 #define PTP_PEROUT_REQUEST _IOW(PTP_CLK_MAGIC, 3, struct ptp_perout_request)
 #define PTP_ENABLE_PPS     _IOW(PTP_CLK_MAGIC, 4, int)
 #define PTP_SYS_OFFSET     _IOW(PTP_CLK_MAGIC, 5, struct ptp_sys_offset)
+#define PTP_PIN_GETFUNC    _IOWR(PTP_CLK_MAGIC, 6, struct ptp_pin_desc)
+#define PTP_PIN_SETFUNC    _IOW(PTP_CLK_MAGIC, 7, struct ptp_pin_desc)
 
 struct ptp_extts_event {
 	struct ptp_clock_time t; /* Time event occured. */