18a56aa10SArun Parameswaran /* 28a56aa10SArun Parameswaran * Copyright 2017 Broadcom 38a56aa10SArun Parameswaran * 48a56aa10SArun Parameswaran * This program is free software; you can redistribute it and/or 58a56aa10SArun Parameswaran * modify it under the terms of the GNU General Public License as 68a56aa10SArun Parameswaran * published by the Free Software Foundation version 2. 78a56aa10SArun Parameswaran * 88a56aa10SArun Parameswaran * This program is distributed "as is" WITHOUT ANY WARRANTY of any 98a56aa10SArun Parameswaran * kind, whether express or implied; without even the implied warranty 108a56aa10SArun Parameswaran * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 118a56aa10SArun Parameswaran * GNU General Public License for more details. 128a56aa10SArun Parameswaran */ 138a56aa10SArun Parameswaran 148a56aa10SArun Parameswaran #include <linux/err.h> 158a56aa10SArun Parameswaran #include <linux/io.h> 168a56aa10SArun Parameswaran #include <linux/module.h> 17ac316725SRandy Dunlap #include <linux/mod_devicetable.h> 188a56aa10SArun Parameswaran #include <linux/platform_device.h> 198a56aa10SArun Parameswaran #include <linux/ptp_clock_kernel.h> 208a56aa10SArun Parameswaran #include <linux/types.h> 218a56aa10SArun Parameswaran 228a56aa10SArun Parameswaran #define DTE_NCO_LOW_TIME_REG 0x00 238a56aa10SArun Parameswaran #define DTE_NCO_TIME_REG 0x04 248a56aa10SArun Parameswaran #define DTE_NCO_OVERFLOW_REG 0x08 258a56aa10SArun Parameswaran #define DTE_NCO_INC_REG 0x0c 268a56aa10SArun Parameswaran 278a56aa10SArun Parameswaran #define DTE_NCO_SUM2_MASK 0xffffffff 288a56aa10SArun Parameswaran #define DTE_NCO_SUM2_SHIFT 4ULL 298a56aa10SArun Parameswaran 308a56aa10SArun Parameswaran #define DTE_NCO_SUM3_MASK 0xff 318a56aa10SArun Parameswaran #define DTE_NCO_SUM3_SHIFT 36ULL 328a56aa10SArun Parameswaran #define DTE_NCO_SUM3_WR_SHIFT 8 338a56aa10SArun Parameswaran 348a56aa10SArun Parameswaran #define DTE_NCO_TS_WRAP_MASK 0xfff 358a56aa10SArun Parameswaran #define DTE_NCO_TS_WRAP_LSHIFT 32 368a56aa10SArun Parameswaran 378a56aa10SArun Parameswaran #define DTE_NCO_INC_DEFAULT 0x80000000 388a56aa10SArun Parameswaran #define DTE_NUM_REGS_TO_RESTORE 4 398a56aa10SArun Parameswaran 408a56aa10SArun Parameswaran /* Full wrap around is 44bits in ns (~4.887 hrs) */ 418a56aa10SArun Parameswaran #define DTE_WRAP_AROUND_NSEC_SHIFT 44 428a56aa10SArun Parameswaran 438a56aa10SArun Parameswaran /* 44 bits NCO */ 443d05035eSGeert Uytterhoeven #define DTE_NCO_MAX_NS 0xFFFFFFFFFFFLL 458a56aa10SArun Parameswaran 468a56aa10SArun Parameswaran /* 125MHz with 3.29 reg cfg */ 478a56aa10SArun Parameswaran #define DTE_PPB_ADJ(ppb) (u32)(div64_u64((((u64)abs(ppb) * BIT(28)) +\ 488a56aa10SArun Parameswaran 62500000ULL), 125000000ULL)) 498a56aa10SArun Parameswaran 508a56aa10SArun Parameswaran /* ptp dte priv structure */ 518a56aa10SArun Parameswaran struct ptp_dte { 528a56aa10SArun Parameswaran void __iomem *regs; 538a56aa10SArun Parameswaran struct ptp_clock *ptp_clk; 548a56aa10SArun Parameswaran struct ptp_clock_info caps; 558a56aa10SArun Parameswaran struct device *dev; 568a56aa10SArun Parameswaran u32 ts_ovf_last; 578a56aa10SArun Parameswaran u32 ts_wrap_cnt; 588a56aa10SArun Parameswaran spinlock_t lock; 598a56aa10SArun Parameswaran u32 reg_val[DTE_NUM_REGS_TO_RESTORE]; 608a56aa10SArun Parameswaran }; 618a56aa10SArun Parameswaran 628a56aa10SArun Parameswaran static void dte_write_nco(void __iomem *regs, s64 ns) 638a56aa10SArun Parameswaran { 648a56aa10SArun Parameswaran u32 sum2, sum3; 658a56aa10SArun Parameswaran 668a56aa10SArun Parameswaran sum2 = (u32)((ns >> DTE_NCO_SUM2_SHIFT) & DTE_NCO_SUM2_MASK); 678a56aa10SArun Parameswaran /* compensate for ignoring sum1 */ 688a56aa10SArun Parameswaran if (sum2 != DTE_NCO_SUM2_MASK) 698a56aa10SArun Parameswaran sum2++; 708a56aa10SArun Parameswaran 718a56aa10SArun Parameswaran /* to write sum3, bits [15:8] needs to be written */ 728a56aa10SArun Parameswaran sum3 = (u32)(((ns >> DTE_NCO_SUM3_SHIFT) & DTE_NCO_SUM3_MASK) << 738a56aa10SArun Parameswaran DTE_NCO_SUM3_WR_SHIFT); 748a56aa10SArun Parameswaran 758a56aa10SArun Parameswaran writel(0, (regs + DTE_NCO_LOW_TIME_REG)); 768a56aa10SArun Parameswaran writel(sum2, (regs + DTE_NCO_TIME_REG)); 778a56aa10SArun Parameswaran writel(sum3, (regs + DTE_NCO_OVERFLOW_REG)); 788a56aa10SArun Parameswaran } 798a56aa10SArun Parameswaran 808a56aa10SArun Parameswaran static s64 dte_read_nco(void __iomem *regs) 818a56aa10SArun Parameswaran { 828a56aa10SArun Parameswaran u32 sum2, sum3; 838a56aa10SArun Parameswaran s64 ns; 848a56aa10SArun Parameswaran 858a56aa10SArun Parameswaran /* 868a56aa10SArun Parameswaran * ignoring sum1 (4 bits) gives a 16ns resolution, which 878a56aa10SArun Parameswaran * works due to the async register read. 888a56aa10SArun Parameswaran */ 898a56aa10SArun Parameswaran sum3 = readl(regs + DTE_NCO_OVERFLOW_REG) & DTE_NCO_SUM3_MASK; 908a56aa10SArun Parameswaran sum2 = readl(regs + DTE_NCO_TIME_REG); 918a56aa10SArun Parameswaran ns = ((s64)sum3 << DTE_NCO_SUM3_SHIFT) | 928a56aa10SArun Parameswaran ((s64)sum2 << DTE_NCO_SUM2_SHIFT); 938a56aa10SArun Parameswaran 948a56aa10SArun Parameswaran return ns; 958a56aa10SArun Parameswaran } 968a56aa10SArun Parameswaran 978a56aa10SArun Parameswaran static void dte_write_nco_delta(struct ptp_dte *ptp_dte, s64 delta) 988a56aa10SArun Parameswaran { 998a56aa10SArun Parameswaran s64 ns; 1008a56aa10SArun Parameswaran 1018a56aa10SArun Parameswaran ns = dte_read_nco(ptp_dte->regs); 1028a56aa10SArun Parameswaran 1038a56aa10SArun Parameswaran /* handle wraparound conditions */ 1048a56aa10SArun Parameswaran if ((delta < 0) && (abs(delta) > ns)) { 1058a56aa10SArun Parameswaran if (ptp_dte->ts_wrap_cnt) { 1068a56aa10SArun Parameswaran ns += DTE_NCO_MAX_NS + delta; 1078a56aa10SArun Parameswaran ptp_dte->ts_wrap_cnt--; 1088a56aa10SArun Parameswaran } else { 1098a56aa10SArun Parameswaran ns = 0; 1108a56aa10SArun Parameswaran } 1118a56aa10SArun Parameswaran } else { 1128a56aa10SArun Parameswaran ns += delta; 1138a56aa10SArun Parameswaran if (ns > DTE_NCO_MAX_NS) { 1148a56aa10SArun Parameswaran ptp_dte->ts_wrap_cnt++; 1158a56aa10SArun Parameswaran ns -= DTE_NCO_MAX_NS; 1168a56aa10SArun Parameswaran } 1178a56aa10SArun Parameswaran } 1188a56aa10SArun Parameswaran 1198a56aa10SArun Parameswaran dte_write_nco(ptp_dte->regs, ns); 1208a56aa10SArun Parameswaran 1218a56aa10SArun Parameswaran ptp_dte->ts_ovf_last = (ns >> DTE_NCO_TS_WRAP_LSHIFT) & 1228a56aa10SArun Parameswaran DTE_NCO_TS_WRAP_MASK; 1238a56aa10SArun Parameswaran } 1248a56aa10SArun Parameswaran 1258a56aa10SArun Parameswaran static s64 dte_read_nco_with_ovf(struct ptp_dte *ptp_dte) 1268a56aa10SArun Parameswaran { 1278a56aa10SArun Parameswaran u32 ts_ovf; 1288a56aa10SArun Parameswaran s64 ns = 0; 1298a56aa10SArun Parameswaran 1308a56aa10SArun Parameswaran ns = dte_read_nco(ptp_dte->regs); 1318a56aa10SArun Parameswaran 1328a56aa10SArun Parameswaran /*Timestamp overflow: 8 LSB bits of sum3, 4 MSB bits of sum2 */ 1338a56aa10SArun Parameswaran ts_ovf = (ns >> DTE_NCO_TS_WRAP_LSHIFT) & DTE_NCO_TS_WRAP_MASK; 1348a56aa10SArun Parameswaran 1358a56aa10SArun Parameswaran /* Check for wrap around */ 1368a56aa10SArun Parameswaran if (ts_ovf < ptp_dte->ts_ovf_last) 1378a56aa10SArun Parameswaran ptp_dte->ts_wrap_cnt++; 1388a56aa10SArun Parameswaran 1398a56aa10SArun Parameswaran ptp_dte->ts_ovf_last = ts_ovf; 1408a56aa10SArun Parameswaran 1418a56aa10SArun Parameswaran /* adjust for wraparounds */ 1428a56aa10SArun Parameswaran ns += (s64)(BIT_ULL(DTE_WRAP_AROUND_NSEC_SHIFT) * ptp_dte->ts_wrap_cnt); 1438a56aa10SArun Parameswaran 1448a56aa10SArun Parameswaran return ns; 1458a56aa10SArun Parameswaran } 1468a56aa10SArun Parameswaran 1478a56aa10SArun Parameswaran static int ptp_dte_adjfreq(struct ptp_clock_info *ptp, s32 ppb) 1488a56aa10SArun Parameswaran { 1498a56aa10SArun Parameswaran u32 nco_incr; 1508a56aa10SArun Parameswaran unsigned long flags; 1518a56aa10SArun Parameswaran struct ptp_dte *ptp_dte = container_of(ptp, struct ptp_dte, caps); 1528a56aa10SArun Parameswaran 1538a56aa10SArun Parameswaran if (abs(ppb) > ptp_dte->caps.max_adj) { 1548a56aa10SArun Parameswaran dev_err(ptp_dte->dev, "ppb adj too big\n"); 1558a56aa10SArun Parameswaran return -EINVAL; 1568a56aa10SArun Parameswaran } 1578a56aa10SArun Parameswaran 1588a56aa10SArun Parameswaran if (ppb < 0) 1598a56aa10SArun Parameswaran nco_incr = DTE_NCO_INC_DEFAULT - DTE_PPB_ADJ(ppb); 1608a56aa10SArun Parameswaran else 1618a56aa10SArun Parameswaran nco_incr = DTE_NCO_INC_DEFAULT + DTE_PPB_ADJ(ppb); 1628a56aa10SArun Parameswaran 1638a56aa10SArun Parameswaran spin_lock_irqsave(&ptp_dte->lock, flags); 1648a56aa10SArun Parameswaran writel(nco_incr, ptp_dte->regs + DTE_NCO_INC_REG); 1658a56aa10SArun Parameswaran spin_unlock_irqrestore(&ptp_dte->lock, flags); 1668a56aa10SArun Parameswaran 1678a56aa10SArun Parameswaran return 0; 1688a56aa10SArun Parameswaran } 1698a56aa10SArun Parameswaran 1708a56aa10SArun Parameswaran static int ptp_dte_adjtime(struct ptp_clock_info *ptp, s64 delta) 1718a56aa10SArun Parameswaran { 1728a56aa10SArun Parameswaran unsigned long flags; 1738a56aa10SArun Parameswaran struct ptp_dte *ptp_dte = container_of(ptp, struct ptp_dte, caps); 1748a56aa10SArun Parameswaran 1758a56aa10SArun Parameswaran spin_lock_irqsave(&ptp_dte->lock, flags); 1768a56aa10SArun Parameswaran dte_write_nco_delta(ptp_dte, delta); 1778a56aa10SArun Parameswaran spin_unlock_irqrestore(&ptp_dte->lock, flags); 1788a56aa10SArun Parameswaran 1798a56aa10SArun Parameswaran return 0; 1808a56aa10SArun Parameswaran } 1818a56aa10SArun Parameswaran 1828a56aa10SArun Parameswaran static int ptp_dte_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) 1838a56aa10SArun Parameswaran { 1848a56aa10SArun Parameswaran unsigned long flags; 1858a56aa10SArun Parameswaran struct ptp_dte *ptp_dte = container_of(ptp, struct ptp_dte, caps); 1868a56aa10SArun Parameswaran 1878a56aa10SArun Parameswaran spin_lock_irqsave(&ptp_dte->lock, flags); 1888a56aa10SArun Parameswaran *ts = ns_to_timespec64(dte_read_nco_with_ovf(ptp_dte)); 1898a56aa10SArun Parameswaran spin_unlock_irqrestore(&ptp_dte->lock, flags); 1908a56aa10SArun Parameswaran 1918a56aa10SArun Parameswaran return 0; 1928a56aa10SArun Parameswaran } 1938a56aa10SArun Parameswaran 1948a56aa10SArun Parameswaran static int ptp_dte_settime(struct ptp_clock_info *ptp, 1958a56aa10SArun Parameswaran const struct timespec64 *ts) 1968a56aa10SArun Parameswaran { 1978a56aa10SArun Parameswaran unsigned long flags; 1988a56aa10SArun Parameswaran struct ptp_dte *ptp_dte = container_of(ptp, struct ptp_dte, caps); 1998a56aa10SArun Parameswaran 2008a56aa10SArun Parameswaran spin_lock_irqsave(&ptp_dte->lock, flags); 2018a56aa10SArun Parameswaran 2028a56aa10SArun Parameswaran /* Disable nco increment */ 2038a56aa10SArun Parameswaran writel(0, ptp_dte->regs + DTE_NCO_INC_REG); 2048a56aa10SArun Parameswaran 2058a56aa10SArun Parameswaran dte_write_nco(ptp_dte->regs, timespec64_to_ns(ts)); 2068a56aa10SArun Parameswaran 2078a56aa10SArun Parameswaran /* reset overflow and wrap counter */ 2088a56aa10SArun Parameswaran ptp_dte->ts_ovf_last = 0; 2098a56aa10SArun Parameswaran ptp_dte->ts_wrap_cnt = 0; 2108a56aa10SArun Parameswaran 2118a56aa10SArun Parameswaran /* Enable nco increment */ 2128a56aa10SArun Parameswaran writel(DTE_NCO_INC_DEFAULT, ptp_dte->regs + DTE_NCO_INC_REG); 2138a56aa10SArun Parameswaran 2148a56aa10SArun Parameswaran spin_unlock_irqrestore(&ptp_dte->lock, flags); 2158a56aa10SArun Parameswaran 2168a56aa10SArun Parameswaran return 0; 2178a56aa10SArun Parameswaran } 2188a56aa10SArun Parameswaran 2198a56aa10SArun Parameswaran static int ptp_dte_enable(struct ptp_clock_info *ptp, 2208a56aa10SArun Parameswaran struct ptp_clock_request *rq, int on) 2218a56aa10SArun Parameswaran { 2228a56aa10SArun Parameswaran return -EOPNOTSUPP; 2238a56aa10SArun Parameswaran } 2248a56aa10SArun Parameswaran 2257d47e9a2SBhumika Goyal static const struct ptp_clock_info ptp_dte_caps = { 2268a56aa10SArun Parameswaran .owner = THIS_MODULE, 2278a56aa10SArun Parameswaran .name = "DTE PTP timer", 2288a56aa10SArun Parameswaran .max_adj = 50000000, 2298a56aa10SArun Parameswaran .n_ext_ts = 0, 2308a56aa10SArun Parameswaran .n_pins = 0, 2318a56aa10SArun Parameswaran .pps = 0, 2328a56aa10SArun Parameswaran .adjfreq = ptp_dte_adjfreq, 2338a56aa10SArun Parameswaran .adjtime = ptp_dte_adjtime, 2348a56aa10SArun Parameswaran .gettime64 = ptp_dte_gettime, 2358a56aa10SArun Parameswaran .settime64 = ptp_dte_settime, 2368a56aa10SArun Parameswaran .enable = ptp_dte_enable, 2378a56aa10SArun Parameswaran }; 2388a56aa10SArun Parameswaran 2398a56aa10SArun Parameswaran static int ptp_dte_probe(struct platform_device *pdev) 2408a56aa10SArun Parameswaran { 2418a56aa10SArun Parameswaran struct ptp_dte *ptp_dte; 2428a56aa10SArun Parameswaran struct device *dev = &pdev->dev; 2438a56aa10SArun Parameswaran 2448a56aa10SArun Parameswaran ptp_dte = devm_kzalloc(dev, sizeof(struct ptp_dte), GFP_KERNEL); 2458a56aa10SArun Parameswaran if (!ptp_dte) 2468a56aa10SArun Parameswaran return -ENOMEM; 2478a56aa10SArun Parameswaran 248*f063d58bSYueHaibing ptp_dte->regs = devm_platform_ioremap_resource(pdev, 0); 24937f7c66fSDing Xiang if (IS_ERR(ptp_dte->regs)) 2508a56aa10SArun Parameswaran return PTR_ERR(ptp_dte->regs); 2518a56aa10SArun Parameswaran 2528a56aa10SArun Parameswaran spin_lock_init(&ptp_dte->lock); 2538a56aa10SArun Parameswaran 2548a56aa10SArun Parameswaran ptp_dte->dev = dev; 2558a56aa10SArun Parameswaran ptp_dte->caps = ptp_dte_caps; 2568a56aa10SArun Parameswaran ptp_dte->ptp_clk = ptp_clock_register(&ptp_dte->caps, &pdev->dev); 2578a56aa10SArun Parameswaran if (IS_ERR(ptp_dte->ptp_clk)) { 2588a56aa10SArun Parameswaran dev_err(dev, 2598a56aa10SArun Parameswaran "%s: Failed to register ptp clock\n", __func__); 2608a56aa10SArun Parameswaran return PTR_ERR(ptp_dte->ptp_clk); 2618a56aa10SArun Parameswaran } 2628a56aa10SArun Parameswaran 2638a56aa10SArun Parameswaran platform_set_drvdata(pdev, ptp_dte); 2648a56aa10SArun Parameswaran 2658a56aa10SArun Parameswaran dev_info(dev, "ptp clk probe done\n"); 2668a56aa10SArun Parameswaran 2678a56aa10SArun Parameswaran return 0; 2688a56aa10SArun Parameswaran } 2698a56aa10SArun Parameswaran 2708a56aa10SArun Parameswaran static int ptp_dte_remove(struct platform_device *pdev) 2718a56aa10SArun Parameswaran { 2728a56aa10SArun Parameswaran struct ptp_dte *ptp_dte = platform_get_drvdata(pdev); 2738a56aa10SArun Parameswaran u8 i; 2748a56aa10SArun Parameswaran 2758a56aa10SArun Parameswaran ptp_clock_unregister(ptp_dte->ptp_clk); 2768a56aa10SArun Parameswaran 2778a56aa10SArun Parameswaran for (i = 0; i < DTE_NUM_REGS_TO_RESTORE; i++) 2788a56aa10SArun Parameswaran writel(0, ptp_dte->regs + (i * sizeof(u32))); 2798a56aa10SArun Parameswaran 2808a56aa10SArun Parameswaran return 0; 2818a56aa10SArun Parameswaran } 2828a56aa10SArun Parameswaran 2838a56aa10SArun Parameswaran #ifdef CONFIG_PM_SLEEP 2848a56aa10SArun Parameswaran static int ptp_dte_suspend(struct device *dev) 2858a56aa10SArun Parameswaran { 286c0bfdae0SWolfram Sang struct ptp_dte *ptp_dte = dev_get_drvdata(dev); 2878a56aa10SArun Parameswaran u8 i; 2888a56aa10SArun Parameswaran 2898a56aa10SArun Parameswaran for (i = 0; i < DTE_NUM_REGS_TO_RESTORE; i++) { 2908a56aa10SArun Parameswaran ptp_dte->reg_val[i] = 2918a56aa10SArun Parameswaran readl(ptp_dte->regs + (i * sizeof(u32))); 2928a56aa10SArun Parameswaran } 2938a56aa10SArun Parameswaran 2948a56aa10SArun Parameswaran /* disable the nco */ 2958a56aa10SArun Parameswaran writel(0, ptp_dte->regs + DTE_NCO_INC_REG); 2968a56aa10SArun Parameswaran 2978a56aa10SArun Parameswaran return 0; 2988a56aa10SArun Parameswaran } 2998a56aa10SArun Parameswaran 3008a56aa10SArun Parameswaran static int ptp_dte_resume(struct device *dev) 3018a56aa10SArun Parameswaran { 302c0bfdae0SWolfram Sang struct ptp_dte *ptp_dte = dev_get_drvdata(dev); 3038a56aa10SArun Parameswaran u8 i; 3048a56aa10SArun Parameswaran 3058a56aa10SArun Parameswaran for (i = 0; i < DTE_NUM_REGS_TO_RESTORE; i++) { 3068a56aa10SArun Parameswaran if ((i * sizeof(u32)) != DTE_NCO_OVERFLOW_REG) 3078a56aa10SArun Parameswaran writel(ptp_dte->reg_val[i], 3088a56aa10SArun Parameswaran (ptp_dte->regs + (i * sizeof(u32)))); 3098a56aa10SArun Parameswaran else 3108a56aa10SArun Parameswaran writel(((ptp_dte->reg_val[i] & 3118a56aa10SArun Parameswaran DTE_NCO_SUM3_MASK) << DTE_NCO_SUM3_WR_SHIFT), 3128a56aa10SArun Parameswaran (ptp_dte->regs + (i * sizeof(u32)))); 3138a56aa10SArun Parameswaran } 3148a56aa10SArun Parameswaran 3158a56aa10SArun Parameswaran return 0; 3168a56aa10SArun Parameswaran } 3178a56aa10SArun Parameswaran 3188a56aa10SArun Parameswaran static const struct dev_pm_ops ptp_dte_pm_ops = { 3198a56aa10SArun Parameswaran .suspend = ptp_dte_suspend, 3208a56aa10SArun Parameswaran .resume = ptp_dte_resume 3218a56aa10SArun Parameswaran }; 3228a56aa10SArun Parameswaran 3238a56aa10SArun Parameswaran #define PTP_DTE_PM_OPS (&ptp_dte_pm_ops) 3248a56aa10SArun Parameswaran #else 3258a56aa10SArun Parameswaran #define PTP_DTE_PM_OPS NULL 3268a56aa10SArun Parameswaran #endif 3278a56aa10SArun Parameswaran 3288a56aa10SArun Parameswaran static const struct of_device_id ptp_dte_of_match[] = { 3298a56aa10SArun Parameswaran { .compatible = "brcm,ptp-dte", }, 3308a56aa10SArun Parameswaran {}, 3318a56aa10SArun Parameswaran }; 3328a56aa10SArun Parameswaran MODULE_DEVICE_TABLE(of, ptp_dte_of_match); 3338a56aa10SArun Parameswaran 3348a56aa10SArun Parameswaran static struct platform_driver ptp_dte_driver = { 3358a56aa10SArun Parameswaran .driver = { 3368a56aa10SArun Parameswaran .name = "ptp-dte", 3378a56aa10SArun Parameswaran .pm = PTP_DTE_PM_OPS, 3388a56aa10SArun Parameswaran .of_match_table = ptp_dte_of_match, 3398a56aa10SArun Parameswaran }, 3408a56aa10SArun Parameswaran .probe = ptp_dte_probe, 3418a56aa10SArun Parameswaran .remove = ptp_dte_remove, 3428a56aa10SArun Parameswaran }; 3438a56aa10SArun Parameswaran module_platform_driver(ptp_dte_driver); 3448a56aa10SArun Parameswaran 3458a56aa10SArun Parameswaran MODULE_AUTHOR("Broadcom"); 3468a56aa10SArun Parameswaran MODULE_DESCRIPTION("Broadcom DTE PTP Clock driver"); 3478a56aa10SArun Parameswaran MODULE_LICENSE("GPL v2"); 348