Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | // SPDX-License-Identifier: GPL-2.0-or-later /* * (C) Copyright 2022 - Analog Devices, Inc. * * Written and/or maintained by Timesys Corporation * * Converted to driver model by Nathan Barrett-Morrison * * Author: Greg Malysa <greg.malysa@timesys.com> * Additional Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com> * * dm timer implementation for ADI ADSP-SC5xx SoCs * */ #include <clk.h> #include <dm.h> #include <timer.h> #include <asm/io.h> #include <dm/device_compat.h> #include <linux/compiler_types.h> /* * Timer Configuration Register Bits */ #define TIMER_OUT_DIS 0x0800 #define TIMER_PULSE_HI 0x0080 #define TIMER_MODE_PWM_CONT 0x000c #define __BFP(m) u16 m; u16 __pad_##m struct gptimer3 { __BFP(config); u32 counter; u32 period; u32 width; u32 delay; }; struct gptimer3_group_regs { __BFP(run); __BFP(enable); __BFP(disable); __BFP(stop_cfg); __BFP(stop_cfg_set); __BFP(stop_cfg_clr); __BFP(data_imsk); __BFP(stat_imsk); __BFP(tr_msk); __BFP(tr_ie); __BFP(data_ilat); __BFP(stat_ilat); __BFP(err_status); __BFP(bcast_per); __BFP(bcast_wid); __BFP(bcast_dly); }; #define MAX_TIM_LOAD 0xFFFFFFFF struct adi_gptimer_priv { struct gptimer3_group_regs __iomem *timer_group; struct gptimer3 __iomem *timer_base; u32 prev; u64 upper; }; static u64 adi_gptimer_get_count(struct udevice *udev) { struct adi_gptimer_priv *priv = dev_get_priv(udev); u32 now = readl(&priv->timer_base->counter); if (now < priv->prev) priv->upper += (1ull << 32); priv->prev = now; return (priv->upper + (u64)now); } static const struct timer_ops adi_gptimer_ops = { .get_count = adi_gptimer_get_count, }; static int adi_gptimer_probe(struct udevice *udev) { struct timer_dev_priv *uc_priv = dev_get_uclass_priv(udev); struct adi_gptimer_priv *priv = dev_get_priv(udev); struct clk clk; u16 imask; int ret; priv->timer_group = dev_remap_addr_index(udev, 0); priv->timer_base = dev_remap_addr_index(udev, 1); priv->upper = 0; priv->prev = 0; if (!priv->timer_group || !priv->timer_base) { dev_err(udev, "Missing timer_group or timer_base reg entries\n"); return -ENODEV; } ret = clk_get_by_index(udev, 0, &clk); if (ret < 0) { dev_err(udev, "Missing clock reference for timer\n"); return ret; } ret = clk_enable(&clk); if (ret) { dev_err(udev, "Failed to enable clock\n"); return ret; } uc_priv->clock_rate = clk_get_rate(&clk); /* Enable timer */ writew(TIMER_OUT_DIS | TIMER_MODE_PWM_CONT | TIMER_PULSE_HI, &priv->timer_base->config); writel(MAX_TIM_LOAD, &priv->timer_base->period); writel(MAX_TIM_LOAD - 1, &priv->timer_base->width); /* We only use timer 0 in uboot */ imask = readw(&priv->timer_group->data_imsk); imask &= ~(1 << 0); writew(imask, &priv->timer_group->data_imsk); writew((1 << 0), &priv->timer_group->enable); return 0; } static const struct udevice_id adi_gptimer_ids[] = { { .compatible = "adi,sc5xx-gptimer" }, { }, }; U_BOOT_DRIVER(adi_gptimer) = { .name = "adi_gptimer", .id = UCLASS_TIMER, .of_match = adi_gptimer_ids, .priv_auto = sizeof(struct adi_gptimer_priv), .probe = adi_gptimer_probe, .ops = &adi_gptimer_ops, }; |