1 /*
2 * Copyright (c) 2021 IoT.bzh
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 */
7
8 #define DT_DRV_COMPAT renesas_rcar_pfc
9
10 #include <zephyr/arch/cpu.h>
11 #include <zephyr/devicetree.h>
12 #include <zephyr/drivers/pinctrl.h>
13 #include <zephyr/init.h>
14 #include <zephyr/sys/util.h>
15 #include <zephyr/sys/device_mmio.h>
16
17 DEVICE_MMIO_TOPLEVEL_STATIC(pfc, DT_DRV_INST(0));
18
19 #define PFC_REG_BASE DEVICE_MMIO_TOPLEVEL_GET(pfc)
20 #define PFC_RCAR_PMMR 0x0
21 #define PFC_RCAR_GPSR 0x100
22 #define PFC_RCAR_IPSR 0x200
23
24 /*
25 * Each drive step is either encoded in 2 or 3 bits.
26 * So based on a 24 mA maximum value each step is either
27 * 24/4 mA or 24/8 mA.
28 */
29 #define PFC_RCAR_DRIVE_MAX 24U
30 #define PFC_RCAR_DRIVE_STEP(size) \
31 (size == 2 ? PFC_RCAR_DRIVE_MAX / 4 : PFC_RCAR_DRIVE_MAX / 8)
32
33 /* Some registers such as IPSR GPSR or DRVCTRL are protected and
34 * must be preceded to a write to PMMR with the inverse value.
35 */
pfc_rcar_write(uint32_t offs,uint32_t val)36 static void pfc_rcar_write(uint32_t offs, uint32_t val)
37 {
38 sys_write32(~val, PFC_REG_BASE + PFC_RCAR_PMMR);
39 sys_write32(val, PFC_REG_BASE + offs);
40 }
41
42 /* Set the pin either in gpio or peripheral */
pfc_rcar_set_gpsr(uint16_t pin,bool peripheral)43 static void pfc_rcar_set_gpsr(uint16_t pin, bool peripheral)
44 {
45 uint8_t bank = pin / 32;
46 uint8_t bit = pin % 32;
47 uint32_t val = sys_read32(PFC_REG_BASE + PFC_RCAR_GPSR +
48 bank * sizeof(uint32_t));
49
50 if (peripheral) {
51 val |= BIT(bit);
52 } else {
53 val &= ~BIT(bit);
54 }
55 pfc_rcar_write(PFC_RCAR_GPSR + bank * sizeof(uint32_t), val);
56 }
57
58 /* Set peripheral function */
pfc_rcar_set_ipsr(const struct rcar_pin_func * rcar_func)59 static void pfc_rcar_set_ipsr(const struct rcar_pin_func *rcar_func)
60 {
61 uint16_t reg_offs = PFC_RCAR_IPSR + rcar_func->bank * sizeof(uint32_t);
62 uint32_t val = sys_read32(PFC_REG_BASE + reg_offs);
63
64 val &= ~(0xFU << rcar_func->shift);
65 val |= (rcar_func->func << rcar_func->shift);
66 pfc_rcar_write(reg_offs, val);
67 }
68
pfc_rcar_get_drive_reg(uint16_t pin,uint8_t * offset,uint8_t * size)69 static uint32_t pfc_rcar_get_drive_reg(uint16_t pin, uint8_t *offset,
70 uint8_t *size)
71 {
72 const struct pfc_drive_reg *drive_regs = pfc_rcar_get_drive_regs();
73
74 while (drive_regs->reg != 0U) {
75 for (size_t i = 0U; i < ARRAY_SIZE(drive_regs->fields); i++) {
76 if (drive_regs->fields[i].pin == pin) {
77 *offset = drive_regs->fields[i].offset;
78 *size = drive_regs->fields[i].size;
79 return drive_regs->reg;
80 }
81 }
82 drive_regs++;
83 }
84
85 return 0;
86 }
87
88 /*
89 * Maximum drive strength is 24mA. This value can be lowered
90 * using DRVCTRLx registers, some pins have 8 steps (3 bits size encoded)
91 * some have 4 steps (2 bits size encoded).
92 */
pfc_rcar_set_drive_strength(uint16_t pin,uint8_t strength)93 static int pfc_rcar_set_drive_strength(uint16_t pin, uint8_t strength)
94 {
95 uint8_t offset, size, step;
96 uint32_t reg, val;
97
98 reg = pfc_rcar_get_drive_reg(pin, &offset, &size);
99 if (reg == 0U) {
100 return -EINVAL;
101 }
102
103 step = PFC_RCAR_DRIVE_STEP(size);
104 if ((strength < step) || (strength > PFC_RCAR_DRIVE_MAX)) {
105 return -EINVAL;
106 }
107
108 /* Convert the value from mA based on a full drive strength
109 * value of 24mA.
110 */
111 strength = (strength / step) - 1U;
112 /* clear previous drive strength value */
113 val = sys_read32(PFC_REG_BASE + reg);
114 val &= ~GENMASK(offset + size - 1U, offset);
115 val |= strength << offset;
116
117 pfc_rcar_write(reg, val);
118
119 return 0;
120 }
121
pfc_rcar_get_bias_reg(uint16_t pin,uint8_t * bit)122 static const struct pfc_bias_reg *pfc_rcar_get_bias_reg(uint16_t pin,
123 uint8_t *bit)
124 {
125 const struct pfc_bias_reg *bias_regs = pfc_rcar_get_bias_regs();
126
127 /* Loop around all the registers to find the bit for a given pin */
128 while (bias_regs->puen && bias_regs->pud) {
129 for (size_t i = 0U; i < ARRAY_SIZE(bias_regs->pins); i++) {
130 if (bias_regs->pins[i] == pin) {
131 *bit = i;
132 return bias_regs;
133 }
134 }
135 bias_regs++;
136 }
137
138 return NULL;
139 }
140
pfc_rcar_set_bias(uint16_t pin,uint16_t flags)141 int pfc_rcar_set_bias(uint16_t pin, uint16_t flags)
142 {
143 uint32_t val;
144 uint8_t bit;
145 const struct pfc_bias_reg *bias_reg = pfc_rcar_get_bias_reg(pin, &bit);
146
147 if (bias_reg == NULL) {
148 return -EINVAL;
149 }
150
151 /* pull enable/disable*/
152 val = sys_read32(PFC_REG_BASE + bias_reg->puen);
153 if ((flags & RCAR_PIN_FLAGS_PUEN) == 0U) {
154 sys_write32(val & ~BIT(bit), PFC_REG_BASE + bias_reg->puen);
155 return 0;
156 }
157 sys_write32(val | BIT(bit), PFC_REG_BASE + bias_reg->puen);
158
159 /* pull - up/down */
160 val = sys_read32(PFC_REG_BASE + bias_reg->pud);
161 if (flags & RCAR_PIN_FLAGS_PUD) {
162 sys_write32(val | BIT(bit), PFC_REG_BASE + bias_reg->pud);
163 } else {
164 sys_write32(val & ~BIT(bit), PFC_REG_BASE + bias_reg->pud);
165 }
166 return 0;
167 }
168
pinctrl_configure_pin(const pinctrl_soc_pin_t * pin)169 int pinctrl_configure_pin(const pinctrl_soc_pin_t *pin)
170 {
171 int ret = 0;
172
173 /* Set pin as GPIO if capable */
174 if (RCAR_IS_GP_PIN(pin->pin)) {
175 pfc_rcar_set_gpsr(pin->pin, false);
176 } else if ((pin->flags & RCAR_PIN_FLAGS_FUNC_SET) == 0U) {
177 /* A function must be set for non GPIO capable pin */
178 return -EINVAL;
179 }
180
181 /* Select function for pin */
182 if ((pin->flags & RCAR_PIN_FLAGS_FUNC_SET) != 0U) {
183 pfc_rcar_set_ipsr(&pin->func);
184
185 if (RCAR_IS_GP_PIN(pin->pin)) {
186 pfc_rcar_set_gpsr(pin->pin, true);
187 }
188
189 if ((pin->flags & RCAR_PIN_FLAGS_PULL_SET) != 0U) {
190 ret = pfc_rcar_set_bias(pin->pin, pin->flags);
191 if (ret < 0) {
192 return ret;
193 }
194 }
195 }
196
197 if (pin->drive_strength != 0U) {
198 ret = pfc_rcar_set_drive_strength(pin->pin,
199 pin->drive_strength);
200 }
201
202 return ret;
203 }
204
pinctrl_configure_pins(const pinctrl_soc_pin_t * pins,uint8_t pin_cnt,uintptr_t reg)205 int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
206 uintptr_t reg)
207 {
208 int ret = 0;
209
210 ARG_UNUSED(reg);
211 while (pin_cnt-- > 0U) {
212 ret = pinctrl_configure_pin(pins++);
213 if (ret < 0) {
214 break;
215 }
216 }
217
218 return ret;
219 }
220
pfc_rcar_driver_init(void)221 __boot_func static int pfc_rcar_driver_init(void)
222 {
223 DEVICE_MMIO_TOPLEVEL_MAP(pfc, K_MEM_CACHE_NONE);
224 return 0;
225 }
226
227 SYS_INIT(pfc_rcar_driver_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
228