brintos

brintos / linux-shallow public Read only

0
0
Text · 27.3 KiB · 54301fb Raw
1233 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 information23 *			    of the driving current24 * @min:	the minimum current of this group25 * @max:	the maximum current of this group26 * @step:	the step current of this group27 * @scal:	the weight factor28 *29 * formula: output = ((input) / step - 1) * scal30 */31struct mtk_drive_desc {32	u8 min;33	u8 max;34	u8 step;35	u8 scal;36};37 38/* The groups of drive strength */39static const struct mtk_drive_desc mtk_drive[] = {40	[DRV_GRP0] = { 4, 16, 4, 1 },41	[DRV_GRP1] = { 4, 16, 4, 2 },42	[DRV_GRP2] = { 2, 8, 2, 1 },43	[DRV_GRP3] = { 2, 8, 2, 2 },44	[DRV_GRP4] = { 2, 16, 2, 1 },45};46 47static void mtk_w32(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 val)48{49	writel_relaxed(val, pctl->base[i] + reg);50}51 52static u32 mtk_r32(struct mtk_pinctrl *pctl, u8 i, u32 reg)53{54	return readl_relaxed(pctl->base[i] + reg);55}56 57void 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(&pctl->lock, flags);70}71 72static 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_pin95		 && 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		else103			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 the123	 * 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 assumed129	 * 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 happens137	 * which requires the manipulation for bit 0 starting in the next138	 * 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 145static 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 157static 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(pf->mask) - *l;161}162 163static 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, &nbits_h, &nbits_l);169 170	mtk_rmw(hw, pf->index, pf->offset, pf->mask << pf->bitpos,171		(value & pf->mask) << pf->bitpos);172 173	mtk_rmw(hw, pf->index, pf->offset + pf->next, BIT(nbits_h) - 1,174		(value & pf->mask) >> nbits_l);175}176 177static 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, &nbits_h, &nbits_l);183 184	l  = (mtk_r32(hw, pf->index, pf->offset)185	      >> pf->bitpos) & (BIT(nbits_l) - 1);186	h  = (mtk_r32(hw, pf->index, pf->offset + pf->next))187	      & (BIT(nbits_h) - 1);188 189	*value = (h << nbits_l) | l;190}191 192int 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, &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(hw, pf.index, pf.offset, pf.mask << pf.bitpos,207			(value & pf.mask) << pf.bitpos);208	else209		mtk_hw_write_cross_field(hw, &pf, value);210 211	return 0;212}213EXPORT_SYMBOL_GPL(mtk_hw_set_value);214 215int 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, &pf);222	if (err)223		return err;224 225	if (!pf.next)226		*value = (mtk_r32(hw, pf.index, pf.offset)227			  >> pf.bitpos) & pf.mask;228	else229		mtk_hw_read_cross_field(hw, &pf, value);230 231	return 0;232}233EXPORT_SYMBOL_GPL(mtk_hw_get_value);234 235static 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 mapping255 * 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 260bool 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}276EXPORT_SYMBOL_GPL(mtk_is_virt_gpio);277 278static 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	else296		*gpio_n = mtk_xt_find_eint_num(hw, eint_n);297 298	return *gpio_n == EINT_NA ? -EINVAL : 0;299}300 301static 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(hw, eint_n, &gpio_n, &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 322static 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(hw, eint_n, &gpio_n, &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't350	 * support virtual GPIOs, so the extra condition err != -ENOTSUPP351	 * is just for adding EINT support to these virtual GPIOs. It should352	 * add an extra flag in the pin descriptor when more pins with353	 * distinctive characteristic come out.354	 */355	if (err && err != -ENOTSUPP)356		return err;357 358	return 0;359}360 361static 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 367int 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, "interrupt-controller"))376		return -ENODEV;377 378	hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);379	if (!hw->eint)380		return -ENOMEM;381 382	hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint");383	if (IS_ERR(hw->eint->base)) {384		ret = PTR_ERR(hw->eint->base);385		goto err_free_eint;386	}387 388	hw->eint->irq = irq_of_parse_and_map(np, 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(hw->eint);405 406err_free_eint:407	devm_kfree(hw->dev, hw->eint);408	hw->eint = NULL;409	return ret;410}411EXPORT_SYMBOL_GPL(mtk_build_eint);412 413/* Revision 0 */414int 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}431EXPORT_SYMBOL_GPL(mtk_pinconf_bias_disable_set);432 433int 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}454EXPORT_SYMBOL_GPL(mtk_pinconf_bias_disable_get);455 456int 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}474EXPORT_SYMBOL_GPL(mtk_pinconf_bias_set);475 476int 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}494EXPORT_SYMBOL_GPL(mtk_pinconf_bias_get);495 496/* Revision 1 */497int 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}503EXPORT_SYMBOL_GPL(mtk_pinconf_bias_disable_set_rev1);504 505int 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}521EXPORT_SYMBOL_GPL(mtk_pinconf_bias_disable_get_rev1);522 523int 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}541EXPORT_SYMBOL_GPL(mtk_pinconf_bias_set_rev1);542 543int 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}567EXPORT_SYMBOL_GPL(mtk_pinconf_bias_get_rev1);568 569/* Combo for the following pull register type:570 * 1. PU + PD571 * 2. PULLSEL + PULLEN572 * 3. PUPD + R0 + R1573 */574static 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 600out:601	return err;602}603 604static 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 625out:626	return err;627}628 629static 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 664out:665	return err;666}667 668static 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 706static 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 (hw->rsel_si_unit) {713		/* find pin rsel_index from pin_rsel array*/714		err = mtk_hw_pin_rsel_lookup(hw, desc, pullup, arg, &rsel_val);715		if (err)716			return err;717	} else {718		if (arg < MTK_PULL_SET_RSEL_000 || arg > MTK_PULL_SET_RSEL_111)719			return -EINVAL;720 721		rsel_val = arg - MTK_PULL_SET_RSEL_000;722	}723 724	return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_RSEL, rsel_val);725}726 727static int mtk_pinconf_bias_set_pu_pd_rsel(struct mtk_pinctrl *hw,728					   const struct mtk_pin_desc *desc,729					   u32 pullup, u32 arg)730{731	u32 enable = arg == MTK_DISABLE ? MTK_DISABLE : MTK_ENABLE;732	int err;733 734	if (arg != MTK_DISABLE) {735		err = mtk_pinconf_bias_set_rsel(hw, desc, pullup, arg);736		if (err)737			return err;738	}739 740	return mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, enable);741}742 743int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw,744			       const struct mtk_pin_desc *desc,745			       u32 pullup, u32 arg)746{747	int err = -ENOTSUPP;748	u32 try_all_type;749 750	if (hw->soc->pull_type)751		try_all_type = hw->soc->pull_type[desc->number];752	else753		try_all_type = MTK_PULL_TYPE_MASK;754 755	if (try_all_type & MTK_PULL_RSEL_TYPE) {756		err = mtk_pinconf_bias_set_pu_pd_rsel(hw, desc, pullup, arg);757		if (!err)758			return 0;759	}760 761	if (try_all_type & MTK_PULL_PU_PD_TYPE) {762		err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg);763		if (!err)764			return 0;765	}766 767	if (try_all_type & MTK_PULL_PULLSEL_TYPE) {768		err = mtk_pinconf_bias_set_pullsel_pullen(hw, desc,769							  pullup, arg);770		if (!err)771			return 0;772	}773 774	if (try_all_type & MTK_PULL_PUPD_R1R0_TYPE)775		err = mtk_pinconf_bias_set_pupd_r1_r0(hw, desc, pullup, arg);776 777	if (err)778		dev_err(hw->dev, "Invalid pull argument\n");779 780	return err;781}782EXPORT_SYMBOL_GPL(mtk_pinconf_bias_set_combo);783 784static int mtk_rsel_get_si_unit(struct mtk_pinctrl *hw,785				const struct mtk_pin_desc *desc,786				u32 pullup, u32 rsel_val, u32 *si_unit)787{788	const struct mtk_pin_rsel *rsel;789	int check;790 791	rsel = hw->soc->pin_rsel;792 793	for (check = 0; check <= hw->soc->npin_rsel - 1; check++) {794		if (desc->number >= rsel[check].s_pin &&795		    desc->number <= rsel[check].e_pin) {796			if (rsel_val == rsel[check].rsel_index) {797				if (pullup)798					*si_unit = rsel[check].up_rsel;799				else800					*si_unit = rsel[check].down_rsel;801				break;802			}803		}804	}805 806	return 0;807}808 809static int mtk_pinconf_bias_get_pu_pd_rsel(struct mtk_pinctrl *hw,810					   const struct mtk_pin_desc *desc,811					   u32 *pullup, u32 *enable)812{813	int pu, pd, rsel, err;814 815	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_RSEL, &rsel);816	if (err)817		goto out;818 819	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PU, &pu);820	if (err)821		goto out;822 823	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &pd);824	if (err)825		goto out;826 827	if (pu == 0 && pd == 0) {828		*pullup = 0;829		*enable = MTK_DISABLE;830	} else if (pu == 1 && pd == 0) {831		*pullup = 1;832		if (hw->rsel_si_unit)833			mtk_rsel_get_si_unit(hw, desc, *pullup, rsel, enable);834		else835			*enable = rsel + MTK_PULL_SET_RSEL_000;836	} else if (pu == 0 && pd == 1) {837		*pullup = 0;838		if (hw->rsel_si_unit)839			mtk_rsel_get_si_unit(hw, desc, *pullup, rsel, enable);840		else841			*enable = rsel + MTK_PULL_SET_RSEL_000;842	} else {843		err = -EINVAL;844		goto out;845	}846 847out:848	return err;849}850 851static int mtk_pinconf_bias_get_pu_pd(struct mtk_pinctrl *hw,852				const struct mtk_pin_desc *desc,853				u32 *pullup, u32 *enable)854{855	int err, pu, pd;856 857	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PU, &pu);858	if (err)859		goto out;860 861	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &pd);862	if (err)863		goto out;864 865	if (pu == 0 && pd == 0) {866		*pullup = 0;867		*enable = MTK_DISABLE;868	} else if (pu == 1 && pd == 0) {869		*pullup = 1;870		*enable = MTK_ENABLE;871	} else if (pu == 0 && pd == 1) {872		*pullup = 0;873		*enable = MTK_ENABLE;874	} else875		err = -EINVAL;876 877out:878	return err;879}880 881static int mtk_pinconf_bias_get_pullsel_pullen(struct mtk_pinctrl *hw,882				const struct mtk_pin_desc *desc,883				u32 *pullup, u32 *enable)884{885	int err;886 887	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, pullup);888	if (err)889		goto out;890 891	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, enable);892 893out:894	return err;895}896 897static int mtk_pinconf_bias_get_pupd_r1_r0(struct mtk_pinctrl *hw,898				const struct mtk_pin_desc *desc,899				u32 *pullup, u32 *enable)900{901	int err, r0, r1;902 903	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PUPD, pullup);904	if (err)905		goto out;906	/* MTK HW PUPD bit: 1 for pull-down, 0 for pull-up */907	*pullup = !(*pullup);908 909	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R0, &r0);910	if (err)911		goto out;912 913	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R1, &r1);914	if (err)915		goto out;916 917	if ((r1 == 0) && (r0 == 0))918		*enable = MTK_PUPD_SET_R1R0_00;919	else if ((r1 == 0) && (r0 == 1))920		*enable = MTK_PUPD_SET_R1R0_01;921	else if ((r1 == 1) && (r0 == 0))922		*enable = MTK_PUPD_SET_R1R0_10;923	else if ((r1 == 1) && (r0 == 1))924		*enable = MTK_PUPD_SET_R1R0_11;925	else926		err = -EINVAL;927 928out:929	return err;930}931 932int mtk_pinconf_bias_get_combo(struct mtk_pinctrl *hw,933			      const struct mtk_pin_desc *desc,934			      u32 *pullup, u32 *enable)935{936	int err = -ENOTSUPP;937	u32 try_all_type;938 939	if (hw->soc->pull_type)940		try_all_type = hw->soc->pull_type[desc->number];941	else942		try_all_type = MTK_PULL_TYPE_MASK;943 944	if (try_all_type & MTK_PULL_RSEL_TYPE) {945		err = mtk_pinconf_bias_get_pu_pd_rsel(hw, desc, pullup, enable);946		if (!err)947			return 0;948	}949 950	if (try_all_type & MTK_PULL_PU_PD_TYPE) {951		err = mtk_pinconf_bias_get_pu_pd(hw, desc, pullup, enable);952		if (!err)953			return 0;954	}955 956	if (try_all_type & MTK_PULL_PULLSEL_TYPE) {957		err = mtk_pinconf_bias_get_pullsel_pullen(hw, desc,958							  pullup, enable);959		if (!err)960			return 0;961	}962 963	if (try_all_type & MTK_PULL_PUPD_R1R0_TYPE)964		err = mtk_pinconf_bias_get_pupd_r1_r0(hw, desc, pullup, enable);965 966	return err;967}968EXPORT_SYMBOL_GPL(mtk_pinconf_bias_get_combo);969 970/* Revision 0 */971int mtk_pinconf_drive_set(struct mtk_pinctrl *hw,972			  const struct mtk_pin_desc *desc, u32 arg)973{974	const struct mtk_drive_desc *tb;975	int err = -ENOTSUPP;976 977	tb = &mtk_drive[desc->drv_n];978	/* 4mA when (e8, e4) = (0, 0)979	 * 8mA when (e8, e4) = (0, 1)980	 * 12mA when (e8, e4) = (1, 0)981	 * 16mA when (e8, e4) = (1, 1)982	 */983	if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) {984		arg = (arg / tb->step - 1) * tb->scal;985		err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_E4,986				       arg & 0x1);987		if (err)988			return err;989 990		err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_E8,991				       (arg & 0x2) >> 1);992		if (err)993			return err;994	}995 996	return err;997}998EXPORT_SYMBOL_GPL(mtk_pinconf_drive_set);999 1000int mtk_pinconf_drive_get(struct mtk_pinctrl *hw,1001			  const struct mtk_pin_desc *desc, int *val)1002{1003	const struct mtk_drive_desc *tb;1004	int err, val1, val2;1005 1006	tb = &mtk_drive[desc->drv_n];1007 1008	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_E4, &val1);1009	if (err)1010		return err;1011 1012	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_E8, &val2);1013	if (err)1014		return err;1015 1016	/* 4mA when (e8, e4) = (0, 0); 8mA when (e8, e4) = (0, 1)1017	 * 12mA when (e8, e4) = (1, 0); 16mA when (e8, e4) = (1, 1)1018	 */1019	*val = (((val2 << 1) + val1) / tb->scal + 1) * tb->step;1020 1021	return 0;1022}1023EXPORT_SYMBOL_GPL(mtk_pinconf_drive_get);1024 1025/* Revision 1 */1026int mtk_pinconf_drive_set_rev1(struct mtk_pinctrl *hw,1027			       const struct mtk_pin_desc *desc, u32 arg)1028{1029	const struct mtk_drive_desc *tb;1030	int err = -ENOTSUPP;1031 1032	tb = &mtk_drive[desc->drv_n];1033 1034	if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) {1035		arg = (arg / tb->step - 1) * tb->scal;1036 1037		err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV,1038				       arg);1039		if (err)1040			return err;1041	}1042 1043	return err;1044}1045EXPORT_SYMBOL_GPL(mtk_pinconf_drive_set_rev1);1046 1047int mtk_pinconf_drive_get_rev1(struct mtk_pinctrl *hw,1048			       const struct mtk_pin_desc *desc, int *val)1049{1050	const struct mtk_drive_desc *tb;1051	int err, val1;1052 1053	tb = &mtk_drive[desc->drv_n];1054 1055	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV, &val1);1056	if (err)1057		return err;1058 1059	*val = ((val1 & 0x7) / tb->scal + 1) * tb->step;1060 1061	return 0;1062}1063EXPORT_SYMBOL_GPL(mtk_pinconf_drive_get_rev1);1064 1065int mtk_pinconf_drive_set_raw(struct mtk_pinctrl *hw,1066			       const struct mtk_pin_desc *desc, u32 arg)1067{1068	return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV, arg);1069}1070EXPORT_SYMBOL_GPL(mtk_pinconf_drive_set_raw);1071 1072int mtk_pinconf_drive_get_raw(struct mtk_pinctrl *hw,1073			       const struct mtk_pin_desc *desc, int *val)1074{1075	return mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV, val);1076}1077EXPORT_SYMBOL_GPL(mtk_pinconf_drive_get_raw);1078 1079int mtk_pinconf_adv_pull_set(struct mtk_pinctrl *hw,1080			     const struct mtk_pin_desc *desc, bool pullup,1081			     u32 arg)1082{1083	int err;1084 1085	/* 10K off & 50K (75K) off, when (R0, R1) = (0, 0);1086	 * 10K off & 50K (75K) on, when (R0, R1) = (0, 1);1087	 * 10K on & 50K (75K) off, when (R0, R1) = (1, 0);1088	 * 10K on & 50K (75K) on, when (R0, R1) = (1, 1)1089	 */1090	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R0, arg & 1);1091	if (err)1092		return 0;1093 1094	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R1,1095			       !!(arg & 2));1096	if (err)1097		return 0;1098 1099	arg = pullup ? 0 : 1;1100 1101	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PUPD, arg);1102 1103	/* If PUPD register is not supported for that pin, let's fallback to1104	 * general bias control.1105	 */1106	if (err == -ENOTSUPP) {1107		if (hw->soc->bias_set) {1108			err = hw->soc->bias_set(hw, desc, pullup);1109			if (err)1110				return err;1111		} else {1112			err = mtk_pinconf_bias_set_rev1(hw, desc, pullup);1113			if (err)1114				err = mtk_pinconf_bias_set(hw, desc, pullup);1115		}1116	}1117 1118	return err;1119}1120EXPORT_SYMBOL_GPL(mtk_pinconf_adv_pull_set);1121 1122int mtk_pinconf_adv_pull_get(struct mtk_pinctrl *hw,1123			     const struct mtk_pin_desc *desc, bool pullup,1124			     u32 *val)1125{1126	u32 t, t2;1127	int err;1128 1129	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PUPD, &t);1130 1131	/* If PUPD register is not supported for that pin, let's fallback to1132	 * general bias control.1133	 */1134	if (err == -ENOTSUPP) {1135		if (hw->soc->bias_get) {1136			err = hw->soc->bias_get(hw, desc, pullup, val);1137			if (err)1138				return err;1139		} else {1140			return -ENOTSUPP;1141		}1142	} else {1143		/* t == 0 supposes PULLUP for the customized PULL setup */1144		if (err)1145			return err;1146 1147		if (pullup ^ !t)1148			return -EINVAL;1149	}1150 1151	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R0, &t);1152	if (err)1153		return err;1154 1155	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R1, &t2);1156	if (err)1157		return err;1158 1159	*val = (t | t2 << 1) & 0x7;1160 1161	return 0;1162}1163EXPORT_SYMBOL_GPL(mtk_pinconf_adv_pull_get);1164 1165int mtk_pinconf_adv_drive_set(struct mtk_pinctrl *hw,1166			      const struct mtk_pin_desc *desc, u32 arg)1167{1168	int err;1169	int en = arg & 1;1170	int e0 = !!(arg & 2);1171	int e1 = !!(arg & 4);1172 1173	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_EN, en);1174	if (err)1175		return err;1176 1177	if (!en)1178		return err;1179 1180	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_E0, e0);1181	if (err)1182		return err;1183 1184	err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_E1, e1);1185	if (err)1186		return err;1187 1188	return err;1189}1190EXPORT_SYMBOL_GPL(mtk_pinconf_adv_drive_set);1191 1192int mtk_pinconf_adv_drive_get(struct mtk_pinctrl *hw,1193			      const struct mtk_pin_desc *desc, u32 *val)1194{1195	u32 en, e0, e1;1196	int err;1197 1198	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_EN, &en);1199	if (err)1200		return err;1201 1202	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_E0, &e0);1203	if (err)1204		return err;1205 1206	err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_E1, &e1);1207	if (err)1208		return err;1209 1210	*val = (en | e0 << 1 | e1 << 2) & 0x7;1211 1212	return 0;1213}1214EXPORT_SYMBOL_GPL(mtk_pinconf_adv_drive_get);1215 1216int mtk_pinconf_adv_drive_set_raw(struct mtk_pinctrl *hw,1217				  const struct mtk_pin_desc *desc, u32 arg)1218{1219	return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_ADV, arg);1220}1221EXPORT_SYMBOL_GPL(mtk_pinconf_adv_drive_set_raw);1222 1223int mtk_pinconf_adv_drive_get_raw(struct mtk_pinctrl *hw,1224				  const struct mtk_pin_desc *desc, u32 *val)1225{1226	return mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_ADV, val);1227}1228EXPORT_SYMBOL_GPL(mtk_pinconf_adv_drive_get_raw);1229 1230MODULE_LICENSE("GPL v2");1231MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");1232MODULE_DESCRIPTION("Pin configuration library module for mediatek SoCs");1233