// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * NXP NETC Timer driver * Copyright 2023 NXP * Copyright (C) 2023 Wei Fang */ #include #include #include #include #include #include #define NETC_TMR_CTRL 0x0080 #define TMR_CTRL_CK_SEL GENMASK(1, 0) #define TMR_CTRL_TE BIT(2) #define TMR_COMP_MODE BIT(15) #define TMR_CTRL_TCLK_PERIOD GENMASK(25, 16) #define TMR_CTRL_FS BIT(28) #define TMR_ALARM1P BIT(31) #define NETC_TMR_TEVENT 0x0084 #define TMR_TEVNET_PPEN(a) BIT(7 - (a)) #define TMR_TEVENT_PPEN_ALL GENMASK(7, 5) #define TMR_TEVENT_ALM1EN BIT(16) #define TMR_TEVENT_ALM2EN BIT(17) #define TMR_TEVENT_ETS1_THREN BIT(20) #define TMR_TEVENT_ETS2_THREN BIT(21) #define TMR_TEVENT_ETS1EN BIT(24) #define TMR_TEVENT_ETS2EN BIT(25) #define TMR_TEVENT_ETS1_OVEN BIT(28) #define TMR_TEVENT_ETS2_OVEN BIT(29) #define NETC_TMR_TEMASK 0x0088 #define NETC_TMR_STAT 0x0094 #define NETC_TMR_CNT_L 0x0098 #define NETC_TMR_CNT_H 0x009c #define NETC_TMR_ADD 0x00a0 #define NETC_TMR_ACC 0x00a4 #define NETC_TMR_PRSC 0x00a8 #define NETC_TMR_ECTRL 0x00ac #define NETC_TMR_OFF_L 0x00b0 #define NETC_TMR_OFF_H 0x00b4 /* a = 0 or 1, a = 0 indicates TMR_ALARM1, a = 1 indicates TMR_ALARM2 */ #define NETC_TMR_ALARM_L(a) (0x00b8 + (a) * 8) #define NETC_TMR_ALARM_H(a) (0x00bc + (a) * 8) #define NETC_TMR_ALARM_CTRL 0x00cc #define ALARM_CTRL_PW(a) (GENMASK(4, 0) << (a) * 8) #define ALARM_CTRL_PG(a) (BIT(7) << (a) * 8) /* a = 0, 1, 2. a = 0 indicates TMR_FIPER1, a = 1 indicates TMR_FIPER2, * a = 2 indicates TMR_FIPER3. */ #define NETC_TMR_FIPER(a) (0x00d0 + (a) * 4) #define NETC_TMR_FIPER_CTRL 0x00dc #define FIPER_CTRL_PW(a) (GENMASK(4, 0) << (a) * 8) #define FIPER_CTRL_PG(a) (BIT(6) << (a) * 8) #define FIPER_CTRL_DIS(a) (BIT(7) << (a) * 8) #define NETC_TMR_ETTS1_L 0x00e0 #define NETC_TMR_ETTS1_H 0x00e4 #define NETC_TMR_ETTS2_L 0x00e8 #define NETC_TMR_ETTS2_H 0x00ec #define NETC_TMR_PARAM 0x00f8 #define NETC_TMR_REGS_BAR 0 #define NETC_TMR_FIPER_NUM 3 #define NETC_TMR_DEFAULT_PRSC 2 #define NETC_TMR_DEFAULT_ALARM 0xffffffffffffffffULL #define NETC_TMR_DEFAULT_FIPER 0xffffffff #define NETC_TMR_PRSC_OCK_MAX 0xfffe /* 1588 timer reference clock source select */ #define NETC_TMR_CCM_TIMER1 0 /* enet_timer1_clk_root, from CCM */ #define NETC_TMR_SYSTEM_CLK 1 /* enet_clk_root/2, from CCM */ #define NETC_TMR_EXT_OSC 2 /* tmr_1588_clk, from IO pins */ #define NETC_TMR_SYSCLK_RATE 333333333UL #define NETC_TMR_SYSCLK_PERIOD_INT 3 #define NETC_TMR_SYSCLK_PERIOD_FRAC 0xd #define NETC_TMR_FIPER_PW 0x1f struct netc_timer { void __iomem *base; struct device *dev; struct pci_dev *pci_dev; int irq; char irq_name[64]; spinlock_t lock; /* protect regs */ struct ptp_clock *clock; struct ptp_clock_info caps; int phc_index; u32 clk_select; u32 clk_freq; u32 period_int; /* fractional part of clock period * BIT(32) */ u32 period_frac; /* High 32 bits are the integer part, low 32 bits * are the fractional part */ u64 base_period; u32 oclk_prsc; /* must be an even value */ u32 fiper[NETC_TMR_FIPER_NUM]; }; static inline u32 netc_timer_read(void __iomem *reg) { return ioread32(reg); } static inline void netc_timer_write(void __iomem *reg, u32 val) { iowrite32(val, reg); } #define netc_timer_read_reg(p, o) netc_timer_read((p)->base + (o)) #define netc_timer_write_reg(p, o, v) netc_timer_write((p)->base + (o), v) static u64 netc_timer_cnt_read(struct netc_timer *priv) { u32 tmr_cnt_l, tmr_cnt_h; u64 ns; /* The user must read the TMR_CNC_L register first to get * correct 64-bit TMR_CNT_H/L counter values. */ tmr_cnt_l = netc_timer_read_reg(priv, NETC_TMR_CNT_L); tmr_cnt_h = netc_timer_read_reg(priv, NETC_TMR_CNT_H); ns = (((u64)tmr_cnt_h) << 32) | tmr_cnt_l; return ns; } static void netc_timer_cnt_write(struct netc_timer *priv, u64 ns) { u32 tmr_cnt_h = upper_32_bits(ns); u32 tmr_cnt_l = lower_32_bits(ns); /* The user must write to TMR_CNT_L register first. */ netc_timer_write_reg(priv, NETC_TMR_CNT_L, tmr_cnt_l); netc_timer_write_reg(priv, NETC_TMR_CNT_H, tmr_cnt_h); } static void netc_timer_alarm_write(struct netc_timer *priv, u64 alarm, int index) { u32 alarm_h = upper_32_bits(alarm); u32 alarm_l = lower_32_bits(alarm); netc_timer_write_reg(priv, NETC_TMR_ALARM_L(index), alarm_l); netc_timer_write_reg(priv, NETC_TMR_ALARM_H(index), alarm_h); } static void netc_timer_set_oclk_prsc(struct netc_timer *priv, u32 oclk_prsc) { if (oclk_prsc < NETC_TMR_PRSC_OCK_MAX) { if (oclk_prsc % 2 != 0) oclk_prsc++; } else { oclk_prsc = NETC_TMR_PRSC_OCK_MAX; } priv->oclk_prsc = oclk_prsc; if (oclk_prsc == netc_timer_read_reg(priv, NETC_TMR_PRSC)) return; netc_timer_write_reg(priv, NETC_TMR_PRSC, priv->oclk_prsc); } static u32 netc_timer_calculate_fiper_pulse_width(struct netc_timer *priv, u32 fiper) { u32 oclk_prsc = NETC_TMR_DEFAULT_PRSC; u64 pw; /* Set the FIPER pulse width to half FIPER interval by default. * pulse_width = (fiper / 2) / TMR_GCLK_period, * TMR_GCLK_period = NSEC_PER_SEC / TMR_GCLK_freq, * TMR_GCLK_freq = (clk_freq / oclk_prsc) MHz, * so pulse_width = fiper * clk_freq / (2 * NSEC_PER_SEC * oclk_prsc). * * The oclk_prsc value needs to be an even number, so here we use its * default value NETC_TMR_DEFAULT_PRSC to calculate the pw. If pw * exceeds the maximum value, then update the oclk_prsc. */ pw = (u64)fiper * priv->clk_freq; /* 2 * NSEC_PER_SEC * oclk_prsc = 4000000000UL */ pw = div_u64(pw, 4000000000UL); /* The FIPER_PW field only has 5 bits, need to update oclk_prsc */ if (pw > NETC_TMR_FIPER_PW) { oclk_prsc = div_u64(pw, NETC_TMR_FIPER_PW) * oclk_prsc; pw = NETC_TMR_FIPER_PW; } netc_timer_set_oclk_prsc(priv, oclk_prsc); return pw; } static void netc_timer_adjust_period(struct netc_timer *priv, u64 period) { u32 period_frac = lower_32_bits(period); u32 period_int = upper_32_bits(period); u32 tmr_ctrl, old_tmr_ctrl; guard(spinlock_irqsave)(&priv->lock); old_tmr_ctrl = netc_timer_read_reg(priv, NETC_TMR_CTRL); tmr_ctrl = u32_replace_bits(old_tmr_ctrl, period_int, TMR_CTRL_TCLK_PERIOD); if (tmr_ctrl != old_tmr_ctrl) netc_timer_write_reg(priv, NETC_TMR_CTRL, tmr_ctrl); netc_timer_write_reg(priv, NETC_TMR_ADD, period_frac); } static irqreturn_t netc_timer_isr(int irq, void *data) { struct netc_timer *priv = data; struct ptp_clock_event event; u32 tmr_event, tmr_emask; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); tmr_event = netc_timer_read_reg(priv, NETC_TMR_TEVENT); tmr_emask = netc_timer_read_reg(priv, NETC_TMR_TEMASK); /* Clear interrupts status */ netc_timer_write_reg(priv, NETC_TMR_TEVENT, tmr_event); tmr_event &= tmr_emask; if (tmr_event & TMR_TEVENT_PPEN_ALL) { event.type = PTP_CLOCK_PPS; ptp_clock_event(priv->clock, &event); } if (tmr_event & TMR_TEVENT_ALM1EN) { tmr_emask &= ~TMR_TEVENT_ALM1EN; netc_timer_write_reg(priv, NETC_TMR_TEMASK, tmr_emask); netc_timer_alarm_write(priv, NETC_TMR_DEFAULT_ALARM, 0); } spin_unlock_irqrestore(&priv->lock, flags); return IRQ_HANDLED; } static int netc_timer_get_clk_config(struct netc_timer *priv) { struct device_node *node = priv->dev->of_node; u32 clk_cfg[3]; int err; err = of_property_read_u32_array(node, "fsl,clk-cfg", clk_cfg, ARRAY_SIZE(clk_cfg)); if (!err) { priv->clk_freq = clk_cfg[0]; priv->period_int = clk_cfg[1]; priv->period_frac = clk_cfg[2]; priv->base_period = ((u64)priv->period_int << 32) | priv->period_frac; return 0; } priv->clk_freq = NETC_TMR_SYSCLK_RATE; priv->period_int = NETC_TMR_SYSCLK_PERIOD_INT; priv->period_frac = NETC_TMR_SYSCLK_PERIOD_FRAC; priv->base_period = ((u64)priv->period_int << 32) | priv->period_frac; return 0; } /* ppm: parts per million, ppb: parts per billion */ static int netc_timer_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct netc_timer *priv = container_of(ptp, struct netc_timer, caps); u64 new_period; if (!scaled_ppm) return 0; new_period = adjust_by_scaled_ppm(priv->base_period, scaled_ppm); netc_timer_adjust_period(priv, new_period); return 0; } static int netc_timer_adjtime(struct ptp_clock_info *ptp, s64 delta) { struct netc_timer *priv; unsigned long flags; u64 ns, adj_ns; priv = container_of(ptp, struct netc_timer, caps); adj_ns = abs(delta); spin_lock_irqsave(&priv->lock, flags); ns = netc_timer_cnt_read(priv); if (delta < 0) ns -= adj_ns; else ns += adj_ns; netc_timer_cnt_write(priv, ns); spin_unlock_irqrestore(&priv->lock, flags); return 0; } static int netc_timer_gettimex64(struct ptp_clock_info *ptp, struct timespec64 *ts, struct ptp_system_timestamp *sts) { struct netc_timer *priv; unsigned long flags; u64 ns; priv = container_of(ptp, struct netc_timer, caps); spin_lock_irqsave(&priv->lock, flags); ptp_read_system_prets(sts); ns = netc_timer_cnt_read(priv); ptp_read_system_postts(sts); spin_unlock_irqrestore(&priv->lock, flags); *ts = ns_to_timespec64(ns); return 0; } static int netc_timer_settime64(struct ptp_clock_info *ptp, const struct timespec64 *ts) { struct netc_timer *priv; unsigned long flags; u64 ns; priv = container_of(ptp, struct netc_timer, caps); ns = timespec64_to_ns(ts); spin_lock_irqsave(&priv->lock, flags); netc_timer_cnt_write(priv, ns); spin_unlock_irqrestore(&priv->lock, flags); return 0; } static int netc_timer_enable_pps(struct netc_timer *priv, struct ptp_clock_request *rq, int on) { u32 tmr_emask, fiper, fiper_ctrl, fiper_pw; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); tmr_emask = netc_timer_read_reg(priv, NETC_TMR_TEMASK); fiper_ctrl = netc_timer_read_reg(priv, NETC_TMR_FIPER_CTRL); if (on) { fiper = div_u64(NSEC_PER_SEC, priv->period_int) - 1; fiper = fiper * priv->period_int; fiper_pw = netc_timer_calculate_fiper_pulse_width(priv, fiper); fiper_ctrl &= ~(FIPER_CTRL_DIS(0) | FIPER_CTRL_PW(0)); fiper_ctrl |= fiper_pw & FIPER_CTRL_PW(0); tmr_emask |= TMR_TEVNET_PPEN(0); } else { fiper = NETC_TMR_DEFAULT_FIPER; tmr_emask &= ~TMR_TEVNET_PPEN(0); fiper_ctrl |= FIPER_CTRL_DIS(0); } netc_timer_write_reg(priv, NETC_TMR_TEMASK, tmr_emask); netc_timer_write_reg(priv, NETC_TMR_FIPER(0), fiper); netc_timer_write_reg(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl); spin_unlock_irqrestore(&priv->lock, flags); return 0; } static int net_timer_enable_perout(struct netc_timer *priv, struct ptp_clock_request *rq, int on) { u32 tmr_emask, tmr_ctrl, fiper, fiper_ctrl; struct timespec64 period, stime; u64 alarm, period_ns, cur_time; u32 channel, fiper_pw; unsigned long flags; if (rq->perout.flags) return -EOPNOTSUPP; channel = rq->perout.index; if (channel >= NETC_TMR_FIPER_NUM) return -EINVAL; spin_lock_irqsave(&priv->lock, flags); tmr_ctrl = netc_timer_read_reg(priv, NETC_TMR_CTRL); tmr_emask = netc_timer_read_reg(priv, NETC_TMR_TEMASK); fiper_ctrl = netc_timer_read_reg(priv, NETC_TMR_FIPER_CTRL); if (!on) { tmr_emask &= ~(TMR_TEVNET_PPEN(channel) | TMR_TEVENT_ALM1EN); tmr_ctrl &= ~TMR_CTRL_FS; alarm = NETC_TMR_DEFAULT_ALARM; fiper = NETC_TMR_DEFAULT_FIPER; fiper_ctrl |= FIPER_CTRL_DIS(channel); } else { period.tv_sec = rq->perout.period.sec; period.tv_nsec = rq->perout.period.nsec; period_ns = timespec64_to_ns(&period); stime.tv_sec = rq->perout.start.sec; stime.tv_nsec = rq->perout.start.nsec; tmr_emask |= TMR_TEVNET_PPEN(channel) | TMR_TEVENT_ALM1EN; tmr_ctrl |= TMR_CTRL_FS; tmr_ctrl &= ~TMR_ALARM1P; /* fiper is set to desired FIPER interval in ns - TCLK_PERIOD * and should be an integer multiple of TCLK_PERIOD. */ fiper = div_u64(period_ns, priv->period_int) - 1; fiper = fiper * priv->period_int; fiper_pw = netc_timer_calculate_fiper_pulse_width(priv, fiper); if (fiper_pw == 0) { dev_err(priv->dev, "The setting period is too small!\n"); spin_unlock_irqrestore(&priv->lock, flags); return -EINVAL; } fiper_ctrl &= ~(FIPER_CTRL_DIS(channel) | FIPER_CTRL_PW(channel)); fiper_ctrl |= (fiper_pw << 8 * channel) & FIPER_CTRL_PW(channel); /* alarm must be an integer multiple of TCLK_PERIOD in order * to get correct result. In addtion, In FS mode the alarm * trigger is used as an indication to the fiper start down * counting. Only TMR_ALARM1 supports this mode. */ alarm = timespec64_to_ns(&stime); cur_time = netc_timer_cnt_read(priv); if (cur_time >= alarm) { dev_err(priv->dev, "Start time must greater than current time!\n"); spin_unlock_irqrestore(&priv->lock, flags); return -EINVAL; } alarm = div_u64(alarm, priv->period_int); alarm = alarm * priv->period_int; } netc_timer_write_reg(priv, NETC_TMR_CTRL, tmr_ctrl); netc_timer_write_reg(priv, NETC_TMR_TEMASK, tmr_emask); netc_timer_write_reg(priv, NETC_TMR_FIPER(channel), fiper); netc_timer_alarm_write(priv, alarm, 0); netc_timer_write_reg(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl); spin_unlock_irqrestore(&priv->lock, flags); return 0; } static int netc_timer_enable(struct ptp_clock_info *ptp, struct ptp_clock_request *rq, int on) { struct netc_timer *priv; priv = container_of(ptp, struct netc_timer, caps); switch (rq->type) { case PTP_CLK_REQ_PEROUT: return net_timer_enable_perout(priv, rq, on); case PTP_CLK_REQ_PPS: return netc_timer_enable_pps(priv, rq, on); case PTP_CLK_REQ_EXTTS: /* TODO */ default: return -EOPNOTSUPP; } } static const struct ptp_clock_info netc_timer_ptp_caps = { .owner = THIS_MODULE, .name = "NETC Timer PTP clock", .max_adj = 500000000, .n_alarm = 2, .n_ext_ts = 2, .n_per_out = 3, .n_pins = 0, .pps = 1, .adjfine = netc_timer_adjfine, .adjtime = netc_timer_adjtime, .gettimex64 = netc_timer_gettimex64, .settime64 = netc_timer_settime64, .enable = netc_timer_enable, }; int netc_timer_get_phc_index(int domain, unsigned int bus, unsigned int devfn) { struct pci_dev *timer_pdev; struct netc_timer *priv; timer_pdev = pci_get_domain_bus_and_slot(domain, bus, devfn); if (!timer_pdev) return -EINVAL; priv = pci_get_drvdata(timer_pdev); if (!priv) return -EINVAL; return priv->phc_index; } EXPORT_SYMBOL_GPL(netc_timer_get_phc_index); static int netc_timer_init(struct netc_timer *priv) { struct device_node *node = priv->dev->of_node; u32 tmr_ctrl, alarm_ctrl, fiper_ctrl; struct timespec64 now; unsigned long flags; int i, err; u64 ns; priv->caps = netc_timer_ptp_caps; priv->oclk_prsc = NETC_TMR_DEFAULT_PRSC; if (of_property_read_u32(node, "fsl,clk-select", &priv->clk_select)) priv->clk_select = NETC_TMR_SYSTEM_CLK; /* Check whether the clock source is valid */ if (priv->clk_select != NETC_TMR_SYSTEM_CLK && priv->clk_select != NETC_TMR_CCM_TIMER1 && priv->clk_select != NETC_TMR_EXT_OSC) { dev_err(priv->dev, "Wrong clock source %d\n", priv->clk_select); return -EINVAL; } err = netc_timer_get_clk_config(priv); if (err) return err; alarm_ctrl = ALARM_CTRL_PG(0) | ALARM_CTRL_PG(1); spin_lock_init(&priv->lock); spin_lock_irqsave(&priv->lock, flags); /* Software must enable timer first and the clock selected must be * active, otherwise, the registers which are in the timer clock * domain are not accesdible. */ tmr_ctrl = (priv->clk_select & TMR_CTRL_CK_SEL) | TMR_CTRL_TE; netc_timer_write_reg(priv, NETC_TMR_CTRL, tmr_ctrl); /* Output FIPER pulse clock (TMR_GCLK) is generated by dividing the * input clock of Timer by priv->oclk_prsc. For example, if input * clock of Timer is 200MHz, and priv->oclk_prsc is 2, then TMR_GCLK * is 100MHz. */ netc_timer_write_reg(priv, NETC_TMR_PRSC, priv->oclk_prsc); netc_timer_write_reg(priv, NETC_TMR_ALARM_CTRL, alarm_ctrl); fiper_ctrl = netc_timer_read_reg(priv, NETC_TMR_FIPER_CTRL); for (i = 0; i < NETC_TMR_FIPER_NUM; i++) fiper_ctrl |= FIPER_CTRL_DIS(i); netc_timer_write_reg(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl); ktime_get_real_ts64(&now); ns = timespec64_to_ns(&now); netc_timer_cnt_write(priv, ns); /* Allow atomic writes to TCLK_PERIOD and TMR_ADD, An update * to TCLK_PERIOD doesn't take effect until TMR_ADD is written. */ tmr_ctrl |= ((priv->period_int << 16) & TMR_CTRL_TCLK_PERIOD) | TMR_COMP_MODE; netc_timer_write_reg(priv, NETC_TMR_CTRL, tmr_ctrl); netc_timer_write_reg(priv, NETC_TMR_ADD, priv->period_frac); spin_unlock_irqrestore(&priv->lock, flags); return 0; } static void netc_timer_deinit(struct netc_timer *priv) { unsigned long flags; u32 fiper_ctrl; int i; spin_lock_irqsave(&priv->lock, flags); netc_timer_write_reg(priv, NETC_TMR_TEMASK, 0); netc_timer_alarm_write(priv, NETC_TMR_DEFAULT_ALARM, 0); fiper_ctrl = netc_timer_read_reg(priv, NETC_TMR_FIPER_CTRL); for (i = 0; i < NETC_TMR_FIPER_NUM; i++) { netc_timer_write_reg(priv, NETC_TMR_FIPER(i), NETC_TMR_DEFAULT_FIPER); fiper_ctrl |= FIPER_CTRL_DIS(i); } netc_timer_write_reg(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl); spin_unlock_irqrestore(&priv->lock, flags); } static int netc_timer_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct device *dev = &pdev->dev; struct netc_timer *priv; int err, len, n; err = netc_ierb_get_init_status(); if (err) { if (err != -EPROBE_DEFER) dev_err(dev, "Can't get IERB init status: %d\n", err); return err; } err = pci_enable_device_mem(pdev); if (err) return dev_err_probe(dev, err, "device enable failed\n"); err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); if (err) { dev_err(dev, "DMA configuration failed: 0x%x\n", err); goto disable_dev; } err = pci_request_mem_regions(pdev, KBUILD_MODNAME); if (err) { dev_err(dev, "pci_request_regions failed err=%d\n", err); goto disable_dev; } pci_set_master(pdev); priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { err = -ENOMEM; goto release_mem_regions; } priv->dev = dev; priv->pci_dev = pdev; priv->phc_index = -1; /* initialize it as an invalid index */ len = pci_resource_len(pdev, NETC_TMR_REGS_BAR); priv->base = ioremap(pci_resource_start(pdev, NETC_TMR_REGS_BAR), len); if (!priv->base) { err = -ENXIO; dev_err(dev, "ioremap() failed\n"); goto free_priv; } n = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX); if (n != 1) { err = -EPERM; goto unmap_resource; } priv->irq = pci_irq_vector(pdev, 0); snprintf(priv->irq_name, sizeof(priv->irq_name), "ptp-netc %s", pci_name(pdev)); err = request_irq(priv->irq, netc_timer_isr, 0, priv->irq_name, priv); if (err) { dev_err(dev, "request_irq() failed!\n"); goto free_irq_vectors; } err = netc_timer_init(priv); if (err) { dev_err(dev, "NETC Timer initialization failed\n"); goto free_irq; } priv->clock = ptp_clock_register(&priv->caps, priv->dev); if (IS_ERR(priv->clock)) { err = PTR_ERR(priv->clock); goto deinit_timer; } priv->phc_index = ptp_clock_index(priv->clock); pci_set_drvdata(pdev, priv); return 0; deinit_timer: netc_timer_deinit(priv); free_irq: free_irq(priv->irq, priv); free_irq_vectors: pci_free_irq_vectors(pdev); unmap_resource: iounmap(priv->base); free_priv: kfree(priv); release_mem_regions: pci_release_mem_regions(pdev); disable_dev: pci_disable_device(pdev); return err; } static void netc_timer_remove(struct pci_dev *pdev) { struct netc_timer *priv = pci_get_drvdata(pdev); netc_timer_deinit(priv); ptp_clock_unregister(priv->clock); iounmap(priv->base); free_irq(priv->irq, priv); pci_free_irq_vectors(pdev); kfree(priv); pci_release_mem_regions(pdev); pci_disable_device(pdev); } static const struct pci_device_id netc_timer_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_NXP2, PCI_DEVICE_ID_NXP2_NETC_TIMER) }, { 0, } /* End of table. */ }; MODULE_DEVICE_TABLE(pci, netc_timer_id_table); static int ptp_netc_shutdown(struct netc_timer *priv) { struct pci_dev *pdev = priv->pci_dev; netc_timer_deinit(priv); disable_irq(priv->irq); irq_set_affinity_hint(priv->irq, NULL); free_irq(priv->irq, priv); pci_free_irq_vectors(pdev); pci_save_state(pdev); pci_disable_device(priv->pci_dev); return 0; } static int ptp_netc_powerup(struct netc_timer *priv) { struct pci_dev *pdev = priv->pci_dev; int err, n; err = netc_ierb_get_init_status(); if (err) { dev_err(&pdev->dev, "Can't get IERB init status: %d\n", err); return err; } err = pci_enable_device_mem(pdev); if (err) { dev_err(&pdev->dev, "device enable failed\n"); return err; } pci_restore_state(pdev); pci_set_master(pdev); n = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX); if (n != 1) { err = -EPERM; goto disable_dev; } priv->irq = pci_irq_vector(pdev, 0); err = request_irq(priv->irq, netc_timer_isr, 0, priv->irq_name, priv); if (err) { dev_err(&pdev->dev, "request_irq() failed!\n"); goto free_irq_vectors; } err = netc_timer_init(priv); if (err) { dev_err(&pdev->dev, "NETC Timer initialization failed, err=%d\n", err); goto free_irq; } return 0; free_irq: free_irq(priv->irq, priv); free_irq_vectors: pci_free_irq_vectors(pdev); disable_dev: pci_disable_device(pdev); return err; } static int ptp_netc_suspend_noirq(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct netc_timer *priv; int err; priv = pci_get_drvdata(pdev); if (netc_ierb_may_wakeonlan()) return 0; err = ptp_netc_shutdown(priv); if (err) { dev_err(dev, "NETC Timer shutdown failed\n"); return err; } return err; } static int ptp_netc_resume_noirq(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct netc_timer *priv; int err; priv = pci_get_drvdata(pdev); if (netc_ierb_may_wakeonlan()) return 0; err = ptp_netc_powerup(priv); if (err) { dev_err(dev, "NETC Timer powerup failed\n"); kfree(priv); return err; } return err; } static const struct dev_pm_ops __maybe_unused ptp_netc_pm_ops = { SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(ptp_netc_suspend_noirq, ptp_netc_resume_noirq) }; static struct pci_driver netc_timer_driver = { .name = KBUILD_MODNAME, .id_table = netc_timer_id_table, .probe = netc_timer_probe, .remove = netc_timer_remove, .driver.pm = &ptp_netc_pm_ops, }; module_pci_driver(netc_timer_driver); MODULE_AUTHOR("Wei Fang "); MODULE_DESCRIPTION("NXP NETC Timer Driver"); MODULE_LICENSE("Dual BSD/GPL");