diff options
Diffstat (limited to 'drivers/ptp/ptp_chardev.c')
-rw-r--r-- | drivers/ptp/ptp_chardev.c | 128 |
1 files changed, 127 insertions, 1 deletions
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index 34a0c607318e..419056d7887e 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c | |||
@@ -25,6 +25,96 @@ | |||
25 | 25 | ||
26 | #include "ptp_private.h" | 26 | #include "ptp_private.h" |
27 | 27 | ||
28 | static int ptp_disable_pinfunc(struct ptp_clock_info *ops, | ||
29 | enum ptp_pin_function func, unsigned int chan) | ||
30 | { | ||
31 | struct ptp_clock_request rq; | ||
32 | int err = 0; | ||
33 | |||
34 | memset(&rq, 0, sizeof(rq)); | ||
35 | |||
36 | switch (func) { | ||
37 | case PTP_PF_NONE: | ||
38 | break; | ||
39 | case PTP_PF_EXTTS: | ||
40 | rq.type = PTP_CLK_REQ_EXTTS; | ||
41 | rq.extts.index = chan; | ||
42 | err = ops->enable(ops, &rq, 0); | ||
43 | break; | ||
44 | case PTP_PF_PEROUT: | ||
45 | rq.type = PTP_CLK_REQ_PEROUT; | ||
46 | rq.perout.index = chan; | ||
47 | err = ops->enable(ops, &rq, 0); | ||
48 | break; | ||
49 | case PTP_PF_PHYSYNC: | ||
50 | break; | ||
51 | default: | ||
52 | return -EINVAL; | ||
53 | } | ||
54 | |||
55 | return err; | ||
56 | } | ||
57 | |||
58 | int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin, | ||
59 | enum ptp_pin_function func, unsigned int chan) | ||
60 | { | ||
61 | struct ptp_clock_info *info = ptp->info; | ||
62 | struct ptp_pin_desc *pin1 = NULL, *pin2 = &info->pin_config[pin]; | ||
63 | unsigned int i; | ||
64 | |||
65 | /* Check to see if any other pin previously had this function. */ | ||
66 | for (i = 0; i < info->n_pins; i++) { | ||
67 | if (info->pin_config[i].func == func && | ||
68 | info->pin_config[i].chan == chan) { | ||
69 | pin1 = &info->pin_config[i]; | ||
70 | break; | ||
71 | } | ||
72 | } | ||
73 | if (pin1 && i == pin) | ||
74 | return 0; | ||
75 | |||
76 | /* Check the desired function and channel. */ | ||
77 | switch (func) { | ||
78 | case PTP_PF_NONE: | ||
79 | break; | ||
80 | case PTP_PF_EXTTS: | ||
81 | if (chan >= info->n_ext_ts) | ||
82 | return -EINVAL; | ||
83 | break; | ||
84 | case PTP_PF_PEROUT: | ||
85 | if (chan >= info->n_per_out) | ||
86 | return -EINVAL; | ||
87 | break; | ||
88 | case PTP_PF_PHYSYNC: | ||
89 | pr_err("sorry, cannot reassign the calibration pin\n"); | ||
90 | return -EINVAL; | ||
91 | default: | ||
92 | return -EINVAL; | ||
93 | } | ||
94 | |||
95 | if (pin2->func == PTP_PF_PHYSYNC) { | ||
96 | pr_err("sorry, cannot reprogram the calibration pin\n"); | ||
97 | return -EINVAL; | ||
98 | } | ||
99 | |||
100 | if (info->verify(info, pin, func, chan)) { | ||
101 | pr_err("driver cannot use function %u on pin %u\n", func, chan); | ||
102 | return -EOPNOTSUPP; | ||
103 | } | ||
104 | |||
105 | /* Disable whatever function was previously assigned. */ | ||
106 | if (pin1) { | ||
107 | ptp_disable_pinfunc(info, func, chan); | ||
108 | pin1->func = PTP_PF_NONE; | ||
109 | pin1->chan = 0; | ||
110 | } | ||
111 | ptp_disable_pinfunc(info, pin2->func, pin2->chan); | ||
112 | pin2->func = func; | ||
113 | pin2->chan = chan; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
28 | int ptp_open(struct posix_clock *pc, fmode_t fmode) | 118 | int ptp_open(struct posix_clock *pc, fmode_t fmode) |
29 | { | 119 | { |
30 | return 0; | 120 | return 0; |
@@ -35,12 +125,13 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) | |||
35 | struct ptp_clock_caps caps; | 125 | struct ptp_clock_caps caps; |
36 | struct ptp_clock_request req; | 126 | struct ptp_clock_request req; |
37 | struct ptp_sys_offset *sysoff = NULL; | 127 | struct ptp_sys_offset *sysoff = NULL; |
128 | struct ptp_pin_desc pd; | ||
38 | struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); | 129 | struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); |
39 | struct ptp_clock_info *ops = ptp->info; | 130 | struct ptp_clock_info *ops = ptp->info; |
40 | struct ptp_clock_time *pct; | 131 | struct ptp_clock_time *pct; |
41 | struct timespec ts; | 132 | struct timespec ts; |
42 | int enable, err = 0; | 133 | int enable, err = 0; |
43 | unsigned int i; | 134 | unsigned int i, pin_index; |
44 | 135 | ||
45 | switch (cmd) { | 136 | switch (cmd) { |
46 | 137 | ||
@@ -51,6 +142,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) | |||
51 | caps.n_ext_ts = ptp->info->n_ext_ts; | 142 | caps.n_ext_ts = ptp->info->n_ext_ts; |
52 | caps.n_per_out = ptp->info->n_per_out; | 143 | caps.n_per_out = ptp->info->n_per_out; |
53 | caps.pps = ptp->info->pps; | 144 | caps.pps = ptp->info->pps; |
145 | caps.n_pins = ptp->info->n_pins; | ||
54 | if (copy_to_user((void __user *)arg, &caps, sizeof(caps))) | 146 | if (copy_to_user((void __user *)arg, &caps, sizeof(caps))) |
55 | err = -EFAULT; | 147 | err = -EFAULT; |
56 | break; | 148 | break; |
@@ -126,6 +218,40 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) | |||
126 | err = -EFAULT; | 218 | err = -EFAULT; |
127 | break; | 219 | break; |
128 | 220 | ||
221 | case PTP_PIN_GETFUNC: | ||
222 | if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) { | ||
223 | err = -EFAULT; | ||
224 | break; | ||
225 | } | ||
226 | pin_index = pd.index; | ||
227 | if (pin_index >= ops->n_pins) { | ||
228 | err = -EINVAL; | ||
229 | break; | ||
230 | } | ||
231 | if (mutex_lock_interruptible(&ptp->pincfg_mux)) | ||
232 | return -ERESTARTSYS; | ||
233 | pd = ops->pin_config[pin_index]; | ||
234 | mutex_unlock(&ptp->pincfg_mux); | ||
235 | if (!err && copy_to_user((void __user *)arg, &pd, sizeof(pd))) | ||
236 | err = -EFAULT; | ||
237 | break; | ||
238 | |||
239 | case PTP_PIN_SETFUNC: | ||
240 | if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) { | ||
241 | err = -EFAULT; | ||
242 | break; | ||
243 | } | ||
244 | pin_index = pd.index; | ||
245 | if (pin_index >= ops->n_pins) { | ||
246 | err = -EINVAL; | ||
247 | break; | ||
248 | } | ||
249 | if (mutex_lock_interruptible(&ptp->pincfg_mux)) | ||
250 | return -ERESTARTSYS; | ||
251 | err = ptp_set_pinfunc(ptp, pin_index, pd.func, pd.chan); | ||
252 | mutex_unlock(&ptp->pincfg_mux); | ||
253 | break; | ||
254 | |||
129 | default: | 255 | default: |
130 | err = -ENOTTY; | 256 | err = -ENOTTY; |
131 | break; | 257 | break; |