123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- /*
- * Copyright (c) 2018 MediaTek Inc.
- * Author: Light Hsieh <light.hsieh@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #if defined(CONFIG_PINCTRL_MTK_ALTERNATIVE)
- static int mtk_pinctrl_get_gpio_output(struct mtk_pinctrl *pctl, int pin)
- {
- return mtk_pinctrl_get_gpio_value(pctl, pin,
- pctl->devdata->n_pin_dout, pctl->devdata->pin_dout_grps);
- }
- static int mtk_pinctrl_set_gpio_output(struct mtk_pinctrl *pctl,
- int pin, int value)
- {
- #ifndef GPIO_DEBUG
- return mtk_pinctrl_update_gpio_value(pctl, pin, value,
- pctl->devdata->n_pin_dout, pctl->devdata->pin_dout_grps);
- #else
- pr_info("config pin = %d, value = %d\n", pin, value);
- mtk_pinctrl_update_gpio_value(pctl, pin, value,
- pctl->devdata->n_pin_dout, pctl->devdata->pin_dout_grps);
- pr_info("set pin = %d, value = %d\n", pin,
- mtk_pinctrl_get_gpio_output(pctl, pin));
- return 0;
- #endif
- }
- static int mtk_pinctrl_get_gpio_input(struct mtk_pinctrl *pctl, int pin)
- {
- return mtk_pinctrl_get_gpio_value(pctl, pin,
- pctl->devdata->n_pin_din, pctl->devdata->pin_din_grps);
- }
- static int mtk_pinctrl_get_gpio_direction(struct mtk_pinctrl *pctl, int pin)
- {
- return mtk_pinctrl_get_gpio_value(pctl, pin,
- pctl->devdata->n_pin_dir, pctl->devdata->pin_dir_grps);
- }
- static int mtk_pinctrl_set_gpio_direction(struct mtk_pinctrl *pctl,
- int pin, bool input)
- {
- #ifndef GPIO_DEBUG
- return mtk_pinctrl_update_gpio_value(pctl, pin, input,
- pctl->devdata->n_pin_dir, pctl->devdata->pin_dir_grps);
- #else
- pr_info("config pin = %d, dir = %d\n", pin, input);
- mtk_pinctrl_update_gpio_value(pctl, pin, input,
- pctl->devdata->n_pin_dir, pctl->devdata->pin_dir_grps);
- pr_info("set pin = %d, dir = %d\n", pin,
- mtk_pinctrl_get_gpio_direction(pctl, pin));
- return 0;
- #endif
- }
- static int mtk_pinctrl_get_gpio_mode(struct mtk_pinctrl *pctl, int pin)
- {
- return mtk_pinctrl_get_gpio_value(pctl, pin,
- pctl->devdata->n_pin_mode, pctl->devdata->pin_mode_grps);
- }
- static int mtk_pinctrl_set_gpio_mode(struct mtk_pinctrl *pctl,
- int pin, unsigned long mode)
- {
- #ifndef GPIO_DEBUG
- return mtk_pinctrl_update_gpio_value(pctl, pin, mode,
- pctl->devdata->n_pin_mode, pctl->devdata->pin_mode_grps);
- #else
- pr_info("config pin = %d, mode = %d\n", pin, (int)mode);
- mtk_pinctrl_update_gpio_value(pctl, pin, mode,
- pctl->devdata->n_pin_mode, pctl->devdata->pin_mode_grps);
- pr_info("set pin = %d, mode = %d\n", pin,
- mtk_pinctrl_get_gpio_mode(pctl, pin));
- return 0;
- #endif
- }
- static int mtk_pinctrl_get_gpio_driving(struct mtk_pinctrl *pctl, int pin)
- {
- return mtk_pinctrl_get_gpio_value(pctl, pin,
- pctl->devdata->n_pin_drv, pctl->devdata->pin_drv_grps);
- }
- static int mtk_pinctrl_set_gpio_driving(struct mtk_pinctrl *pctl,
- int pin, unsigned char driving)
- {
- #ifndef GPIO_DEBUG
- return mtk_pinctrl_update_gpio_value(pctl, pin, driving,
- pctl->devdata->n_pin_drv, pctl->devdata->pin_drv_grps);
- #else
- pr_info("config pin = %d, driving = %d\n", pin, driving);
- mtk_pinctrl_update_gpio_value(pctl, pin, driving,
- pctl->devdata->n_pin_drv, pctl->devdata->pin_drv_grps);
- pr_info("set pin = %d, driving = %d\n", pin,
- mtk_pinctrl_get_gpio_driving(pctl, pin));
- return 0;
- #endif
- }
- static int mtk_pinctrl_get_gpio_smt(struct mtk_pinctrl *pctl, int pin)
- {
- return mtk_pinctrl_get_gpio_value(pctl, pin,
- pctl->devdata->n_pin_smt, pctl->devdata->pin_smt_grps);
- }
- static int mtk_pinctrl_set_gpio_smt(struct mtk_pinctrl *pctl,
- int pin, bool enable)
- {
- return mtk_pinctrl_update_gpio_value(pctl, pin, enable,
- pctl->devdata->n_pin_smt, pctl->devdata->pin_smt_grps);
- }
- static int mtk_pinctrl_get_gpio_ies(struct mtk_pinctrl *pctl, int pin)
- {
- return mtk_pinctrl_get_gpio_value(pctl, pin,
- pctl->devdata->n_pin_ies, pctl->devdata->pin_ies_grps);
- }
- static int mtk_pinctrl_set_gpio_ies(struct mtk_pinctrl *pctl,
- int pin, bool enable)
- {
- return mtk_pinctrl_update_gpio_value(pctl, pin, enable,
- pctl->devdata->n_pin_ies, pctl->devdata->pin_ies_grps);
- }
- static int mtk_pinmux_get(struct gpio_chip *chip, unsigned int offset)
- {
- unsigned int reg_addr;
- unsigned char bit;
- unsigned int pinmux = 0;
- unsigned int mask = (1L << GPIO_MODE_BITS) - 1;
- struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
- if (pctl->devdata->pin_mode_grps)
- return mtk_pinctrl_get_gpio_mode(pctl, offset);
- reg_addr = ((offset / MAX_GPIO_MODE_PER_REG) << pctl->devdata->port_shf)
- + pctl->devdata->pinmux_offset;
- bit = offset % MAX_GPIO_MODE_PER_REG;
- mask <<= (GPIO_MODE_BITS * bit);
- regmap_read(mtk_get_regmap(pctl, offset), reg_addr, &pinmux);
- return ((pinmux & mask) >> (GPIO_MODE_BITS * bit));
- }
- static int mtk_gpio_get_in(struct gpio_chip *chip, unsigned int offset)
- {
- unsigned int reg_addr;
- unsigned int bit;
- unsigned int read_val = 0;
- struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
- if (pctl->devdata->pin_din_grps)
- return mtk_pinctrl_get_gpio_input(pctl, offset);
- reg_addr = mtk_get_port(pctl, offset) +
- pctl->devdata->din_offset;
- bit = BIT(offset & 0xf);
- regmap_read(mtk_get_regmap(pctl, offset), reg_addr, &read_val);
- return !!(read_val & bit);
- }
- static int mtk_gpio_get_out(struct gpio_chip *chip, unsigned int offset)
- {
- unsigned int reg_addr;
- unsigned int bit;
- unsigned int read_val = 0;
- struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
- if (pctl->devdata->pin_dout_grps)
- return mtk_pinctrl_get_gpio_output(pctl, offset);
- reg_addr = mtk_get_port(pctl, offset) +
- pctl->devdata->dout_offset;
- bit = BIT(offset & pctl->devdata->port_mask);
- regmap_read(mtk_get_regmap(pctl, offset), reg_addr, &read_val);
- return !!(read_val & bit);
- }
- static int mtk_pullen_get(struct gpio_chip *chip, unsigned int offset)
- {
- unsigned int reg_addr;
- unsigned int bit;
- unsigned int pull_en = 0;
- struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
- int samereg = 0;
- /* For phone, if the pull_en have been implemented */
- if (pctl->devdata->mtk_pctl_get_pull_en)
- return pctl->devdata->mtk_pctl_get_pull_en(pctl, offset);
- if (pctl->devdata->spec_pull_get) {
- samereg =
- pctl->devdata->spec_pull_get(mtk_get_regmap(pctl,
- offset), offset);
- if (samereg != -1) {
- pull_en = (samereg >> 1) & 0x3;
- return pull_en;
- }
- }
- reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->pullen_offset;
- bit = BIT(offset & pctl->devdata->port_mask);
- regmap_read(mtk_get_regmap(pctl, offset), reg_addr, &pull_en);
- return !!(pull_en & bit);
- }
- static int mtk_pullsel_get(struct gpio_chip *chip, unsigned int offset)
- {
- unsigned int reg_addr;
- unsigned int bit;
- unsigned int pull_sel = 0;
- struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
- if (pctl->devdata->mtk_pctl_get_pull_sel)
- return pctl->devdata->mtk_pctl_get_pull_sel(pctl, offset);
- if (pctl->devdata->spec_pull_get) {
- pull_sel =
- pctl->devdata->spec_pull_get(mtk_get_regmap(pctl,
- offset), offset);
- if (pull_sel != -1)
- return pull_sel;
- }
- reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->pullsel_offset;
- bit = BIT(offset & pctl->devdata->port_mask);
- regmap_read(mtk_get_regmap(pctl, offset), reg_addr, &pull_sel);
- return !!(pull_sel & bit);
- }
- static int mtk_ies_get(struct gpio_chip *chip, unsigned int offset)
- {
- unsigned int reg_addr;
- unsigned char bit;
- unsigned int ies;
- struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
- if (pctl->devdata->pin_ies_grps)
- return mtk_pinctrl_get_gpio_ies(pctl, offset);
- if (!pctl->devdata->spec_ies_get ||
- pctl->devdata->ies_offset == MTK_PINCTRL_NOT_SUPPORT)
- return -1;
- /**
- * Due to some soc are not support ies config, add this special
- * control to handle it.
- */
- if (pctl->devdata->spec_ies_get) {
- ies = pctl->devdata->spec_ies_get(mtk_get_regmap(pctl, offset),
- offset);
- if (ies != -1)
- return ies;
- }
- reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->ies_offset;
- bit = BIT(offset & pctl->devdata->port_mask);
- regmap_read(mtk_get_regmap(pctl, offset), reg_addr, &ies);
- return !!(ies & bit);
- }
- static int mtk_smt_get(struct gpio_chip *chip, unsigned int offset)
- {
- unsigned int reg_addr;
- unsigned char bit;
- unsigned int smt;
- struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
- if (pctl->devdata->pin_smt_grps)
- return mtk_pinctrl_get_gpio_smt(pctl, offset);
- if (!pctl->devdata->spec_smt_get ||
- pctl->devdata->smt_offset == MTK_PINCTRL_NOT_SUPPORT)
- return -1;
- /**
- * Due to some soc are not support smt config, add this special
- * control to handle it.
- */
- if (pctl->devdata->spec_smt_get) {
- smt = pctl->devdata->spec_smt_get(mtk_get_regmap(pctl, offset),
- offset);
- if (smt != -1)
- return smt;
- }
- reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->smt_offset;
- bit = BIT(offset & pctl->devdata->port_mask);
- regmap_read(mtk_get_regmap(pctl, offset), reg_addr, &smt);
- return !!(smt & bit);
- }
- static int mtk_driving_get(struct gpio_chip *chip, unsigned int offset)
- {
- const struct mtk_pin_drv_grp *pin_drv;
- unsigned int val = 0;
- unsigned int bits, mask, shift;
- const struct mtk_drv_group_desc *drv_grp;
- struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
- if (offset >= pctl->devdata->npins)
- return -1;
- if (pctl->devdata->pin_drv_grps)
- return mtk_pinctrl_get_gpio_driving(pctl, offset);
- pin_drv = mtk_find_pin_drv_grp_by_pin(pctl, offset);
- if (!pin_drv || pin_drv->grp > pctl->devdata->n_grp_cls)
- return -1;
- drv_grp = pctl->devdata->grp_desc + pin_drv->grp;
- bits = drv_grp->high_bit - drv_grp->low_bit + 1;
- mask = BIT(bits) - 1;
- shift = pin_drv->bit + drv_grp->low_bit;
- mask <<= shift;
- regmap_read(mtk_get_regmap(pctl, offset), pin_drv->offset, &val);
- return ((val & mask) >> shift);
- }
- static ssize_t mtk_gpio_show_pin(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- int len = 0;
- int bufLen = PAGE_SIZE;
- struct mtk_pinctrl *pctl = dev_get_drvdata(dev);
- struct gpio_chip *chip = pctl->chip;
- unsigned int i;
- int pull_val;
- len += snprintf(buf+len, bufLen-len,
- "PIN: [MODE] [DIR] [DOUT] [DIN] [PULL_EN] [PULL_SEL] [IES] [SMT] [DRIVE] ( [R1] [R0] )\n");
- for (i = 0; i < chip->ngpio; i++) {
- pull_val = mtk_pullsel_get(chip, i);
- len += snprintf(buf+len, bufLen-len,
- "%4d:% d% d% d% d% d% d% d% d% d",
- i,
- mtk_pinmux_get(chip, i),
- !mtk_gpio_get_direction(chip, i),
- mtk_gpio_get_out(chip, i),
- mtk_gpio_get_in(chip, i),
- mtk_pullen_get(chip, i),
- (pull_val >= 0) ? (pull_val&1) : -1,
- mtk_ies_get(chip, i),
- mtk_smt_get(chip, i),
- mtk_driving_get(chip, i));
- if ((pull_val & 8) && (pull_val >= 0))
- len += snprintf(buf+len, bufLen-len, " %d %d",
- !!(pull_val&4), !!(pull_val&2));
- len += snprintf(buf+len, bufLen-len, "\n");
- }
- return len;
- }
- void gpio_dump_regs_range(int start, int end)
- {
- struct gpio_chip *chip;
- unsigned int i;
- int pull_val;
- if (!pctl_alt) {
- pr_debug("[gpio_dump_regs]error: pinctrl does not exist\n");
- return;
- }
- chip = pctl_alt->chip;
- pr_debug("PIN: [MODE] [DIR] [DOUT] [DIN][PULL_EN] [PULL_SEL] [IES] [SMT] [DRIVE] ( [R1] [R0] )\n");
- if (start < 0) {
- start = 0;
- end = chip->ngpio-1;
- }
- if (end > chip->ngpio - 1)
- end = chip->ngpio - 1;
- for (i = start; i <= end; i++) {
- pull_val = mtk_pullsel_get(chip, i);
- pr_debug("%4d: %d%d%d%d%d%d%d%d%d",
- i, mtk_pinmux_get(chip, i),
- !mtk_gpio_get_direction(chip, i),
- mtk_gpio_get_out(chip, i),
- mtk_gpio_get_in(chip, i),
- mtk_pullen_get(chip, i),
- (pull_val >= 0) ? (pull_val&1) : -1,
- mtk_ies_get(chip, i),
- mtk_smt_get(chip, i),
- mtk_driving_get(chip, i));
- if ((pull_val & MTK_PUPD_R1R0_BIT_SUPPORT) && (pull_val >= 0))
- pr_debug(" %d %d\n", !!(pull_val&4), !!(pull_val&2));
- else
- pr_debug("\n");
- }
- }
- void gpio_dump_regs(void)
- {
- gpio_dump_regs_range(-1, -1);
- }
- static ssize_t mtk_gpio_store_pin(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- int pin, val;
- int val_set;
- struct mtk_pinctrl *pctl = dev_get_drvdata(dev);
- struct pinctrl_dev *pctldev = pctl->pctl_dev;
- if (!strncmp(buf, "mode", 4) &&
- (sscanf(buf+4, "%d %d", &pin, &val) == 2)) {
- val_set = mtk_pmx_set_mode(pctldev, pin, val);
- } else if (!strncmp(buf, "dir", 3) &&
- (sscanf(buf+3, "%d %d", &pin, &val) == 2)) {
- val_set = mtk_pmx_gpio_set_direction(pctldev, NULL, pin, !val);
- } else if (!strncmp(buf, "out", 3) &&
- (sscanf(buf+3, "%d %d", &pin, &val) == 2)) {
- mtk_pmx_gpio_set_direction(pctldev, NULL, pin, false);
- mtk_gpio_set(pctl->chip, pin, val);
- } else if (!strncmp(buf, "pullen", 6) &&
- (sscanf(buf+6, "%d %d", &pin, &val) == 2)) {
- val_set = mtk_pconf_set_pull_select(pctl, pin, !!val,
- false, MTK_PUPD_SET_R1R0_00 + val);
- } else if (!strncmp(buf, "pullsel", 7) &&
- (sscanf(buf+7, "%d %d", &pin, &val) == 2)) {
- val_set = mtk_pconf_set_pull_select(pctl, pin, true,
- !!val, MTK_PUPD_SET_R1R0_01);
- } else if (!strncmp(buf, "ies", 3) &&
- (sscanf(buf+3, "%d %d", &pin, &val) == 2)) {
- val_set = mtk_pconf_set_ies_smt(pctl, pin, val,
- PIN_CONFIG_INPUT_ENABLE);
- } else if (!strncmp(buf, "smt", 3) &&
- (sscanf(buf+3, "%d %d", &pin, &val) == 2)) {
- val_set = mtk_pconf_set_ies_smt(pctl, pin, val,
- PIN_CONFIG_INPUT_SCHMITT_ENABLE);
- }
- return count;
- }
- static DEVICE_ATTR(mt_gpio, 0664, mtk_gpio_show_pin, mtk_gpio_store_pin);
- static struct device_attribute *gpio_attr_list[] = {
- &dev_attr_mt_gpio,
- };
- static int mtk_gpio_create_attr(struct device *dev)
- {
- int idx, err = 0;
- int num = ARRAY_SIZE(gpio_attr_list);
- if (!dev)
- return -EINVAL;
- for (idx = 0; idx < num; idx++) {
- err = device_create_file(dev, gpio_attr_list[idx]);
- if (err)
- break;
- }
- return err;
- }
- int mtk_pctrl_get_gpio_chip_base(void)
- {
- if (pctl_alt)
- return pctl_alt->chip->base;
- pr_info("mtk_pinctrl is not initialized\n");
- return 0;
- }
- #endif
|