1*a7e1abadSJonathan Lemon // SPDX-License-Identifier: GPL-2.0-only 2*a7e1abadSJonathan Lemon /* Copyright (c) 2020 Facebook */ 3*a7e1abadSJonathan Lemon 4*a7e1abadSJonathan Lemon #include <linux/err.h> 5*a7e1abadSJonathan Lemon #include <linux/kernel.h> 6*a7e1abadSJonathan Lemon #include <linux/module.h> 7*a7e1abadSJonathan Lemon #include <linux/init.h> 8*a7e1abadSJonathan Lemon #include <linux/pci.h> 9*a7e1abadSJonathan Lemon #include <linux/ptp_clock_kernel.h> 10*a7e1abadSJonathan Lemon 11*a7e1abadSJonathan Lemon static const struct pci_device_id ptp_ocp_pcidev_id[] = { 12*a7e1abadSJonathan Lemon { PCI_DEVICE(0x1d9b, 0x0400) }, 13*a7e1abadSJonathan Lemon { 0 } 14*a7e1abadSJonathan Lemon }; 15*a7e1abadSJonathan Lemon MODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id); 16*a7e1abadSJonathan Lemon 17*a7e1abadSJonathan Lemon #define OCP_REGISTER_OFFSET 0x01000000 18*a7e1abadSJonathan Lemon 19*a7e1abadSJonathan Lemon struct ocp_reg { 20*a7e1abadSJonathan Lemon u32 ctrl; 21*a7e1abadSJonathan Lemon u32 status; 22*a7e1abadSJonathan Lemon u32 select; 23*a7e1abadSJonathan Lemon u32 version; 24*a7e1abadSJonathan Lemon u32 time_ns; 25*a7e1abadSJonathan Lemon u32 time_sec; 26*a7e1abadSJonathan Lemon u32 __pad0[2]; 27*a7e1abadSJonathan Lemon u32 adjust_ns; 28*a7e1abadSJonathan Lemon u32 adjust_sec; 29*a7e1abadSJonathan Lemon u32 __pad1[2]; 30*a7e1abadSJonathan Lemon u32 offset_ns; 31*a7e1abadSJonathan Lemon u32 offset_window_ns; 32*a7e1abadSJonathan Lemon }; 33*a7e1abadSJonathan Lemon 34*a7e1abadSJonathan Lemon #define OCP_CTRL_ENABLE BIT(0) 35*a7e1abadSJonathan Lemon #define OCP_CTRL_ADJUST_TIME BIT(1) 36*a7e1abadSJonathan Lemon #define OCP_CTRL_ADJUST_OFFSET BIT(2) 37*a7e1abadSJonathan Lemon #define OCP_CTRL_READ_TIME_REQ BIT(30) 38*a7e1abadSJonathan Lemon #define OCP_CTRL_READ_TIME_DONE BIT(31) 39*a7e1abadSJonathan Lemon 40*a7e1abadSJonathan Lemon #define OCP_STATUS_IN_SYNC BIT(0) 41*a7e1abadSJonathan Lemon 42*a7e1abadSJonathan Lemon #define OCP_SELECT_CLK_NONE 0 43*a7e1abadSJonathan Lemon #define OCP_SELECT_CLK_REG 6 44*a7e1abadSJonathan Lemon 45*a7e1abadSJonathan Lemon struct tod_reg { 46*a7e1abadSJonathan Lemon u32 ctrl; 47*a7e1abadSJonathan Lemon u32 status; 48*a7e1abadSJonathan Lemon u32 uart_polarity; 49*a7e1abadSJonathan Lemon u32 version; 50*a7e1abadSJonathan Lemon u32 correction_sec; 51*a7e1abadSJonathan Lemon u32 __pad0[3]; 52*a7e1abadSJonathan Lemon u32 uart_baud; 53*a7e1abadSJonathan Lemon u32 __pad1[3]; 54*a7e1abadSJonathan Lemon u32 utc_status; 55*a7e1abadSJonathan Lemon u32 leap; 56*a7e1abadSJonathan Lemon }; 57*a7e1abadSJonathan Lemon 58*a7e1abadSJonathan Lemon #define TOD_REGISTER_OFFSET 0x01050000 59*a7e1abadSJonathan Lemon 60*a7e1abadSJonathan Lemon #define TOD_CTRL_PROTOCOL BIT(28) 61*a7e1abadSJonathan Lemon #define TOD_CTRL_DISABLE_FMT_A BIT(17) 62*a7e1abadSJonathan Lemon #define TOD_CTRL_DISABLE_FMT_B BIT(16) 63*a7e1abadSJonathan Lemon #define TOD_CTRL_ENABLE BIT(0) 64*a7e1abadSJonathan Lemon #define TOD_CTRL_GNSS_MASK ((1U << 4) - 1) 65*a7e1abadSJonathan Lemon #define TOD_CTRL_GNSS_SHIFT 24 66*a7e1abadSJonathan Lemon 67*a7e1abadSJonathan Lemon #define TOD_STATUS_UTC_MASK 0xff 68*a7e1abadSJonathan Lemon #define TOD_STATUS_UTC_VALID BIT(8) 69*a7e1abadSJonathan Lemon #define TOD_STATUS_LEAP_VALID BIT(16) 70*a7e1abadSJonathan Lemon 71*a7e1abadSJonathan Lemon struct ptp_ocp { 72*a7e1abadSJonathan Lemon struct pci_dev *pdev; 73*a7e1abadSJonathan Lemon spinlock_t lock; 74*a7e1abadSJonathan Lemon void __iomem *base; 75*a7e1abadSJonathan Lemon struct ocp_reg __iomem *reg; 76*a7e1abadSJonathan Lemon struct tod_reg __iomem *tod; 77*a7e1abadSJonathan Lemon struct ptp_clock *ptp; 78*a7e1abadSJonathan Lemon struct ptp_clock_info ptp_info; 79*a7e1abadSJonathan Lemon }; 80*a7e1abadSJonathan Lemon 81*a7e1abadSJonathan Lemon static int 82*a7e1abadSJonathan Lemon __ptp_ocp_gettime_locked(struct ptp_ocp *bp, struct timespec64 *ts, 83*a7e1abadSJonathan Lemon struct ptp_system_timestamp *sts) 84*a7e1abadSJonathan Lemon { 85*a7e1abadSJonathan Lemon u32 ctrl, time_sec, time_ns; 86*a7e1abadSJonathan Lemon int i; 87*a7e1abadSJonathan Lemon 88*a7e1abadSJonathan Lemon ctrl = ioread32(&bp->reg->ctrl); 89*a7e1abadSJonathan Lemon ctrl |= OCP_CTRL_READ_TIME_REQ; 90*a7e1abadSJonathan Lemon 91*a7e1abadSJonathan Lemon ptp_read_system_prets(sts); 92*a7e1abadSJonathan Lemon iowrite32(ctrl, &bp->reg->ctrl); 93*a7e1abadSJonathan Lemon 94*a7e1abadSJonathan Lemon for (i = 0; i < 100; i++) { 95*a7e1abadSJonathan Lemon ctrl = ioread32(&bp->reg->ctrl); 96*a7e1abadSJonathan Lemon if (ctrl & OCP_CTRL_READ_TIME_DONE) 97*a7e1abadSJonathan Lemon break; 98*a7e1abadSJonathan Lemon } 99*a7e1abadSJonathan Lemon ptp_read_system_postts(sts); 100*a7e1abadSJonathan Lemon 101*a7e1abadSJonathan Lemon time_ns = ioread32(&bp->reg->time_ns); 102*a7e1abadSJonathan Lemon time_sec = ioread32(&bp->reg->time_sec); 103*a7e1abadSJonathan Lemon 104*a7e1abadSJonathan Lemon ts->tv_sec = time_sec; 105*a7e1abadSJonathan Lemon ts->tv_nsec = time_ns; 106*a7e1abadSJonathan Lemon 107*a7e1abadSJonathan Lemon return ctrl & OCP_CTRL_READ_TIME_DONE ? 0 : -ETIMEDOUT; 108*a7e1abadSJonathan Lemon } 109*a7e1abadSJonathan Lemon 110*a7e1abadSJonathan Lemon static int 111*a7e1abadSJonathan Lemon ptp_ocp_gettimex(struct ptp_clock_info *ptp_info, struct timespec64 *ts, 112*a7e1abadSJonathan Lemon struct ptp_system_timestamp *sts) 113*a7e1abadSJonathan Lemon { 114*a7e1abadSJonathan Lemon struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info); 115*a7e1abadSJonathan Lemon unsigned long flags; 116*a7e1abadSJonathan Lemon int err; 117*a7e1abadSJonathan Lemon 118*a7e1abadSJonathan Lemon spin_lock_irqsave(&bp->lock, flags); 119*a7e1abadSJonathan Lemon err = __ptp_ocp_gettime_locked(bp, ts, sts); 120*a7e1abadSJonathan Lemon spin_unlock_irqrestore(&bp->lock, flags); 121*a7e1abadSJonathan Lemon 122*a7e1abadSJonathan Lemon return err; 123*a7e1abadSJonathan Lemon } 124*a7e1abadSJonathan Lemon 125*a7e1abadSJonathan Lemon static void 126*a7e1abadSJonathan Lemon __ptp_ocp_settime_locked(struct ptp_ocp *bp, const struct timespec64 *ts) 127*a7e1abadSJonathan Lemon { 128*a7e1abadSJonathan Lemon u32 ctrl, time_sec, time_ns; 129*a7e1abadSJonathan Lemon u32 select; 130*a7e1abadSJonathan Lemon 131*a7e1abadSJonathan Lemon time_ns = ts->tv_nsec; 132*a7e1abadSJonathan Lemon time_sec = ts->tv_sec; 133*a7e1abadSJonathan Lemon 134*a7e1abadSJonathan Lemon select = ioread32(&bp->reg->select); 135*a7e1abadSJonathan Lemon iowrite32(OCP_SELECT_CLK_REG, &bp->reg->select); 136*a7e1abadSJonathan Lemon 137*a7e1abadSJonathan Lemon iowrite32(time_ns, &bp->reg->adjust_ns); 138*a7e1abadSJonathan Lemon iowrite32(time_sec, &bp->reg->adjust_sec); 139*a7e1abadSJonathan Lemon 140*a7e1abadSJonathan Lemon ctrl = ioread32(&bp->reg->ctrl); 141*a7e1abadSJonathan Lemon ctrl |= OCP_CTRL_ADJUST_TIME; 142*a7e1abadSJonathan Lemon iowrite32(ctrl, &bp->reg->ctrl); 143*a7e1abadSJonathan Lemon 144*a7e1abadSJonathan Lemon /* restore clock selection */ 145*a7e1abadSJonathan Lemon iowrite32(select >> 16, &bp->reg->select); 146*a7e1abadSJonathan Lemon } 147*a7e1abadSJonathan Lemon 148*a7e1abadSJonathan Lemon static int 149*a7e1abadSJonathan Lemon ptp_ocp_settime(struct ptp_clock_info *ptp_info, const struct timespec64 *ts) 150*a7e1abadSJonathan Lemon { 151*a7e1abadSJonathan Lemon struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info); 152*a7e1abadSJonathan Lemon unsigned long flags; 153*a7e1abadSJonathan Lemon 154*a7e1abadSJonathan Lemon if (ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC) 155*a7e1abadSJonathan Lemon return 0; 156*a7e1abadSJonathan Lemon 157*a7e1abadSJonathan Lemon spin_lock_irqsave(&bp->lock, flags); 158*a7e1abadSJonathan Lemon __ptp_ocp_settime_locked(bp, ts); 159*a7e1abadSJonathan Lemon spin_unlock_irqrestore(&bp->lock, flags); 160*a7e1abadSJonathan Lemon 161*a7e1abadSJonathan Lemon return 0; 162*a7e1abadSJonathan Lemon } 163*a7e1abadSJonathan Lemon 164*a7e1abadSJonathan Lemon static int 165*a7e1abadSJonathan Lemon ptp_ocp_adjtime(struct ptp_clock_info *ptp_info, s64 delta_ns) 166*a7e1abadSJonathan Lemon { 167*a7e1abadSJonathan Lemon struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info); 168*a7e1abadSJonathan Lemon struct timespec64 ts; 169*a7e1abadSJonathan Lemon unsigned long flags; 170*a7e1abadSJonathan Lemon int err; 171*a7e1abadSJonathan Lemon 172*a7e1abadSJonathan Lemon if (ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC) 173*a7e1abadSJonathan Lemon return 0; 174*a7e1abadSJonathan Lemon 175*a7e1abadSJonathan Lemon spin_lock_irqsave(&bp->lock, flags); 176*a7e1abadSJonathan Lemon err = __ptp_ocp_gettime_locked(bp, &ts, NULL); 177*a7e1abadSJonathan Lemon if (likely(!err)) { 178*a7e1abadSJonathan Lemon timespec64_add_ns(&ts, delta_ns); 179*a7e1abadSJonathan Lemon __ptp_ocp_settime_locked(bp, &ts); 180*a7e1abadSJonathan Lemon } 181*a7e1abadSJonathan Lemon spin_unlock_irqrestore(&bp->lock, flags); 182*a7e1abadSJonathan Lemon 183*a7e1abadSJonathan Lemon return err; 184*a7e1abadSJonathan Lemon } 185*a7e1abadSJonathan Lemon 186*a7e1abadSJonathan Lemon static int 187*a7e1abadSJonathan Lemon ptp_ocp_null_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm) 188*a7e1abadSJonathan Lemon { 189*a7e1abadSJonathan Lemon if (scaled_ppm == 0) 190*a7e1abadSJonathan Lemon return 0; 191*a7e1abadSJonathan Lemon 192*a7e1abadSJonathan Lemon return -EOPNOTSUPP; 193*a7e1abadSJonathan Lemon } 194*a7e1abadSJonathan Lemon 195*a7e1abadSJonathan Lemon static const struct ptp_clock_info ptp_ocp_clock_info = { 196*a7e1abadSJonathan Lemon .owner = THIS_MODULE, 197*a7e1abadSJonathan Lemon .name = KBUILD_MODNAME, 198*a7e1abadSJonathan Lemon .max_adj = 100000000, 199*a7e1abadSJonathan Lemon .gettimex64 = ptp_ocp_gettimex, 200*a7e1abadSJonathan Lemon .settime64 = ptp_ocp_settime, 201*a7e1abadSJonathan Lemon .adjtime = ptp_ocp_adjtime, 202*a7e1abadSJonathan Lemon .adjfine = ptp_ocp_null_adjfine, 203*a7e1abadSJonathan Lemon }; 204*a7e1abadSJonathan Lemon 205*a7e1abadSJonathan Lemon static int 206*a7e1abadSJonathan Lemon ptp_ocp_check_clock(struct ptp_ocp *bp) 207*a7e1abadSJonathan Lemon { 208*a7e1abadSJonathan Lemon struct timespec64 ts; 209*a7e1abadSJonathan Lemon bool sync; 210*a7e1abadSJonathan Lemon u32 ctrl; 211*a7e1abadSJonathan Lemon 212*a7e1abadSJonathan Lemon /* make sure clock is enabled */ 213*a7e1abadSJonathan Lemon ctrl = ioread32(&bp->reg->ctrl); 214*a7e1abadSJonathan Lemon ctrl |= OCP_CTRL_ENABLE; 215*a7e1abadSJonathan Lemon iowrite32(ctrl, &bp->reg->ctrl); 216*a7e1abadSJonathan Lemon 217*a7e1abadSJonathan Lemon if ((ioread32(&bp->reg->ctrl) & OCP_CTRL_ENABLE) == 0) { 218*a7e1abadSJonathan Lemon dev_err(&bp->pdev->dev, "clock not enabled\n"); 219*a7e1abadSJonathan Lemon return -ENODEV; 220*a7e1abadSJonathan Lemon } 221*a7e1abadSJonathan Lemon 222*a7e1abadSJonathan Lemon sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC; 223*a7e1abadSJonathan Lemon if (!sync) { 224*a7e1abadSJonathan Lemon ktime_get_real_ts64(&ts); 225*a7e1abadSJonathan Lemon ptp_ocp_settime(&bp->ptp_info, &ts); 226*a7e1abadSJonathan Lemon } 227*a7e1abadSJonathan Lemon if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, NULL)) 228*a7e1abadSJonathan Lemon dev_info(&bp->pdev->dev, "Time: %lld.%ld, %s\n", 229*a7e1abadSJonathan Lemon ts.tv_sec, ts.tv_nsec, 230*a7e1abadSJonathan Lemon sync ? "in-sync" : "UNSYNCED"); 231*a7e1abadSJonathan Lemon 232*a7e1abadSJonathan Lemon return 0; 233*a7e1abadSJonathan Lemon } 234*a7e1abadSJonathan Lemon 235*a7e1abadSJonathan Lemon static void 236*a7e1abadSJonathan Lemon ptp_ocp_tod_info(struct ptp_ocp *bp) 237*a7e1abadSJonathan Lemon { 238*a7e1abadSJonathan Lemon static const char * const proto_name[] = { 239*a7e1abadSJonathan Lemon "NMEA", "NMEA_ZDA", "NMEA_RMC", "NMEA_none", 240*a7e1abadSJonathan Lemon "UBX", "UBX_UTC", "UBX_LS", "UBX_none" 241*a7e1abadSJonathan Lemon }; 242*a7e1abadSJonathan Lemon static const char * const gnss_name[] = { 243*a7e1abadSJonathan Lemon "ALL", "COMBINED", "GPS", "GLONASS", "GALILEO", "BEIDOU", 244*a7e1abadSJonathan Lemon }; 245*a7e1abadSJonathan Lemon u32 version, ctrl, reg; 246*a7e1abadSJonathan Lemon int idx; 247*a7e1abadSJonathan Lemon 248*a7e1abadSJonathan Lemon version = ioread32(&bp->tod->version); 249*a7e1abadSJonathan Lemon dev_info(&bp->pdev->dev, "TOD Version %d.%d.%d\n", 250*a7e1abadSJonathan Lemon version >> 24, (version >> 16) & 0xff, version & 0xffff); 251*a7e1abadSJonathan Lemon 252*a7e1abadSJonathan Lemon ctrl = ioread32(&bp->tod->ctrl); 253*a7e1abadSJonathan Lemon ctrl |= TOD_CTRL_PROTOCOL | TOD_CTRL_ENABLE; 254*a7e1abadSJonathan Lemon ctrl &= ~(TOD_CTRL_DISABLE_FMT_A | TOD_CTRL_DISABLE_FMT_B); 255*a7e1abadSJonathan Lemon iowrite32(ctrl, &bp->tod->ctrl); 256*a7e1abadSJonathan Lemon 257*a7e1abadSJonathan Lemon ctrl = ioread32(&bp->tod->ctrl); 258*a7e1abadSJonathan Lemon idx = ctrl & TOD_CTRL_PROTOCOL ? 4 : 0; 259*a7e1abadSJonathan Lemon idx += (ctrl >> 16) & 3; 260*a7e1abadSJonathan Lemon dev_info(&bp->pdev->dev, "control: %x\n", ctrl); 261*a7e1abadSJonathan Lemon dev_info(&bp->pdev->dev, "TOD Protocol %s %s\n", proto_name[idx], 262*a7e1abadSJonathan Lemon ctrl & TOD_CTRL_ENABLE ? "enabled" : ""); 263*a7e1abadSJonathan Lemon 264*a7e1abadSJonathan Lemon idx = (ctrl >> TOD_CTRL_GNSS_SHIFT) & TOD_CTRL_GNSS_MASK; 265*a7e1abadSJonathan Lemon if (idx < ARRAY_SIZE(gnss_name)) 266*a7e1abadSJonathan Lemon dev_info(&bp->pdev->dev, "GNSS %s\n", gnss_name[idx]); 267*a7e1abadSJonathan Lemon 268*a7e1abadSJonathan Lemon reg = ioread32(&bp->tod->status); 269*a7e1abadSJonathan Lemon dev_info(&bp->pdev->dev, "status: %x\n", reg); 270*a7e1abadSJonathan Lemon 271*a7e1abadSJonathan Lemon reg = ioread32(&bp->tod->correction_sec); 272*a7e1abadSJonathan Lemon dev_info(&bp->pdev->dev, "correction: %d\n", reg); 273*a7e1abadSJonathan Lemon 274*a7e1abadSJonathan Lemon reg = ioread32(&bp->tod->utc_status); 275*a7e1abadSJonathan Lemon dev_info(&bp->pdev->dev, "utc_status: %x\n", reg); 276*a7e1abadSJonathan Lemon dev_info(&bp->pdev->dev, "utc_offset: %d valid:%d leap_valid:%d\n", 277*a7e1abadSJonathan Lemon reg & TOD_STATUS_UTC_MASK, reg & TOD_STATUS_UTC_VALID ? 1 : 0, 278*a7e1abadSJonathan Lemon reg & TOD_STATUS_LEAP_VALID ? 1 : 0); 279*a7e1abadSJonathan Lemon } 280*a7e1abadSJonathan Lemon 281*a7e1abadSJonathan Lemon static void 282*a7e1abadSJonathan Lemon ptp_ocp_info(struct ptp_ocp *bp) 283*a7e1abadSJonathan Lemon { 284*a7e1abadSJonathan Lemon static const char * const clock_name[] = { 285*a7e1abadSJonathan Lemon "NO", "TOD", "IRIG", "PPS", "PTP", "RTC", "REGS", "EXT" 286*a7e1abadSJonathan Lemon }; 287*a7e1abadSJonathan Lemon u32 version, select; 288*a7e1abadSJonathan Lemon 289*a7e1abadSJonathan Lemon version = ioread32(&bp->reg->version); 290*a7e1abadSJonathan Lemon select = ioread32(&bp->reg->select); 291*a7e1abadSJonathan Lemon dev_info(&bp->pdev->dev, "Version %d.%d.%d, clock %s, device ptp%d\n", 292*a7e1abadSJonathan Lemon version >> 24, (version >> 16) & 0xff, version & 0xffff, 293*a7e1abadSJonathan Lemon clock_name[select & 7], 294*a7e1abadSJonathan Lemon ptp_clock_index(bp->ptp)); 295*a7e1abadSJonathan Lemon 296*a7e1abadSJonathan Lemon ptp_ocp_tod_info(bp); 297*a7e1abadSJonathan Lemon } 298*a7e1abadSJonathan Lemon 299*a7e1abadSJonathan Lemon static int 300*a7e1abadSJonathan Lemon ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id) 301*a7e1abadSJonathan Lemon { 302*a7e1abadSJonathan Lemon struct ptp_ocp *bp; 303*a7e1abadSJonathan Lemon int err; 304*a7e1abadSJonathan Lemon 305*a7e1abadSJonathan Lemon bp = kzalloc(sizeof(*bp), GFP_KERNEL); 306*a7e1abadSJonathan Lemon if (!bp) 307*a7e1abadSJonathan Lemon return -ENOMEM; 308*a7e1abadSJonathan Lemon bp->pdev = pdev; 309*a7e1abadSJonathan Lemon pci_set_drvdata(pdev, bp); 310*a7e1abadSJonathan Lemon 311*a7e1abadSJonathan Lemon err = pci_enable_device(pdev); 312*a7e1abadSJonathan Lemon if (err) { 313*a7e1abadSJonathan Lemon dev_err(&pdev->dev, "pci_enable_device\n"); 314*a7e1abadSJonathan Lemon goto out_free; 315*a7e1abadSJonathan Lemon } 316*a7e1abadSJonathan Lemon 317*a7e1abadSJonathan Lemon err = pci_request_regions(pdev, KBUILD_MODNAME); 318*a7e1abadSJonathan Lemon if (err) { 319*a7e1abadSJonathan Lemon dev_err(&pdev->dev, "pci_request_region\n"); 320*a7e1abadSJonathan Lemon goto out_disable; 321*a7e1abadSJonathan Lemon } 322*a7e1abadSJonathan Lemon 323*a7e1abadSJonathan Lemon bp->base = pci_ioremap_bar(pdev, 0); 324*a7e1abadSJonathan Lemon if (!bp->base) { 325*a7e1abadSJonathan Lemon dev_err(&pdev->dev, "io_remap bar0\n"); 326*a7e1abadSJonathan Lemon err = -ENOMEM; 327*a7e1abadSJonathan Lemon goto out; 328*a7e1abadSJonathan Lemon } 329*a7e1abadSJonathan Lemon bp->reg = bp->base + OCP_REGISTER_OFFSET; 330*a7e1abadSJonathan Lemon bp->tod = bp->base + TOD_REGISTER_OFFSET; 331*a7e1abadSJonathan Lemon bp->ptp_info = ptp_ocp_clock_info; 332*a7e1abadSJonathan Lemon spin_lock_init(&bp->lock); 333*a7e1abadSJonathan Lemon 334*a7e1abadSJonathan Lemon err = ptp_ocp_check_clock(bp); 335*a7e1abadSJonathan Lemon if (err) 336*a7e1abadSJonathan Lemon goto out; 337*a7e1abadSJonathan Lemon 338*a7e1abadSJonathan Lemon bp->ptp = ptp_clock_register(&bp->ptp_info, &pdev->dev); 339*a7e1abadSJonathan Lemon if (IS_ERR(bp->ptp)) { 340*a7e1abadSJonathan Lemon dev_err(&pdev->dev, "ptp_clock_register\n"); 341*a7e1abadSJonathan Lemon err = PTR_ERR(bp->ptp); 342*a7e1abadSJonathan Lemon goto out; 343*a7e1abadSJonathan Lemon } 344*a7e1abadSJonathan Lemon 345*a7e1abadSJonathan Lemon ptp_ocp_info(bp); 346*a7e1abadSJonathan Lemon 347*a7e1abadSJonathan Lemon return 0; 348*a7e1abadSJonathan Lemon 349*a7e1abadSJonathan Lemon out: 350*a7e1abadSJonathan Lemon pci_release_regions(pdev); 351*a7e1abadSJonathan Lemon out_disable: 352*a7e1abadSJonathan Lemon pci_disable_device(pdev); 353*a7e1abadSJonathan Lemon out_free: 354*a7e1abadSJonathan Lemon kfree(bp); 355*a7e1abadSJonathan Lemon 356*a7e1abadSJonathan Lemon return err; 357*a7e1abadSJonathan Lemon } 358*a7e1abadSJonathan Lemon 359*a7e1abadSJonathan Lemon static void 360*a7e1abadSJonathan Lemon ptp_ocp_remove(struct pci_dev *pdev) 361*a7e1abadSJonathan Lemon { 362*a7e1abadSJonathan Lemon struct ptp_ocp *bp = pci_get_drvdata(pdev); 363*a7e1abadSJonathan Lemon 364*a7e1abadSJonathan Lemon ptp_clock_unregister(bp->ptp); 365*a7e1abadSJonathan Lemon pci_iounmap(pdev, bp->base); 366*a7e1abadSJonathan Lemon pci_release_regions(pdev); 367*a7e1abadSJonathan Lemon pci_disable_device(pdev); 368*a7e1abadSJonathan Lemon pci_set_drvdata(pdev, NULL); 369*a7e1abadSJonathan Lemon kfree(bp); 370*a7e1abadSJonathan Lemon } 371*a7e1abadSJonathan Lemon 372*a7e1abadSJonathan Lemon static struct pci_driver ptp_ocp_driver = { 373*a7e1abadSJonathan Lemon .name = KBUILD_MODNAME, 374*a7e1abadSJonathan Lemon .id_table = ptp_ocp_pcidev_id, 375*a7e1abadSJonathan Lemon .probe = ptp_ocp_probe, 376*a7e1abadSJonathan Lemon .remove = ptp_ocp_remove, 377*a7e1abadSJonathan Lemon }; 378*a7e1abadSJonathan Lemon 379*a7e1abadSJonathan Lemon static int __init 380*a7e1abadSJonathan Lemon ptp_ocp_init(void) 381*a7e1abadSJonathan Lemon { 382*a7e1abadSJonathan Lemon int err; 383*a7e1abadSJonathan Lemon 384*a7e1abadSJonathan Lemon err = pci_register_driver(&ptp_ocp_driver); 385*a7e1abadSJonathan Lemon return err; 386*a7e1abadSJonathan Lemon } 387*a7e1abadSJonathan Lemon 388*a7e1abadSJonathan Lemon static void __exit 389*a7e1abadSJonathan Lemon ptp_ocp_fini(void) 390*a7e1abadSJonathan Lemon { 391*a7e1abadSJonathan Lemon pci_unregister_driver(&ptp_ocp_driver); 392*a7e1abadSJonathan Lemon } 393*a7e1abadSJonathan Lemon 394*a7e1abadSJonathan Lemon module_init(ptp_ocp_init); 395*a7e1abadSJonathan Lemon module_exit(ptp_ocp_fini); 396*a7e1abadSJonathan Lemon 397*a7e1abadSJonathan Lemon MODULE_DESCRIPTION("OpenCompute TimeCard driver"); 398*a7e1abadSJonathan Lemon MODULE_LICENSE("GPL v2"); 399