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