Lines Matching +full:am654 +full:- +full:icssg

1 // SPDX-License-Identifier: GPL-2.0
3 /* Texas Instruments ICSSG Industrial Ethernet Peripheral (IEP) Driver
5 * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com
57 * icss_iep_get_count_hi() - Get the upper 32 bit IEP counter
66 if (iep && (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)) in icss_iep_get_count_hi()
67 val = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG1]); in icss_iep_get_count_hi()
74 * icss_iep_get_count_low() - Get the lower 32 bit IEP counter
84 val = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG0]); in icss_iep_get_count_low()
91 * icss_iep_get_ptp_clock_idx() - Get PTP clock index using IEP driver
94 * Return: PTP clock index, -1 if not registered
98 if (!iep || !iep->ptp_clock) in icss_iep_get_ptp_clock_idx()
99 return -1; in icss_iep_get_ptp_clock_idx()
100 return ptp_clock_index(iep->ptp_clock); in icss_iep_get_ptp_clock_idx()
106 if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) in icss_iep_set_counter()
107 writel(upper_32_bits(ns), iep->base + in icss_iep_set_counter()
108 iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG1]); in icss_iep_set_counter()
109 writel(lower_32_bits(ns), iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG0]); in icss_iep_set_counter()
115 * icss_iep_settime() - Set time of the PTP clock using IEP driver
124 if (iep->ops && iep->ops->settime) { in icss_iep_settime()
125 iep->ops->settime(iep->clockops_data, ns); in icss_iep_settime()
129 if (iep->pps_enabled || iep->perout_enabled) in icss_iep_settime()
130 writel(0, iep->base + iep->plat_data->reg_offs[ICSS_IEP_SYNC_CTRL_REG]); in icss_iep_settime()
134 if (iep->pps_enabled || iep->perout_enabled) { in icss_iep_settime()
137 iep->base + iep->plat_data->reg_offs[ICSS_IEP_SYNC_CTRL_REG]); in icss_iep_settime()
142 * icss_iep_gettime() - Get time of the PTP clock using IEP driver
157 if (iep->ops && iep->ops->gettime) in icss_iep_gettime()
158 return iep->ops->gettime(iep->clockops_data, sts); in icss_iep_gettime()
160 /* use local_irq_x() to make it work for both RT/non-RT */ in icss_iep_gettime()
163 /* no need to play with hi-lo, hi is latched when lo is read */ in icss_iep_gettime()
165 ts_lo = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG0]); in icss_iep_gettime()
167 if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) in icss_iep_gettime()
168 ts_hi = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG1]); in icss_iep_gettime()
177 regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_CFG_REG, in icss_iep_enable()
184 regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_CFG_REG, in icss_iep_disable()
194 cycle_time = iep->cycle_time_ns - iep->def_inc; in icss_iep_enable_shadow_mode()
199 regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, in icss_iep_enable_shadow_mode()
203 regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, in icss_iep_enable_shadow_mode()
210 regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_STATUS_REG, in icss_iep_enable_shadow_mode()
216 regmap_update_bits(iep->map, ICSS_IEP_CMP_STAT_REG, in icss_iep_enable_shadow_mode()
219 regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, in icss_iep_enable_shadow_mode()
224 regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, in icss_iep_enable_shadow_mode()
228 regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, in icss_iep_enable_shadow_mode()
233 regmap_write(iep->map, ICSS_IEP_CMP0_REG0, cycle_time); in icss_iep_enable_shadow_mode()
234 if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) in icss_iep_enable_shadow_mode()
235 regmap_write(iep->map, ICSS_IEP_CMP0_REG1, cycle_time); in icss_iep_enable_shadow_mode()
243 regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_CFG_REG, in icss_iep_set_default_inc()
250 struct device *dev = regmap_get_device(iep->map); in icss_iep_set_compensation_inc()
258 regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_CFG_REG, in icss_iep_set_compensation_inc()
266 struct device *dev = regmap_get_device(iep->map); in icss_iep_set_compensation_count()
274 regmap_write(iep->map, ICSS_IEP_COMPEN_REG, compen_count); in icss_iep_set_compensation_count()
280 regmap_write(iep->map, ICSS_IEP_SLOW_COMPEN_REG, compen_count); in icss_iep_set_slow_compensation_count()
291 mutex_lock(&iep->ptp_clk_mutex); in icss_iep_ptp_adjfine()
303 * The minimum adjustment we can do is +-1ns per cycle so let's in icss_iep_ptp_adjfine()
309 if (iep->cycle_time_ns) in icss_iep_ptp_adjfine()
310 iep->slow_cmp_inc = iep->clk_tick_time; /* 4ns adj per cycle */ in icss_iep_ptp_adjfine()
312 iep->slow_cmp_inc = 1; /* 1ns adjust per cycle */ in icss_iep_ptp_adjfine()
315 iep->slow_cmp_inc = -iep->slow_cmp_inc; in icss_iep_ptp_adjfine()
316 ppb = -ppb; in icss_iep_ptp_adjfine()
323 if (!iep->cycle_time_ns) in icss_iep_ptp_adjfine()
324 cyc_count /= iep->clk_tick_time; in icss_iep_ptp_adjfine()
325 iep->slow_cmp_count = cyc_count; in icss_iep_ptp_adjfine()
327 /* iep->clk_tick_time is def_inc */ in icss_iep_ptp_adjfine()
328 cmp_inc = iep->clk_tick_time + iep->slow_cmp_inc; in icss_iep_ptp_adjfine()
330 icss_iep_set_slow_compensation_count(iep, iep->slow_cmp_count); in icss_iep_ptp_adjfine()
332 mutex_unlock(&iep->ptp_clk_mutex); in icss_iep_ptp_adjfine()
342 mutex_lock(&iep->ptp_clk_mutex); in icss_iep_ptp_adjtime()
343 if (iep->ops && iep->ops->adjtime) { in icss_iep_ptp_adjtime()
344 iep->ops->adjtime(iep->clockops_data, delta); in icss_iep_ptp_adjtime()
350 mutex_unlock(&iep->ptp_clk_mutex); in icss_iep_ptp_adjtime()
362 mutex_lock(&iep->ptp_clk_mutex); in icss_iep_ptp_gettimeex()
365 mutex_unlock(&iep->ptp_clk_mutex); in icss_iep_ptp_gettimeex()
376 mutex_lock(&iep->ptp_clk_mutex); in icss_iep_ptp_settime()
379 mutex_unlock(&iep->ptp_clk_mutex); in icss_iep_ptp_settime()
392 p_ns = iep->period; in icss_iep_update_to_next_boundary()
394 start_ns += p_ns - 1; in icss_iep_update_to_next_boundary()
398 if (p_ns - offset < 10) in icss_iep_update_to_next_boundary()
401 regmap_write(iep->map, ICSS_IEP_CMP1_REG0, lower_32_bits(start_ns)); in icss_iep_update_to_next_boundary()
402 if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) in icss_iep_update_to_next_boundary()
403 regmap_write(iep->map, ICSS_IEP_CMP1_REG1, upper_32_bits(start_ns)); in icss_iep_update_to_next_boundary()
417 regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, in icss_iep_perout_enable_hw()
421 regmap_write(iep->map, ICSS_IEP_CMP1_REG0, 0); in icss_iep_perout_enable_hw()
422 if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) in icss_iep_perout_enable_hw()
423 regmap_write(iep->map, ICSS_IEP_CMP1_REG1, 0); in icss_iep_perout_enable_hw()
426 regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); in icss_iep_perout_enable_hw()
432 ts.tv_sec = req->on.sec; in icss_iep_perout_enable_hw()
433 ts.tv_nsec = req->on.nsec; in icss_iep_perout_enable_hw()
436 if (req->flags & PTP_PEROUT_PHASE) { in icss_iep_perout_enable_hw()
437 ts.tv_sec = req->phase.sec; in icss_iep_perout_enable_hw()
438 ts.tv_nsec = req->phase.nsec; in icss_iep_perout_enable_hw()
444 if (iep->ops && iep->ops->perout_enable) { in icss_iep_perout_enable_hw()
445 ret = iep->ops->perout_enable(iep->clockops_data, req, on, &cmp); in icss_iep_perout_enable_hw()
450 regmap_write(iep->map, ICSS_IEP_CMP1_REG0, lower_32_bits(cmp)); in icss_iep_perout_enable_hw()
451 if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) in icss_iep_perout_enable_hw()
452 regmap_write(iep->map, ICSS_IEP_CMP1_REG1, upper_32_bits(cmp)); in icss_iep_perout_enable_hw()
454 regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, in icss_iep_perout_enable_hw()
455 div_u64(ns_width, iep->def_inc)); in icss_iep_perout_enable_hw()
456 regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0); in icss_iep_perout_enable_hw()
457 regmap_write(iep->map, ICSS_IEP_SYNC_START_REG, in icss_iep_perout_enable_hw()
458 div_u64(ns_start, iep->def_inc)); in icss_iep_perout_enable_hw()
459 regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); /* one-shot mode */ in icss_iep_perout_enable_hw()
461 regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, in icss_iep_perout_enable_hw()
466 iep->period = ((u64)req->period.sec * NSEC_PER_SEC) + in icss_iep_perout_enable_hw()
467 req->period.nsec; in icss_iep_perout_enable_hw()
468 start_ns = ((u64)req->period.sec * NSEC_PER_SEC) in icss_iep_perout_enable_hw()
469 + req->period.nsec; in icss_iep_perout_enable_hw()
472 regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, in icss_iep_perout_enable_hw()
473 div_u64(ns_width, iep->def_inc)); in icss_iep_perout_enable_hw()
474 regmap_write(iep->map, ICSS_IEP_SYNC_START_REG, in icss_iep_perout_enable_hw()
475 div_u64(ns_start, iep->def_inc)); in icss_iep_perout_enable_hw()
477 regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, in icss_iep_perout_enable_hw()
480 regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, in icss_iep_perout_enable_hw()
496 if (req->flags & ~(PTP_PEROUT_DUTY_CYCLE | in icss_iep_perout_enable()
498 return -EOPNOTSUPP; in icss_iep_perout_enable()
501 if (!(req->flags & PTP_PEROUT_DUTY_CYCLE)) { in icss_iep_perout_enable()
502 req->on.sec = 0; in icss_iep_perout_enable()
503 req->on.nsec = NSEC_PER_MSEC; in icss_iep_perout_enable()
507 mutex_lock(&iep->ptp_clk_mutex); in icss_iep_perout_enable()
509 if (iep->pps_enabled) { in icss_iep_perout_enable()
510 ret = -EBUSY; in icss_iep_perout_enable()
514 if (iep->perout_enabled == !!on) in icss_iep_perout_enable()
519 iep->perout_enabled = !!on; in icss_iep_perout_enable()
522 mutex_unlock(&iep->ptp_clk_mutex); in icss_iep_perout_enable()
530 const u32 *reg_offs = iep->plat_data->reg_offs; in icss_iep_cap_cmp_work()
535 mutex_lock(&iep->ptp_clk_mutex); in icss_iep_cap_cmp_work()
537 ns = readl(iep->base + reg_offs[ICSS_IEP_CMP1_REG0]); in icss_iep_cap_cmp_work()
538 if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) { in icss_iep_cap_cmp_work()
539 val = readl(iep->base + reg_offs[ICSS_IEP_CMP1_REG1]); in icss_iep_cap_cmp_work()
543 ns_next = ns + iep->period; in icss_iep_cap_cmp_work()
545 iep->base + reg_offs[ICSS_IEP_CMP1_REG0]); in icss_iep_cap_cmp_work()
546 if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) in icss_iep_cap_cmp_work()
548 iep->base + reg_offs[ICSS_IEP_CMP1_REG1]); in icss_iep_cap_cmp_work()
553 ptp_clock_event(iep->ptp_clock, &pevent); in icss_iep_cap_cmp_work()
554 dev_dbg(iep->dev, "IEP:pps ts: %llu next:%llu:\n", ns, ns_next); in icss_iep_cap_cmp_work()
556 mutex_unlock(&iep->ptp_clk_mutex); in icss_iep_cap_cmp_work()
562 const u32 *reg_offs = iep->plat_data->reg_offs; in icss_iep_cap_cmp_irq()
565 val = readl(iep->base + reg_offs[ICSS_IEP_CMP_STAT_REG]); in icss_iep_cap_cmp_irq()
569 writel(BIT(1), iep->base + reg_offs[ICSS_IEP_CMP_STAT_REG]); in icss_iep_cap_cmp_irq()
570 if (iep->pps_enabled || iep->perout_enabled) in icss_iep_cap_cmp_irq()
571 schedule_work(&iep->work); in icss_iep_cap_cmp_irq()
585 mutex_lock(&iep->ptp_clk_mutex); in icss_iep_pps_enable()
587 if (iep->perout_enabled) { in icss_iep_pps_enable()
588 ret = -EBUSY; in icss_iep_pps_enable()
592 if (iep->pps_enabled == !!on) in icss_iep_pps_enable()
609 if (iep->cap_cmp_irq) in icss_iep_pps_enable()
610 cancel_work_sync(&iep->work); in icss_iep_pps_enable()
614 iep->pps_enabled = !!on; in icss_iep_pps_enable()
617 mutex_unlock(&iep->ptp_clk_mutex); in icss_iep_pps_enable()
626 mutex_lock(&iep->ptp_clk_mutex); in icss_iep_extts_enable()
628 if (iep->ops && iep->ops->extts_enable) { in icss_iep_extts_enable()
629 ret = iep->ops->extts_enable(iep->clockops_data, index, on); in icss_iep_extts_enable()
633 if (((iep->latch_enable & BIT(index)) >> index) == on) in icss_iep_extts_enable()
636 regmap_read(iep->map, ICSS_IEP_CAPTURE_CFG_REG, &val); in icss_iep_extts_enable()
640 iep->latch_enable |= BIT(index); in icss_iep_extts_enable()
643 iep->latch_enable &= ~BIT(index); in icss_iep_extts_enable()
645 regmap_write(iep->map, ICSS_IEP_CAPTURE_CFG_REG, val); in icss_iep_extts_enable()
648 mutex_unlock(&iep->ptp_clk_mutex); in icss_iep_extts_enable()
658 switch (rq->type) { in icss_iep_ptp_enable()
660 return icss_iep_perout_enable(iep, &rq->perout, on); in icss_iep_ptp_enable()
664 return icss_iep_extts_enable(iep, rq->extts.index, on); in icss_iep_ptp_enable()
669 return -EOPNOTSUPP; in icss_iep_ptp_enable()
691 return ERR_PTR(-ENODEV); in icss_iep_get_idx()
698 return ERR_PTR(-EPROBE_DEFER); in icss_iep_get_idx()
702 return ERR_PTR(-EPROBE_DEFER); in icss_iep_get_idx()
704 device_lock(iep->dev); in icss_iep_get_idx()
705 if (iep->client_np) { in icss_iep_get_idx()
706 device_unlock(iep->dev); in icss_iep_get_idx()
707 dev_err(iep->dev, "IEP is already acquired by %s", in icss_iep_get_idx()
708 iep->client_np->name); in icss_iep_get_idx()
709 return ERR_PTR(-EBUSY); in icss_iep_get_idx()
711 iep->client_np = np; in icss_iep_get_idx()
712 device_unlock(iep->dev); in icss_iep_get_idx()
713 get_device(iep->dev); in icss_iep_get_idx()
727 device_lock(iep->dev); in icss_iep_put()
728 iep->client_np = NULL; in icss_iep_put()
729 device_unlock(iep->dev); in icss_iep_put()
730 put_device(iep->dev); in icss_iep_put()
737 iep->clk_tick_time = iep->def_inc; in icss_iep_init_fw()
738 iep->cycle_time_ns = 0; in icss_iep_init_fw()
739 iep->ops = NULL; in icss_iep_init_fw()
740 iep->clockops_data = NULL; in icss_iep_init_fw()
741 icss_iep_set_default_inc(iep, iep->def_inc); in icss_iep_init_fw()
742 icss_iep_set_compensation_inc(iep, iep->def_inc); in icss_iep_init_fw()
744 regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, iep->refclk_freq / 10); /* 100 ms pulse */ in icss_iep_init_fw()
745 regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0); in icss_iep_init_fw()
746 if (iep->plat_data->flags & ICSS_IEP_SLOW_COMPEN_REG_SUPPORT) in icss_iep_init_fw()
765 iep->cycle_time_ns = cycle_time_ns; in icss_iep_init()
766 iep->clk_tick_time = iep->def_inc; in icss_iep_init()
767 iep->ops = clkops; in icss_iep_init()
768 iep->clockops_data = clockops_data; in icss_iep_init()
769 icss_iep_set_default_inc(iep, iep->def_inc); in icss_iep_init()
770 icss_iep_set_compensation_inc(iep, iep->def_inc); in icss_iep_init()
772 regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, iep->refclk_freq / 10); /* 100 ms pulse */ in icss_iep_init()
773 regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0); in icss_iep_init()
774 if (iep->plat_data->flags & ICSS_IEP_SLOW_COMPEN_REG_SUPPORT) in icss_iep_init()
777 if (!(iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) || in icss_iep_init()
778 !(iep->plat_data->flags & ICSS_IEP_SLOW_COMPEN_REG_SUPPORT)) in icss_iep_init()
781 if (iep->ops && iep->ops->perout_enable) { in icss_iep_init()
782 iep->ptp_info.n_per_out = 1; in icss_iep_init()
783 iep->ptp_info.pps = 1; in icss_iep_init()
784 } else if (iep->cap_cmp_irq) { in icss_iep_init()
785 iep->ptp_info.pps = 1; in icss_iep_init()
788 if (iep->ops && iep->ops->extts_enable) in icss_iep_init()
789 iep->ptp_info.n_ext_ts = 2; in icss_iep_init()
798 iep->ptp_clock = ptp_clock_register(&iep->ptp_info, iep->dev); in icss_iep_init()
799 if (IS_ERR(iep->ptp_clock)) { in icss_iep_init()
800 ret = PTR_ERR(iep->ptp_clock); in icss_iep_init()
801 iep->ptp_clock = NULL; in icss_iep_init()
802 dev_err(iep->dev, "Failed to register ptp clk %d\n", ret); in icss_iep_init()
811 if (iep->ptp_clock) { in icss_iep_exit()
812 ptp_clock_unregister(iep->ptp_clock); in icss_iep_exit()
813 iep->ptp_clock = NULL; in icss_iep_exit()
817 if (iep->pps_enabled) in icss_iep_exit()
819 else if (iep->perout_enabled) in icss_iep_exit()
828 struct device *dev = &pdev->dev; in icss_iep_probe()
835 return -ENOMEM; in icss_iep_probe()
837 iep->dev = dev; in icss_iep_probe()
838 iep->base = devm_platform_ioremap_resource(pdev, 0); in icss_iep_probe()
839 if (IS_ERR(iep->base)) in icss_iep_probe()
840 return -ENODEV; in icss_iep_probe()
843 if (irq == -EPROBE_DEFER) in icss_iep_probe()
850 dev_info(iep->dev, "cap_cmp irq request failed: %x\n", in icss_iep_probe()
853 iep->cap_cmp_irq = irq; in icss_iep_probe()
854 INIT_WORK(&iep->work, icss_iep_cap_cmp_work); in icss_iep_probe()
862 iep->refclk_freq = clk_get_rate(iep_clk); in icss_iep_probe()
864 iep->def_inc = NSEC_PER_SEC / iep->refclk_freq; /* ns per clock tick */ in icss_iep_probe()
865 if (iep->def_inc > IEP_MAX_DEF_INC) { in icss_iep_probe()
867 iep->def_inc); in icss_iep_probe()
868 return -EINVAL; in icss_iep_probe()
871 iep->plat_data = device_get_match_data(dev); in icss_iep_probe()
872 if (!iep->plat_data) in icss_iep_probe()
873 return -EINVAL; in icss_iep_probe()
875 iep->map = devm_regmap_init(dev, NULL, iep, iep->plat_data->config); in icss_iep_probe()
876 if (IS_ERR(iep->map)) { in icss_iep_probe()
878 PTR_ERR(iep->map)); in icss_iep_probe()
879 return PTR_ERR(iep->map); in icss_iep_probe()
882 iep->ptp_info = icss_iep_ptp_info; in icss_iep_probe()
883 mutex_init(&iep->ptp_clk_mutex); in icss_iep_probe()
907 writel(val, iep->base + iep->plat_data->reg_offs[reg]); in icss_iep_regmap_write()
917 *val = readl(iep->base + iep->plat_data->reg_offs[reg]); in icss_iep_regmap_read()
973 .compatible = "ti,am654-icss-iep",
982 .name = "icss-iep",