aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/dp83640.c
diff options
context:
space:
mode:
authorRichard Cochran <richardcochran@gmail.com>2011-09-19 21:43:14 -0400
committerDavid S. Miller <davem@davemloft.net>2011-09-26 16:02:43 -0400
commit49b3fd4aff7ede794d4fe50b80095eb33cc9d911 (patch)
tree3f2c723c3ea48ebc61f07f9679db7e7f19ba3d3d /drivers/net/phy/dp83640.c
parent7777de9af54a1402c79bf7663b38ff5ba308dd45 (diff)
dp83640: enable six external events and one periodic output
This patch enables six external event channels and one periodic output. One GPIO is reserved for synchronizing multiple PHYs. The assignment of GPIO functions can be changed via a module parameter. The code supports multiple simultaneous events by inducing a PTP clock event for every channel marked in the PHY's extended status word. Signed-off-by: Richard Cochran <richard.cochran@omicron.at> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy/dp83640.c')
-rw-r--r--drivers/net/phy/dp83640.c135
1 files changed, 116 insertions, 19 deletions
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index cb6e0b486b1e..f99937905bda 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -35,16 +35,15 @@
35#define LAYER4 0x02 35#define LAYER4 0x02
36#define LAYER2 0x01 36#define LAYER2 0x01
37#define MAX_RXTS 64 37#define MAX_RXTS 64
38#define N_EXT_TS 1 38#define N_EXT_TS 6
39#define PSF_PTPVER 2 39#define PSF_PTPVER 2
40#define PSF_EVNT 0x4000 40#define PSF_EVNT 0x4000
41#define PSF_RX 0x2000 41#define PSF_RX 0x2000
42#define PSF_TX 0x1000 42#define PSF_TX 0x1000
43#define EXT_EVENT 1 43#define EXT_EVENT 1
44#define EXT_GPIO 1 44#define CAL_EVENT 7
45#define CAL_EVENT 2 45#define CAL_TRIGGER 7
46#define CAL_GPIO 9 46#define PER_TRIGGER 6
47#define CAL_TRIGGER 2
48 47
49/* phyter seems to miss the mark by 16 ns */ 48/* phyter seems to miss the mark by 16 ns */
50#define ADJTIME_FIX 16 49#define ADJTIME_FIX 16
@@ -131,16 +130,30 @@ struct dp83640_clock {
131 130
132/* globals */ 131/* globals */
133 132
133enum {
134 CALIBRATE_GPIO,
135 PEROUT_GPIO,
136 EXTTS0_GPIO,
137 EXTTS1_GPIO,
138 EXTTS2_GPIO,
139 EXTTS3_GPIO,
140 EXTTS4_GPIO,
141 EXTTS5_GPIO,
142 GPIO_TABLE_SIZE
143};
144
134static int chosen_phy = -1; 145static int chosen_phy = -1;
135static ushort cal_gpio = 4; 146static ushort gpio_tab[GPIO_TABLE_SIZE] = {
147 1, 2, 3, 4, 8, 9, 10, 11
148};
136 149
137module_param(chosen_phy, int, 0444); 150module_param(chosen_phy, int, 0444);
138module_param(cal_gpio, ushort, 0444); 151module_param_array(gpio_tab, ushort, NULL, 0444);
139 152
140MODULE_PARM_DESC(chosen_phy, \ 153MODULE_PARM_DESC(chosen_phy, \
141 "The address of the PHY to use for the ancillary clock features"); 154 "The address of the PHY to use for the ancillary clock features");
142MODULE_PARM_DESC(cal_gpio, \ 155MODULE_PARM_DESC(gpio_tab, \
143 "Which GPIO line to use for synchronizing multiple PHYs"); 156 "Which GPIO line to use for which purpose: cal,perout,extts1,...,extts6");
144 157
145/* a list of clocks and a mutex to protect it */ 158/* a list of clocks and a mutex to protect it */
146static LIST_HEAD(phyter_clocks); 159static LIST_HEAD(phyter_clocks);
@@ -235,6 +248,61 @@ static u64 phy2txts(struct phy_txts *p)
235 return ns; 248 return ns;
236} 249}
237 250
251static void periodic_output(struct dp83640_clock *clock,
252 struct ptp_clock_request *clkreq, bool on)
253{
254 struct dp83640_private *dp83640 = clock->chosen;
255 struct phy_device *phydev = dp83640->phydev;
256 u32 sec, nsec, period;
257 u16 gpio, ptp_trig, trigger, val;
258
259 gpio = on ? gpio_tab[PEROUT_GPIO] : 0;
260 trigger = PER_TRIGGER;
261
262 ptp_trig = TRIG_WR |
263 (trigger & TRIG_CSEL_MASK) << TRIG_CSEL_SHIFT |
264 (gpio & TRIG_GPIO_MASK) << TRIG_GPIO_SHIFT |
265 TRIG_PER |
266 TRIG_PULSE;
267
268 val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT;
269
270 if (!on) {
271 val |= TRIG_DIS;
272 mutex_lock(&clock->extreg_lock);
273 ext_write(0, phydev, PAGE5, PTP_TRIG, ptp_trig);
274 ext_write(0, phydev, PAGE4, PTP_CTL, val);
275 mutex_unlock(&clock->extreg_lock);
276 return;
277 }
278
279 sec = clkreq->perout.start.sec;
280 nsec = clkreq->perout.start.nsec;
281 period = clkreq->perout.period.sec * 1000000000UL;
282 period += clkreq->perout.period.nsec;
283
284 mutex_lock(&clock->extreg_lock);
285
286 ext_write(0, phydev, PAGE5, PTP_TRIG, ptp_trig);
287
288 /*load trigger*/
289 val |= TRIG_LOAD;
290 ext_write(0, phydev, PAGE4, PTP_CTL, val);
291 ext_write(0, phydev, PAGE4, PTP_TDR, nsec & 0xffff); /* ns[15:0] */
292 ext_write(0, phydev, PAGE4, PTP_TDR, nsec >> 16); /* ns[31:16] */
293 ext_write(0, phydev, PAGE4, PTP_TDR, sec & 0xffff); /* sec[15:0] */
294 ext_write(0, phydev, PAGE4, PTP_TDR, sec >> 16); /* sec[31:16] */
295 ext_write(0, phydev, PAGE4, PTP_TDR, period & 0xffff); /* ns[15:0] */
296 ext_write(0, phydev, PAGE4, PTP_TDR, period >> 16); /* ns[31:16] */
297
298 /*enable trigger*/
299 val &= ~TRIG_LOAD;
300 val |= TRIG_EN;
301 ext_write(0, phydev, PAGE4, PTP_CTL, val);
302
303 mutex_unlock(&clock->extreg_lock);
304}
305
238/* ptp clock methods */ 306/* ptp clock methods */
239 307
240static int ptp_dp83640_adjfreq(struct ptp_clock_info *ptp, s32 ppb) 308static int ptp_dp83640_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
@@ -338,19 +406,30 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
338 struct dp83640_clock *clock = 406 struct dp83640_clock *clock =
339 container_of(ptp, struct dp83640_clock, caps); 407 container_of(ptp, struct dp83640_clock, caps);
340 struct phy_device *phydev = clock->chosen->phydev; 408 struct phy_device *phydev = clock->chosen->phydev;
341 u16 evnt; 409 int index;
410 u16 evnt, event_num, gpio_num;
342 411
343 switch (rq->type) { 412 switch (rq->type) {
344 case PTP_CLK_REQ_EXTTS: 413 case PTP_CLK_REQ_EXTTS:
345 if (rq->extts.index != 0) 414 index = rq->extts.index;
415 if (index < 0 || index >= N_EXT_TS)
346 return -EINVAL; 416 return -EINVAL;
347 evnt = EVNT_WR | (EXT_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT; 417 event_num = EXT_EVENT + index;
418 evnt = EVNT_WR | (event_num & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
348 if (on) { 419 if (on) {
349 evnt |= (EXT_GPIO & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT; 420 gpio_num = gpio_tab[EXTTS0_GPIO + index];
421 evnt |= (gpio_num & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
350 evnt |= EVNT_RISE; 422 evnt |= EVNT_RISE;
351 } 423 }
352 ext_write(0, phydev, PAGE5, PTP_EVNT, evnt); 424 ext_write(0, phydev, PAGE5, PTP_EVNT, evnt);
353 return 0; 425 return 0;
426
427 case PTP_CLK_REQ_PEROUT:
428 if (rq->perout.index != 0)
429 return -EINVAL;
430 periodic_output(clock, rq, on);
431 return 0;
432
354 default: 433 default:
355 break; 434 break;
356 } 435 }
@@ -441,9 +520,10 @@ static void recalibrate(struct dp83640_clock *clock)
441 struct list_head *this; 520 struct list_head *this;
442 struct dp83640_private *tmp; 521 struct dp83640_private *tmp;
443 struct phy_device *master = clock->chosen->phydev; 522 struct phy_device *master = clock->chosen->phydev;
444 u16 cfg0, evnt, ptp_trig, trigger, val; 523 u16 cal_gpio, cfg0, evnt, ptp_trig, trigger, val;
445 524
446 trigger = CAL_TRIGGER; 525 trigger = CAL_TRIGGER;
526 cal_gpio = gpio_tab[CALIBRATE_GPIO];
447 527
448 mutex_lock(&clock->extreg_lock); 528 mutex_lock(&clock->extreg_lock);
449 529
@@ -542,11 +622,17 @@ static void recalibrate(struct dp83640_clock *clock)
542 622
543/* time stamping methods */ 623/* time stamping methods */
544 624
625static inline u16 exts_chan_to_edata(int ch)
626{
627 return 1 << ((ch + EXT_EVENT) * 2);
628}
629
545static int decode_evnt(struct dp83640_private *dp83640, 630static int decode_evnt(struct dp83640_private *dp83640,
546 void *data, u16 ests) 631 void *data, u16 ests)
547{ 632{
548 struct phy_txts *phy_txts; 633 struct phy_txts *phy_txts;
549 struct ptp_clock_event event; 634 struct ptp_clock_event event;
635 int i, parsed;
550 int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK; 636 int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK;
551 u16 ext_status = 0; 637 u16 ext_status = 0;
552 638
@@ -568,14 +654,25 @@ static int decode_evnt(struct dp83640_private *dp83640,
568 dp83640->edata.ns_lo = phy_txts->ns_lo; 654 dp83640->edata.ns_lo = phy_txts->ns_lo;
569 } 655 }
570 656
657 if (ext_status) {
658 parsed = words + 2;
659 } else {
660 parsed = words + 1;
661 i = ((ests >> EVNT_NUM_SHIFT) & EVNT_NUM_MASK) - EXT_EVENT;
662 ext_status = exts_chan_to_edata(i);
663 }
664
571 event.type = PTP_CLOCK_EXTTS; 665 event.type = PTP_CLOCK_EXTTS;
572 event.index = 0;
573 event.timestamp = phy2txts(&dp83640->edata); 666 event.timestamp = phy2txts(&dp83640->edata);
574 667
575 ptp_clock_event(dp83640->clock->ptp_clock, &event); 668 for (i = 0; i < N_EXT_TS; i++) {
669 if (ext_status & exts_chan_to_edata(i)) {
670 event.index = i;
671 ptp_clock_event(dp83640->clock->ptp_clock, &event);
672 }
673 }
576 674
577 words = ext_status ? words + 2 : words + 1; 675 return parsed * sizeof(u16);
578 return words * sizeof(u16);
579} 676}
580 677
581static void decode_rxts(struct dp83640_private *dp83640, 678static void decode_rxts(struct dp83640_private *dp83640,
@@ -740,7 +837,7 @@ static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus)
740 clock->caps.max_adj = 1953124; 837 clock->caps.max_adj = 1953124;
741 clock->caps.n_alarm = 0; 838 clock->caps.n_alarm = 0;
742 clock->caps.n_ext_ts = N_EXT_TS; 839 clock->caps.n_ext_ts = N_EXT_TS;
743 clock->caps.n_per_out = 0; 840 clock->caps.n_per_out = 1;
744 clock->caps.pps = 0; 841 clock->caps.pps = 0;
745 clock->caps.adjfreq = ptp_dp83640_adjfreq; 842 clock->caps.adjfreq = ptp_dp83640_adjfreq;
746 clock->caps.adjtime = ptp_dp83640_adjtime; 843 clock->caps.adjtime = ptp_dp83640_adjtime;