1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2018 MediaTek Inc. |
4 | * |
5 | * Author: Sean Wang <sean.wang@mediatek.com> |
6 | * |
7 | */ |
8 | |
9 | #include <dt-bindings/pinctrl/mt65xx.h> |
10 | #include <linux/device.h> |
11 | #include <linux/err.h> |
12 | #include <linux/gpio/driver.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/io.h> |
15 | #include <linux/module.h> |
16 | #include <linux/of_irq.h> |
17 | |
18 | #include "mtk-eint.h" |
19 | #include "pinctrl-mtk-common-v2.h" |
20 | |
21 | /** |
22 | * struct mtk_drive_desc - the structure that holds the information |
23 | * of the driving current |
24 | * @min: the minimum current of this group |
25 | * @max: the maximum current of this group |
26 | * @step: the step current of this group |
27 | * @scal: the weight factor |
28 | * |
29 | * formula: output = ((input) / step - 1) * scal |
30 | */ |
31 | struct mtk_drive_desc { |
32 | u8 min; |
33 | u8 max; |
34 | u8 step; |
35 | u8 scal; |
36 | }; |
37 | |
38 | /* The groups of drive strength */ |
39 | static const struct mtk_drive_desc mtk_drive[] = { |
40 | [DRV_GRP0] = { 4, 16, 4, 1 }, |
41 | [DRV_GRP1] = { .min: 4, .max: 16, .step: 4, .scal: 2 }, |
42 | [DRV_GRP2] = { .min: 2, .max: 8, .step: 2, .scal: 1 }, |
43 | [DRV_GRP3] = { .min: 2, .max: 8, .step: 2, .scal: 2 }, |
44 | [DRV_GRP4] = { .min: 2, .max: 16, .step: 2, .scal: 1 }, |
45 | }; |
46 | |
47 | static void mtk_w32(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 val) |
48 | { |
49 | writel_relaxed(val, pctl->base[i] + reg); |
50 | } |
51 | |
52 | static u32 mtk_r32(struct mtk_pinctrl *pctl, u8 i, u32 reg) |
53 | { |
54 | return readl_relaxed(pctl->base[i] + reg); |
55 | } |
56 | |
57 | void mtk_rmw(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 mask, u32 set) |
58 | { |
59 | u32 val; |
60 | unsigned long flags; |
61 | |
62 | spin_lock_irqsave(&pctl->lock, flags); |
63 | |
64 | val = mtk_r32(pctl, i, reg); |
65 | val &= ~mask; |
66 | val |= set; |
67 | mtk_w32(pctl, i, reg, val); |
68 | |
69 | spin_unlock_irqrestore(lock: &pctl->lock, flags); |
70 | } |
71 | |
72 | static int mtk_hw_pin_field_lookup(struct mtk_pinctrl *hw, |
73 | const struct mtk_pin_desc *desc, |
74 | int field, struct mtk_pin_field *pfd) |
75 | { |
76 | const struct mtk_pin_field_calc *c; |
77 | const struct mtk_pin_reg_calc *rc; |
78 | int start = 0, end, check; |
79 | bool found = false; |
80 | u32 bits; |
81 | |
82 | if (hw->soc->reg_cal && hw->soc->reg_cal[field].range) { |
83 | rc = &hw->soc->reg_cal[field]; |
84 | } else { |
85 | dev_dbg(hw->dev, |
86 | "Not support field %d for this soc\n" , field); |
87 | return -ENOTSUPP; |
88 | } |
89 | |
90 | end = rc->nranges - 1; |
91 | |
92 | while (start <= end) { |
93 | check = (start + end) >> 1; |
94 | if (desc->number >= rc->range[check].s_pin |
95 | && desc->number <= rc->range[check].e_pin) { |
96 | found = true; |
97 | break; |
98 | } else if (start == end) |
99 | break; |
100 | else if (desc->number < rc->range[check].s_pin) |
101 | end = check - 1; |
102 | else |
103 | start = check + 1; |
104 | } |
105 | |
106 | if (!found) { |
107 | dev_dbg(hw->dev, "Not support field %d for pin = %d (%s)\n" , |
108 | field, desc->number, desc->name); |
109 | return -ENOTSUPP; |
110 | } |
111 | |
112 | c = rc->range + check; |
113 | |
114 | if (c->i_base > hw->nbase - 1) { |
115 | dev_err(hw->dev, |
116 | "Invalid base for field %d for pin = %d (%s)\n" , |
117 | field, desc->number, desc->name); |
118 | return -EINVAL; |
119 | } |
120 | |
121 | /* Calculated bits as the overall offset the pin is located at, |
122 | * if c->fixed is held, that determines the all the pins in the |
123 | * range use the same field with the s_pin. |
124 | */ |
125 | bits = c->fixed ? c->s_bit : c->s_bit + |
126 | (desc->number - c->s_pin) * (c->x_bits); |
127 | |
128 | /* Fill pfd from bits. For example 32-bit register applied is assumed |
129 | * when c->sz_reg is equal to 32. |
130 | */ |
131 | pfd->index = c->i_base; |
132 | pfd->offset = c->s_addr + c->x_addrs * (bits / c->sz_reg); |
133 | pfd->bitpos = bits % c->sz_reg; |
134 | pfd->mask = (1 << c->x_bits) - 1; |
135 | |
136 | /* pfd->next is used for indicating that bit wrapping-around happens |
137 | * which requires the manipulation for bit 0 starting in the next |
138 | * register to form the complete field read/write. |
139 | */ |
140 | pfd->next = pfd->bitpos + c->x_bits > c->sz_reg ? c->x_addrs : 0; |
141 | |
142 | return 0; |
143 | } |
144 | |
145 | static int mtk_hw_pin_field_get(struct mtk_pinctrl *hw, |
146 | const struct mtk_pin_desc *desc, |
147 | int field, struct mtk_pin_field *pfd) |
148 | { |
149 | if (field < 0 || field >= PINCTRL_PIN_REG_MAX) { |
150 | dev_err(hw->dev, "Invalid Field %d\n" , field); |
151 | return -EINVAL; |
152 | } |
153 | |
154 | return mtk_hw_pin_field_lookup(hw, desc, field, pfd); |
155 | } |
156 | |
157 | static void mtk_hw_bits_part(struct mtk_pin_field *pf, int *h, int *l) |
158 | { |
159 | *l = 32 - pf->bitpos; |
160 | *h = get_count_order(count: pf->mask) - *l; |
161 | } |
162 | |
163 | static void mtk_hw_write_cross_field(struct mtk_pinctrl *hw, |
164 | struct mtk_pin_field *pf, int value) |
165 | { |
166 | int nbits_l, nbits_h; |
167 | |
168 | mtk_hw_bits_part(pf, h: &nbits_h, l: &nbits_l); |
169 | |
170 | mtk_rmw(pctl: hw, i: pf->index, reg: pf->offset, mask: pf->mask << pf->bitpos, |
171 | set: (value & pf->mask) << pf->bitpos); |
172 | |
173 | mtk_rmw(pctl: hw, i: pf->index, reg: pf->offset + pf->next, BIT(nbits_h) - 1, |
174 | set: (value & pf->mask) >> nbits_l); |
175 | } |
176 | |
177 | static void mtk_hw_read_cross_field(struct mtk_pinctrl *hw, |
178 | struct mtk_pin_field *pf, int *value) |
179 | { |
180 | int nbits_l, nbits_h, h, l; |
181 | |
182 | mtk_hw_bits_part(pf, h: &nbits_h, l: &nbits_l); |
183 | |
184 | l = (mtk_r32(pctl: hw, i: pf->index, reg: pf->offset) |
185 | >> pf->bitpos) & (BIT(nbits_l) - 1); |
186 | h = (mtk_r32(pctl: hw, i: pf->index, reg: pf->offset + pf->next)) |
187 | & (BIT(nbits_h) - 1); |
188 | |
189 | *value = (h << nbits_l) | l; |
190 | } |
191 | |
192 | int mtk_hw_set_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc, |
193 | int field, int value) |
194 | { |
195 | struct mtk_pin_field pf; |
196 | int err; |
197 | |
198 | err = mtk_hw_pin_field_get(hw, desc, field, pfd: &pf); |
199 | if (err) |
200 | return err; |
201 | |
202 | if (value < 0 || value > pf.mask) |
203 | return -EINVAL; |
204 | |
205 | if (!pf.next) |
206 | mtk_rmw(pctl: hw, i: pf.index, reg: pf.offset, mask: pf.mask << pf.bitpos, |
207 | set: (value & pf.mask) << pf.bitpos); |
208 | else |
209 | mtk_hw_write_cross_field(hw, pf: &pf, value); |
210 | |
211 | return 0; |
212 | } |
213 | EXPORT_SYMBOL_GPL(mtk_hw_set_value); |
214 | |
215 | int mtk_hw_get_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc, |
216 | int field, int *value) |
217 | { |
218 | struct mtk_pin_field pf; |
219 | int err; |
220 | |
221 | err = mtk_hw_pin_field_get(hw, desc, field, pfd: &pf); |
222 | if (err) |
223 | return err; |
224 | |
225 | if (!pf.next) |
226 | *value = (mtk_r32(pctl: hw, i: pf.index, reg: pf.offset) |
227 | >> pf.bitpos) & pf.mask; |
228 | else |
229 | mtk_hw_read_cross_field(hw, pf: &pf, value); |
230 | |
231 | return 0; |
232 | } |
233 | EXPORT_SYMBOL_GPL(mtk_hw_get_value); |
234 | |
235 | static int mtk_xt_find_eint_num(struct mtk_pinctrl *hw, unsigned long eint_n) |
236 | { |
237 | const struct mtk_pin_desc *desc; |
238 | int i = 0; |
239 | |
240 | desc = (const struct mtk_pin_desc *)hw->soc->pins; |
241 | |
242 | while (i < hw->soc->npins) { |
243 | if (desc[i].eint.eint_n == eint_n) |
244 | return desc[i].number; |
245 | i++; |
246 | } |
247 | |
248 | return EINT_NA; |
249 | } |
250 | |
251 | /* |
252 | * Virtual GPIO only used inside SOC and not being exported to outside SOC. |
253 | * Some modules use virtual GPIO as eint (e.g. pmif or usb). |
254 | * In MTK platform, external interrupt (EINT) and GPIO is 1-1 mapping |
255 | * and we can set GPIO as eint. |
256 | * But some modules use specific eint which doesn't have real GPIO pin. |
257 | * So we use virtual GPIO to map it. |
258 | */ |
259 | |
260 | bool mtk_is_virt_gpio(struct mtk_pinctrl *hw, unsigned int gpio_n) |
261 | { |
262 | const struct mtk_pin_desc *desc; |
263 | bool virt_gpio = false; |
264 | |
265 | desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio_n]; |
266 | |
267 | /* if the GPIO is not supported for eint mode */ |
268 | if (desc->eint.eint_m == NO_EINT_SUPPORT) |
269 | return virt_gpio; |
270 | |
271 | if (desc->funcs && !desc->funcs[desc->eint.eint_m].name) |
272 | virt_gpio = true; |
273 | |
274 | return virt_gpio; |
275 | } |
276 | EXPORT_SYMBOL_GPL(mtk_is_virt_gpio); |
277 | |
278 | static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n, |
279 | unsigned int *gpio_n, |
280 | struct gpio_chip **gpio_chip) |
281 | { |
282 | struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; |
283 | const struct mtk_pin_desc *desc; |
284 | |
285 | desc = (const struct mtk_pin_desc *)hw->soc->pins; |
286 | *gpio_chip = &hw->chip; |
287 | |
288 | /* |
289 | * Be greedy to guess first gpio_n is equal to eint_n. |
290 | * Only eint virtual eint number is greater than gpio number. |
291 | */ |
292 | if (hw->soc->npins > eint_n && |
293 | desc[eint_n].eint.eint_n == eint_n) |
294 | *gpio_n = eint_n; |
295 | else |
296 | *gpio_n = mtk_xt_find_eint_num(hw, eint_n); |
297 | |
298 | return *gpio_n == EINT_NA ? -EINVAL : 0; |
299 | } |
300 | |
301 | static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n) |
302 | { |
303 | struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; |
304 | const struct mtk_pin_desc *desc; |
305 | struct gpio_chip *gpio_chip; |
306 | unsigned int gpio_n; |
307 | int value, err; |
308 | |
309 | err = mtk_xt_get_gpio_n(data: hw, eint_n, gpio_n: &gpio_n, gpio_chip: &gpio_chip); |
310 | if (err) |
311 | return err; |
312 | |
313 | desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio_n]; |
314 | |
315 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value); |
316 | if (err) |
317 | return err; |
318 | |
319 | return !!value; |
320 | } |
321 | |
322 | static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n) |
323 | { |
324 | struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; |
325 | const struct mtk_pin_desc *desc; |
326 | struct gpio_chip *gpio_chip; |
327 | unsigned int gpio_n; |
328 | int err; |
329 | |
330 | err = mtk_xt_get_gpio_n(data: hw, eint_n, gpio_n: &gpio_n, gpio_chip: &gpio_chip); |
331 | if (err) |
332 | return err; |
333 | |
334 | if (mtk_is_virt_gpio(hw, gpio_n)) |
335 | return 0; |
336 | |
337 | desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio_n]; |
338 | |
339 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, |
340 | desc->eint.eint_m); |
341 | if (err) |
342 | return err; |
343 | |
344 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, MTK_INPUT); |
345 | if (err) |
346 | return err; |
347 | |
348 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, MTK_ENABLE); |
349 | /* SMT is supposed to be supported by every real GPIO and doesn't |
350 | * support virtual GPIOs, so the extra condition err != -ENOTSUPP |
351 | * is just for adding EINT support to these virtual GPIOs. It should |
352 | * add an extra flag in the pin descriptor when more pins with |
353 | * distinctive characteristic come out. |
354 | */ |
355 | if (err && err != -ENOTSUPP) |
356 | return err; |
357 | |
358 | return 0; |
359 | } |
360 | |
361 | static const struct mtk_eint_xt mtk_eint_xt = { |
362 | .get_gpio_n = mtk_xt_get_gpio_n, |
363 | .get_gpio_state = mtk_xt_get_gpio_state, |
364 | .set_gpio_as_eint = mtk_xt_set_gpio_as_eint, |
365 | }; |
366 | |
367 | int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) |
368 | { |
369 | struct device_node *np = pdev->dev.of_node; |
370 | int ret; |
371 | |
372 | if (!IS_ENABLED(CONFIG_EINT_MTK)) |
373 | return 0; |
374 | |
375 | if (!of_property_read_bool(np, propname: "interrupt-controller" )) |
376 | return -ENODEV; |
377 | |
378 | hw->eint = devm_kzalloc(dev: hw->dev, size: sizeof(*hw->eint), GFP_KERNEL); |
379 | if (!hw->eint) |
380 | return -ENOMEM; |
381 | |
382 | hw->eint->base = devm_platform_ioremap_resource_byname(pdev, name: "eint" ); |
383 | if (IS_ERR(ptr: hw->eint->base)) { |
384 | ret = PTR_ERR(ptr: hw->eint->base); |
385 | goto err_free_eint; |
386 | } |
387 | |
388 | hw->eint->irq = irq_of_parse_and_map(node: np, index: 0); |
389 | if (!hw->eint->irq) { |
390 | ret = -EINVAL; |
391 | goto err_free_eint; |
392 | } |
393 | |
394 | if (!hw->soc->eint_hw) { |
395 | ret = -ENODEV; |
396 | goto err_free_eint; |
397 | } |
398 | |
399 | hw->eint->dev = &pdev->dev; |
400 | hw->eint->hw = hw->soc->eint_hw; |
401 | hw->eint->pctl = hw; |
402 | hw->eint->gpio_xlate = &mtk_eint_xt; |
403 | |
404 | return mtk_eint_do_init(eint: hw->eint); |
405 | |
406 | err_free_eint: |
407 | devm_kfree(dev: hw->dev, p: hw->eint); |
408 | hw->eint = NULL; |
409 | return ret; |
410 | } |
411 | EXPORT_SYMBOL_GPL(mtk_build_eint); |
412 | |
413 | /* Revision 0 */ |
414 | int mtk_pinconf_bias_disable_set(struct mtk_pinctrl *hw, |
415 | const struct mtk_pin_desc *desc) |
416 | { |
417 | int err; |
418 | |
419 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, |
420 | MTK_DISABLE); |
421 | if (err) |
422 | return err; |
423 | |
424 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, |
425 | MTK_DISABLE); |
426 | if (err) |
427 | return err; |
428 | |
429 | return 0; |
430 | } |
431 | EXPORT_SYMBOL_GPL(mtk_pinconf_bias_disable_set); |
432 | |
433 | int mtk_pinconf_bias_disable_get(struct mtk_pinctrl *hw, |
434 | const struct mtk_pin_desc *desc, int *res) |
435 | { |
436 | int v, v2; |
437 | int err; |
438 | |
439 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PU, &v); |
440 | if (err) |
441 | return err; |
442 | |
443 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &v2); |
444 | if (err) |
445 | return err; |
446 | |
447 | if (v == MTK_ENABLE || v2 == MTK_ENABLE) |
448 | return -EINVAL; |
449 | |
450 | *res = 1; |
451 | |
452 | return 0; |
453 | } |
454 | EXPORT_SYMBOL_GPL(mtk_pinconf_bias_disable_get); |
455 | |
456 | int mtk_pinconf_bias_set(struct mtk_pinctrl *hw, |
457 | const struct mtk_pin_desc *desc, bool pullup) |
458 | { |
459 | int err, arg; |
460 | |
461 | arg = pullup ? 1 : 2; |
462 | |
463 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, arg & 1); |
464 | if (err) |
465 | return err; |
466 | |
467 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, |
468 | !!(arg & 2)); |
469 | if (err) |
470 | return err; |
471 | |
472 | return 0; |
473 | } |
474 | EXPORT_SYMBOL_GPL(mtk_pinconf_bias_set); |
475 | |
476 | int mtk_pinconf_bias_get(struct mtk_pinctrl *hw, |
477 | const struct mtk_pin_desc *desc, bool pullup, int *res) |
478 | { |
479 | int reg, err, v; |
480 | |
481 | reg = pullup ? PINCTRL_PIN_REG_PU : PINCTRL_PIN_REG_PD; |
482 | |
483 | err = mtk_hw_get_value(hw, desc, reg, &v); |
484 | if (err) |
485 | return err; |
486 | |
487 | if (!v) |
488 | return -EINVAL; |
489 | |
490 | *res = 1; |
491 | |
492 | return 0; |
493 | } |
494 | EXPORT_SYMBOL_GPL(mtk_pinconf_bias_get); |
495 | |
496 | /* Revision 1 */ |
497 | int mtk_pinconf_bias_disable_set_rev1(struct mtk_pinctrl *hw, |
498 | const struct mtk_pin_desc *desc) |
499 | { |
500 | return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN, |
501 | MTK_DISABLE); |
502 | } |
503 | EXPORT_SYMBOL_GPL(mtk_pinconf_bias_disable_set_rev1); |
504 | |
505 | int mtk_pinconf_bias_disable_get_rev1(struct mtk_pinctrl *hw, |
506 | const struct mtk_pin_desc *desc, int *res) |
507 | { |
508 | int v, err; |
509 | |
510 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, &v); |
511 | if (err) |
512 | return err; |
513 | |
514 | if (v == MTK_ENABLE) |
515 | return -EINVAL; |
516 | |
517 | *res = 1; |
518 | |
519 | return 0; |
520 | } |
521 | EXPORT_SYMBOL_GPL(mtk_pinconf_bias_disable_get_rev1); |
522 | |
523 | int mtk_pinconf_bias_set_rev1(struct mtk_pinctrl *hw, |
524 | const struct mtk_pin_desc *desc, bool pullup) |
525 | { |
526 | int err, arg; |
527 | |
528 | arg = pullup ? MTK_PULLUP : MTK_PULLDOWN; |
529 | |
530 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN, |
531 | MTK_ENABLE); |
532 | if (err) |
533 | return err; |
534 | |
535 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, arg); |
536 | if (err) |
537 | return err; |
538 | |
539 | return 0; |
540 | } |
541 | EXPORT_SYMBOL_GPL(mtk_pinconf_bias_set_rev1); |
542 | |
543 | int mtk_pinconf_bias_get_rev1(struct mtk_pinctrl *hw, |
544 | const struct mtk_pin_desc *desc, bool pullup, |
545 | int *res) |
546 | { |
547 | int err, v; |
548 | |
549 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, &v); |
550 | if (err) |
551 | return err; |
552 | |
553 | if (v == MTK_DISABLE) |
554 | return -EINVAL; |
555 | |
556 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, &v); |
557 | if (err) |
558 | return err; |
559 | |
560 | if (pullup ^ (v == MTK_PULLUP)) |
561 | return -EINVAL; |
562 | |
563 | *res = 1; |
564 | |
565 | return 0; |
566 | } |
567 | EXPORT_SYMBOL_GPL(mtk_pinconf_bias_get_rev1); |
568 | |
569 | /* Combo for the following pull register type: |
570 | * 1. PU + PD |
571 | * 2. PULLSEL + PULLEN |
572 | * 3. PUPD + R0 + R1 |
573 | */ |
574 | static int mtk_pinconf_bias_set_pu_pd(struct mtk_pinctrl *hw, |
575 | const struct mtk_pin_desc *desc, |
576 | u32 pullup, u32 arg) |
577 | { |
578 | int err, pu, pd; |
579 | |
580 | if (arg == MTK_DISABLE) { |
581 | pu = 0; |
582 | pd = 0; |
583 | } else if ((arg == MTK_ENABLE) && pullup) { |
584 | pu = 1; |
585 | pd = 0; |
586 | } else if ((arg == MTK_ENABLE) && !pullup) { |
587 | pu = 0; |
588 | pd = 1; |
589 | } else { |
590 | err = -EINVAL; |
591 | goto out; |
592 | } |
593 | |
594 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, pu); |
595 | if (err) |
596 | goto out; |
597 | |
598 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd); |
599 | |
600 | out: |
601 | return err; |
602 | } |
603 | |
604 | static int mtk_pinconf_bias_set_pullsel_pullen(struct mtk_pinctrl *hw, |
605 | const struct mtk_pin_desc *desc, |
606 | u32 pullup, u32 arg) |
607 | { |
608 | int err, enable; |
609 | |
610 | if (arg == MTK_DISABLE) |
611 | enable = 0; |
612 | else if (arg == MTK_ENABLE) |
613 | enable = 1; |
614 | else { |
615 | err = -EINVAL; |
616 | goto out; |
617 | } |
618 | |
619 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN, enable); |
620 | if (err) |
621 | goto out; |
622 | |
623 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, pullup); |
624 | |
625 | out: |
626 | return err; |
627 | } |
628 | |
629 | static int mtk_pinconf_bias_set_pupd_r1_r0(struct mtk_pinctrl *hw, |
630 | const struct mtk_pin_desc *desc, |
631 | u32 pullup, u32 arg) |
632 | { |
633 | int err, r0, r1; |
634 | |
635 | if ((arg == MTK_DISABLE) || (arg == MTK_PUPD_SET_R1R0_00)) { |
636 | pullup = 0; |
637 | r0 = 0; |
638 | r1 = 0; |
639 | } else if (arg == MTK_PUPD_SET_R1R0_01) { |
640 | r0 = 1; |
641 | r1 = 0; |
642 | } else if (arg == MTK_PUPD_SET_R1R0_10) { |
643 | r0 = 0; |
644 | r1 = 1; |
645 | } else if (arg == MTK_PUPD_SET_R1R0_11) { |
646 | r0 = 1; |
647 | r1 = 1; |
648 | } else { |
649 | err = -EINVAL; |
650 | goto out; |
651 | } |
652 | |
653 | /* MTK HW PUPD bit: 1 for pull-down, 0 for pull-up */ |
654 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PUPD, !pullup); |
655 | if (err) |
656 | goto out; |
657 | |
658 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R0, r0); |
659 | if (err) |
660 | goto out; |
661 | |
662 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R1, r1); |
663 | |
664 | out: |
665 | return err; |
666 | } |
667 | |
668 | static int mtk_hw_pin_rsel_lookup(struct mtk_pinctrl *hw, |
669 | const struct mtk_pin_desc *desc, |
670 | u32 pullup, u32 arg, u32 *rsel_val) |
671 | { |
672 | const struct mtk_pin_rsel *rsel; |
673 | int check; |
674 | bool found = false; |
675 | |
676 | rsel = hw->soc->pin_rsel; |
677 | |
678 | for (check = 0; check <= hw->soc->npin_rsel - 1; check++) { |
679 | if (desc->number >= rsel[check].s_pin && |
680 | desc->number <= rsel[check].e_pin) { |
681 | if (pullup) { |
682 | if (rsel[check].up_rsel == arg) { |
683 | found = true; |
684 | *rsel_val = rsel[check].rsel_index; |
685 | break; |
686 | } |
687 | } else { |
688 | if (rsel[check].down_rsel == arg) { |
689 | found = true; |
690 | *rsel_val = rsel[check].rsel_index; |
691 | break; |
692 | } |
693 | } |
694 | } |
695 | } |
696 | |
697 | if (!found) { |
698 | dev_err(hw->dev, "Not support rsel value %d Ohm for pin = %d (%s)\n" , |
699 | arg, desc->number, desc->name); |
700 | return -ENOTSUPP; |
701 | } |
702 | |
703 | return 0; |
704 | } |
705 | |
706 | static int mtk_pinconf_bias_set_rsel(struct mtk_pinctrl *hw, |
707 | const struct mtk_pin_desc *desc, |
708 | u32 pullup, u32 arg) |
709 | { |
710 | int err, rsel_val; |
711 | |
712 | if (!pullup && arg == MTK_DISABLE) |
713 | return 0; |
714 | |
715 | if (hw->rsel_si_unit) { |
716 | /* find pin rsel_index from pin_rsel array*/ |
717 | err = mtk_hw_pin_rsel_lookup(hw, desc, pullup, arg, rsel_val: &rsel_val); |
718 | if (err) |
719 | goto out; |
720 | } else { |
721 | if (arg < MTK_PULL_SET_RSEL_000 || |
722 | arg > MTK_PULL_SET_RSEL_111) { |
723 | err = -EINVAL; |
724 | goto out; |
725 | } |
726 | |
727 | rsel_val = arg - MTK_PULL_SET_RSEL_000; |
728 | } |
729 | |
730 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_RSEL, rsel_val); |
731 | if (err) |
732 | goto out; |
733 | |
734 | err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, MTK_ENABLE); |
735 | |
736 | out: |
737 | return err; |
738 | } |
739 | |
740 | int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw, |
741 | const struct mtk_pin_desc *desc, |
742 | u32 pullup, u32 arg) |
743 | { |
744 | int err = -ENOTSUPP; |
745 | u32 try_all_type; |
746 | |
747 | if (hw->soc->pull_type) |
748 | try_all_type = hw->soc->pull_type[desc->number]; |
749 | else |
750 | try_all_type = MTK_PULL_TYPE_MASK; |
751 | |
752 | if (try_all_type & MTK_PULL_RSEL_TYPE) { |
753 | err = mtk_pinconf_bias_set_rsel(hw, desc, pullup, arg); |
754 | if (!err) |
755 | return err; |
756 | } |
757 | |
758 | if (try_all_type & MTK_PULL_PU_PD_TYPE) { |
759 | err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg); |
760 | if (!err) |
761 | return err; |
762 | } |
763 | |
764 | if (try_all_type & MTK_PULL_PULLSEL_TYPE) { |
765 | err = mtk_pinconf_bias_set_pullsel_pullen(hw, desc, |
766 | pullup, arg); |
767 | if (!err) |
768 | return err; |
769 | } |
770 | |
771 | if (try_all_type & MTK_PULL_PUPD_R1R0_TYPE) |
772 | err = mtk_pinconf_bias_set_pupd_r1_r0(hw, desc, pullup, arg); |
773 | |
774 | if (err) |
775 | dev_err(hw->dev, "Invalid pull argument\n" ); |
776 | |
777 | return err; |
778 | } |
779 | EXPORT_SYMBOL_GPL(mtk_pinconf_bias_set_combo); |
780 | |
781 | static int mtk_rsel_get_si_unit(struct mtk_pinctrl *hw, |
782 | const struct mtk_pin_desc *desc, |
783 | u32 pullup, u32 rsel_val, u32 *si_unit) |
784 | { |
785 | const struct mtk_pin_rsel *rsel; |
786 | int check; |
787 | |
788 | rsel = hw->soc->pin_rsel; |
789 | |
790 | for (check = 0; check <= hw->soc->npin_rsel - 1; check++) { |
791 | if (desc->number >= rsel[check].s_pin && |
792 | desc->number <= rsel[check].e_pin) { |
793 | if (rsel_val == rsel[check].rsel_index) { |
794 | if (pullup) |
795 | *si_unit = rsel[check].up_rsel; |
796 | else |
797 | *si_unit = rsel[check].down_rsel; |
798 | break; |
799 | } |
800 | } |
801 | } |
802 | |
803 | return 0; |
804 | } |
805 | |
806 | static int mtk_pinconf_bias_get_rsel(struct mtk_pinctrl *hw, |
807 | const struct mtk_pin_desc *desc, |
808 | u32 *pullup, u32 *enable) |
809 | { |
810 | int pu, pd, rsel, err; |
811 | |
812 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_RSEL, &rsel); |
813 | if (err) |
814 | goto out; |
815 | |
816 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PU, &pu); |
817 | if (err) |
818 | goto out; |
819 | |
820 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &pd); |
821 | if (err) |
822 | goto out; |
823 | |
824 | if (pu == 0 && pd == 0) { |
825 | *pullup = 0; |
826 | *enable = MTK_DISABLE; |
827 | } else if (pu == 1 && pd == 0) { |
828 | *pullup = 1; |
829 | if (hw->rsel_si_unit) |
830 | mtk_rsel_get_si_unit(hw, desc, pullup: *pullup, rsel_val: rsel, si_unit: enable); |
831 | else |
832 | *enable = rsel + MTK_PULL_SET_RSEL_000; |
833 | } else if (pu == 0 && pd == 1) { |
834 | *pullup = 0; |
835 | if (hw->rsel_si_unit) |
836 | mtk_rsel_get_si_unit(hw, desc, pullup: *pullup, rsel_val: rsel, si_unit: enable); |
837 | else |
838 | *enable = rsel + MTK_PULL_SET_RSEL_000; |
839 | } else { |
840 | err = -EINVAL; |
841 | goto out; |
842 | } |
843 | |
844 | out: |
845 | return err; |
846 | } |
847 | |
848 | static int mtk_pinconf_bias_get_pu_pd(struct mtk_pinctrl *hw, |
849 | const struct mtk_pin_desc *desc, |
850 | u32 *pullup, u32 *enable) |
851 | { |
852 | int err, pu, pd; |
853 | |
854 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PU, &pu); |
855 | if (err) |
856 | goto out; |
857 | |
858 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &pd); |
859 | if (err) |
860 | goto out; |
861 | |
862 | if (pu == 0 && pd == 0) { |
863 | *pullup = 0; |
864 | *enable = MTK_DISABLE; |
865 | } else if (pu == 1 && pd == 0) { |
866 | *pullup = 1; |
867 | *enable = MTK_ENABLE; |
868 | } else if (pu == 0 && pd == 1) { |
869 | *pullup = 0; |
870 | *enable = MTK_ENABLE; |
871 | } else |
872 | err = -EINVAL; |
873 | |
874 | out: |
875 | return err; |
876 | } |
877 | |
878 | static int mtk_pinconf_bias_get_pullsel_pullen(struct mtk_pinctrl *hw, |
879 | const struct mtk_pin_desc *desc, |
880 | u32 *pullup, u32 *enable) |
881 | { |
882 | int err; |
883 | |
884 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, pullup); |
885 | if (err) |
886 | goto out; |
887 | |
888 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, enable); |
889 | |
890 | out: |
891 | return err; |
892 | } |
893 | |
894 | static int mtk_pinconf_bias_get_pupd_r1_r0(struct mtk_pinctrl *hw, |
895 | const struct mtk_pin_desc *desc, |
896 | u32 *pullup, u32 *enable) |
897 | { |
898 | int err, r0, r1; |
899 | |
900 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PUPD, pullup); |
901 | if (err) |
902 | goto out; |
903 | /* MTK HW PUPD bit: 1 for pull-down, 0 for pull-up */ |
904 | *pullup = !(*pullup); |
905 | |
906 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R0, &r0); |
907 | if (err) |
908 | goto out; |
909 | |
910 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R1, &r1); |
911 | if (err) |
912 | goto out; |
913 | |
914 | if ((r1 == 0) && (r0 == 0)) |
915 | *enable = MTK_PUPD_SET_R1R0_00; |
916 | else if ((r1 == 0) && (r0 == 1)) |
917 | *enable = MTK_PUPD_SET_R1R0_01; |
918 | else if ((r1 == 1) && (r0 == 0)) |
919 | *enable = MTK_PUPD_SET_R1R0_10; |
920 | else if ((r1 == 1) && (r0 == 1)) |
921 | *enable = MTK_PUPD_SET_R1R0_11; |
922 | else |
923 | err = -EINVAL; |
924 | |
925 | out: |
926 | return err; |
927 | } |
928 | |
929 | int mtk_pinconf_bias_get_combo(struct mtk_pinctrl *hw, |
930 | const struct mtk_pin_desc *desc, |
931 | u32 *pullup, u32 *enable) |
932 | { |
933 | int err = -ENOTSUPP; |
934 | u32 try_all_type; |
935 | |
936 | if (hw->soc->pull_type) |
937 | try_all_type = hw->soc->pull_type[desc->number]; |
938 | else |
939 | try_all_type = MTK_PULL_TYPE_MASK; |
940 | |
941 | if (try_all_type & MTK_PULL_RSEL_TYPE) { |
942 | err = mtk_pinconf_bias_get_rsel(hw, desc, pullup, enable); |
943 | if (!err) |
944 | return err; |
945 | } |
946 | |
947 | if (try_all_type & MTK_PULL_PU_PD_TYPE) { |
948 | err = mtk_pinconf_bias_get_pu_pd(hw, desc, pullup, enable); |
949 | if (!err) |
950 | return err; |
951 | } |
952 | |
953 | if (try_all_type & MTK_PULL_PULLSEL_TYPE) { |
954 | err = mtk_pinconf_bias_get_pullsel_pullen(hw, desc, |
955 | pullup, enable); |
956 | if (!err) |
957 | return err; |
958 | } |
959 | |
960 | if (try_all_type & MTK_PULL_PUPD_R1R0_TYPE) |
961 | err = mtk_pinconf_bias_get_pupd_r1_r0(hw, desc, pullup, enable); |
962 | |
963 | return err; |
964 | } |
965 | EXPORT_SYMBOL_GPL(mtk_pinconf_bias_get_combo); |
966 | |
967 | /* Revision 0 */ |
968 | int mtk_pinconf_drive_set(struct mtk_pinctrl *hw, |
969 | const struct mtk_pin_desc *desc, u32 arg) |
970 | { |
971 | const struct mtk_drive_desc *tb; |
972 | int err = -ENOTSUPP; |
973 | |
974 | tb = &mtk_drive[desc->drv_n]; |
975 | /* 4mA when (e8, e4) = (0, 0) |
976 | * 8mA when (e8, e4) = (0, 1) |
977 | * 12mA when (e8, e4) = (1, 0) |
978 | * 16mA when (e8, e4) = (1, 1) |
979 | */ |
980 | if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) { |
981 | arg = (arg / tb->step - 1) * tb->scal; |
982 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_E4, |
983 | arg & 0x1); |
984 | if (err) |
985 | return err; |
986 | |
987 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_E8, |
988 | (arg & 0x2) >> 1); |
989 | if (err) |
990 | return err; |
991 | } |
992 | |
993 | return err; |
994 | } |
995 | EXPORT_SYMBOL_GPL(mtk_pinconf_drive_set); |
996 | |
997 | int mtk_pinconf_drive_get(struct mtk_pinctrl *hw, |
998 | const struct mtk_pin_desc *desc, int *val) |
999 | { |
1000 | const struct mtk_drive_desc *tb; |
1001 | int err, val1, val2; |
1002 | |
1003 | tb = &mtk_drive[desc->drv_n]; |
1004 | |
1005 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_E4, &val1); |
1006 | if (err) |
1007 | return err; |
1008 | |
1009 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_E8, &val2); |
1010 | if (err) |
1011 | return err; |
1012 | |
1013 | /* 4mA when (e8, e4) = (0, 0); 8mA when (e8, e4) = (0, 1) |
1014 | * 12mA when (e8, e4) = (1, 0); 16mA when (e8, e4) = (1, 1) |
1015 | */ |
1016 | *val = (((val2 << 1) + val1) / tb->scal + 1) * tb->step; |
1017 | |
1018 | return 0; |
1019 | } |
1020 | EXPORT_SYMBOL_GPL(mtk_pinconf_drive_get); |
1021 | |
1022 | /* Revision 1 */ |
1023 | int mtk_pinconf_drive_set_rev1(struct mtk_pinctrl *hw, |
1024 | const struct mtk_pin_desc *desc, u32 arg) |
1025 | { |
1026 | const struct mtk_drive_desc *tb; |
1027 | int err = -ENOTSUPP; |
1028 | |
1029 | tb = &mtk_drive[desc->drv_n]; |
1030 | |
1031 | if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) { |
1032 | arg = (arg / tb->step - 1) * tb->scal; |
1033 | |
1034 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV, |
1035 | arg); |
1036 | if (err) |
1037 | return err; |
1038 | } |
1039 | |
1040 | return err; |
1041 | } |
1042 | EXPORT_SYMBOL_GPL(mtk_pinconf_drive_set_rev1); |
1043 | |
1044 | int mtk_pinconf_drive_get_rev1(struct mtk_pinctrl *hw, |
1045 | const struct mtk_pin_desc *desc, int *val) |
1046 | { |
1047 | const struct mtk_drive_desc *tb; |
1048 | int err, val1; |
1049 | |
1050 | tb = &mtk_drive[desc->drv_n]; |
1051 | |
1052 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV, &val1); |
1053 | if (err) |
1054 | return err; |
1055 | |
1056 | *val = ((val1 & 0x7) / tb->scal + 1) * tb->step; |
1057 | |
1058 | return 0; |
1059 | } |
1060 | EXPORT_SYMBOL_GPL(mtk_pinconf_drive_get_rev1); |
1061 | |
1062 | int mtk_pinconf_drive_set_raw(struct mtk_pinctrl *hw, |
1063 | const struct mtk_pin_desc *desc, u32 arg) |
1064 | { |
1065 | return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV, arg); |
1066 | } |
1067 | EXPORT_SYMBOL_GPL(mtk_pinconf_drive_set_raw); |
1068 | |
1069 | int mtk_pinconf_drive_get_raw(struct mtk_pinctrl *hw, |
1070 | const struct mtk_pin_desc *desc, int *val) |
1071 | { |
1072 | return mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV, val); |
1073 | } |
1074 | EXPORT_SYMBOL_GPL(mtk_pinconf_drive_get_raw); |
1075 | |
1076 | int mtk_pinconf_adv_pull_set(struct mtk_pinctrl *hw, |
1077 | const struct mtk_pin_desc *desc, bool pullup, |
1078 | u32 arg) |
1079 | { |
1080 | int err; |
1081 | |
1082 | /* 10K off & 50K (75K) off, when (R0, R1) = (0, 0); |
1083 | * 10K off & 50K (75K) on, when (R0, R1) = (0, 1); |
1084 | * 10K on & 50K (75K) off, when (R0, R1) = (1, 0); |
1085 | * 10K on & 50K (75K) on, when (R0, R1) = (1, 1) |
1086 | */ |
1087 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R0, arg & 1); |
1088 | if (err) |
1089 | return 0; |
1090 | |
1091 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R1, |
1092 | !!(arg & 2)); |
1093 | if (err) |
1094 | return 0; |
1095 | |
1096 | arg = pullup ? 0 : 1; |
1097 | |
1098 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PUPD, arg); |
1099 | |
1100 | /* If PUPD register is not supported for that pin, let's fallback to |
1101 | * general bias control. |
1102 | */ |
1103 | if (err == -ENOTSUPP) { |
1104 | if (hw->soc->bias_set) { |
1105 | err = hw->soc->bias_set(hw, desc, pullup); |
1106 | if (err) |
1107 | return err; |
1108 | } else { |
1109 | err = mtk_pinconf_bias_set_rev1(hw, desc, pullup); |
1110 | if (err) |
1111 | err = mtk_pinconf_bias_set(hw, desc, pullup); |
1112 | } |
1113 | } |
1114 | |
1115 | return err; |
1116 | } |
1117 | EXPORT_SYMBOL_GPL(mtk_pinconf_adv_pull_set); |
1118 | |
1119 | int mtk_pinconf_adv_pull_get(struct mtk_pinctrl *hw, |
1120 | const struct mtk_pin_desc *desc, bool pullup, |
1121 | u32 *val) |
1122 | { |
1123 | u32 t, t2; |
1124 | int err; |
1125 | |
1126 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PUPD, &t); |
1127 | |
1128 | /* If PUPD register is not supported for that pin, let's fallback to |
1129 | * general bias control. |
1130 | */ |
1131 | if (err == -ENOTSUPP) { |
1132 | if (hw->soc->bias_get) { |
1133 | err = hw->soc->bias_get(hw, desc, pullup, val); |
1134 | if (err) |
1135 | return err; |
1136 | } else { |
1137 | return -ENOTSUPP; |
1138 | } |
1139 | } else { |
1140 | /* t == 0 supposes PULLUP for the customized PULL setup */ |
1141 | if (err) |
1142 | return err; |
1143 | |
1144 | if (pullup ^ !t) |
1145 | return -EINVAL; |
1146 | } |
1147 | |
1148 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R0, &t); |
1149 | if (err) |
1150 | return err; |
1151 | |
1152 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R1, &t2); |
1153 | if (err) |
1154 | return err; |
1155 | |
1156 | *val = (t | t2 << 1) & 0x7; |
1157 | |
1158 | return 0; |
1159 | } |
1160 | EXPORT_SYMBOL_GPL(mtk_pinconf_adv_pull_get); |
1161 | |
1162 | int mtk_pinconf_adv_drive_set(struct mtk_pinctrl *hw, |
1163 | const struct mtk_pin_desc *desc, u32 arg) |
1164 | { |
1165 | int err; |
1166 | int en = arg & 1; |
1167 | int e0 = !!(arg & 2); |
1168 | int e1 = !!(arg & 4); |
1169 | |
1170 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_EN, en); |
1171 | if (err) |
1172 | return err; |
1173 | |
1174 | if (!en) |
1175 | return err; |
1176 | |
1177 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_E0, e0); |
1178 | if (err) |
1179 | return err; |
1180 | |
1181 | err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_E1, e1); |
1182 | if (err) |
1183 | return err; |
1184 | |
1185 | return err; |
1186 | } |
1187 | EXPORT_SYMBOL_GPL(mtk_pinconf_adv_drive_set); |
1188 | |
1189 | int mtk_pinconf_adv_drive_get(struct mtk_pinctrl *hw, |
1190 | const struct mtk_pin_desc *desc, u32 *val) |
1191 | { |
1192 | u32 en, e0, e1; |
1193 | int err; |
1194 | |
1195 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_EN, &en); |
1196 | if (err) |
1197 | return err; |
1198 | |
1199 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_E0, &e0); |
1200 | if (err) |
1201 | return err; |
1202 | |
1203 | err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_E1, &e1); |
1204 | if (err) |
1205 | return err; |
1206 | |
1207 | *val = (en | e0 << 1 | e1 << 2) & 0x7; |
1208 | |
1209 | return 0; |
1210 | } |
1211 | EXPORT_SYMBOL_GPL(mtk_pinconf_adv_drive_get); |
1212 | |
1213 | int mtk_pinconf_adv_drive_set_raw(struct mtk_pinctrl *hw, |
1214 | const struct mtk_pin_desc *desc, u32 arg) |
1215 | { |
1216 | return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_ADV, arg); |
1217 | } |
1218 | EXPORT_SYMBOL_GPL(mtk_pinconf_adv_drive_set_raw); |
1219 | |
1220 | int mtk_pinconf_adv_drive_get_raw(struct mtk_pinctrl *hw, |
1221 | const struct mtk_pin_desc *desc, u32 *val) |
1222 | { |
1223 | return mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_ADV, val); |
1224 | } |
1225 | EXPORT_SYMBOL_GPL(mtk_pinconf_adv_drive_get_raw); |
1226 | |
1227 | MODULE_LICENSE("GPL v2" ); |
1228 | MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>" ); |
1229 | MODULE_DESCRIPTION("Pin configuration library module for mediatek SoCs" ); |
1230 | |