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 9cafe19dbSLight Hsieh #include <dt-bindings/pinctrl/mt65xx.h> 10a1a503a8SSean Wang #include <linux/device.h> 11a1a503a8SSean Wang #include <linux/err.h> 1222d7fe49SLinus Walleij #include <linux/gpio/driver.h> 1389132dd8SSean Wang #include <linux/platform_device.h> 14a1a503a8SSean Wang #include <linux/io.h> 158174a851SLight Hsieh #include <linux/module.h> 1689132dd8SSean Wang #include <linux/of_irq.h> 17a1a503a8SSean Wang 1889132dd8SSean Wang #include "mtk-eint.h" 19a1a503a8SSean Wang #include "pinctrl-mtk-common-v2.h" 20a1a503a8SSean Wang 21c2832197SSean Wang /** 22c2832197SSean Wang * struct mtk_drive_desc - the structure that holds the information 23c2832197SSean Wang * of the driving current 24c2832197SSean Wang * @min: the minimum current of this group 25c2832197SSean Wang * @max: the maximum current of this group 26c2832197SSean Wang * @step: the step current of this group 27c2832197SSean Wang * @scal: the weight factor 28c2832197SSean Wang * 29c2832197SSean Wang * formula: output = ((input) / step - 1) * scal 30c2832197SSean Wang */ 31c2832197SSean Wang struct mtk_drive_desc { 32c2832197SSean Wang u8 min; 33c2832197SSean Wang u8 max; 34c2832197SSean Wang u8 step; 35c2832197SSean Wang u8 scal; 36c2832197SSean Wang }; 37c2832197SSean Wang 38c2832197SSean Wang /* The groups of drive strength */ 3907c6b037SWei Yongjun static const struct mtk_drive_desc mtk_drive[] = { 40c2832197SSean Wang [DRV_GRP0] = { 4, 16, 4, 1 }, 41c2832197SSean Wang [DRV_GRP1] = { 4, 16, 4, 2 }, 42c2832197SSean Wang [DRV_GRP2] = { 2, 8, 2, 1 }, 43c2832197SSean Wang [DRV_GRP3] = { 2, 8, 2, 2 }, 44c2832197SSean Wang [DRV_GRP4] = { 2, 16, 2, 1 }, 45c2832197SSean Wang }; 46c2832197SSean Wang 472bc47dfeSSean Wang static void mtk_w32(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 val) 48a1a503a8SSean Wang { 492bc47dfeSSean Wang writel_relaxed(val, pctl->base[i] + reg); 50a1a503a8SSean Wang } 51a1a503a8SSean Wang 522bc47dfeSSean Wang static u32 mtk_r32(struct mtk_pinctrl *pctl, u8 i, u32 reg) 53a1a503a8SSean Wang { 542bc47dfeSSean Wang return readl_relaxed(pctl->base[i] + reg); 55a1a503a8SSean Wang } 56a1a503a8SSean Wang 572bc47dfeSSean Wang void mtk_rmw(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 mask, u32 set) 58a1a503a8SSean Wang { 59a1a503a8SSean Wang u32 val; 60*56ab29ecSTzung-Bi Shih unsigned long flags; 61a1a503a8SSean Wang 62*56ab29ecSTzung-Bi Shih spin_lock_irqsave(&pctl->lock, flags); 6342a46434SZhiyong Tao 642bc47dfeSSean Wang val = mtk_r32(pctl, i, reg); 65a1a503a8SSean Wang val &= ~mask; 66a1a503a8SSean Wang val |= set; 672bc47dfeSSean Wang mtk_w32(pctl, i, reg, val); 6842a46434SZhiyong Tao 69*56ab29ecSTzung-Bi Shih spin_unlock_irqrestore(&pctl->lock, flags); 70a1a503a8SSean Wang } 71a1a503a8SSean Wang 72ea051eb3SSean Wang static int mtk_hw_pin_field_lookup(struct mtk_pinctrl *hw, 73ea051eb3SSean Wang const struct mtk_pin_desc *desc, 749d9b171cSSean Wang int field, struct mtk_pin_field *pfd) 75a1a503a8SSean Wang { 7686ecb7d6SYueHaibing const struct mtk_pin_field_calc *c; 779d9b171cSSean Wang const struct mtk_pin_reg_calc *rc; 783de7deefSLight Hsieh int start = 0, end, check; 793de7deefSLight Hsieh bool found = false; 80a1a503a8SSean Wang u32 bits; 81a1a503a8SSean Wang 829d9b171cSSean Wang if (hw->soc->reg_cal && hw->soc->reg_cal[field].range) { 839d9b171cSSean Wang rc = &hw->soc->reg_cal[field]; 849d9b171cSSean Wang } else { 859d9b171cSSean Wang dev_dbg(hw->dev, 863de7deefSLight Hsieh "Not support field %d for this soc\n", field); 879d9b171cSSean Wang return -ENOTSUPP; 889d9b171cSSean Wang } 899d9b171cSSean Wang 903de7deefSLight Hsieh end = rc->nranges - 1; 91a1a503a8SSean Wang 923de7deefSLight Hsieh while (start <= end) { 933de7deefSLight Hsieh check = (start + end) >> 1; 943de7deefSLight Hsieh if (desc->number >= rc->range[check].s_pin 953de7deefSLight Hsieh && desc->number <= rc->range[check].e_pin) { 963de7deefSLight Hsieh found = true; 97a1a503a8SSean Wang break; 983de7deefSLight Hsieh } else if (start == end) 993de7deefSLight Hsieh break; 1003de7deefSLight Hsieh else if (desc->number < rc->range[check].s_pin) 1013de7deefSLight Hsieh end = check - 1; 1023de7deefSLight Hsieh else 1033de7deefSLight Hsieh start = check + 1; 104a1a503a8SSean Wang } 105a1a503a8SSean Wang 1063de7deefSLight Hsieh if (!found) { 1079d9b171cSSean Wang dev_dbg(hw->dev, "Not support field %d for pin = %d (%s)\n", 1089d9b171cSSean Wang field, desc->number, desc->name); 1099d9b171cSSean Wang return -ENOTSUPP; 110a1a503a8SSean Wang } 111a1a503a8SSean Wang 1123de7deefSLight Hsieh c = rc->range + check; 1133de7deefSLight Hsieh 1142bc47dfeSSean Wang if (c->i_base > hw->nbase - 1) { 1159d9b171cSSean Wang dev_err(hw->dev, 1169d9b171cSSean Wang "Invalid base for field %d for pin = %d (%s)\n", 1179d9b171cSSean Wang field, desc->number, desc->name); 1182bc47dfeSSean Wang return -EINVAL; 1192bc47dfeSSean Wang } 1202bc47dfeSSean Wang 121b906faf7SSean Wang /* Calculated bits as the overall offset the pin is located at, 122b906faf7SSean Wang * if c->fixed is held, that determines the all the pins in the 123b906faf7SSean Wang * range use the same field with the s_pin. 124b906faf7SSean Wang */ 125ea051eb3SSean Wang bits = c->fixed ? c->s_bit : c->s_bit + 126ea051eb3SSean Wang (desc->number - c->s_pin) * (c->x_bits); 127a1a503a8SSean Wang 128b906faf7SSean Wang /* Fill pfd from bits. For example 32-bit register applied is assumed 129b906faf7SSean Wang * when c->sz_reg is equal to 32. 130b906faf7SSean Wang */ 1312bc47dfeSSean Wang pfd->index = c->i_base; 132b906faf7SSean Wang pfd->offset = c->s_addr + c->x_addrs * (bits / c->sz_reg); 133b906faf7SSean Wang pfd->bitpos = bits % c->sz_reg; 134a1a503a8SSean Wang pfd->mask = (1 << c->x_bits) - 1; 135a1a503a8SSean Wang 136a1a503a8SSean Wang /* pfd->next is used for indicating that bit wrapping-around happens 137a1a503a8SSean Wang * which requires the manipulation for bit 0 starting in the next 138a1a503a8SSean Wang * register to form the complete field read/write. 139a1a503a8SSean Wang */ 140b906faf7SSean Wang pfd->next = pfd->bitpos + c->x_bits > c->sz_reg ? c->x_addrs : 0; 141a1a503a8SSean Wang 142a1a503a8SSean Wang return 0; 143a1a503a8SSean Wang } 144a1a503a8SSean Wang 145ea051eb3SSean Wang static int mtk_hw_pin_field_get(struct mtk_pinctrl *hw, 146ea051eb3SSean Wang const struct mtk_pin_desc *desc, 147a1a503a8SSean Wang int field, struct mtk_pin_field *pfd) 148a1a503a8SSean Wang { 149a1a503a8SSean Wang if (field < 0 || field >= PINCTRL_PIN_REG_MAX) { 150a1a503a8SSean Wang dev_err(hw->dev, "Invalid Field %d\n", field); 151a1a503a8SSean Wang return -EINVAL; 152a1a503a8SSean Wang } 153a1a503a8SSean Wang 1549d9b171cSSean Wang return mtk_hw_pin_field_lookup(hw, desc, field, pfd); 155a1a503a8SSean Wang } 156a1a503a8SSean Wang 157a1a503a8SSean Wang static void mtk_hw_bits_part(struct mtk_pin_field *pf, int *h, int *l) 158a1a503a8SSean Wang { 159a1a503a8SSean Wang *l = 32 - pf->bitpos; 160a1a503a8SSean Wang *h = get_count_order(pf->mask) - *l; 161a1a503a8SSean Wang } 162a1a503a8SSean Wang 163a1a503a8SSean Wang static void mtk_hw_write_cross_field(struct mtk_pinctrl *hw, 164a1a503a8SSean Wang struct mtk_pin_field *pf, int value) 165a1a503a8SSean Wang { 166a1a503a8SSean Wang int nbits_l, nbits_h; 167a1a503a8SSean Wang 168a1a503a8SSean Wang mtk_hw_bits_part(pf, &nbits_h, &nbits_l); 169a1a503a8SSean Wang 1702bc47dfeSSean Wang mtk_rmw(hw, pf->index, pf->offset, pf->mask << pf->bitpos, 171a1a503a8SSean Wang (value & pf->mask) << pf->bitpos); 172a1a503a8SSean Wang 1732bc47dfeSSean Wang mtk_rmw(hw, pf->index, pf->offset + pf->next, BIT(nbits_h) - 1, 174a1a503a8SSean Wang (value & pf->mask) >> nbits_l); 175a1a503a8SSean Wang } 176a1a503a8SSean Wang 177a1a503a8SSean Wang static void mtk_hw_read_cross_field(struct mtk_pinctrl *hw, 178a1a503a8SSean Wang struct mtk_pin_field *pf, int *value) 179a1a503a8SSean Wang { 180a1a503a8SSean Wang int nbits_l, nbits_h, h, l; 181a1a503a8SSean Wang 182a1a503a8SSean Wang mtk_hw_bits_part(pf, &nbits_h, &nbits_l); 183a1a503a8SSean Wang 1842bc47dfeSSean Wang l = (mtk_r32(hw, pf->index, pf->offset) 1852bc47dfeSSean Wang >> pf->bitpos) & (BIT(nbits_l) - 1); 1862bc47dfeSSean Wang h = (mtk_r32(hw, pf->index, pf->offset + pf->next)) 1872bc47dfeSSean Wang & (BIT(nbits_h) - 1); 188a1a503a8SSean Wang 189a1a503a8SSean Wang *value = (h << nbits_l) | l; 190a1a503a8SSean Wang } 191a1a503a8SSean Wang 192ea051eb3SSean Wang int mtk_hw_set_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc, 193ea051eb3SSean Wang int field, int value) 194a1a503a8SSean Wang { 195a1a503a8SSean Wang struct mtk_pin_field pf; 196a1a503a8SSean Wang int err; 197a1a503a8SSean Wang 198ea051eb3SSean Wang err = mtk_hw_pin_field_get(hw, desc, field, &pf); 199a1a503a8SSean Wang if (err) 200a1a503a8SSean Wang return err; 201a1a503a8SSean Wang 2023de7deefSLight Hsieh if (value < 0 || value > pf.mask) 2033de7deefSLight Hsieh return -EINVAL; 2043de7deefSLight Hsieh 205a1a503a8SSean Wang if (!pf.next) 2062bc47dfeSSean Wang mtk_rmw(hw, pf.index, pf.offset, pf.mask << pf.bitpos, 207a1a503a8SSean Wang (value & pf.mask) << pf.bitpos); 208a1a503a8SSean Wang else 209a1a503a8SSean Wang mtk_hw_write_cross_field(hw, &pf, value); 210a1a503a8SSean Wang 211a1a503a8SSean Wang return 0; 212a1a503a8SSean Wang } 2138174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_hw_set_value); 214a1a503a8SSean Wang 215ea051eb3SSean Wang int mtk_hw_get_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc, 216ea051eb3SSean Wang int field, int *value) 217a1a503a8SSean Wang { 218a1a503a8SSean Wang struct mtk_pin_field pf; 219a1a503a8SSean Wang int err; 220a1a503a8SSean Wang 221ea051eb3SSean Wang err = mtk_hw_pin_field_get(hw, desc, field, &pf); 222a1a503a8SSean Wang if (err) 223a1a503a8SSean Wang return err; 224a1a503a8SSean Wang 225a1a503a8SSean Wang if (!pf.next) 2262bc47dfeSSean Wang *value = (mtk_r32(hw, pf.index, pf.offset) 2272bc47dfeSSean Wang >> pf.bitpos) & pf.mask; 228a1a503a8SSean Wang else 229a1a503a8SSean Wang mtk_hw_read_cross_field(hw, &pf, value); 230a1a503a8SSean Wang 231a1a503a8SSean Wang return 0; 232a1a503a8SSean Wang } 2338174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_hw_get_value); 234c2832197SSean Wang 23589132dd8SSean Wang static int mtk_xt_find_eint_num(struct mtk_pinctrl *hw, unsigned long eint_n) 23689132dd8SSean Wang { 23789132dd8SSean Wang const struct mtk_pin_desc *desc; 23889132dd8SSean Wang int i = 0; 23989132dd8SSean Wang 24089132dd8SSean Wang desc = (const struct mtk_pin_desc *)hw->soc->pins; 24189132dd8SSean Wang 24289132dd8SSean Wang while (i < hw->soc->npins) { 24389132dd8SSean Wang if (desc[i].eint.eint_n == eint_n) 24489132dd8SSean Wang return desc[i].number; 24589132dd8SSean Wang i++; 24689132dd8SSean Wang } 24789132dd8SSean Wang 24889132dd8SSean Wang return EINT_NA; 24989132dd8SSean Wang } 25089132dd8SSean Wang 251edd54646SHanks Chen /* 252edd54646SHanks Chen * Virtual GPIO only used inside SOC and not being exported to outside SOC. 253edd54646SHanks Chen * Some modules use virtual GPIO as eint (e.g. pmif or usb). 254edd54646SHanks Chen * In MTK platform, external interrupt (EINT) and GPIO is 1-1 mapping 255edd54646SHanks Chen * and we can set GPIO as eint. 256edd54646SHanks Chen * But some modules use specific eint which doesn't have real GPIO pin. 257edd54646SHanks Chen * So we use virtual GPIO to map it. 258edd54646SHanks Chen */ 259edd54646SHanks Chen 260edd54646SHanks Chen bool mtk_is_virt_gpio(struct mtk_pinctrl *hw, unsigned int gpio_n) 261edd54646SHanks Chen { 262edd54646SHanks Chen const struct mtk_pin_desc *desc; 263edd54646SHanks Chen bool virt_gpio = false; 264edd54646SHanks Chen 265edd54646SHanks Chen desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio_n]; 266edd54646SHanks Chen 26739c4dbe4SHanks Chen /* if the GPIO is not supported for eint mode */ 26839c4dbe4SHanks Chen if (desc->eint.eint_m == NO_EINT_SUPPORT) 26939c4dbe4SHanks Chen return virt_gpio; 27039c4dbe4SHanks Chen 271edd54646SHanks Chen if (desc->funcs && !desc->funcs[desc->eint.eint_m].name) 272edd54646SHanks Chen virt_gpio = true; 273edd54646SHanks Chen 274edd54646SHanks Chen return virt_gpio; 275edd54646SHanks Chen } 276047cd9a6SRandy Dunlap EXPORT_SYMBOL_GPL(mtk_is_virt_gpio); 277edd54646SHanks Chen 27889132dd8SSean Wang static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n, 27989132dd8SSean Wang unsigned int *gpio_n, 28089132dd8SSean Wang struct gpio_chip **gpio_chip) 28189132dd8SSean Wang { 28289132dd8SSean Wang struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; 28389132dd8SSean Wang const struct mtk_pin_desc *desc; 28489132dd8SSean Wang 28589132dd8SSean Wang desc = (const struct mtk_pin_desc *)hw->soc->pins; 28689132dd8SSean Wang *gpio_chip = &hw->chip; 28789132dd8SSean Wang 28889132dd8SSean Wang /* Be greedy to guess first gpio_n is equal to eint_n */ 28989132dd8SSean Wang if (desc[eint_n].eint.eint_n == eint_n) 29089132dd8SSean Wang *gpio_n = eint_n; 29189132dd8SSean Wang else 29289132dd8SSean Wang *gpio_n = mtk_xt_find_eint_num(hw, eint_n); 29389132dd8SSean Wang 29489132dd8SSean Wang return *gpio_n == EINT_NA ? -EINVAL : 0; 29589132dd8SSean Wang } 29689132dd8SSean Wang 29789132dd8SSean Wang static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n) 29889132dd8SSean Wang { 29989132dd8SSean Wang struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; 30089132dd8SSean Wang const struct mtk_pin_desc *desc; 30189132dd8SSean Wang struct gpio_chip *gpio_chip; 30289132dd8SSean Wang unsigned int gpio_n; 30389132dd8SSean Wang int value, err; 30489132dd8SSean Wang 30589132dd8SSean Wang err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip); 30689132dd8SSean Wang if (err) 30789132dd8SSean Wang return err; 30889132dd8SSean Wang 30989132dd8SSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio_n]; 31089132dd8SSean Wang 31189132dd8SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value); 31289132dd8SSean Wang if (err) 31389132dd8SSean Wang return err; 31489132dd8SSean Wang 31589132dd8SSean Wang return !!value; 31689132dd8SSean Wang } 31789132dd8SSean Wang 31889132dd8SSean Wang static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n) 31989132dd8SSean Wang { 32089132dd8SSean Wang struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; 32189132dd8SSean Wang const struct mtk_pin_desc *desc; 32289132dd8SSean Wang struct gpio_chip *gpio_chip; 32389132dd8SSean Wang unsigned int gpio_n; 32489132dd8SSean Wang int err; 32589132dd8SSean Wang 32689132dd8SSean Wang err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip); 32789132dd8SSean Wang if (err) 32889132dd8SSean Wang return err; 32989132dd8SSean Wang 330edd54646SHanks Chen if (mtk_is_virt_gpio(hw, gpio_n)) 331edd54646SHanks Chen return 0; 332edd54646SHanks Chen 33389132dd8SSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio_n]; 33489132dd8SSean Wang 33589132dd8SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, 33689132dd8SSean Wang desc->eint.eint_m); 33789132dd8SSean Wang if (err) 33889132dd8SSean Wang return err; 33989132dd8SSean Wang 34089132dd8SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, MTK_INPUT); 34189132dd8SSean Wang if (err) 34289132dd8SSean Wang return err; 34389132dd8SSean Wang 34489132dd8SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, MTK_ENABLE); 3456e737a4eSchuanjia.liu /* SMT is supposed to be supported by every real GPIO and doesn't 3466e737a4eSchuanjia.liu * support virtual GPIOs, so the extra condition err != -ENOTSUPP 3476e737a4eSchuanjia.liu * is just for adding EINT support to these virtual GPIOs. It should 3486e737a4eSchuanjia.liu * add an extra flag in the pin descriptor when more pins with 3496e737a4eSchuanjia.liu * distinctive characteristic come out. 3506e737a4eSchuanjia.liu */ 3516e737a4eSchuanjia.liu if (err && err != -ENOTSUPP) 35289132dd8SSean Wang return err; 35389132dd8SSean Wang 35489132dd8SSean Wang return 0; 35589132dd8SSean Wang } 35689132dd8SSean Wang 35789132dd8SSean Wang static const struct mtk_eint_xt mtk_eint_xt = { 35889132dd8SSean Wang .get_gpio_n = mtk_xt_get_gpio_n, 35989132dd8SSean Wang .get_gpio_state = mtk_xt_get_gpio_state, 36089132dd8SSean Wang .set_gpio_as_eint = mtk_xt_set_gpio_as_eint, 36189132dd8SSean Wang }; 36289132dd8SSean Wang 36389132dd8SSean Wang int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) 36489132dd8SSean Wang { 36589132dd8SSean Wang struct device_node *np = pdev->dev.of_node; 366db751578SEnric Balletbo i Serra int ret; 36789132dd8SSean Wang 36889132dd8SSean Wang if (!IS_ENABLED(CONFIG_EINT_MTK)) 36989132dd8SSean Wang return 0; 37089132dd8SSean Wang 37189132dd8SSean Wang if (!of_property_read_bool(np, "interrupt-controller")) 37289132dd8SSean Wang return -ENODEV; 37389132dd8SSean Wang 37489132dd8SSean Wang hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL); 37589132dd8SSean Wang if (!hw->eint) 37689132dd8SSean Wang return -ENOMEM; 37789132dd8SSean Wang 37848548c78SWang Xiaojun hw->eint->base = devm_platform_ioremap_resource_byname(pdev, "eint"); 379db751578SEnric Balletbo i Serra if (IS_ERR(hw->eint->base)) { 380db751578SEnric Balletbo i Serra ret = PTR_ERR(hw->eint->base); 381db751578SEnric Balletbo i Serra goto err_free_eint; 38289132dd8SSean Wang } 38389132dd8SSean Wang 38489132dd8SSean Wang hw->eint->irq = irq_of_parse_and_map(np, 0); 385db751578SEnric Balletbo i Serra if (!hw->eint->irq) { 386db751578SEnric Balletbo i Serra ret = -EINVAL; 387db751578SEnric Balletbo i Serra goto err_free_eint; 388db751578SEnric Balletbo i Serra } 38989132dd8SSean Wang 390db751578SEnric Balletbo i Serra if (!hw->soc->eint_hw) { 391db751578SEnric Balletbo i Serra ret = -ENODEV; 392db751578SEnric Balletbo i Serra goto err_free_eint; 393db751578SEnric Balletbo i Serra } 39489132dd8SSean Wang 39589132dd8SSean Wang hw->eint->dev = &pdev->dev; 39689132dd8SSean Wang hw->eint->hw = hw->soc->eint_hw; 39789132dd8SSean Wang hw->eint->pctl = hw; 39889132dd8SSean Wang hw->eint->gpio_xlate = &mtk_eint_xt; 39989132dd8SSean Wang 40089132dd8SSean Wang return mtk_eint_do_init(hw->eint); 401db751578SEnric Balletbo i Serra 402db751578SEnric Balletbo i Serra err_free_eint: 403db751578SEnric Balletbo i Serra devm_kfree(hw->dev, hw->eint); 404db751578SEnric Balletbo i Serra hw->eint = NULL; 405db751578SEnric Balletbo i Serra return ret; 40689132dd8SSean Wang } 4078174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_build_eint); 40889132dd8SSean Wang 4099afc305bSSean Wang /* Revision 0 */ 41085430152SSean Wang int mtk_pinconf_bias_disable_set(struct mtk_pinctrl *hw, 41185430152SSean Wang const struct mtk_pin_desc *desc) 41285430152SSean Wang { 41385430152SSean Wang int err; 41485430152SSean Wang 415ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, 41685430152SSean Wang MTK_DISABLE); 41785430152SSean Wang if (err) 41885430152SSean Wang return err; 41985430152SSean Wang 420ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, 42185430152SSean Wang MTK_DISABLE); 42285430152SSean Wang if (err) 42385430152SSean Wang return err; 42485430152SSean Wang 42585430152SSean Wang return 0; 42685430152SSean Wang } 4278174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_bias_disable_set); 42885430152SSean Wang 42985430152SSean Wang int mtk_pinconf_bias_disable_get(struct mtk_pinctrl *hw, 43085430152SSean Wang const struct mtk_pin_desc *desc, int *res) 43185430152SSean Wang { 43285430152SSean Wang int v, v2; 43385430152SSean Wang int err; 43485430152SSean Wang 435ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PU, &v); 43685430152SSean Wang if (err) 43785430152SSean Wang return err; 43885430152SSean Wang 439ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &v2); 44085430152SSean Wang if (err) 44185430152SSean Wang return err; 44285430152SSean Wang 44385430152SSean Wang if (v == MTK_ENABLE || v2 == MTK_ENABLE) 44485430152SSean Wang return -EINVAL; 44585430152SSean Wang 44685430152SSean Wang *res = 1; 44785430152SSean Wang 44885430152SSean Wang return 0; 44985430152SSean Wang } 4508174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_bias_disable_get); 45185430152SSean Wang 45285430152SSean Wang int mtk_pinconf_bias_set(struct mtk_pinctrl *hw, 45385430152SSean Wang const struct mtk_pin_desc *desc, bool pullup) 45485430152SSean Wang { 45585430152SSean Wang int err, arg; 45685430152SSean Wang 45785430152SSean Wang arg = pullup ? 1 : 2; 45885430152SSean Wang 459ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, arg & 1); 46085430152SSean Wang if (err) 46185430152SSean Wang return err; 46285430152SSean Wang 463ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, 46485430152SSean Wang !!(arg & 2)); 46585430152SSean Wang if (err) 46685430152SSean Wang return err; 46785430152SSean Wang 46885430152SSean Wang return 0; 46985430152SSean Wang } 4708174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_bias_set); 47185430152SSean Wang 47285430152SSean Wang int mtk_pinconf_bias_get(struct mtk_pinctrl *hw, 47385430152SSean Wang const struct mtk_pin_desc *desc, bool pullup, int *res) 47485430152SSean Wang { 47585430152SSean Wang int reg, err, v; 47685430152SSean Wang 47785430152SSean Wang reg = pullup ? PINCTRL_PIN_REG_PU : PINCTRL_PIN_REG_PD; 47885430152SSean Wang 479ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, reg, &v); 48085430152SSean Wang if (err) 48185430152SSean Wang return err; 48285430152SSean Wang 48385430152SSean Wang if (!v) 48485430152SSean Wang return -EINVAL; 48585430152SSean Wang 48685430152SSean Wang *res = 1; 48785430152SSean Wang 48885430152SSean Wang return 0; 48985430152SSean Wang } 4908174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_bias_get); 49185430152SSean Wang 4929afc305bSSean Wang /* Revision 1 */ 4939afc305bSSean Wang int mtk_pinconf_bias_disable_set_rev1(struct mtk_pinctrl *hw, 4949afc305bSSean Wang const struct mtk_pin_desc *desc) 4959afc305bSSean Wang { 496a15f8596SZheng Yongjun return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN, 4979afc305bSSean Wang MTK_DISABLE); 4989afc305bSSean Wang } 4998174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_bias_disable_set_rev1); 5009afc305bSSean Wang 5019afc305bSSean Wang int mtk_pinconf_bias_disable_get_rev1(struct mtk_pinctrl *hw, 5029afc305bSSean Wang const struct mtk_pin_desc *desc, int *res) 5039afc305bSSean Wang { 5049afc305bSSean Wang int v, err; 5059afc305bSSean Wang 506ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, &v); 5079afc305bSSean Wang if (err) 5089afc305bSSean Wang return err; 5099afc305bSSean Wang 5109afc305bSSean Wang if (v == MTK_ENABLE) 5119afc305bSSean Wang return -EINVAL; 5129afc305bSSean Wang 5139afc305bSSean Wang *res = 1; 5149afc305bSSean Wang 5159afc305bSSean Wang return 0; 5169afc305bSSean Wang } 5178174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_bias_disable_get_rev1); 5189afc305bSSean Wang 5199afc305bSSean Wang int mtk_pinconf_bias_set_rev1(struct mtk_pinctrl *hw, 5209afc305bSSean Wang const struct mtk_pin_desc *desc, bool pullup) 5219afc305bSSean Wang { 5229afc305bSSean Wang int err, arg; 5239afc305bSSean Wang 5249afc305bSSean Wang arg = pullup ? MTK_PULLUP : MTK_PULLDOWN; 5259afc305bSSean Wang 526ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN, 5279afc305bSSean Wang MTK_ENABLE); 5289afc305bSSean Wang if (err) 5299afc305bSSean Wang return err; 5309afc305bSSean Wang 531ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, arg); 5329afc305bSSean Wang if (err) 5339afc305bSSean Wang return err; 5349afc305bSSean Wang 5359afc305bSSean Wang return 0; 5369afc305bSSean Wang } 5378174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_bias_set_rev1); 5389afc305bSSean Wang 5399afc305bSSean Wang int mtk_pinconf_bias_get_rev1(struct mtk_pinctrl *hw, 5409afc305bSSean Wang const struct mtk_pin_desc *desc, bool pullup, 5419afc305bSSean Wang int *res) 5429afc305bSSean Wang { 5439afc305bSSean Wang int err, v; 5449afc305bSSean Wang 545ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, &v); 5469afc305bSSean Wang if (err) 5479afc305bSSean Wang return err; 5489afc305bSSean Wang 5499afc305bSSean Wang if (v == MTK_DISABLE) 5509afc305bSSean Wang return -EINVAL; 5519afc305bSSean Wang 552ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, &v); 5539afc305bSSean Wang if (err) 5549afc305bSSean Wang return err; 5559afc305bSSean Wang 5569afc305bSSean Wang if (pullup ^ (v == MTK_PULLUP)) 5579afc305bSSean Wang return -EINVAL; 5589afc305bSSean Wang 5599afc305bSSean Wang *res = 1; 5609afc305bSSean Wang 5619afc305bSSean Wang return 0; 5629afc305bSSean Wang } 5638174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_bias_get_rev1); 5649afc305bSSean Wang 565cafe19dbSLight Hsieh /* Combo for the following pull register type: 566cafe19dbSLight Hsieh * 1. PU + PD 567cafe19dbSLight Hsieh * 2. PULLSEL + PULLEN 568cafe19dbSLight Hsieh * 3. PUPD + R0 + R1 569cafe19dbSLight Hsieh */ 570cafe19dbSLight Hsieh static int mtk_pinconf_bias_set_pu_pd(struct mtk_pinctrl *hw, 571cafe19dbSLight Hsieh const struct mtk_pin_desc *desc, 572cafe19dbSLight Hsieh u32 pullup, u32 arg) 573cafe19dbSLight Hsieh { 574cafe19dbSLight Hsieh int err, pu, pd; 575cafe19dbSLight Hsieh 576cafe19dbSLight Hsieh if (arg == MTK_DISABLE) { 577cafe19dbSLight Hsieh pu = 0; 578cafe19dbSLight Hsieh pd = 0; 579cafe19dbSLight Hsieh } else if ((arg == MTK_ENABLE) && pullup) { 580cafe19dbSLight Hsieh pu = 1; 581cafe19dbSLight Hsieh pd = 0; 582cafe19dbSLight Hsieh } else if ((arg == MTK_ENABLE) && !pullup) { 583cafe19dbSLight Hsieh pu = 0; 584cafe19dbSLight Hsieh pd = 1; 585cafe19dbSLight Hsieh } else { 586cafe19dbSLight Hsieh err = -EINVAL; 587cafe19dbSLight Hsieh goto out; 588cafe19dbSLight Hsieh } 589cafe19dbSLight Hsieh 590cafe19dbSLight Hsieh err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, pu); 591cafe19dbSLight Hsieh if (err) 592cafe19dbSLight Hsieh goto out; 593cafe19dbSLight Hsieh 594cafe19dbSLight Hsieh err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd); 595cafe19dbSLight Hsieh 596cafe19dbSLight Hsieh out: 597cafe19dbSLight Hsieh return err; 598cafe19dbSLight Hsieh } 599cafe19dbSLight Hsieh 600cafe19dbSLight Hsieh static int mtk_pinconf_bias_set_pullsel_pullen(struct mtk_pinctrl *hw, 601cafe19dbSLight Hsieh const struct mtk_pin_desc *desc, 602cafe19dbSLight Hsieh u32 pullup, u32 arg) 603cafe19dbSLight Hsieh { 604cafe19dbSLight Hsieh int err, enable; 605cafe19dbSLight Hsieh 606cafe19dbSLight Hsieh if (arg == MTK_DISABLE) 607cafe19dbSLight Hsieh enable = 0; 608cafe19dbSLight Hsieh else if (arg == MTK_ENABLE) 609cafe19dbSLight Hsieh enable = 1; 610cafe19dbSLight Hsieh else { 611cafe19dbSLight Hsieh err = -EINVAL; 612cafe19dbSLight Hsieh goto out; 613cafe19dbSLight Hsieh } 614cafe19dbSLight Hsieh 615cafe19dbSLight Hsieh err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN, enable); 616cafe19dbSLight Hsieh if (err) 617cafe19dbSLight Hsieh goto out; 618cafe19dbSLight Hsieh 619cafe19dbSLight Hsieh err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, pullup); 620cafe19dbSLight Hsieh 621cafe19dbSLight Hsieh out: 622cafe19dbSLight Hsieh return err; 623cafe19dbSLight Hsieh } 624cafe19dbSLight Hsieh 625cafe19dbSLight Hsieh static int mtk_pinconf_bias_set_pupd_r1_r0(struct mtk_pinctrl *hw, 626cafe19dbSLight Hsieh const struct mtk_pin_desc *desc, 627cafe19dbSLight Hsieh u32 pullup, u32 arg) 628cafe19dbSLight Hsieh { 629cafe19dbSLight Hsieh int err, r0, r1; 630cafe19dbSLight Hsieh 631cafe19dbSLight Hsieh if ((arg == MTK_DISABLE) || (arg == MTK_PUPD_SET_R1R0_00)) { 632cafe19dbSLight Hsieh pullup = 0; 633cafe19dbSLight Hsieh r0 = 0; 634cafe19dbSLight Hsieh r1 = 0; 635cafe19dbSLight Hsieh } else if (arg == MTK_PUPD_SET_R1R0_01) { 636cafe19dbSLight Hsieh r0 = 1; 637cafe19dbSLight Hsieh r1 = 0; 638cafe19dbSLight Hsieh } else if (arg == MTK_PUPD_SET_R1R0_10) { 639cafe19dbSLight Hsieh r0 = 0; 640cafe19dbSLight Hsieh r1 = 1; 641cafe19dbSLight Hsieh } else if (arg == MTK_PUPD_SET_R1R0_11) { 642cafe19dbSLight Hsieh r0 = 1; 643cafe19dbSLight Hsieh r1 = 1; 644cafe19dbSLight Hsieh } else { 645cafe19dbSLight Hsieh err = -EINVAL; 646cafe19dbSLight Hsieh goto out; 647cafe19dbSLight Hsieh } 648cafe19dbSLight Hsieh 649cafe19dbSLight Hsieh /* MTK HW PUPD bit: 1 for pull-down, 0 for pull-up */ 650cafe19dbSLight Hsieh err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PUPD, !pullup); 651cafe19dbSLight Hsieh if (err) 652cafe19dbSLight Hsieh goto out; 653cafe19dbSLight Hsieh 654cafe19dbSLight Hsieh err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R0, r0); 655cafe19dbSLight Hsieh if (err) 656cafe19dbSLight Hsieh goto out; 657cafe19dbSLight Hsieh 658cafe19dbSLight Hsieh err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R1, r1); 659cafe19dbSLight Hsieh 660cafe19dbSLight Hsieh out: 661cafe19dbSLight Hsieh return err; 662cafe19dbSLight Hsieh } 663cafe19dbSLight Hsieh 664cafe19dbSLight Hsieh static int mtk_pinconf_bias_get_pu_pd(struct mtk_pinctrl *hw, 665cafe19dbSLight Hsieh const struct mtk_pin_desc *desc, 666cafe19dbSLight Hsieh u32 *pullup, u32 *enable) 667cafe19dbSLight Hsieh { 668cafe19dbSLight Hsieh int err, pu, pd; 669cafe19dbSLight Hsieh 670cafe19dbSLight Hsieh err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PU, &pu); 671cafe19dbSLight Hsieh if (err) 672cafe19dbSLight Hsieh goto out; 673cafe19dbSLight Hsieh 674cafe19dbSLight Hsieh err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &pd); 675cafe19dbSLight Hsieh if (err) 676cafe19dbSLight Hsieh goto out; 677cafe19dbSLight Hsieh 678cafe19dbSLight Hsieh if (pu == 0 && pd == 0) { 679cafe19dbSLight Hsieh *pullup = 0; 680cafe19dbSLight Hsieh *enable = MTK_DISABLE; 681cafe19dbSLight Hsieh } else if (pu == 1 && pd == 0) { 682cafe19dbSLight Hsieh *pullup = 1; 683cafe19dbSLight Hsieh *enable = MTK_ENABLE; 684cafe19dbSLight Hsieh } else if (pu == 0 && pd == 1) { 685cafe19dbSLight Hsieh *pullup = 0; 686cafe19dbSLight Hsieh *enable = MTK_ENABLE; 687cafe19dbSLight Hsieh } else 688cafe19dbSLight Hsieh err = -EINVAL; 689cafe19dbSLight Hsieh 690cafe19dbSLight Hsieh out: 691cafe19dbSLight Hsieh return err; 692cafe19dbSLight Hsieh } 693cafe19dbSLight Hsieh 694cafe19dbSLight Hsieh static int mtk_pinconf_bias_get_pullsel_pullen(struct mtk_pinctrl *hw, 695cafe19dbSLight Hsieh const struct mtk_pin_desc *desc, 696cafe19dbSLight Hsieh u32 *pullup, u32 *enable) 697cafe19dbSLight Hsieh { 698cafe19dbSLight Hsieh int err; 699cafe19dbSLight Hsieh 700cafe19dbSLight Hsieh err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, pullup); 701cafe19dbSLight Hsieh if (err) 702cafe19dbSLight Hsieh goto out; 703cafe19dbSLight Hsieh 704cafe19dbSLight Hsieh err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, enable); 705cafe19dbSLight Hsieh 706cafe19dbSLight Hsieh out: 707cafe19dbSLight Hsieh return err; 708cafe19dbSLight Hsieh } 709cafe19dbSLight Hsieh 710cafe19dbSLight Hsieh static int mtk_pinconf_bias_get_pupd_r1_r0(struct mtk_pinctrl *hw, 711cafe19dbSLight Hsieh const struct mtk_pin_desc *desc, 712cafe19dbSLight Hsieh u32 *pullup, u32 *enable) 713cafe19dbSLight Hsieh { 714cafe19dbSLight Hsieh int err, r0, r1; 715cafe19dbSLight Hsieh 716cafe19dbSLight Hsieh err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PUPD, pullup); 717cafe19dbSLight Hsieh if (err) 718cafe19dbSLight Hsieh goto out; 719cafe19dbSLight Hsieh /* MTK HW PUPD bit: 1 for pull-down, 0 for pull-up */ 720cafe19dbSLight Hsieh *pullup = !(*pullup); 721cafe19dbSLight Hsieh 722cafe19dbSLight Hsieh err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R0, &r0); 723cafe19dbSLight Hsieh if (err) 724cafe19dbSLight Hsieh goto out; 725cafe19dbSLight Hsieh 726cafe19dbSLight Hsieh err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R1, &r1); 727cafe19dbSLight Hsieh if (err) 728cafe19dbSLight Hsieh goto out; 729cafe19dbSLight Hsieh 730cafe19dbSLight Hsieh if ((r1 == 0) && (r0 == 0)) 731cafe19dbSLight Hsieh *enable = MTK_PUPD_SET_R1R0_00; 732cafe19dbSLight Hsieh else if ((r1 == 0) && (r0 == 1)) 733cafe19dbSLight Hsieh *enable = MTK_PUPD_SET_R1R0_01; 734cafe19dbSLight Hsieh else if ((r1 == 1) && (r0 == 0)) 735cafe19dbSLight Hsieh *enable = MTK_PUPD_SET_R1R0_10; 736cafe19dbSLight Hsieh else if ((r1 == 1) && (r0 == 1)) 737cafe19dbSLight Hsieh *enable = MTK_PUPD_SET_R1R0_11; 738cafe19dbSLight Hsieh else 739cafe19dbSLight Hsieh err = -EINVAL; 740cafe19dbSLight Hsieh 741cafe19dbSLight Hsieh out: 742cafe19dbSLight Hsieh return err; 743cafe19dbSLight Hsieh } 744cafe19dbSLight Hsieh 745cafe19dbSLight Hsieh int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw, 746cafe19dbSLight Hsieh const struct mtk_pin_desc *desc, 747cafe19dbSLight Hsieh u32 pullup, u32 arg) 748cafe19dbSLight Hsieh { 749cafe19dbSLight Hsieh int err; 750cafe19dbSLight Hsieh 751cafe19dbSLight Hsieh err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg); 752cafe19dbSLight Hsieh if (!err) 753cafe19dbSLight Hsieh goto out; 754cafe19dbSLight Hsieh 755cafe19dbSLight Hsieh err = mtk_pinconf_bias_set_pullsel_pullen(hw, desc, pullup, arg); 756cafe19dbSLight Hsieh if (!err) 757cafe19dbSLight Hsieh goto out; 758cafe19dbSLight Hsieh 759cafe19dbSLight Hsieh err = mtk_pinconf_bias_set_pupd_r1_r0(hw, desc, pullup, arg); 760cafe19dbSLight Hsieh 761cafe19dbSLight Hsieh out: 762cafe19dbSLight Hsieh return err; 763cafe19dbSLight Hsieh } 7648174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_bias_set_combo); 765cafe19dbSLight Hsieh 766cafe19dbSLight Hsieh int mtk_pinconf_bias_get_combo(struct mtk_pinctrl *hw, 767cafe19dbSLight Hsieh const struct mtk_pin_desc *desc, 768cafe19dbSLight Hsieh u32 *pullup, u32 *enable) 769cafe19dbSLight Hsieh { 770cafe19dbSLight Hsieh int err; 771cafe19dbSLight Hsieh 772cafe19dbSLight Hsieh err = mtk_pinconf_bias_get_pu_pd(hw, desc, pullup, enable); 773cafe19dbSLight Hsieh if (!err) 774cafe19dbSLight Hsieh goto out; 775cafe19dbSLight Hsieh 776cafe19dbSLight Hsieh err = mtk_pinconf_bias_get_pullsel_pullen(hw, desc, pullup, enable); 777cafe19dbSLight Hsieh if (!err) 778cafe19dbSLight Hsieh goto out; 779cafe19dbSLight Hsieh 780cafe19dbSLight Hsieh err = mtk_pinconf_bias_get_pupd_r1_r0(hw, desc, pullup, enable); 781cafe19dbSLight Hsieh 782cafe19dbSLight Hsieh out: 783cafe19dbSLight Hsieh return err; 784cafe19dbSLight Hsieh } 7858174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_bias_get_combo); 786cafe19dbSLight Hsieh 787c2832197SSean Wang /* Revision 0 */ 788c2832197SSean Wang int mtk_pinconf_drive_set(struct mtk_pinctrl *hw, 789c2832197SSean Wang const struct mtk_pin_desc *desc, u32 arg) 790c2832197SSean Wang { 791c2832197SSean Wang const struct mtk_drive_desc *tb; 792c2832197SSean Wang int err = -ENOTSUPP; 793c2832197SSean Wang 794c2832197SSean Wang tb = &mtk_drive[desc->drv_n]; 795c2832197SSean Wang /* 4mA when (e8, e4) = (0, 0) 796c2832197SSean Wang * 8mA when (e8, e4) = (0, 1) 797c2832197SSean Wang * 12mA when (e8, e4) = (1, 0) 798c2832197SSean Wang * 16mA when (e8, e4) = (1, 1) 799c2832197SSean Wang */ 800c2832197SSean Wang if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) { 801c2832197SSean Wang arg = (arg / tb->step - 1) * tb->scal; 802ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_E4, 803c2832197SSean Wang arg & 0x1); 804c2832197SSean Wang if (err) 805c2832197SSean Wang return err; 806c2832197SSean Wang 807ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_E8, 808c2832197SSean Wang (arg & 0x2) >> 1); 809c2832197SSean Wang if (err) 810c2832197SSean Wang return err; 811c2832197SSean Wang } 812c2832197SSean Wang 813c2832197SSean Wang return err; 814c2832197SSean Wang } 8158174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_drive_set); 816c2832197SSean Wang 817c2832197SSean Wang int mtk_pinconf_drive_get(struct mtk_pinctrl *hw, 818c2832197SSean Wang const struct mtk_pin_desc *desc, int *val) 819c2832197SSean Wang { 820c2832197SSean Wang const struct mtk_drive_desc *tb; 821c2832197SSean Wang int err, val1, val2; 822c2832197SSean Wang 823c2832197SSean Wang tb = &mtk_drive[desc->drv_n]; 824c2832197SSean Wang 825ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_E4, &val1); 826c2832197SSean Wang if (err) 827c2832197SSean Wang return err; 828c2832197SSean Wang 829ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_E8, &val2); 830c2832197SSean Wang if (err) 831c2832197SSean Wang return err; 832c2832197SSean Wang 833c2832197SSean Wang /* 4mA when (e8, e4) = (0, 0); 8mA when (e8, e4) = (0, 1) 834c2832197SSean Wang * 12mA when (e8, e4) = (1, 0); 16mA when (e8, e4) = (1, 1) 835c2832197SSean Wang */ 836c2832197SSean Wang *val = (((val2 << 1) + val1) / tb->scal + 1) * tb->step; 837c2832197SSean Wang 838c2832197SSean Wang return 0; 839c2832197SSean Wang } 8408174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_drive_get); 8413ad38a14SSean Wang 8423ad38a14SSean Wang /* Revision 1 */ 8433ad38a14SSean Wang int mtk_pinconf_drive_set_rev1(struct mtk_pinctrl *hw, 8443ad38a14SSean Wang const struct mtk_pin_desc *desc, u32 arg) 8453ad38a14SSean Wang { 8463ad38a14SSean Wang const struct mtk_drive_desc *tb; 8473ad38a14SSean Wang int err = -ENOTSUPP; 8483ad38a14SSean Wang 8493ad38a14SSean Wang tb = &mtk_drive[desc->drv_n]; 8503ad38a14SSean Wang 8513ad38a14SSean Wang if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) { 8523ad38a14SSean Wang arg = (arg / tb->step - 1) * tb->scal; 8533ad38a14SSean Wang 854ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV, 8553ad38a14SSean Wang arg); 8563ad38a14SSean Wang if (err) 8573ad38a14SSean Wang return err; 8583ad38a14SSean Wang } 8593ad38a14SSean Wang 8603ad38a14SSean Wang return err; 8613ad38a14SSean Wang } 8628174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_drive_set_rev1); 8633ad38a14SSean Wang 8643ad38a14SSean Wang int mtk_pinconf_drive_get_rev1(struct mtk_pinctrl *hw, 8653ad38a14SSean Wang const struct mtk_pin_desc *desc, int *val) 8663ad38a14SSean Wang { 8673ad38a14SSean Wang const struct mtk_drive_desc *tb; 8683ad38a14SSean Wang int err, val1; 8693ad38a14SSean Wang 8703ad38a14SSean Wang tb = &mtk_drive[desc->drv_n]; 8713ad38a14SSean Wang 872ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV, &val1); 8733ad38a14SSean Wang if (err) 8743ad38a14SSean Wang return err; 8753ad38a14SSean Wang 8763ad38a14SSean Wang *val = ((val1 & 0x7) / tb->scal + 1) * tb->step; 8773ad38a14SSean Wang 8783ad38a14SSean Wang return 0; 8793ad38a14SSean Wang } 8808174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_drive_get_rev1); 8810d7ca772SSean Wang 8825f755e1fSLight Hsieh int mtk_pinconf_drive_set_raw(struct mtk_pinctrl *hw, 8835f755e1fSLight Hsieh const struct mtk_pin_desc *desc, u32 arg) 8845f755e1fSLight Hsieh { 8855f755e1fSLight Hsieh return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV, arg); 8865f755e1fSLight Hsieh } 8878174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_drive_set_raw); 8885f755e1fSLight Hsieh 8895f755e1fSLight Hsieh int mtk_pinconf_drive_get_raw(struct mtk_pinctrl *hw, 8905f755e1fSLight Hsieh const struct mtk_pin_desc *desc, int *val) 8915f755e1fSLight Hsieh { 8925f755e1fSLight Hsieh return mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV, val); 8935f755e1fSLight Hsieh } 8948174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_drive_get_raw); 8955f755e1fSLight Hsieh 8960d7ca772SSean Wang int mtk_pinconf_adv_pull_set(struct mtk_pinctrl *hw, 8970d7ca772SSean Wang const struct mtk_pin_desc *desc, bool pullup, 8980d7ca772SSean Wang u32 arg) 8990d7ca772SSean Wang { 9000d7ca772SSean Wang int err; 9010d7ca772SSean Wang 9020d7ca772SSean Wang /* 10K off & 50K (75K) off, when (R0, R1) = (0, 0); 9030d7ca772SSean Wang * 10K off & 50K (75K) on, when (R0, R1) = (0, 1); 9040d7ca772SSean Wang * 10K on & 50K (75K) off, when (R0, R1) = (1, 0); 9050d7ca772SSean Wang * 10K on & 50K (75K) on, when (R0, R1) = (1, 1) 9060d7ca772SSean Wang */ 907ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R0, arg & 1); 9080d7ca772SSean Wang if (err) 9090d7ca772SSean Wang return 0; 9100d7ca772SSean Wang 911ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R1, 9120d7ca772SSean Wang !!(arg & 2)); 9130d7ca772SSean Wang if (err) 9140d7ca772SSean Wang return 0; 9150d7ca772SSean Wang 9160d7ca772SSean Wang arg = pullup ? 0 : 1; 9170d7ca772SSean Wang 918ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PUPD, arg); 9190d7ca772SSean Wang 92079348f6fSSean Wang /* If PUPD register is not supported for that pin, let's fallback to 92179348f6fSSean Wang * general bias control. 92279348f6fSSean Wang */ 92379348f6fSSean Wang if (err == -ENOTSUPP) { 92479348f6fSSean Wang if (hw->soc->bias_set) { 92579348f6fSSean Wang err = hw->soc->bias_set(hw, desc, pullup); 92679348f6fSSean Wang if (err) 92779348f6fSSean Wang return err; 92881bd1579SHsin-Yi Wang } else if (hw->soc->bias_set_combo) { 92981bd1579SHsin-Yi Wang err = hw->soc->bias_set_combo(hw, desc, pullup, arg); 93081bd1579SHsin-Yi Wang if (err) 93181bd1579SHsin-Yi Wang return err; 93279348f6fSSean Wang } else { 93379348f6fSSean Wang return -ENOTSUPP; 93479348f6fSSean Wang } 93579348f6fSSean Wang } 93679348f6fSSean Wang 9370d7ca772SSean Wang return err; 9380d7ca772SSean Wang } 9398174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_adv_pull_set); 9400d7ca772SSean Wang 9410d7ca772SSean Wang int mtk_pinconf_adv_pull_get(struct mtk_pinctrl *hw, 9420d7ca772SSean Wang const struct mtk_pin_desc *desc, bool pullup, 9430d7ca772SSean Wang u32 *val) 9440d7ca772SSean Wang { 9450d7ca772SSean Wang u32 t, t2; 9460d7ca772SSean Wang int err; 9470d7ca772SSean Wang 948ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PUPD, &t); 94979348f6fSSean Wang 95079348f6fSSean Wang /* If PUPD register is not supported for that pin, let's fallback to 95179348f6fSSean Wang * general bias control. 95279348f6fSSean Wang */ 95379348f6fSSean Wang if (err == -ENOTSUPP) { 95479348f6fSSean Wang if (hw->soc->bias_get) { 95579348f6fSSean Wang err = hw->soc->bias_get(hw, desc, pullup, val); 95679348f6fSSean Wang if (err) 95779348f6fSSean Wang return err; 95879348f6fSSean Wang } else { 95979348f6fSSean Wang return -ENOTSUPP; 96079348f6fSSean Wang } 96179348f6fSSean Wang } else { 96279348f6fSSean Wang /* t == 0 supposes PULLUP for the customized PULL setup */ 9630d7ca772SSean Wang if (err) 9640d7ca772SSean Wang return err; 9650d7ca772SSean Wang 9660d7ca772SSean Wang if (pullup ^ !t) 9670d7ca772SSean Wang return -EINVAL; 96879348f6fSSean Wang } 9690d7ca772SSean Wang 970ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R0, &t); 9710d7ca772SSean Wang if (err) 9720d7ca772SSean Wang return err; 9730d7ca772SSean Wang 974ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R1, &t2); 9750d7ca772SSean Wang if (err) 9760d7ca772SSean Wang return err; 9770d7ca772SSean Wang 9780d7ca772SSean Wang *val = (t | t2 << 1) & 0x7; 9790d7ca772SSean Wang 9800d7ca772SSean Wang return 0; 9810d7ca772SSean Wang } 9828174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_adv_pull_get); 9835e73de34SZhiyong Tao 9845e73de34SZhiyong Tao int mtk_pinconf_adv_drive_set(struct mtk_pinctrl *hw, 9855e73de34SZhiyong Tao const struct mtk_pin_desc *desc, u32 arg) 9865e73de34SZhiyong Tao { 9875e73de34SZhiyong Tao int err; 9885e73de34SZhiyong Tao int en = arg & 1; 9895e73de34SZhiyong Tao int e0 = !!(arg & 2); 9905e73de34SZhiyong Tao int e1 = !!(arg & 4); 9915e73de34SZhiyong Tao 9925e73de34SZhiyong Tao err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_EN, en); 9935e73de34SZhiyong Tao if (err) 9945e73de34SZhiyong Tao return err; 9955e73de34SZhiyong Tao 9965e73de34SZhiyong Tao if (!en) 9975e73de34SZhiyong Tao return err; 9985e73de34SZhiyong Tao 9995e73de34SZhiyong Tao err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_E0, e0); 10005e73de34SZhiyong Tao if (err) 10015e73de34SZhiyong Tao return err; 10025e73de34SZhiyong Tao 10035e73de34SZhiyong Tao err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_E1, e1); 10045e73de34SZhiyong Tao if (err) 10055e73de34SZhiyong Tao return err; 10065e73de34SZhiyong Tao 10075e73de34SZhiyong Tao return err; 10085e73de34SZhiyong Tao } 10098174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_adv_drive_set); 10105e73de34SZhiyong Tao 10115e73de34SZhiyong Tao int mtk_pinconf_adv_drive_get(struct mtk_pinctrl *hw, 10125e73de34SZhiyong Tao const struct mtk_pin_desc *desc, u32 *val) 10135e73de34SZhiyong Tao { 10145e73de34SZhiyong Tao u32 en, e0, e1; 10155e73de34SZhiyong Tao int err; 10165e73de34SZhiyong Tao 10175e73de34SZhiyong Tao err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_EN, &en); 10185e73de34SZhiyong Tao if (err) 10195e73de34SZhiyong Tao return err; 10205e73de34SZhiyong Tao 10215e73de34SZhiyong Tao err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_E0, &e0); 10225e73de34SZhiyong Tao if (err) 10235e73de34SZhiyong Tao return err; 10245e73de34SZhiyong Tao 10255e73de34SZhiyong Tao err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_E1, &e1); 10265e73de34SZhiyong Tao if (err) 10275e73de34SZhiyong Tao return err; 10285e73de34SZhiyong Tao 10295e73de34SZhiyong Tao *val = (en | e0 << 1 | e1 << 2) & 0x7; 10305e73de34SZhiyong Tao 10315e73de34SZhiyong Tao return 0; 10325e73de34SZhiyong Tao } 10338174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pinconf_adv_drive_get); 1034c7acd6feSArnd Bergmann 1035ea9d2ed4SZhiyong Tao int mtk_pinconf_adv_drive_set_raw(struct mtk_pinctrl *hw, 1036ea9d2ed4SZhiyong Tao const struct mtk_pin_desc *desc, u32 arg) 1037ea9d2ed4SZhiyong Tao { 1038ea9d2ed4SZhiyong Tao return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_ADV, arg); 1039ea9d2ed4SZhiyong Tao } 1040ea9d2ed4SZhiyong Tao EXPORT_SYMBOL_GPL(mtk_pinconf_adv_drive_set_raw); 1041ea9d2ed4SZhiyong Tao 1042ea9d2ed4SZhiyong Tao int mtk_pinconf_adv_drive_get_raw(struct mtk_pinctrl *hw, 1043ea9d2ed4SZhiyong Tao const struct mtk_pin_desc *desc, u32 *val) 1044ea9d2ed4SZhiyong Tao { 1045ea9d2ed4SZhiyong Tao return mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_ADV, val); 1046ea9d2ed4SZhiyong Tao } 1047ea9d2ed4SZhiyong Tao EXPORT_SYMBOL_GPL(mtk_pinconf_adv_drive_get_raw); 1048ea9d2ed4SZhiyong Tao 1049c7acd6feSArnd Bergmann MODULE_LICENSE("GPL v2"); 1050c7acd6feSArnd Bergmann MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); 1051c7acd6feSArnd Bergmann MODULE_DESCRIPTION("Pin configuration library module for mediatek SoCs"); 1052