xref: /linux/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c (revision 22d7fe4984a23fea13f2fbc285e505624469de2a)
1a1a503a8SSean Wang // SPDX-License-Identifier: GPL-2.0
2a1a503a8SSean Wang /*
3a1a503a8SSean Wang  * Copyright (C) 2018 MediaTek Inc.
4a1a503a8SSean Wang  *
5a1a503a8SSean Wang  * Author: Sean Wang <sean.wang@mediatek.com>
6a1a503a8SSean Wang  *
7a1a503a8SSean Wang  */
8a1a503a8SSean Wang 
9a1a503a8SSean Wang #include <linux/device.h>
10a1a503a8SSean Wang #include <linux/err.h>
11*22d7fe49SLinus Walleij #include <linux/gpio/driver.h>
1289132dd8SSean Wang #include <linux/platform_device.h>
13a1a503a8SSean Wang #include <linux/io.h>
1489132dd8SSean Wang #include <linux/of_irq.h>
15a1a503a8SSean Wang 
1689132dd8SSean Wang #include "mtk-eint.h"
17a1a503a8SSean Wang #include "pinctrl-mtk-common-v2.h"
18a1a503a8SSean Wang 
19c2832197SSean Wang /**
20c2832197SSean Wang  * struct mtk_drive_desc - the structure that holds the information
21c2832197SSean Wang  *			    of the driving current
22c2832197SSean Wang  * @min:	the minimum current of this group
23c2832197SSean Wang  * @max:	the maximum current of this group
24c2832197SSean Wang  * @step:	the step current of this group
25c2832197SSean Wang  * @scal:	the weight factor
26c2832197SSean Wang  *
27c2832197SSean Wang  * formula: output = ((input) / step - 1) * scal
28c2832197SSean Wang  */
29c2832197SSean Wang struct mtk_drive_desc {
30c2832197SSean Wang 	u8 min;
31c2832197SSean Wang 	u8 max;
32c2832197SSean Wang 	u8 step;
33c2832197SSean Wang 	u8 scal;
34c2832197SSean Wang };
35c2832197SSean Wang 
36c2832197SSean Wang /* The groups of drive strength */
37c2832197SSean Wang const struct mtk_drive_desc mtk_drive[] = {
38c2832197SSean Wang 	[DRV_GRP0] = { 4, 16, 4, 1 },
39c2832197SSean Wang 	[DRV_GRP1] = { 4, 16, 4, 2 },
40c2832197SSean Wang 	[DRV_GRP2] = { 2, 8, 2, 1 },
41c2832197SSean Wang 	[DRV_GRP3] = { 2, 8, 2, 2 },
42c2832197SSean Wang 	[DRV_GRP4] = { 2, 16, 2, 1 },
43c2832197SSean Wang };
44c2832197SSean Wang 
452bc47dfeSSean Wang static void mtk_w32(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 val)
46a1a503a8SSean Wang {
472bc47dfeSSean Wang 	writel_relaxed(val, pctl->base[i] + reg);
48a1a503a8SSean Wang }
49a1a503a8SSean Wang 
502bc47dfeSSean Wang static u32 mtk_r32(struct mtk_pinctrl *pctl, u8 i, u32 reg)
51a1a503a8SSean Wang {
522bc47dfeSSean Wang 	return readl_relaxed(pctl->base[i] + reg);
53a1a503a8SSean Wang }
54a1a503a8SSean Wang 
552bc47dfeSSean Wang void mtk_rmw(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 mask, u32 set)
56a1a503a8SSean Wang {
57a1a503a8SSean Wang 	u32 val;
58a1a503a8SSean Wang 
592bc47dfeSSean Wang 	val = mtk_r32(pctl, i, reg);
60a1a503a8SSean Wang 	val &= ~mask;
61a1a503a8SSean Wang 	val |= set;
622bc47dfeSSean Wang 	mtk_w32(pctl, i, reg, val);
63a1a503a8SSean Wang }
64a1a503a8SSean Wang 
65ea051eb3SSean Wang static int mtk_hw_pin_field_lookup(struct mtk_pinctrl *hw,
66ea051eb3SSean Wang 				   const struct mtk_pin_desc *desc,
679d9b171cSSean Wang 				   int field, struct mtk_pin_field *pfd)
68a1a503a8SSean Wang {
69a1a503a8SSean Wang 	const struct mtk_pin_field_calc *c, *e;
709d9b171cSSean Wang 	const struct mtk_pin_reg_calc *rc;
71a1a503a8SSean Wang 	u32 bits;
72a1a503a8SSean Wang 
739d9b171cSSean Wang 	if (hw->soc->reg_cal && hw->soc->reg_cal[field].range) {
749d9b171cSSean Wang 		rc = &hw->soc->reg_cal[field];
759d9b171cSSean Wang 	} else {
769d9b171cSSean Wang 		dev_dbg(hw->dev,
779d9b171cSSean Wang 			"Not support field %d for pin %d (%s)\n",
789d9b171cSSean Wang 			field, desc->number, desc->name);
799d9b171cSSean Wang 		return -ENOTSUPP;
809d9b171cSSean Wang 	}
819d9b171cSSean Wang 
82a1a503a8SSean Wang 	c = rc->range;
83a1a503a8SSean Wang 	e = c + rc->nranges;
84a1a503a8SSean Wang 
85a1a503a8SSean Wang 	while (c < e) {
86ea051eb3SSean Wang 		if (desc->number >= c->s_pin && desc->number <= c->e_pin)
87a1a503a8SSean Wang 			break;
88a1a503a8SSean Wang 		c++;
89a1a503a8SSean Wang 	}
90a1a503a8SSean Wang 
91a1a503a8SSean Wang 	if (c >= e) {
929d9b171cSSean Wang 		dev_dbg(hw->dev, "Not support field %d for pin = %d (%s)\n",
939d9b171cSSean Wang 			field, desc->number, desc->name);
949d9b171cSSean Wang 		return -ENOTSUPP;
95a1a503a8SSean Wang 	}
96a1a503a8SSean Wang 
972bc47dfeSSean Wang 	if (c->i_base > hw->nbase - 1) {
989d9b171cSSean Wang 		dev_err(hw->dev,
999d9b171cSSean Wang 			"Invalid base for field %d for pin = %d (%s)\n",
1009d9b171cSSean Wang 			field, desc->number, desc->name);
1012bc47dfeSSean Wang 		return -EINVAL;
1022bc47dfeSSean Wang 	}
1032bc47dfeSSean Wang 
104b906faf7SSean Wang 	/* Calculated bits as the overall offset the pin is located at,
105b906faf7SSean Wang 	 * if c->fixed is held, that determines the all the pins in the
106b906faf7SSean Wang 	 * range use the same field with the s_pin.
107b906faf7SSean Wang 	 */
108ea051eb3SSean Wang 	bits = c->fixed ? c->s_bit : c->s_bit +
109ea051eb3SSean Wang 	       (desc->number - c->s_pin) * (c->x_bits);
110a1a503a8SSean Wang 
111b906faf7SSean Wang 	/* Fill pfd from bits. For example 32-bit register applied is assumed
112b906faf7SSean Wang 	 * when c->sz_reg is equal to 32.
113b906faf7SSean Wang 	 */
1142bc47dfeSSean Wang 	pfd->index = c->i_base;
115b906faf7SSean Wang 	pfd->offset = c->s_addr + c->x_addrs * (bits / c->sz_reg);
116b906faf7SSean Wang 	pfd->bitpos = bits % c->sz_reg;
117a1a503a8SSean Wang 	pfd->mask = (1 << c->x_bits) - 1;
118a1a503a8SSean Wang 
119a1a503a8SSean Wang 	/* pfd->next is used for indicating that bit wrapping-around happens
120a1a503a8SSean Wang 	 * which requires the manipulation for bit 0 starting in the next
121a1a503a8SSean Wang 	 * register to form the complete field read/write.
122a1a503a8SSean Wang 	 */
123b906faf7SSean Wang 	pfd->next = pfd->bitpos + c->x_bits > c->sz_reg ? c->x_addrs : 0;
124a1a503a8SSean Wang 
125a1a503a8SSean Wang 	return 0;
126a1a503a8SSean Wang }
127a1a503a8SSean Wang 
128ea051eb3SSean Wang static int mtk_hw_pin_field_get(struct mtk_pinctrl *hw,
129ea051eb3SSean Wang 				const struct mtk_pin_desc *desc,
130a1a503a8SSean Wang 				int field, struct mtk_pin_field *pfd)
131a1a503a8SSean Wang {
132a1a503a8SSean Wang 	if (field < 0 || field >= PINCTRL_PIN_REG_MAX) {
133a1a503a8SSean Wang 		dev_err(hw->dev, "Invalid Field %d\n", field);
134a1a503a8SSean Wang 		return -EINVAL;
135a1a503a8SSean Wang 	}
136a1a503a8SSean Wang 
1379d9b171cSSean Wang 	return mtk_hw_pin_field_lookup(hw, desc, field, pfd);
138a1a503a8SSean Wang }
139a1a503a8SSean Wang 
140a1a503a8SSean Wang static void mtk_hw_bits_part(struct mtk_pin_field *pf, int *h, int *l)
141a1a503a8SSean Wang {
142a1a503a8SSean Wang 	*l = 32 - pf->bitpos;
143a1a503a8SSean Wang 	*h = get_count_order(pf->mask) - *l;
144a1a503a8SSean Wang }
145a1a503a8SSean Wang 
146a1a503a8SSean Wang static void mtk_hw_write_cross_field(struct mtk_pinctrl *hw,
147a1a503a8SSean Wang 				     struct mtk_pin_field *pf, int value)
148a1a503a8SSean Wang {
149a1a503a8SSean Wang 	int nbits_l, nbits_h;
150a1a503a8SSean Wang 
151a1a503a8SSean Wang 	mtk_hw_bits_part(pf, &nbits_h, &nbits_l);
152a1a503a8SSean Wang 
1532bc47dfeSSean Wang 	mtk_rmw(hw, pf->index, pf->offset, pf->mask << pf->bitpos,
154a1a503a8SSean Wang 		(value & pf->mask) << pf->bitpos);
155a1a503a8SSean Wang 
1562bc47dfeSSean Wang 	mtk_rmw(hw, pf->index, pf->offset + pf->next, BIT(nbits_h) - 1,
157a1a503a8SSean Wang 		(value & pf->mask) >> nbits_l);
158a1a503a8SSean Wang }
159a1a503a8SSean Wang 
160a1a503a8SSean Wang static void mtk_hw_read_cross_field(struct mtk_pinctrl *hw,
161a1a503a8SSean Wang 				    struct mtk_pin_field *pf, int *value)
162a1a503a8SSean Wang {
163a1a503a8SSean Wang 	int nbits_l, nbits_h, h, l;
164a1a503a8SSean Wang 
165a1a503a8SSean Wang 	mtk_hw_bits_part(pf, &nbits_h, &nbits_l);
166a1a503a8SSean Wang 
1672bc47dfeSSean Wang 	l  = (mtk_r32(hw, pf->index, pf->offset)
1682bc47dfeSSean Wang 	      >> pf->bitpos) & (BIT(nbits_l) - 1);
1692bc47dfeSSean Wang 	h  = (mtk_r32(hw, pf->index, pf->offset + pf->next))
1702bc47dfeSSean Wang 	      & (BIT(nbits_h) - 1);
171a1a503a8SSean Wang 
172a1a503a8SSean Wang 	*value = (h << nbits_l) | l;
173a1a503a8SSean Wang }
174a1a503a8SSean Wang 
175ea051eb3SSean Wang int mtk_hw_set_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc,
176ea051eb3SSean Wang 		     int field, int value)
177a1a503a8SSean Wang {
178a1a503a8SSean Wang 	struct mtk_pin_field pf;
179a1a503a8SSean Wang 	int err;
180a1a503a8SSean Wang 
181ea051eb3SSean Wang 	err = mtk_hw_pin_field_get(hw, desc, field, &pf);
182a1a503a8SSean Wang 	if (err)
183a1a503a8SSean Wang 		return err;
184a1a503a8SSean Wang 
185a1a503a8SSean Wang 	if (!pf.next)
1862bc47dfeSSean Wang 		mtk_rmw(hw, pf.index, pf.offset, pf.mask << pf.bitpos,
187a1a503a8SSean Wang 			(value & pf.mask) << pf.bitpos);
188a1a503a8SSean Wang 	else
189a1a503a8SSean Wang 		mtk_hw_write_cross_field(hw, &pf, value);
190a1a503a8SSean Wang 
191a1a503a8SSean Wang 	return 0;
192a1a503a8SSean Wang }
193a1a503a8SSean Wang 
194ea051eb3SSean Wang int mtk_hw_get_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc,
195ea051eb3SSean Wang 		     int field, int *value)
196a1a503a8SSean Wang {
197a1a503a8SSean Wang 	struct mtk_pin_field pf;
198a1a503a8SSean Wang 	int err;
199a1a503a8SSean Wang 
200ea051eb3SSean Wang 	err = mtk_hw_pin_field_get(hw, desc, field, &pf);
201a1a503a8SSean Wang 	if (err)
202a1a503a8SSean Wang 		return err;
203a1a503a8SSean Wang 
204a1a503a8SSean Wang 	if (!pf.next)
2052bc47dfeSSean Wang 		*value = (mtk_r32(hw, pf.index, pf.offset)
2062bc47dfeSSean Wang 			  >> pf.bitpos) & pf.mask;
207a1a503a8SSean Wang 	else
208a1a503a8SSean Wang 		mtk_hw_read_cross_field(hw, &pf, value);
209a1a503a8SSean Wang 
210a1a503a8SSean Wang 	return 0;
211a1a503a8SSean Wang }
212c2832197SSean Wang 
21389132dd8SSean Wang static int mtk_xt_find_eint_num(struct mtk_pinctrl *hw, unsigned long eint_n)
21489132dd8SSean Wang {
21589132dd8SSean Wang 	const struct mtk_pin_desc *desc;
21689132dd8SSean Wang 	int i = 0;
21789132dd8SSean Wang 
21889132dd8SSean Wang 	desc = (const struct mtk_pin_desc *)hw->soc->pins;
21989132dd8SSean Wang 
22089132dd8SSean Wang 	while (i < hw->soc->npins) {
22189132dd8SSean Wang 		if (desc[i].eint.eint_n == eint_n)
22289132dd8SSean Wang 			return desc[i].number;
22389132dd8SSean Wang 		i++;
22489132dd8SSean Wang 	}
22589132dd8SSean Wang 
22689132dd8SSean Wang 	return EINT_NA;
22789132dd8SSean Wang }
22889132dd8SSean Wang 
22989132dd8SSean Wang static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n,
23089132dd8SSean Wang 			     unsigned int *gpio_n,
23189132dd8SSean Wang 			     struct gpio_chip **gpio_chip)
23289132dd8SSean Wang {
23389132dd8SSean Wang 	struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
23489132dd8SSean Wang 	const struct mtk_pin_desc *desc;
23589132dd8SSean Wang 
23689132dd8SSean Wang 	desc = (const struct mtk_pin_desc *)hw->soc->pins;
23789132dd8SSean Wang 	*gpio_chip = &hw->chip;
23889132dd8SSean Wang 
23989132dd8SSean Wang 	/* Be greedy to guess first gpio_n is equal to eint_n */
24089132dd8SSean Wang 	if (desc[eint_n].eint.eint_n == eint_n)
24189132dd8SSean Wang 		*gpio_n = eint_n;
24289132dd8SSean Wang 	else
24389132dd8SSean Wang 		*gpio_n = mtk_xt_find_eint_num(hw, eint_n);
24489132dd8SSean Wang 
24589132dd8SSean Wang 	return *gpio_n == EINT_NA ? -EINVAL : 0;
24689132dd8SSean Wang }
24789132dd8SSean Wang 
24889132dd8SSean Wang static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n)
24989132dd8SSean Wang {
25089132dd8SSean Wang 	struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
25189132dd8SSean Wang 	const struct mtk_pin_desc *desc;
25289132dd8SSean Wang 	struct gpio_chip *gpio_chip;
25389132dd8SSean Wang 	unsigned int gpio_n;
25489132dd8SSean Wang 	int value, err;
25589132dd8SSean Wang 
25689132dd8SSean Wang 	err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
25789132dd8SSean Wang 	if (err)
25889132dd8SSean Wang 		return err;
25989132dd8SSean Wang 
26089132dd8SSean Wang 	desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio_n];
26189132dd8SSean Wang 
26289132dd8SSean Wang 	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value);
26389132dd8SSean Wang 	if (err)
26489132dd8SSean Wang 		return err;
26589132dd8SSean Wang 
26689132dd8SSean Wang 	return !!value;
26789132dd8SSean Wang }
26889132dd8SSean Wang 
26989132dd8SSean Wang static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n)
27089132dd8SSean Wang {
27189132dd8SSean Wang 	struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
27289132dd8SSean Wang 	const struct mtk_pin_desc *desc;
27389132dd8SSean Wang 	struct gpio_chip *gpio_chip;
27489132dd8SSean Wang 	unsigned int gpio_n;
27589132dd8SSean Wang 	int err;
27689132dd8SSean Wang 
27789132dd8SSean Wang 	err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
27889132dd8SSean Wang 	if (err)
27989132dd8SSean Wang 		return err;
28089132dd8SSean Wang 
28189132dd8SSean Wang 	desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio_n];
28289132dd8SSean Wang 
28389132dd8SSean Wang 	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE,
28489132dd8SSean Wang 			       desc->eint.eint_m);
28589132dd8SSean Wang 	if (err)
28689132dd8SSean Wang 		return err;
28789132dd8SSean Wang 
28889132dd8SSean Wang 	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, MTK_INPUT);
28989132dd8SSean Wang 	if (err)
29089132dd8SSean Wang 		return err;
29189132dd8SSean Wang 
29289132dd8SSean Wang 	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, MTK_ENABLE);
29389132dd8SSean Wang 	if (err)
29489132dd8SSean Wang 		return err;
29589132dd8SSean Wang 
29689132dd8SSean Wang 	return 0;
29789132dd8SSean Wang }
29889132dd8SSean Wang 
29989132dd8SSean Wang static const struct mtk_eint_xt mtk_eint_xt = {
30089132dd8SSean Wang 	.get_gpio_n = mtk_xt_get_gpio_n,
30189132dd8SSean Wang 	.get_gpio_state = mtk_xt_get_gpio_state,
30289132dd8SSean Wang 	.set_gpio_as_eint = mtk_xt_set_gpio_as_eint,
30389132dd8SSean Wang };
30489132dd8SSean Wang 
30589132dd8SSean Wang int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
30689132dd8SSean Wang {
30789132dd8SSean Wang 	struct device_node *np = pdev->dev.of_node;
30889132dd8SSean Wang 	struct resource *res;
30989132dd8SSean Wang 
31089132dd8SSean Wang 	if (!IS_ENABLED(CONFIG_EINT_MTK))
31189132dd8SSean Wang 		return 0;
31289132dd8SSean Wang 
31389132dd8SSean Wang 	if (!of_property_read_bool(np, "interrupt-controller"))
31489132dd8SSean Wang 		return -ENODEV;
31589132dd8SSean Wang 
31689132dd8SSean Wang 	hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);
31789132dd8SSean Wang 	if (!hw->eint)
31889132dd8SSean Wang 		return -ENOMEM;
31989132dd8SSean Wang 
32089132dd8SSean Wang 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eint");
32189132dd8SSean Wang 	if (!res) {
32289132dd8SSean Wang 		dev_err(&pdev->dev, "Unable to get eint resource\n");
32389132dd8SSean Wang 		return -ENODEV;
32489132dd8SSean Wang 	}
32589132dd8SSean Wang 
32689132dd8SSean Wang 	hw->eint->base = devm_ioremap_resource(&pdev->dev, res);
32789132dd8SSean Wang 	if (IS_ERR(hw->eint->base))
32889132dd8SSean Wang 		return PTR_ERR(hw->eint->base);
32989132dd8SSean Wang 
33089132dd8SSean Wang 	hw->eint->irq = irq_of_parse_and_map(np, 0);
33189132dd8SSean Wang 	if (!hw->eint->irq)
33289132dd8SSean Wang 		return -EINVAL;
33389132dd8SSean Wang 
33489132dd8SSean Wang 	if (!hw->soc->eint_hw)
33589132dd8SSean Wang 		return -ENODEV;
33689132dd8SSean Wang 
33789132dd8SSean Wang 	hw->eint->dev = &pdev->dev;
33889132dd8SSean Wang 	hw->eint->hw = hw->soc->eint_hw;
33989132dd8SSean Wang 	hw->eint->pctl = hw;
34089132dd8SSean Wang 	hw->eint->gpio_xlate = &mtk_eint_xt;
34189132dd8SSean Wang 
34289132dd8SSean Wang 	return mtk_eint_do_init(hw->eint);
34389132dd8SSean Wang }
34489132dd8SSean Wang 
3459afc305bSSean Wang /* Revision 0 */
34685430152SSean Wang int mtk_pinconf_bias_disable_set(struct mtk_pinctrl *hw,
34785430152SSean Wang 				 const struct mtk_pin_desc *desc)
34885430152SSean Wang {
34985430152SSean Wang 	int err;
35085430152SSean Wang 
351ea051eb3SSean Wang 	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU,
35285430152SSean Wang 			       MTK_DISABLE);
35385430152SSean Wang 	if (err)
35485430152SSean Wang 		return err;
35585430152SSean Wang 
356ea051eb3SSean Wang 	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD,
35785430152SSean Wang 			       MTK_DISABLE);
35885430152SSean Wang 	if (err)
35985430152SSean Wang 		return err;
36085430152SSean Wang 
36185430152SSean Wang 	return 0;
36285430152SSean Wang }
36385430152SSean Wang 
36485430152SSean Wang int mtk_pinconf_bias_disable_get(struct mtk_pinctrl *hw,
36585430152SSean Wang 				 const struct mtk_pin_desc *desc, int *res)
36685430152SSean Wang {
36785430152SSean Wang 	int v, v2;
36885430152SSean Wang 	int err;
36985430152SSean Wang 
370ea051eb3SSean Wang 	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PU, &v);
37185430152SSean Wang 	if (err)
37285430152SSean Wang 		return err;
37385430152SSean Wang 
374ea051eb3SSean Wang 	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &v2);
37585430152SSean Wang 	if (err)
37685430152SSean Wang 		return err;
37785430152SSean Wang 
37885430152SSean Wang 	if (v == MTK_ENABLE || v2 == MTK_ENABLE)
37985430152SSean Wang 		return -EINVAL;
38085430152SSean Wang 
38185430152SSean Wang 	*res = 1;
38285430152SSean Wang 
38385430152SSean Wang 	return 0;
38485430152SSean Wang }
38585430152SSean Wang 
38685430152SSean Wang int mtk_pinconf_bias_set(struct mtk_pinctrl *hw,
38785430152SSean Wang 			 const struct mtk_pin_desc *desc, bool pullup)
38885430152SSean Wang {
38985430152SSean Wang 	int err, arg;
39085430152SSean Wang 
39185430152SSean Wang 	arg = pullup ? 1 : 2;
39285430152SSean Wang 
393ea051eb3SSean Wang 	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, arg & 1);
39485430152SSean Wang 	if (err)
39585430152SSean Wang 		return err;
39685430152SSean Wang 
397ea051eb3SSean Wang 	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD,
39885430152SSean Wang 			       !!(arg & 2));
39985430152SSean Wang 	if (err)
40085430152SSean Wang 		return err;
40185430152SSean Wang 
40285430152SSean Wang 	return 0;
40385430152SSean Wang }
40485430152SSean Wang 
40585430152SSean Wang int mtk_pinconf_bias_get(struct mtk_pinctrl *hw,
40685430152SSean Wang 			 const struct mtk_pin_desc *desc, bool pullup, int *res)
40785430152SSean Wang {
40885430152SSean Wang 	int reg, err, v;
40985430152SSean Wang 
41085430152SSean Wang 	reg = pullup ? PINCTRL_PIN_REG_PU : PINCTRL_PIN_REG_PD;
41185430152SSean Wang 
412ea051eb3SSean Wang 	err = mtk_hw_get_value(hw, desc, reg, &v);
41385430152SSean Wang 	if (err)
41485430152SSean Wang 		return err;
41585430152SSean Wang 
41685430152SSean Wang 	if (!v)
41785430152SSean Wang 		return -EINVAL;
41885430152SSean Wang 
41985430152SSean Wang 	*res = 1;
42085430152SSean Wang 
42185430152SSean Wang 	return 0;
42285430152SSean Wang }
42385430152SSean Wang 
4249afc305bSSean Wang /* Revision 1 */
4259afc305bSSean Wang int mtk_pinconf_bias_disable_set_rev1(struct mtk_pinctrl *hw,
4269afc305bSSean Wang 				      const struct mtk_pin_desc *desc)
4279afc305bSSean Wang {
4289afc305bSSean Wang 	int err;
4299afc305bSSean Wang 
430ea051eb3SSean Wang 	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN,
4319afc305bSSean Wang 			       MTK_DISABLE);
4329afc305bSSean Wang 	if (err)
4339afc305bSSean Wang 		return err;
4349afc305bSSean Wang 
4359afc305bSSean Wang 	return 0;
4369afc305bSSean Wang }
4379afc305bSSean Wang 
4389afc305bSSean Wang int mtk_pinconf_bias_disable_get_rev1(struct mtk_pinctrl *hw,
4399afc305bSSean Wang 				      const struct mtk_pin_desc *desc, int *res)
4409afc305bSSean Wang {
4419afc305bSSean Wang 	int v, err;
4429afc305bSSean Wang 
443ea051eb3SSean Wang 	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, &v);
4449afc305bSSean Wang 	if (err)
4459afc305bSSean Wang 		return err;
4469afc305bSSean Wang 
4479afc305bSSean Wang 	if (v == MTK_ENABLE)
4489afc305bSSean Wang 		return -EINVAL;
4499afc305bSSean Wang 
4509afc305bSSean Wang 	*res = 1;
4519afc305bSSean Wang 
4529afc305bSSean Wang 	return 0;
4539afc305bSSean Wang }
4549afc305bSSean Wang 
4559afc305bSSean Wang int mtk_pinconf_bias_set_rev1(struct mtk_pinctrl *hw,
4569afc305bSSean Wang 			      const struct mtk_pin_desc *desc, bool pullup)
4579afc305bSSean Wang {
4589afc305bSSean Wang 	int err, arg;
4599afc305bSSean Wang 
4609afc305bSSean Wang 	arg = pullup ? MTK_PULLUP : MTK_PULLDOWN;
4619afc305bSSean Wang 
462ea051eb3SSean Wang 	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN,
4639afc305bSSean Wang 			       MTK_ENABLE);
4649afc305bSSean Wang 	if (err)
4659afc305bSSean Wang 		return err;
4669afc305bSSean Wang 
467ea051eb3SSean Wang 	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, arg);
4689afc305bSSean Wang 	if (err)
4699afc305bSSean Wang 		return err;
4709afc305bSSean Wang 
4719afc305bSSean Wang 	return 0;
4729afc305bSSean Wang }
4739afc305bSSean Wang 
4749afc305bSSean Wang int mtk_pinconf_bias_get_rev1(struct mtk_pinctrl *hw,
4759afc305bSSean Wang 			      const struct mtk_pin_desc *desc, bool pullup,
4769afc305bSSean Wang 			      int *res)
4779afc305bSSean Wang {
4789afc305bSSean Wang 	int err, v;
4799afc305bSSean Wang 
480ea051eb3SSean Wang 	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, &v);
4819afc305bSSean Wang 	if (err)
4829afc305bSSean Wang 		return err;
4839afc305bSSean Wang 
4849afc305bSSean Wang 	if (v == MTK_DISABLE)
4859afc305bSSean Wang 		return -EINVAL;
4869afc305bSSean Wang 
487ea051eb3SSean Wang 	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, &v);
4889afc305bSSean Wang 	if (err)
4899afc305bSSean Wang 		return err;
4909afc305bSSean Wang 
4919afc305bSSean Wang 	if (pullup ^ (v == MTK_PULLUP))
4929afc305bSSean Wang 		return -EINVAL;
4939afc305bSSean Wang 
4949afc305bSSean Wang 	*res = 1;
4959afc305bSSean Wang 
4969afc305bSSean Wang 	return 0;
4979afc305bSSean Wang }
4989afc305bSSean Wang 
499c2832197SSean Wang /* Revision 0 */
500c2832197SSean Wang int mtk_pinconf_drive_set(struct mtk_pinctrl *hw,
501c2832197SSean Wang 			  const struct mtk_pin_desc *desc, u32 arg)
502c2832197SSean Wang {
503c2832197SSean Wang 	const struct mtk_drive_desc *tb;
504c2832197SSean Wang 	int err = -ENOTSUPP;
505c2832197SSean Wang 
506c2832197SSean Wang 	tb = &mtk_drive[desc->drv_n];
507c2832197SSean Wang 	/* 4mA when (e8, e4) = (0, 0)
508c2832197SSean Wang 	 * 8mA when (e8, e4) = (0, 1)
509c2832197SSean Wang 	 * 12mA when (e8, e4) = (1, 0)
510c2832197SSean Wang 	 * 16mA when (e8, e4) = (1, 1)
511c2832197SSean Wang 	 */
512c2832197SSean Wang 	if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) {
513c2832197SSean Wang 		arg = (arg / tb->step - 1) * tb->scal;
514ea051eb3SSean Wang 		err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_E4,
515c2832197SSean Wang 				       arg & 0x1);
516c2832197SSean Wang 		if (err)
517c2832197SSean Wang 			return err;
518c2832197SSean Wang 
519ea051eb3SSean Wang 		err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_E8,
520c2832197SSean Wang 				       (arg & 0x2) >> 1);
521c2832197SSean Wang 		if (err)
522c2832197SSean Wang 			return err;
523c2832197SSean Wang 	}
524c2832197SSean Wang 
525c2832197SSean Wang 	return err;
526c2832197SSean Wang }
527c2832197SSean Wang 
528c2832197SSean Wang int mtk_pinconf_drive_get(struct mtk_pinctrl *hw,
529c2832197SSean Wang 			  const struct mtk_pin_desc *desc, int *val)
530c2832197SSean Wang {
531c2832197SSean Wang 	const struct mtk_drive_desc *tb;
532c2832197SSean Wang 	int err, val1, val2;
533c2832197SSean Wang 
534c2832197SSean Wang 	tb = &mtk_drive[desc->drv_n];
535c2832197SSean Wang 
536ea051eb3SSean Wang 	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_E4, &val1);
537c2832197SSean Wang 	if (err)
538c2832197SSean Wang 		return err;
539c2832197SSean Wang 
540ea051eb3SSean Wang 	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_E8, &val2);
541c2832197SSean Wang 	if (err)
542c2832197SSean Wang 		return err;
543c2832197SSean Wang 
544c2832197SSean Wang 	/* 4mA when (e8, e4) = (0, 0); 8mA when (e8, e4) = (0, 1)
545c2832197SSean Wang 	 * 12mA when (e8, e4) = (1, 0); 16mA when (e8, e4) = (1, 1)
546c2832197SSean Wang 	 */
547c2832197SSean Wang 	*val = (((val2 << 1) + val1) / tb->scal + 1) * tb->step;
548c2832197SSean Wang 
549c2832197SSean Wang 	return 0;
550c2832197SSean Wang }
5513ad38a14SSean Wang 
5523ad38a14SSean Wang /* Revision 1 */
5533ad38a14SSean Wang int mtk_pinconf_drive_set_rev1(struct mtk_pinctrl *hw,
5543ad38a14SSean Wang 			       const struct mtk_pin_desc *desc, u32 arg)
5553ad38a14SSean Wang {
5563ad38a14SSean Wang 	const struct mtk_drive_desc *tb;
5573ad38a14SSean Wang 	int err = -ENOTSUPP;
5583ad38a14SSean Wang 
5593ad38a14SSean Wang 	tb = &mtk_drive[desc->drv_n];
5603ad38a14SSean Wang 
5613ad38a14SSean Wang 	if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) {
5623ad38a14SSean Wang 		arg = (arg / tb->step - 1) * tb->scal;
5633ad38a14SSean Wang 
564ea051eb3SSean Wang 		err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV,
5653ad38a14SSean Wang 				       arg);
5663ad38a14SSean Wang 		if (err)
5673ad38a14SSean Wang 			return err;
5683ad38a14SSean Wang 	}
5693ad38a14SSean Wang 
5703ad38a14SSean Wang 	return err;
5713ad38a14SSean Wang }
5723ad38a14SSean Wang 
5733ad38a14SSean Wang int mtk_pinconf_drive_get_rev1(struct mtk_pinctrl *hw,
5743ad38a14SSean Wang 			       const struct mtk_pin_desc *desc, int *val)
5753ad38a14SSean Wang {
5763ad38a14SSean Wang 	const struct mtk_drive_desc *tb;
5773ad38a14SSean Wang 	int err, val1;
5783ad38a14SSean Wang 
5793ad38a14SSean Wang 	tb = &mtk_drive[desc->drv_n];
5803ad38a14SSean Wang 
581ea051eb3SSean Wang 	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV, &val1);
5823ad38a14SSean Wang 	if (err)
5833ad38a14SSean Wang 		return err;
5843ad38a14SSean Wang 
5853ad38a14SSean Wang 	*val = ((val1 & 0x7) / tb->scal + 1) * tb->step;
5863ad38a14SSean Wang 
5873ad38a14SSean Wang 	return 0;
5883ad38a14SSean Wang }
5890d7ca772SSean Wang 
5900d7ca772SSean Wang int mtk_pinconf_adv_pull_set(struct mtk_pinctrl *hw,
5910d7ca772SSean Wang 			     const struct mtk_pin_desc *desc, bool pullup,
5920d7ca772SSean Wang 			     u32 arg)
5930d7ca772SSean Wang {
5940d7ca772SSean Wang 	int err;
5950d7ca772SSean Wang 
5960d7ca772SSean Wang 	/* 10K off & 50K (75K) off, when (R0, R1) = (0, 0);
5970d7ca772SSean Wang 	 * 10K off & 50K (75K) on, when (R0, R1) = (0, 1);
5980d7ca772SSean Wang 	 * 10K on & 50K (75K) off, when (R0, R1) = (1, 0);
5990d7ca772SSean Wang 	 * 10K on & 50K (75K) on, when (R0, R1) = (1, 1)
6000d7ca772SSean Wang 	 */
601ea051eb3SSean Wang 	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R0, arg & 1);
6020d7ca772SSean Wang 	if (err)
6030d7ca772SSean Wang 		return 0;
6040d7ca772SSean Wang 
605ea051eb3SSean Wang 	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R1,
6060d7ca772SSean Wang 			       !!(arg & 2));
6070d7ca772SSean Wang 	if (err)
6080d7ca772SSean Wang 		return 0;
6090d7ca772SSean Wang 
6100d7ca772SSean Wang 	arg = pullup ? 0 : 1;
6110d7ca772SSean Wang 
612ea051eb3SSean Wang 	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PUPD, arg);
6130d7ca772SSean Wang 
61479348f6fSSean Wang 	/* If PUPD register is not supported for that pin, let's fallback to
61579348f6fSSean Wang 	 * general bias control.
61679348f6fSSean Wang 	 */
61779348f6fSSean Wang 	if (err == -ENOTSUPP) {
61879348f6fSSean Wang 		if (hw->soc->bias_set) {
61979348f6fSSean Wang 			err = hw->soc->bias_set(hw, desc, pullup);
62079348f6fSSean Wang 			if (err)
62179348f6fSSean Wang 				return err;
62279348f6fSSean Wang 		} else {
62379348f6fSSean Wang 			return -ENOTSUPP;
62479348f6fSSean Wang 		}
62579348f6fSSean Wang 	}
62679348f6fSSean Wang 
6270d7ca772SSean Wang 	return err;
6280d7ca772SSean Wang }
6290d7ca772SSean Wang 
6300d7ca772SSean Wang int mtk_pinconf_adv_pull_get(struct mtk_pinctrl *hw,
6310d7ca772SSean Wang 			     const struct mtk_pin_desc *desc, bool pullup,
6320d7ca772SSean Wang 			     u32 *val)
6330d7ca772SSean Wang {
6340d7ca772SSean Wang 	u32 t, t2;
6350d7ca772SSean Wang 	int err;
6360d7ca772SSean Wang 
637ea051eb3SSean Wang 	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PUPD, &t);
63879348f6fSSean Wang 
63979348f6fSSean Wang 	/* If PUPD register is not supported for that pin, let's fallback to
64079348f6fSSean Wang 	 * general bias control.
64179348f6fSSean Wang 	 */
64279348f6fSSean Wang 	if (err == -ENOTSUPP) {
64379348f6fSSean Wang 		if (hw->soc->bias_get) {
64479348f6fSSean Wang 			err = hw->soc->bias_get(hw, desc, pullup, val);
64579348f6fSSean Wang 			if (err)
64679348f6fSSean Wang 				return err;
64779348f6fSSean Wang 		} else {
64879348f6fSSean Wang 			return -ENOTSUPP;
64979348f6fSSean Wang 		}
65079348f6fSSean Wang 	} else {
65179348f6fSSean Wang 		/* t == 0 supposes PULLUP for the customized PULL setup */
6520d7ca772SSean Wang 		if (err)
6530d7ca772SSean Wang 			return err;
6540d7ca772SSean Wang 
6550d7ca772SSean Wang 		if (pullup ^ !t)
6560d7ca772SSean Wang 			return -EINVAL;
65779348f6fSSean Wang 	}
6580d7ca772SSean Wang 
659ea051eb3SSean Wang 	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R0, &t);
6600d7ca772SSean Wang 	if (err)
6610d7ca772SSean Wang 		return err;
6620d7ca772SSean Wang 
663ea051eb3SSean Wang 	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R1, &t2);
6640d7ca772SSean Wang 	if (err)
6650d7ca772SSean Wang 		return err;
6660d7ca772SSean Wang 
6670d7ca772SSean Wang 	*val = (t | t2 << 1) & 0x7;
6680d7ca772SSean Wang 
6690d7ca772SSean Wang 	return 0;
6700d7ca772SSean Wang }
671