diff options
author | Takahiro Shimizu <tshimizu818@gmail.com> | 2012-03-07 17:16:26 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-03-09 16:55:34 -0500 |
commit | 863d08ece9bf11043541e8017cfbdd16b800fbe5 (patch) | |
tree | 3974d8ffc9c4da70094f6cf6eb5989d7f934cc9b /drivers/ptp | |
parent | 74dd1521d0b4f940cdd3ce7b9d988836bef589b8 (diff) |
supports eg20t ptp clock
Supports EG20T ptp clock in the driver
Changes e-mail address.
Adds number.
Signed-off-by: Takahiro Shimizu <tshimizu818@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/ptp')
-rw-r--r-- | drivers/ptp/Kconfig | 13 | ||||
-rw-r--r-- | drivers/ptp/Makefile | 1 | ||||
-rw-r--r-- | drivers/ptp/ptp_pch.c | 730 |
3 files changed, 744 insertions, 0 deletions
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index 68d720102296..cd9bc3b129bc 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig | |||
@@ -72,4 +72,17 @@ config DP83640_PHY | |||
72 | In order for this to work, your MAC driver must also | 72 | In order for this to work, your MAC driver must also |
73 | implement the skb_tx_timetamp() function. | 73 | implement the skb_tx_timetamp() function. |
74 | 74 | ||
75 | config PTP_1588_CLOCK_PCH | ||
76 | tristate "Intel PCH EG20T as PTP clock" | ||
77 | depends on PTP_1588_CLOCK | ||
78 | depends on PCH_GBE | ||
79 | help | ||
80 | This driver adds support for using the PCH EG20T as a PTP | ||
81 | clock. This clock is only useful if your PTP programs are | ||
82 | getting hardware time stamps on the PTP Ethernet packets | ||
83 | using the SO_TIMESTAMPING API. | ||
84 | |||
85 | To compile this driver as a module, choose M here: the module | ||
86 | will be called ptp_pch. | ||
87 | |||
75 | endmenu | 88 | endmenu |
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile index f6933e83de72..8b58597298de 100644 --- a/drivers/ptp/Makefile +++ b/drivers/ptp/Makefile | |||
@@ -5,3 +5,4 @@ | |||
5 | ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o | 5 | ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o |
6 | obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o | 6 | obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o |
7 | obj-$(CONFIG_PTP_1588_CLOCK_IXP46X) += ptp_ixp46x.o | 7 | obj-$(CONFIG_PTP_1588_CLOCK_IXP46X) += ptp_ixp46x.o |
8 | obj-$(CONFIG_PTP_1588_CLOCK_PCH) += ptp_pch.o | ||
diff --git a/drivers/ptp/ptp_pch.c b/drivers/ptp/ptp_pch.c new file mode 100644 index 000000000000..0b38ee1b0f85 --- /dev/null +++ b/drivers/ptp/ptp_pch.c | |||
@@ -0,0 +1,730 @@ | |||
1 | /* | ||
2 | * PTP 1588 clock using the EG20T PCH | ||
3 | * | ||
4 | * Copyright (C) 2010 OMICRON electronics GmbH | ||
5 | * Copyright (C) 2011-2012 LAPIS SEMICONDUCTOR Co., LTD. | ||
6 | * | ||
7 | * This code was derived from the IXP46X driver. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/device.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/pci.h> | ||
32 | #include <linux/ptp_clock_kernel.h> | ||
33 | |||
34 | #define STATION_ADDR_LEN 20 | ||
35 | #define PCI_DEVICE_ID_PCH_1588 0x8819 | ||
36 | #define IO_MEM_BAR 1 | ||
37 | |||
38 | #define DEFAULT_ADDEND 0xA0000000 | ||
39 | #define TICKS_NS_SHIFT 5 | ||
40 | #define N_EXT_TS 2 | ||
41 | |||
42 | enum pch_status { | ||
43 | PCH_SUCCESS, | ||
44 | PCH_INVALIDPARAM, | ||
45 | PCH_NOTIMESTAMP, | ||
46 | PCH_INTERRUPTMODEINUSE, | ||
47 | PCH_FAILED, | ||
48 | PCH_UNSUPPORTED, | ||
49 | }; | ||
50 | /** | ||
51 | * struct pch_ts_regs - IEEE 1588 registers | ||
52 | */ | ||
53 | struct pch_ts_regs { | ||
54 | u32 control; | ||
55 | u32 event; | ||
56 | u32 addend; | ||
57 | u32 accum; | ||
58 | u32 test; | ||
59 | u32 ts_compare; | ||
60 | u32 rsystime_lo; | ||
61 | u32 rsystime_hi; | ||
62 | u32 systime_lo; | ||
63 | u32 systime_hi; | ||
64 | u32 trgt_lo; | ||
65 | u32 trgt_hi; | ||
66 | u32 asms_lo; | ||
67 | u32 asms_hi; | ||
68 | u32 amms_lo; | ||
69 | u32 amms_hi; | ||
70 | u32 ch_control; | ||
71 | u32 ch_event; | ||
72 | u32 tx_snap_lo; | ||
73 | u32 tx_snap_hi; | ||
74 | u32 rx_snap_lo; | ||
75 | u32 rx_snap_hi; | ||
76 | u32 src_uuid_lo; | ||
77 | u32 src_uuid_hi; | ||
78 | u32 can_status; | ||
79 | u32 can_snap_lo; | ||
80 | u32 can_snap_hi; | ||
81 | u32 ts_sel; | ||
82 | u32 ts_st[6]; | ||
83 | u32 reserve1[14]; | ||
84 | u32 stl_max_set_en; | ||
85 | u32 stl_max_set; | ||
86 | u32 reserve2[13]; | ||
87 | u32 srst; | ||
88 | }; | ||
89 | |||
90 | #define PCH_TSC_RESET (1 << 0) | ||
91 | #define PCH_TSC_TTM_MASK (1 << 1) | ||
92 | #define PCH_TSC_ASMS_MASK (1 << 2) | ||
93 | #define PCH_TSC_AMMS_MASK (1 << 3) | ||
94 | #define PCH_TSC_PPSM_MASK (1 << 4) | ||
95 | #define PCH_TSE_TTIPEND (1 << 1) | ||
96 | #define PCH_TSE_SNS (1 << 2) | ||
97 | #define PCH_TSE_SNM (1 << 3) | ||
98 | #define PCH_TSE_PPS (1 << 4) | ||
99 | #define PCH_CC_MM (1 << 0) | ||
100 | #define PCH_CC_TA (1 << 1) | ||
101 | |||
102 | #define PCH_CC_MODE_SHIFT 16 | ||
103 | #define PCH_CC_MODE_MASK 0x001F0000 | ||
104 | #define PCH_CC_VERSION (1 << 31) | ||
105 | #define PCH_CE_TXS (1 << 0) | ||
106 | #define PCH_CE_RXS (1 << 1) | ||
107 | #define PCH_CE_OVR (1 << 0) | ||
108 | #define PCH_CE_VAL (1 << 1) | ||
109 | #define PCH_ECS_ETH (1 << 0) | ||
110 | |||
111 | #define PCH_ECS_CAN (1 << 1) | ||
112 | #define PCH_STATION_BYTES 6 | ||
113 | |||
114 | #define PCH_IEEE1588_ETH (1 << 0) | ||
115 | #define PCH_IEEE1588_CAN (1 << 1) | ||
116 | /** | ||
117 | * struct pch_dev - Driver private data | ||
118 | */ | ||
119 | struct pch_dev { | ||
120 | struct pch_ts_regs *regs; | ||
121 | struct ptp_clock *ptp_clock; | ||
122 | struct ptp_clock_info caps; | ||
123 | int exts0_enabled; | ||
124 | int exts1_enabled; | ||
125 | |||
126 | u32 mem_base; | ||
127 | u32 mem_size; | ||
128 | u32 irq; | ||
129 | struct pci_dev *pdev; | ||
130 | spinlock_t register_lock; | ||
131 | }; | ||
132 | |||
133 | /** | ||
134 | * struct pch_params - 1588 module parameter | ||
135 | */ | ||
136 | struct pch_params { | ||
137 | u8 station[STATION_ADDR_LEN]; | ||
138 | }; | ||
139 | |||
140 | /* structure to hold the module parameters */ | ||
141 | static struct pch_params pch_param = { | ||
142 | "00:00:00:00:00:00" | ||
143 | }; | ||
144 | |||
145 | /* | ||
146 | * Register access functions | ||
147 | */ | ||
148 | static inline void pch_eth_enable_set(struct pch_dev *chip) | ||
149 | { | ||
150 | u32 val; | ||
151 | /* SET the eth_enable bit */ | ||
152 | val = ioread32(&chip->regs->ts_sel) | (PCH_ECS_ETH); | ||
153 | iowrite32(val, (&chip->regs->ts_sel)); | ||
154 | } | ||
155 | |||
156 | static u64 pch_systime_read(struct pch_ts_regs *regs) | ||
157 | { | ||
158 | u64 ns; | ||
159 | u32 lo, hi; | ||
160 | |||
161 | lo = ioread32(®s->systime_lo); | ||
162 | hi = ioread32(®s->systime_hi); | ||
163 | |||
164 | ns = ((u64) hi) << 32; | ||
165 | ns |= lo; | ||
166 | ns <<= TICKS_NS_SHIFT; | ||
167 | |||
168 | return ns; | ||
169 | } | ||
170 | |||
171 | static void pch_systime_write(struct pch_ts_regs *regs, u64 ns) | ||
172 | { | ||
173 | u32 hi, lo; | ||
174 | |||
175 | ns >>= TICKS_NS_SHIFT; | ||
176 | hi = ns >> 32; | ||
177 | lo = ns & 0xffffffff; | ||
178 | |||
179 | iowrite32(lo, ®s->systime_lo); | ||
180 | iowrite32(hi, ®s->systime_hi); | ||
181 | } | ||
182 | |||
183 | static inline void pch_block_reset(struct pch_dev *chip) | ||
184 | { | ||
185 | u32 val; | ||
186 | /* Reset Hardware Assist block */ | ||
187 | val = ioread32(&chip->regs->control) | PCH_TSC_RESET; | ||
188 | iowrite32(val, (&chip->regs->control)); | ||
189 | val = val & ~PCH_TSC_RESET; | ||
190 | iowrite32(val, (&chip->regs->control)); | ||
191 | } | ||
192 | |||
193 | u32 pch_ch_control_read(struct pci_dev *pdev) | ||
194 | { | ||
195 | struct pch_dev *chip = pci_get_drvdata(pdev); | ||
196 | u32 val; | ||
197 | |||
198 | val = ioread32(&chip->regs->ch_control); | ||
199 | |||
200 | return val; | ||
201 | } | ||
202 | EXPORT_SYMBOL(pch_ch_control_read); | ||
203 | |||
204 | void pch_ch_control_write(struct pci_dev *pdev, u32 val) | ||
205 | { | ||
206 | struct pch_dev *chip = pci_get_drvdata(pdev); | ||
207 | |||
208 | iowrite32(val, (&chip->regs->ch_control)); | ||
209 | } | ||
210 | EXPORT_SYMBOL(pch_ch_control_write); | ||
211 | |||
212 | u32 pch_ch_event_read(struct pci_dev *pdev) | ||
213 | { | ||
214 | struct pch_dev *chip = pci_get_drvdata(pdev); | ||
215 | u32 val; | ||
216 | |||
217 | val = ioread32(&chip->regs->ch_event); | ||
218 | |||
219 | return val; | ||
220 | } | ||
221 | EXPORT_SYMBOL(pch_ch_event_read); | ||
222 | |||
223 | void pch_ch_event_write(struct pci_dev *pdev, u32 val) | ||
224 | { | ||
225 | struct pch_dev *chip = pci_get_drvdata(pdev); | ||
226 | |||
227 | iowrite32(val, (&chip->regs->ch_event)); | ||
228 | } | ||
229 | EXPORT_SYMBOL(pch_ch_event_write); | ||
230 | |||
231 | u32 pch_src_uuid_lo_read(struct pci_dev *pdev) | ||
232 | { | ||
233 | struct pch_dev *chip = pci_get_drvdata(pdev); | ||
234 | u32 val; | ||
235 | |||
236 | val = ioread32(&chip->regs->src_uuid_lo); | ||
237 | |||
238 | return val; | ||
239 | } | ||
240 | EXPORT_SYMBOL(pch_src_uuid_lo_read); | ||
241 | |||
242 | u32 pch_src_uuid_hi_read(struct pci_dev *pdev) | ||
243 | { | ||
244 | struct pch_dev *chip = pci_get_drvdata(pdev); | ||
245 | u32 val; | ||
246 | |||
247 | val = ioread32(&chip->regs->src_uuid_hi); | ||
248 | |||
249 | return val; | ||
250 | } | ||
251 | EXPORT_SYMBOL(pch_src_uuid_hi_read); | ||
252 | |||
253 | u64 pch_rx_snap_read(struct pci_dev *pdev) | ||
254 | { | ||
255 | struct pch_dev *chip = pci_get_drvdata(pdev); | ||
256 | u64 ns; | ||
257 | u32 lo, hi; | ||
258 | |||
259 | lo = ioread32(&chip->regs->rx_snap_lo); | ||
260 | hi = ioread32(&chip->regs->rx_snap_hi); | ||
261 | |||
262 | ns = ((u64) hi) << 32; | ||
263 | ns |= lo; | ||
264 | |||
265 | return ns; | ||
266 | } | ||
267 | EXPORT_SYMBOL(pch_rx_snap_read); | ||
268 | |||
269 | u64 pch_tx_snap_read(struct pci_dev *pdev) | ||
270 | { | ||
271 | struct pch_dev *chip = pci_get_drvdata(pdev); | ||
272 | u64 ns; | ||
273 | u32 lo, hi; | ||
274 | |||
275 | lo = ioread32(&chip->regs->tx_snap_lo); | ||
276 | hi = ioread32(&chip->regs->tx_snap_hi); | ||
277 | |||
278 | ns = ((u64) hi) << 32; | ||
279 | ns |= lo; | ||
280 | |||
281 | return ns; | ||
282 | } | ||
283 | EXPORT_SYMBOL(pch_tx_snap_read); | ||
284 | |||
285 | /* This function enables all 64 bits in system time registers [high & low]. | ||
286 | This is a work-around for non continuous value in the SystemTime Register*/ | ||
287 | static void pch_set_system_time_count(struct pch_dev *chip) | ||
288 | { | ||
289 | iowrite32(0x01, &chip->regs->stl_max_set_en); | ||
290 | iowrite32(0xFFFFFFFF, &chip->regs->stl_max_set); | ||
291 | iowrite32(0x00, &chip->regs->stl_max_set_en); | ||
292 | } | ||
293 | |||
294 | static void pch_reset(struct pch_dev *chip) | ||
295 | { | ||
296 | /* Reset Hardware Assist */ | ||
297 | pch_block_reset(chip); | ||
298 | |||
299 | /* enable all 32 bits in system time registers */ | ||
300 | pch_set_system_time_count(chip); | ||
301 | } | ||
302 | |||
303 | /** | ||
304 | * pch_set_station_address() - This API sets the station address used by | ||
305 | * IEEE 1588 hardware when looking at PTP | ||
306 | * traffic on the ethernet interface | ||
307 | * @addr: dress which contain the column separated address to be used. | ||
308 | */ | ||
309 | static int pch_set_station_address(u8 *addr, struct pci_dev *pdev) | ||
310 | { | ||
311 | s32 i; | ||
312 | struct pch_dev *chip = pci_get_drvdata(pdev); | ||
313 | |||
314 | /* Verify the parameter */ | ||
315 | if ((chip->regs == 0) || addr == (u8 *)NULL) { | ||
316 | dev_err(&pdev->dev, | ||
317 | "invalid params returning PCH_INVALIDPARAM\n"); | ||
318 | return PCH_INVALIDPARAM; | ||
319 | } | ||
320 | /* For all station address bytes */ | ||
321 | for (i = 0; i < PCH_STATION_BYTES; i++) { | ||
322 | u32 val; | ||
323 | s32 tmp; | ||
324 | |||
325 | tmp = hex_to_bin(addr[i * 3]); | ||
326 | if (tmp < 0) { | ||
327 | dev_err(&pdev->dev, | ||
328 | "invalid params returning PCH_INVALIDPARAM\n"); | ||
329 | return PCH_INVALIDPARAM; | ||
330 | } | ||
331 | val = tmp * 16; | ||
332 | tmp = hex_to_bin(addr[(i * 3) + 1]); | ||
333 | if (tmp < 0) { | ||
334 | dev_err(&pdev->dev, | ||
335 | "invalid params returning PCH_INVALIDPARAM\n"); | ||
336 | return PCH_INVALIDPARAM; | ||
337 | } | ||
338 | val += tmp; | ||
339 | /* Expects ':' separated addresses */ | ||
340 | if ((i < 5) && (addr[(i * 3) + 2] != ':')) { | ||
341 | dev_err(&pdev->dev, | ||
342 | "invalid params returning PCH_INVALIDPARAM\n"); | ||
343 | return PCH_INVALIDPARAM; | ||
344 | } | ||
345 | |||
346 | /* Ideally we should set the address only after validating | ||
347 | entire string */ | ||
348 | dev_dbg(&pdev->dev, "invoking pch_station_set\n"); | ||
349 | iowrite32(val, &chip->regs->ts_st[i]); | ||
350 | } | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | /* | ||
355 | * Interrupt service routine | ||
356 | */ | ||
357 | static irqreturn_t isr(int irq, void *priv) | ||
358 | { | ||
359 | struct pch_dev *pch_dev = priv; | ||
360 | struct pch_ts_regs *regs = pch_dev->regs; | ||
361 | struct ptp_clock_event event; | ||
362 | u32 ack = 0, lo, hi, val; | ||
363 | |||
364 | val = ioread32(®s->event); | ||
365 | |||
366 | if (val & PCH_TSE_SNS) { | ||
367 | ack |= PCH_TSE_SNS; | ||
368 | if (pch_dev->exts0_enabled) { | ||
369 | hi = ioread32(®s->asms_hi); | ||
370 | lo = ioread32(®s->asms_lo); | ||
371 | event.type = PTP_CLOCK_EXTTS; | ||
372 | event.index = 0; | ||
373 | event.timestamp = ((u64) hi) << 32; | ||
374 | event.timestamp |= lo; | ||
375 | event.timestamp <<= TICKS_NS_SHIFT; | ||
376 | ptp_clock_event(pch_dev->ptp_clock, &event); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | if (val & PCH_TSE_SNM) { | ||
381 | ack |= PCH_TSE_SNM; | ||
382 | if (pch_dev->exts1_enabled) { | ||
383 | hi = ioread32(®s->amms_hi); | ||
384 | lo = ioread32(®s->amms_lo); | ||
385 | event.type = PTP_CLOCK_EXTTS; | ||
386 | event.index = 1; | ||
387 | event.timestamp = ((u64) hi) << 32; | ||
388 | event.timestamp |= lo; | ||
389 | event.timestamp <<= TICKS_NS_SHIFT; | ||
390 | ptp_clock_event(pch_dev->ptp_clock, &event); | ||
391 | } | ||
392 | } | ||
393 | |||
394 | if (val & PCH_TSE_TTIPEND) | ||
395 | ack |= PCH_TSE_TTIPEND; /* this bit seems to be always set */ | ||
396 | |||
397 | if (ack) { | ||
398 | iowrite32(ack, ®s->event); | ||
399 | return IRQ_HANDLED; | ||
400 | } else | ||
401 | return IRQ_NONE; | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | * PTP clock operations | ||
406 | */ | ||
407 | |||
408 | static int ptp_pch_adjfreq(struct ptp_clock_info *ptp, s32 ppb) | ||
409 | { | ||
410 | u64 adj; | ||
411 | u32 diff, addend; | ||
412 | int neg_adj = 0; | ||
413 | struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps); | ||
414 | struct pch_ts_regs *regs = pch_dev->regs; | ||
415 | |||
416 | if (ppb < 0) { | ||
417 | neg_adj = 1; | ||
418 | ppb = -ppb; | ||
419 | } | ||
420 | addend = DEFAULT_ADDEND; | ||
421 | adj = addend; | ||
422 | adj *= ppb; | ||
423 | diff = div_u64(adj, 1000000000ULL); | ||
424 | |||
425 | addend = neg_adj ? addend - diff : addend + diff; | ||
426 | |||
427 | iowrite32(addend, ®s->addend); | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static int ptp_pch_adjtime(struct ptp_clock_info *ptp, s64 delta) | ||
433 | { | ||
434 | s64 now; | ||
435 | unsigned long flags; | ||
436 | struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps); | ||
437 | struct pch_ts_regs *regs = pch_dev->regs; | ||
438 | |||
439 | spin_lock_irqsave(&pch_dev->register_lock, flags); | ||
440 | now = pch_systime_read(regs); | ||
441 | now += delta; | ||
442 | pch_systime_write(regs, now); | ||
443 | spin_unlock_irqrestore(&pch_dev->register_lock, flags); | ||
444 | |||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int ptp_pch_gettime(struct ptp_clock_info *ptp, struct timespec *ts) | ||
449 | { | ||
450 | u64 ns; | ||
451 | u32 remainder; | ||
452 | unsigned long flags; | ||
453 | struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps); | ||
454 | struct pch_ts_regs *regs = pch_dev->regs; | ||
455 | |||
456 | spin_lock_irqsave(&pch_dev->register_lock, flags); | ||
457 | ns = pch_systime_read(regs); | ||
458 | spin_unlock_irqrestore(&pch_dev->register_lock, flags); | ||
459 | |||
460 | ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder); | ||
461 | ts->tv_nsec = remainder; | ||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static int ptp_pch_settime(struct ptp_clock_info *ptp, | ||
466 | const struct timespec *ts) | ||
467 | { | ||
468 | u64 ns; | ||
469 | unsigned long flags; | ||
470 | struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps); | ||
471 | struct pch_ts_regs *regs = pch_dev->regs; | ||
472 | |||
473 | ns = ts->tv_sec * 1000000000ULL; | ||
474 | ns += ts->tv_nsec; | ||
475 | |||
476 | spin_lock_irqsave(&pch_dev->register_lock, flags); | ||
477 | pch_systime_write(regs, ns); | ||
478 | spin_unlock_irqrestore(&pch_dev->register_lock, flags); | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static int ptp_pch_enable(struct ptp_clock_info *ptp, | ||
484 | struct ptp_clock_request *rq, int on) | ||
485 | { | ||
486 | struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps); | ||
487 | |||
488 | switch (rq->type) { | ||
489 | case PTP_CLK_REQ_EXTTS: | ||
490 | switch (rq->extts.index) { | ||
491 | case 0: | ||
492 | pch_dev->exts0_enabled = on ? 1 : 0; | ||
493 | break; | ||
494 | case 1: | ||
495 | pch_dev->exts1_enabled = on ? 1 : 0; | ||
496 | break; | ||
497 | default: | ||
498 | return -EINVAL; | ||
499 | } | ||
500 | return 0; | ||
501 | default: | ||
502 | break; | ||
503 | } | ||
504 | |||
505 | return -EOPNOTSUPP; | ||
506 | } | ||
507 | |||
508 | static struct ptp_clock_info ptp_pch_caps = { | ||
509 | .owner = THIS_MODULE, | ||
510 | .name = "PCH timer", | ||
511 | .max_adj = 50000000, | ||
512 | .n_ext_ts = N_EXT_TS, | ||
513 | .pps = 0, | ||
514 | .adjfreq = ptp_pch_adjfreq, | ||
515 | .adjtime = ptp_pch_adjtime, | ||
516 | .gettime = ptp_pch_gettime, | ||
517 | .settime = ptp_pch_settime, | ||
518 | .enable = ptp_pch_enable, | ||
519 | }; | ||
520 | |||
521 | |||
522 | #ifdef CONFIG_PM | ||
523 | static s32 pch_suspend(struct pci_dev *pdev, pm_message_t state) | ||
524 | { | ||
525 | pci_disable_device(pdev); | ||
526 | pci_enable_wake(pdev, PCI_D3hot, 0); | ||
527 | |||
528 | if (pci_save_state(pdev) != 0) { | ||
529 | dev_err(&pdev->dev, "could not save PCI config state\n"); | ||
530 | return -ENOMEM; | ||
531 | } | ||
532 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static s32 pch_resume(struct pci_dev *pdev) | ||
538 | { | ||
539 | s32 ret; | ||
540 | |||
541 | pci_set_power_state(pdev, PCI_D0); | ||
542 | pci_restore_state(pdev); | ||
543 | ret = pci_enable_device(pdev); | ||
544 | if (ret) { | ||
545 | dev_err(&pdev->dev, "pci_enable_device failed\n"); | ||
546 | return ret; | ||
547 | } | ||
548 | pci_enable_wake(pdev, PCI_D3hot, 0); | ||
549 | return 0; | ||
550 | } | ||
551 | #else | ||
552 | #define pch_suspend NULL | ||
553 | #define pch_resume NULL | ||
554 | #endif | ||
555 | |||
556 | static void __devexit pch_remove(struct pci_dev *pdev) | ||
557 | { | ||
558 | struct pch_dev *chip = pci_get_drvdata(pdev); | ||
559 | |||
560 | ptp_clock_unregister(chip->ptp_clock); | ||
561 | /* free the interrupt */ | ||
562 | if (pdev->irq != 0) | ||
563 | free_irq(pdev->irq, chip); | ||
564 | |||
565 | /* unmap the virtual IO memory space */ | ||
566 | if (chip->regs != 0) { | ||
567 | iounmap(chip->regs); | ||
568 | chip->regs = 0; | ||
569 | } | ||
570 | /* release the reserved IO memory space */ | ||
571 | if (chip->mem_base != 0) { | ||
572 | release_mem_region(chip->mem_base, chip->mem_size); | ||
573 | chip->mem_base = 0; | ||
574 | } | ||
575 | pci_disable_device(pdev); | ||
576 | kfree(chip); | ||
577 | dev_info(&pdev->dev, "complete\n"); | ||
578 | } | ||
579 | |||
580 | static s32 __devinit | ||
581 | pch_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
582 | { | ||
583 | s32 ret; | ||
584 | unsigned long flags; | ||
585 | struct pch_dev *chip; | ||
586 | |||
587 | chip = kzalloc(sizeof(struct pch_dev), GFP_KERNEL); | ||
588 | if (chip == NULL) | ||
589 | return -ENOMEM; | ||
590 | |||
591 | /* enable the 1588 pci device */ | ||
592 | ret = pci_enable_device(pdev); | ||
593 | if (ret != 0) { | ||
594 | dev_err(&pdev->dev, "could not enable the pci device\n"); | ||
595 | goto err_pci_en; | ||
596 | } | ||
597 | |||
598 | chip->mem_base = pci_resource_start(pdev, IO_MEM_BAR); | ||
599 | if (!chip->mem_base) { | ||
600 | dev_err(&pdev->dev, "could not locate IO memory address\n"); | ||
601 | ret = -ENODEV; | ||
602 | goto err_pci_start; | ||
603 | } | ||
604 | |||
605 | /* retrieve the available length of the IO memory space */ | ||
606 | chip->mem_size = pci_resource_len(pdev, IO_MEM_BAR); | ||
607 | |||
608 | /* allocate the memory for the device registers */ | ||
609 | if (!request_mem_region(chip->mem_base, chip->mem_size, "1588_regs")) { | ||
610 | dev_err(&pdev->dev, | ||
611 | "could not allocate register memory space\n"); | ||
612 | ret = -EBUSY; | ||
613 | goto err_req_mem_region; | ||
614 | } | ||
615 | |||
616 | /* get the virtual address to the 1588 registers */ | ||
617 | chip->regs = ioremap(chip->mem_base, chip->mem_size); | ||
618 | |||
619 | if (!chip->regs) { | ||
620 | dev_err(&pdev->dev, "Could not get virtual address\n"); | ||
621 | ret = -ENOMEM; | ||
622 | goto err_ioremap; | ||
623 | } | ||
624 | |||
625 | chip->caps = ptp_pch_caps; | ||
626 | chip->ptp_clock = ptp_clock_register(&chip->caps); | ||
627 | |||
628 | if (IS_ERR(chip->ptp_clock)) | ||
629 | return PTR_ERR(chip->ptp_clock); | ||
630 | |||
631 | spin_lock_init(&chip->register_lock); | ||
632 | |||
633 | ret = request_irq(pdev->irq, &isr, IRQF_SHARED, KBUILD_MODNAME, chip); | ||
634 | if (ret != 0) { | ||
635 | dev_err(&pdev->dev, "failed to get irq %d\n", pdev->irq); | ||
636 | goto err_req_irq; | ||
637 | } | ||
638 | |||
639 | /* indicate success */ | ||
640 | chip->irq = pdev->irq; | ||
641 | chip->pdev = pdev; | ||
642 | pci_set_drvdata(pdev, chip); | ||
643 | |||
644 | spin_lock_irqsave(&chip->register_lock, flags); | ||
645 | /* reset the ieee1588 h/w */ | ||
646 | pch_reset(chip); | ||
647 | |||
648 | iowrite32(DEFAULT_ADDEND, &chip->regs->addend); | ||
649 | iowrite32(1, &chip->regs->trgt_lo); | ||
650 | iowrite32(0, &chip->regs->trgt_hi); | ||
651 | iowrite32(PCH_TSE_TTIPEND, &chip->regs->event); | ||
652 | /* Version: IEEE1588 v1 and IEEE1588-2008, Mode: All Evwnt, Locked */ | ||
653 | iowrite32(0x80020000, &chip->regs->ch_control); | ||
654 | |||
655 | pch_eth_enable_set(chip); | ||
656 | |||
657 | if (strcmp(pch_param.station, "00:00:00:00:00:00") != 0) { | ||
658 | if (pch_set_station_address(pch_param.station, pdev) != 0) { | ||
659 | dev_err(&pdev->dev, | ||
660 | "Invalid station address parameter\n" | ||
661 | "Module loaded but station address not set correctly\n" | ||
662 | ); | ||
663 | } | ||
664 | } | ||
665 | spin_unlock_irqrestore(&chip->register_lock, flags); | ||
666 | return 0; | ||
667 | |||
668 | err_req_irq: | ||
669 | ptp_clock_unregister(chip->ptp_clock); | ||
670 | iounmap(chip->regs); | ||
671 | chip->regs = 0; | ||
672 | |||
673 | err_ioremap: | ||
674 | release_mem_region(chip->mem_base, chip->mem_size); | ||
675 | |||
676 | err_req_mem_region: | ||
677 | chip->mem_base = 0; | ||
678 | |||
679 | err_pci_start: | ||
680 | pci_disable_device(pdev); | ||
681 | |||
682 | err_pci_en: | ||
683 | kfree(chip); | ||
684 | dev_err(&pdev->dev, "probe failed(ret=0x%x)\n", ret); | ||
685 | |||
686 | return ret; | ||
687 | } | ||
688 | |||
689 | static DEFINE_PCI_DEVICE_TABLE(pch_ieee1588_pcidev_id) = { | ||
690 | { | ||
691 | .vendor = PCI_VENDOR_ID_INTEL, | ||
692 | .device = PCI_DEVICE_ID_PCH_1588 | ||
693 | }, | ||
694 | {0} | ||
695 | }; | ||
696 | |||
697 | static struct pci_driver pch_pcidev = { | ||
698 | .name = KBUILD_MODNAME, | ||
699 | .id_table = pch_ieee1588_pcidev_id, | ||
700 | .probe = pch_probe, | ||
701 | .remove = pch_remove, | ||
702 | .suspend = pch_suspend, | ||
703 | .resume = pch_resume, | ||
704 | }; | ||
705 | |||
706 | static void __exit ptp_pch_exit(void) | ||
707 | { | ||
708 | pci_unregister_driver(&pch_pcidev); | ||
709 | } | ||
710 | |||
711 | static s32 __init ptp_pch_init(void) | ||
712 | { | ||
713 | s32 ret; | ||
714 | |||
715 | /* register the driver with the pci core */ | ||
716 | ret = pci_register_driver(&pch_pcidev); | ||
717 | |||
718 | return ret; | ||
719 | } | ||
720 | |||
721 | module_init(ptp_pch_init); | ||
722 | module_exit(ptp_pch_exit); | ||
723 | |||
724 | module_param_string(station, pch_param.station, sizeof pch_param.station, 0444); | ||
725 | MODULE_PARM_DESC(station, | ||
726 | "IEEE 1588 station address to use - column separated hex values"); | ||
727 | |||
728 | MODULE_AUTHOR("LAPIS SEMICONDUCTOR, <tshimizu818@gmail.com>"); | ||
729 | MODULE_DESCRIPTION("PTP clock using the EG20T timer"); | ||
730 | MODULE_LICENSE("GPL"); | ||