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