18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PTP 1588 clock using the EG20T PCH 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010 OMICRON electronics GmbH 68c2ecf20Sopenharmony_ci * Copyright (C) 2011-2012 LAPIS SEMICONDUCTOR Co., LTD. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This code was derived from the IXP46X driver. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/device.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/io.h> 168c2ecf20Sopenharmony_ci#include <linux/irq.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/pci.h> 208c2ecf20Sopenharmony_ci#include <linux/ptp_clock_kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define STATION_ADDR_LEN 20 248c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_PCH_1588 0x8819 258c2ecf20Sopenharmony_ci#define IO_MEM_BAR 1 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define DEFAULT_ADDEND 0xA0000000 288c2ecf20Sopenharmony_ci#define TICKS_NS_SHIFT 5 298c2ecf20Sopenharmony_ci#define N_EXT_TS 2 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cienum pch_status { 328c2ecf20Sopenharmony_ci PCH_SUCCESS, 338c2ecf20Sopenharmony_ci PCH_INVALIDPARAM, 348c2ecf20Sopenharmony_ci PCH_NOTIMESTAMP, 358c2ecf20Sopenharmony_ci PCH_INTERRUPTMODEINUSE, 368c2ecf20Sopenharmony_ci PCH_FAILED, 378c2ecf20Sopenharmony_ci PCH_UNSUPPORTED, 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci/** 408c2ecf20Sopenharmony_ci * struct pch_ts_regs - IEEE 1588 registers 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_cistruct pch_ts_regs { 438c2ecf20Sopenharmony_ci u32 control; 448c2ecf20Sopenharmony_ci u32 event; 458c2ecf20Sopenharmony_ci u32 addend; 468c2ecf20Sopenharmony_ci u32 accum; 478c2ecf20Sopenharmony_ci u32 test; 488c2ecf20Sopenharmony_ci u32 ts_compare; 498c2ecf20Sopenharmony_ci u32 rsystime_lo; 508c2ecf20Sopenharmony_ci u32 rsystime_hi; 518c2ecf20Sopenharmony_ci u32 systime_lo; 528c2ecf20Sopenharmony_ci u32 systime_hi; 538c2ecf20Sopenharmony_ci u32 trgt_lo; 548c2ecf20Sopenharmony_ci u32 trgt_hi; 558c2ecf20Sopenharmony_ci u32 asms_lo; 568c2ecf20Sopenharmony_ci u32 asms_hi; 578c2ecf20Sopenharmony_ci u32 amms_lo; 588c2ecf20Sopenharmony_ci u32 amms_hi; 598c2ecf20Sopenharmony_ci u32 ch_control; 608c2ecf20Sopenharmony_ci u32 ch_event; 618c2ecf20Sopenharmony_ci u32 tx_snap_lo; 628c2ecf20Sopenharmony_ci u32 tx_snap_hi; 638c2ecf20Sopenharmony_ci u32 rx_snap_lo; 648c2ecf20Sopenharmony_ci u32 rx_snap_hi; 658c2ecf20Sopenharmony_ci u32 src_uuid_lo; 668c2ecf20Sopenharmony_ci u32 src_uuid_hi; 678c2ecf20Sopenharmony_ci u32 can_status; 688c2ecf20Sopenharmony_ci u32 can_snap_lo; 698c2ecf20Sopenharmony_ci u32 can_snap_hi; 708c2ecf20Sopenharmony_ci u32 ts_sel; 718c2ecf20Sopenharmony_ci u32 ts_st[6]; 728c2ecf20Sopenharmony_ci u32 reserve1[14]; 738c2ecf20Sopenharmony_ci u32 stl_max_set_en; 748c2ecf20Sopenharmony_ci u32 stl_max_set; 758c2ecf20Sopenharmony_ci u32 reserve2[13]; 768c2ecf20Sopenharmony_ci u32 srst; 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define PCH_TSC_RESET (1 << 0) 808c2ecf20Sopenharmony_ci#define PCH_TSC_TTM_MASK (1 << 1) 818c2ecf20Sopenharmony_ci#define PCH_TSC_ASMS_MASK (1 << 2) 828c2ecf20Sopenharmony_ci#define PCH_TSC_AMMS_MASK (1 << 3) 838c2ecf20Sopenharmony_ci#define PCH_TSC_PPSM_MASK (1 << 4) 848c2ecf20Sopenharmony_ci#define PCH_TSE_TTIPEND (1 << 1) 858c2ecf20Sopenharmony_ci#define PCH_TSE_SNS (1 << 2) 868c2ecf20Sopenharmony_ci#define PCH_TSE_SNM (1 << 3) 878c2ecf20Sopenharmony_ci#define PCH_TSE_PPS (1 << 4) 888c2ecf20Sopenharmony_ci#define PCH_CC_MM (1 << 0) 898c2ecf20Sopenharmony_ci#define PCH_CC_TA (1 << 1) 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#define PCH_CC_MODE_SHIFT 16 928c2ecf20Sopenharmony_ci#define PCH_CC_MODE_MASK 0x001F0000 938c2ecf20Sopenharmony_ci#define PCH_CC_VERSION (1 << 31) 948c2ecf20Sopenharmony_ci#define PCH_CE_TXS (1 << 0) 958c2ecf20Sopenharmony_ci#define PCH_CE_RXS (1 << 1) 968c2ecf20Sopenharmony_ci#define PCH_CE_OVR (1 << 0) 978c2ecf20Sopenharmony_ci#define PCH_CE_VAL (1 << 1) 988c2ecf20Sopenharmony_ci#define PCH_ECS_ETH (1 << 0) 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define PCH_ECS_CAN (1 << 1) 1018c2ecf20Sopenharmony_ci#define PCH_STATION_BYTES 6 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define PCH_IEEE1588_ETH (1 << 0) 1048c2ecf20Sopenharmony_ci#define PCH_IEEE1588_CAN (1 << 1) 1058c2ecf20Sopenharmony_ci/** 1068c2ecf20Sopenharmony_ci * struct pch_dev - Driver private data 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_cistruct pch_dev { 1098c2ecf20Sopenharmony_ci struct pch_ts_regs __iomem *regs; 1108c2ecf20Sopenharmony_ci struct ptp_clock *ptp_clock; 1118c2ecf20Sopenharmony_ci struct ptp_clock_info caps; 1128c2ecf20Sopenharmony_ci int exts0_enabled; 1138c2ecf20Sopenharmony_ci int exts1_enabled; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci u32 mem_base; 1168c2ecf20Sopenharmony_ci u32 mem_size; 1178c2ecf20Sopenharmony_ci u32 irq; 1188c2ecf20Sopenharmony_ci struct pci_dev *pdev; 1198c2ecf20Sopenharmony_ci spinlock_t register_lock; 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/** 1238c2ecf20Sopenharmony_ci * struct pch_params - 1588 module parameter 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_cistruct pch_params { 1268c2ecf20Sopenharmony_ci u8 station[STATION_ADDR_LEN]; 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* structure to hold the module parameters */ 1308c2ecf20Sopenharmony_cistatic struct pch_params pch_param = { 1318c2ecf20Sopenharmony_ci "00:00:00:00:00:00" 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* 1358c2ecf20Sopenharmony_ci * Register access functions 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_cistatic inline void pch_eth_enable_set(struct pch_dev *chip) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci u32 val; 1408c2ecf20Sopenharmony_ci /* SET the eth_enable bit */ 1418c2ecf20Sopenharmony_ci val = ioread32(&chip->regs->ts_sel) | (PCH_ECS_ETH); 1428c2ecf20Sopenharmony_ci iowrite32(val, (&chip->regs->ts_sel)); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic u64 pch_systime_read(struct pch_ts_regs __iomem *regs) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci u64 ns; 1488c2ecf20Sopenharmony_ci u32 lo, hi; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci lo = ioread32(®s->systime_lo); 1518c2ecf20Sopenharmony_ci hi = ioread32(®s->systime_hi); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci ns = ((u64) hi) << 32; 1548c2ecf20Sopenharmony_ci ns |= lo; 1558c2ecf20Sopenharmony_ci ns <<= TICKS_NS_SHIFT; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return ns; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic void pch_systime_write(struct pch_ts_regs __iomem *regs, u64 ns) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci u32 hi, lo; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci ns >>= TICKS_NS_SHIFT; 1658c2ecf20Sopenharmony_ci hi = ns >> 32; 1668c2ecf20Sopenharmony_ci lo = ns & 0xffffffff; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci iowrite32(lo, ®s->systime_lo); 1698c2ecf20Sopenharmony_ci iowrite32(hi, ®s->systime_hi); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic inline void pch_block_reset(struct pch_dev *chip) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci u32 val; 1758c2ecf20Sopenharmony_ci /* Reset Hardware Assist block */ 1768c2ecf20Sopenharmony_ci val = ioread32(&chip->regs->control) | PCH_TSC_RESET; 1778c2ecf20Sopenharmony_ci iowrite32(val, (&chip->regs->control)); 1788c2ecf20Sopenharmony_ci val = val & ~PCH_TSC_RESET; 1798c2ecf20Sopenharmony_ci iowrite32(val, (&chip->regs->control)); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciu32 pch_ch_control_read(struct pci_dev *pdev) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct pch_dev *chip = pci_get_drvdata(pdev); 1858c2ecf20Sopenharmony_ci u32 val; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci val = ioread32(&chip->regs->ch_control); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return val; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pch_ch_control_read); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_civoid pch_ch_control_write(struct pci_dev *pdev, u32 val) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct pch_dev *chip = pci_get_drvdata(pdev); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci iowrite32(val, (&chip->regs->ch_control)); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pch_ch_control_write); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ciu32 pch_ch_event_read(struct pci_dev *pdev) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct pch_dev *chip = pci_get_drvdata(pdev); 2048c2ecf20Sopenharmony_ci u32 val; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci val = ioread32(&chip->regs->ch_event); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return val; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pch_ch_event_read); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_civoid pch_ch_event_write(struct pci_dev *pdev, u32 val) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct pch_dev *chip = pci_get_drvdata(pdev); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci iowrite32(val, (&chip->regs->ch_event)); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pch_ch_event_write); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ciu32 pch_src_uuid_lo_read(struct pci_dev *pdev) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct pch_dev *chip = pci_get_drvdata(pdev); 2238c2ecf20Sopenharmony_ci u32 val; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci val = ioread32(&chip->regs->src_uuid_lo); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return val; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pch_src_uuid_lo_read); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ciu32 pch_src_uuid_hi_read(struct pci_dev *pdev) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct pch_dev *chip = pci_get_drvdata(pdev); 2348c2ecf20Sopenharmony_ci u32 val; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci val = ioread32(&chip->regs->src_uuid_hi); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return val; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pch_src_uuid_hi_read); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciu64 pch_rx_snap_read(struct pci_dev *pdev) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct pch_dev *chip = pci_get_drvdata(pdev); 2458c2ecf20Sopenharmony_ci u64 ns; 2468c2ecf20Sopenharmony_ci u32 lo, hi; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci lo = ioread32(&chip->regs->rx_snap_lo); 2498c2ecf20Sopenharmony_ci hi = ioread32(&chip->regs->rx_snap_hi); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci ns = ((u64) hi) << 32; 2528c2ecf20Sopenharmony_ci ns |= lo; 2538c2ecf20Sopenharmony_ci ns <<= TICKS_NS_SHIFT; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci return ns; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pch_rx_snap_read); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ciu64 pch_tx_snap_read(struct pci_dev *pdev) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct pch_dev *chip = pci_get_drvdata(pdev); 2628c2ecf20Sopenharmony_ci u64 ns; 2638c2ecf20Sopenharmony_ci u32 lo, hi; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci lo = ioread32(&chip->regs->tx_snap_lo); 2668c2ecf20Sopenharmony_ci hi = ioread32(&chip->regs->tx_snap_hi); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci ns = ((u64) hi) << 32; 2698c2ecf20Sopenharmony_ci ns |= lo; 2708c2ecf20Sopenharmony_ci ns <<= TICKS_NS_SHIFT; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return ns; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pch_tx_snap_read); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/* This function enables all 64 bits in system time registers [high & low]. 2778c2ecf20Sopenharmony_ciThis is a work-around for non continuous value in the SystemTime Register*/ 2788c2ecf20Sopenharmony_cistatic void pch_set_system_time_count(struct pch_dev *chip) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci iowrite32(0x01, &chip->regs->stl_max_set_en); 2818c2ecf20Sopenharmony_ci iowrite32(0xFFFFFFFF, &chip->regs->stl_max_set); 2828c2ecf20Sopenharmony_ci iowrite32(0x00, &chip->regs->stl_max_set_en); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void pch_reset(struct pch_dev *chip) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci /* Reset Hardware Assist */ 2888c2ecf20Sopenharmony_ci pch_block_reset(chip); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* enable all 32 bits in system time registers */ 2918c2ecf20Sopenharmony_ci pch_set_system_time_count(chip); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci/** 2958c2ecf20Sopenharmony_ci * pch_set_station_address() - This API sets the station address used by 2968c2ecf20Sopenharmony_ci * IEEE 1588 hardware when looking at PTP 2978c2ecf20Sopenharmony_ci * traffic on the ethernet interface 2988c2ecf20Sopenharmony_ci * @addr: dress which contain the column separated address to be used. 2998c2ecf20Sopenharmony_ci */ 3008c2ecf20Sopenharmony_ciint pch_set_station_address(u8 *addr, struct pci_dev *pdev) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci s32 i; 3038c2ecf20Sopenharmony_ci struct pch_dev *chip = pci_get_drvdata(pdev); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* Verify the parameter */ 3068c2ecf20Sopenharmony_ci if ((chip->regs == NULL) || addr == (u8 *)NULL) { 3078c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 3088c2ecf20Sopenharmony_ci "invalid params returning PCH_INVALIDPARAM\n"); 3098c2ecf20Sopenharmony_ci return PCH_INVALIDPARAM; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci /* For all station address bytes */ 3128c2ecf20Sopenharmony_ci for (i = 0; i < PCH_STATION_BYTES; i++) { 3138c2ecf20Sopenharmony_ci u32 val; 3148c2ecf20Sopenharmony_ci s32 tmp; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci tmp = hex_to_bin(addr[i * 3]); 3178c2ecf20Sopenharmony_ci if (tmp < 0) { 3188c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 3198c2ecf20Sopenharmony_ci "invalid params returning PCH_INVALIDPARAM\n"); 3208c2ecf20Sopenharmony_ci return PCH_INVALIDPARAM; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci val = tmp * 16; 3238c2ecf20Sopenharmony_ci tmp = hex_to_bin(addr[(i * 3) + 1]); 3248c2ecf20Sopenharmony_ci if (tmp < 0) { 3258c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 3268c2ecf20Sopenharmony_ci "invalid params returning PCH_INVALIDPARAM\n"); 3278c2ecf20Sopenharmony_ci return PCH_INVALIDPARAM; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci val += tmp; 3308c2ecf20Sopenharmony_ci /* Expects ':' separated addresses */ 3318c2ecf20Sopenharmony_ci if ((i < 5) && (addr[(i * 3) + 2] != ':')) { 3328c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 3338c2ecf20Sopenharmony_ci "invalid params returning PCH_INVALIDPARAM\n"); 3348c2ecf20Sopenharmony_ci return PCH_INVALIDPARAM; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* Ideally we should set the address only after validating 3388c2ecf20Sopenharmony_ci entire string */ 3398c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "invoking pch_station_set\n"); 3408c2ecf20Sopenharmony_ci iowrite32(val, &chip->regs->ts_st[i]); 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pch_set_station_address); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci/* 3478c2ecf20Sopenharmony_ci * Interrupt service routine 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_cistatic irqreturn_t isr(int irq, void *priv) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct pch_dev *pch_dev = priv; 3528c2ecf20Sopenharmony_ci struct pch_ts_regs __iomem *regs = pch_dev->regs; 3538c2ecf20Sopenharmony_ci struct ptp_clock_event event; 3548c2ecf20Sopenharmony_ci u32 ack = 0, lo, hi, val; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci val = ioread32(®s->event); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (val & PCH_TSE_SNS) { 3598c2ecf20Sopenharmony_ci ack |= PCH_TSE_SNS; 3608c2ecf20Sopenharmony_ci if (pch_dev->exts0_enabled) { 3618c2ecf20Sopenharmony_ci hi = ioread32(®s->asms_hi); 3628c2ecf20Sopenharmony_ci lo = ioread32(®s->asms_lo); 3638c2ecf20Sopenharmony_ci event.type = PTP_CLOCK_EXTTS; 3648c2ecf20Sopenharmony_ci event.index = 0; 3658c2ecf20Sopenharmony_ci event.timestamp = ((u64) hi) << 32; 3668c2ecf20Sopenharmony_ci event.timestamp |= lo; 3678c2ecf20Sopenharmony_ci event.timestamp <<= TICKS_NS_SHIFT; 3688c2ecf20Sopenharmony_ci ptp_clock_event(pch_dev->ptp_clock, &event); 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (val & PCH_TSE_SNM) { 3738c2ecf20Sopenharmony_ci ack |= PCH_TSE_SNM; 3748c2ecf20Sopenharmony_ci if (pch_dev->exts1_enabled) { 3758c2ecf20Sopenharmony_ci hi = ioread32(®s->amms_hi); 3768c2ecf20Sopenharmony_ci lo = ioread32(®s->amms_lo); 3778c2ecf20Sopenharmony_ci event.type = PTP_CLOCK_EXTTS; 3788c2ecf20Sopenharmony_ci event.index = 1; 3798c2ecf20Sopenharmony_ci event.timestamp = ((u64) hi) << 32; 3808c2ecf20Sopenharmony_ci event.timestamp |= lo; 3818c2ecf20Sopenharmony_ci event.timestamp <<= TICKS_NS_SHIFT; 3828c2ecf20Sopenharmony_ci ptp_clock_event(pch_dev->ptp_clock, &event); 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (val & PCH_TSE_TTIPEND) 3878c2ecf20Sopenharmony_ci ack |= PCH_TSE_TTIPEND; /* this bit seems to be always set */ 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (ack) { 3908c2ecf20Sopenharmony_ci iowrite32(ack, ®s->event); 3918c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3928c2ecf20Sopenharmony_ci } else 3938c2ecf20Sopenharmony_ci return IRQ_NONE; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci/* 3978c2ecf20Sopenharmony_ci * PTP clock operations 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic int ptp_pch_adjfreq(struct ptp_clock_info *ptp, s32 ppb) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci u64 adj; 4038c2ecf20Sopenharmony_ci u32 diff, addend; 4048c2ecf20Sopenharmony_ci int neg_adj = 0; 4058c2ecf20Sopenharmony_ci struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps); 4068c2ecf20Sopenharmony_ci struct pch_ts_regs __iomem *regs = pch_dev->regs; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (ppb < 0) { 4098c2ecf20Sopenharmony_ci neg_adj = 1; 4108c2ecf20Sopenharmony_ci ppb = -ppb; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci addend = DEFAULT_ADDEND; 4138c2ecf20Sopenharmony_ci adj = addend; 4148c2ecf20Sopenharmony_ci adj *= ppb; 4158c2ecf20Sopenharmony_ci diff = div_u64(adj, 1000000000ULL); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci addend = neg_adj ? addend - diff : addend + diff; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci iowrite32(addend, ®s->addend); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic int ptp_pch_adjtime(struct ptp_clock_info *ptp, s64 delta) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci s64 now; 4278c2ecf20Sopenharmony_ci unsigned long flags; 4288c2ecf20Sopenharmony_ci struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps); 4298c2ecf20Sopenharmony_ci struct pch_ts_regs __iomem *regs = pch_dev->regs; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci spin_lock_irqsave(&pch_dev->register_lock, flags); 4328c2ecf20Sopenharmony_ci now = pch_systime_read(regs); 4338c2ecf20Sopenharmony_ci now += delta; 4348c2ecf20Sopenharmony_ci pch_systime_write(regs, now); 4358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pch_dev->register_lock, flags); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic int ptp_pch_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci u64 ns; 4438c2ecf20Sopenharmony_ci unsigned long flags; 4448c2ecf20Sopenharmony_ci struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps); 4458c2ecf20Sopenharmony_ci struct pch_ts_regs __iomem *regs = pch_dev->regs; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci spin_lock_irqsave(&pch_dev->register_lock, flags); 4488c2ecf20Sopenharmony_ci ns = pch_systime_read(regs); 4498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pch_dev->register_lock, flags); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci *ts = ns_to_timespec64(ns); 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic int ptp_pch_settime(struct ptp_clock_info *ptp, 4568c2ecf20Sopenharmony_ci const struct timespec64 *ts) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci u64 ns; 4598c2ecf20Sopenharmony_ci unsigned long flags; 4608c2ecf20Sopenharmony_ci struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps); 4618c2ecf20Sopenharmony_ci struct pch_ts_regs __iomem *regs = pch_dev->regs; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci ns = timespec64_to_ns(ts); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci spin_lock_irqsave(&pch_dev->register_lock, flags); 4668c2ecf20Sopenharmony_ci pch_systime_write(regs, ns); 4678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pch_dev->register_lock, flags); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic int ptp_pch_enable(struct ptp_clock_info *ptp, 4738c2ecf20Sopenharmony_ci struct ptp_clock_request *rq, int on) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci switch (rq->type) { 4788c2ecf20Sopenharmony_ci case PTP_CLK_REQ_EXTTS: 4798c2ecf20Sopenharmony_ci switch (rq->extts.index) { 4808c2ecf20Sopenharmony_ci case 0: 4818c2ecf20Sopenharmony_ci pch_dev->exts0_enabled = on ? 1 : 0; 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci case 1: 4848c2ecf20Sopenharmony_ci pch_dev->exts1_enabled = on ? 1 : 0; 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci default: 4878c2ecf20Sopenharmony_ci return -EINVAL; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci return 0; 4908c2ecf20Sopenharmony_ci default: 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic const struct ptp_clock_info ptp_pch_caps = { 4988c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4998c2ecf20Sopenharmony_ci .name = "PCH timer", 5008c2ecf20Sopenharmony_ci .max_adj = 50000000, 5018c2ecf20Sopenharmony_ci .n_ext_ts = N_EXT_TS, 5028c2ecf20Sopenharmony_ci .n_pins = 0, 5038c2ecf20Sopenharmony_ci .pps = 0, 5048c2ecf20Sopenharmony_ci .adjfreq = ptp_pch_adjfreq, 5058c2ecf20Sopenharmony_ci .adjtime = ptp_pch_adjtime, 5068c2ecf20Sopenharmony_ci .gettime64 = ptp_pch_gettime, 5078c2ecf20Sopenharmony_ci .settime64 = ptp_pch_settime, 5088c2ecf20Sopenharmony_ci .enable = ptp_pch_enable, 5098c2ecf20Sopenharmony_ci}; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci#define pch_suspend NULL 5128c2ecf20Sopenharmony_ci#define pch_resume NULL 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic void pch_remove(struct pci_dev *pdev) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct pch_dev *chip = pci_get_drvdata(pdev); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci ptp_clock_unregister(chip->ptp_clock); 5198c2ecf20Sopenharmony_ci /* free the interrupt */ 5208c2ecf20Sopenharmony_ci if (pdev->irq != 0) 5218c2ecf20Sopenharmony_ci free_irq(pdev->irq, chip); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* unmap the virtual IO memory space */ 5248c2ecf20Sopenharmony_ci if (chip->regs != NULL) { 5258c2ecf20Sopenharmony_ci iounmap(chip->regs); 5268c2ecf20Sopenharmony_ci chip->regs = NULL; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci /* release the reserved IO memory space */ 5298c2ecf20Sopenharmony_ci if (chip->mem_base != 0) { 5308c2ecf20Sopenharmony_ci release_mem_region(chip->mem_base, chip->mem_size); 5318c2ecf20Sopenharmony_ci chip->mem_base = 0; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci pci_disable_device(pdev); 5348c2ecf20Sopenharmony_ci kfree(chip); 5358c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "complete\n"); 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic s32 5398c2ecf20Sopenharmony_cipch_probe(struct pci_dev *pdev, const struct pci_device_id *id) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci s32 ret; 5428c2ecf20Sopenharmony_ci unsigned long flags; 5438c2ecf20Sopenharmony_ci struct pch_dev *chip; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci chip = kzalloc(sizeof(struct pch_dev), GFP_KERNEL); 5468c2ecf20Sopenharmony_ci if (chip == NULL) 5478c2ecf20Sopenharmony_ci return -ENOMEM; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* enable the 1588 pci device */ 5508c2ecf20Sopenharmony_ci ret = pci_enable_device(pdev); 5518c2ecf20Sopenharmony_ci if (ret != 0) { 5528c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "could not enable the pci device\n"); 5538c2ecf20Sopenharmony_ci goto err_pci_en; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci chip->mem_base = pci_resource_start(pdev, IO_MEM_BAR); 5578c2ecf20Sopenharmony_ci if (!chip->mem_base) { 5588c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "could not locate IO memory address\n"); 5598c2ecf20Sopenharmony_ci ret = -ENODEV; 5608c2ecf20Sopenharmony_ci goto err_pci_start; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci /* retrieve the available length of the IO memory space */ 5648c2ecf20Sopenharmony_ci chip->mem_size = pci_resource_len(pdev, IO_MEM_BAR); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* allocate the memory for the device registers */ 5678c2ecf20Sopenharmony_ci if (!request_mem_region(chip->mem_base, chip->mem_size, "1588_regs")) { 5688c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 5698c2ecf20Sopenharmony_ci "could not allocate register memory space\n"); 5708c2ecf20Sopenharmony_ci ret = -EBUSY; 5718c2ecf20Sopenharmony_ci goto err_req_mem_region; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* get the virtual address to the 1588 registers */ 5758c2ecf20Sopenharmony_ci chip->regs = ioremap(chip->mem_base, chip->mem_size); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (!chip->regs) { 5788c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not get virtual address\n"); 5798c2ecf20Sopenharmony_ci ret = -ENOMEM; 5808c2ecf20Sopenharmony_ci goto err_ioremap; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci chip->caps = ptp_pch_caps; 5848c2ecf20Sopenharmony_ci chip->ptp_clock = ptp_clock_register(&chip->caps, &pdev->dev); 5858c2ecf20Sopenharmony_ci if (IS_ERR(chip->ptp_clock)) { 5868c2ecf20Sopenharmony_ci ret = PTR_ERR(chip->ptp_clock); 5878c2ecf20Sopenharmony_ci goto err_ptp_clock_reg; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci spin_lock_init(&chip->register_lock); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci ret = request_irq(pdev->irq, &isr, IRQF_SHARED, KBUILD_MODNAME, chip); 5938c2ecf20Sopenharmony_ci if (ret != 0) { 5948c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get irq %d\n", pdev->irq); 5958c2ecf20Sopenharmony_ci goto err_req_irq; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* indicate success */ 5998c2ecf20Sopenharmony_ci chip->irq = pdev->irq; 6008c2ecf20Sopenharmony_ci chip->pdev = pdev; 6018c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, chip); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci spin_lock_irqsave(&chip->register_lock, flags); 6048c2ecf20Sopenharmony_ci /* reset the ieee1588 h/w */ 6058c2ecf20Sopenharmony_ci pch_reset(chip); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci iowrite32(DEFAULT_ADDEND, &chip->regs->addend); 6088c2ecf20Sopenharmony_ci iowrite32(1, &chip->regs->trgt_lo); 6098c2ecf20Sopenharmony_ci iowrite32(0, &chip->regs->trgt_hi); 6108c2ecf20Sopenharmony_ci iowrite32(PCH_TSE_TTIPEND, &chip->regs->event); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci pch_eth_enable_set(chip); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (strcmp(pch_param.station, "00:00:00:00:00:00") != 0) { 6158c2ecf20Sopenharmony_ci if (pch_set_station_address(pch_param.station, pdev) != 0) { 6168c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 6178c2ecf20Sopenharmony_ci "Invalid station address parameter\n" 6188c2ecf20Sopenharmony_ci "Module loaded but station address not set correctly\n" 6198c2ecf20Sopenharmony_ci ); 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chip->register_lock, flags); 6238c2ecf20Sopenharmony_ci return 0; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cierr_req_irq: 6268c2ecf20Sopenharmony_ci ptp_clock_unregister(chip->ptp_clock); 6278c2ecf20Sopenharmony_cierr_ptp_clock_reg: 6288c2ecf20Sopenharmony_ci iounmap(chip->regs); 6298c2ecf20Sopenharmony_ci chip->regs = NULL; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cierr_ioremap: 6328c2ecf20Sopenharmony_ci release_mem_region(chip->mem_base, chip->mem_size); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cierr_req_mem_region: 6358c2ecf20Sopenharmony_ci chip->mem_base = 0; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cierr_pci_start: 6388c2ecf20Sopenharmony_ci pci_disable_device(pdev); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cierr_pci_en: 6418c2ecf20Sopenharmony_ci kfree(chip); 6428c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "probe failed(ret=0x%x)\n", ret); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return ret; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic const struct pci_device_id pch_ieee1588_pcidev_id[] = { 6488c2ecf20Sopenharmony_ci { 6498c2ecf20Sopenharmony_ci .vendor = PCI_VENDOR_ID_INTEL, 6508c2ecf20Sopenharmony_ci .device = PCI_DEVICE_ID_PCH_1588 6518c2ecf20Sopenharmony_ci }, 6528c2ecf20Sopenharmony_ci {0} 6538c2ecf20Sopenharmony_ci}; 6548c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pch_ieee1588_pcidev_id); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(pch_pm_ops, pch_suspend, pch_resume); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic struct pci_driver pch_driver = { 6598c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 6608c2ecf20Sopenharmony_ci .id_table = pch_ieee1588_pcidev_id, 6618c2ecf20Sopenharmony_ci .probe = pch_probe, 6628c2ecf20Sopenharmony_ci .remove = pch_remove, 6638c2ecf20Sopenharmony_ci .driver.pm = &pch_pm_ops, 6648c2ecf20Sopenharmony_ci}; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic void __exit ptp_pch_exit(void) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci pci_unregister_driver(&pch_driver); 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic s32 __init ptp_pch_init(void) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci s32 ret; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci /* register the driver with the pci core */ 6768c2ecf20Sopenharmony_ci ret = pci_register_driver(&pch_driver); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci return ret; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cimodule_init(ptp_pch_init); 6828c2ecf20Sopenharmony_cimodule_exit(ptp_pch_exit); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cimodule_param_string(station, 6858c2ecf20Sopenharmony_ci pch_param.station, sizeof(pch_param.station), 0444); 6868c2ecf20Sopenharmony_ciMODULE_PARM_DESC(station, 6878c2ecf20Sopenharmony_ci "IEEE 1588 station address to use - colon separated hex values"); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ciMODULE_AUTHOR("LAPIS SEMICONDUCTOR, <tshimizu818@gmail.com>"); 6908c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PTP clock using the EG20T timer"); 6918c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 692