diff options
Diffstat (limited to 'drivers/pinctrl/sophgo/pinctrl-cv18xx.c')
-rw-r--r-- | drivers/pinctrl/sophgo/pinctrl-cv18xx.c | 602 |
1 files changed, 144 insertions, 458 deletions
diff --git a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c index 57f2674e75d6..c3a2dcf71f2a 100644 --- a/drivers/pinctrl/sophgo/pinctrl-cv18xx.c +++ b/drivers/pinctrl/sophgo/pinctrl-cv18xx.c @@ -15,8 +15,6 @@ #include <linux/seq_file.h> #include <linux/spinlock.h> -#include <linux/pinctrl/consumer.h> -#include <linux/pinctrl/machine.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinctrl.h> @@ -24,35 +22,15 @@ #include <dt-bindings/pinctrl/pinctrl-cv18xx.h> -#include "../core.h" #include "../pinctrl-utils.h" -#include "../pinconf.h" #include "../pinmux.h" #include "pinctrl-cv18xx.h" -struct cv1800_pinctrl { - struct device *dev; - struct pinctrl_dev *pctl_dev; - const struct cv1800_pinctrl_data *data; - struct pinctrl_desc pdesc; +struct cv1800_priv { u32 *power_cfg; - - struct mutex mutex; - raw_spinlock_t lock; - void __iomem *regs[2]; }; -struct cv1800_pin_mux_config { - struct cv1800_pin *pin; - u32 config; -}; - -static unsigned int cv1800_dt_get_pin(u32 value) -{ - return value & GENMASK(15, 0); -} - static unsigned int cv1800_dt_get_pin_mux(u32 value) { return (value >> 16) & GENMASK(7, 0); @@ -66,40 +44,28 @@ static unsigned int cv1800_dt_get_pin_mux2(u32 value) #define cv1800_pinctrl_get_component_addr(pctrl, _comp) \ ((pctrl)->regs[(_comp)->area] + (_comp)->offset) -static int cv1800_cmp_pin(const void *key, const void *pivot) -{ - const struct cv1800_pin *pin = pivot; - int pin_id = (long)key; - int pivid = pin->pin; - - return pin_id - pivid; -} - -static int cv1800_set_power_cfg(struct cv1800_pinctrl *pctrl, +static int cv1800_set_power_cfg(struct sophgo_pinctrl *pctrl, u8 domain, u32 cfg) { - if (domain >= pctrl->data->npd) + struct cv1800_priv *priv = pctrl->priv_ctrl; + + if (domain >= pctrl->data->npds) return -ENOTSUPP; - if (pctrl->power_cfg[domain] && pctrl->power_cfg[domain] != cfg) + if (priv->power_cfg[domain] && priv->power_cfg[domain] != cfg) return -EINVAL; - pctrl->power_cfg[domain] = cfg; + priv->power_cfg[domain] = cfg; return 0; } -static int cv1800_get_power_cfg(struct cv1800_pinctrl *pctrl, +static int cv1800_get_power_cfg(struct sophgo_pinctrl *pctrl, u8 domain) { - return pctrl->power_cfg[domain]; -} + struct cv1800_priv *priv = pctrl->priv_ctrl; -static struct cv1800_pin *cv1800_get_pin(struct cv1800_pinctrl *pctrl, - unsigned long pin) -{ - return bsearch((void *)pin, pctrl->data->pindata, pctrl->data->npins, - sizeof(struct cv1800_pin), cv1800_cmp_pin); + return priv->power_cfg[domain]; } #define PIN_BGA_ID_OFFSET 8 @@ -112,7 +78,7 @@ static const char *const io_type_desc[] = { "ETH" }; -static const char *cv1800_get_power_cfg_desc(struct cv1800_pinctrl *pctrl, +static const char *cv1800_get_power_cfg_desc(struct sophgo_pinctrl *pctrl, u8 domain) { return pctrl->data->pdnames[domain]; @@ -121,53 +87,57 @@ static const char *cv1800_get_power_cfg_desc(struct cv1800_pinctrl *pctrl, static void cv1800_pctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *seq, unsigned int pin_id) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct cv1800_priv *priv = pctrl->priv_ctrl; + const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id); + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); + u32 pin_hwid = pin->pin.id; u32 value; void __iomem *reg; - if (pin->pin >> PIN_BGA_ID_OFFSET) + if (pin_hwid >> PIN_BGA_ID_OFFSET) seq_printf(seq, "pos: %c%u ", - 'A' + (pin->pin >> PIN_BGA_ID_OFFSET) - 1, - pin->pin & PIN_BGA_ID_MASK); + 'A' + (pin_hwid >> PIN_BGA_ID_OFFSET) - 1, + pin_hwid & PIN_BGA_ID_MASK); else - seq_printf(seq, "pos: %u ", pin->pin); + seq_printf(seq, "pos: %u ", pin_hwid); seq_printf(seq, "power-domain: %s ", cv1800_get_power_cfg_desc(pctrl, pin->power_domain)); seq_printf(seq, "type: %s ", io_type_desc[type]); - reg = cv1800_pinctrl_get_component_addr(pctrl, &pin->mux); + reg = cv1800_pinctrl_get_component_addr(priv, &pin->mux); value = readl(reg); seq_printf(seq, "mux: 0x%08x ", value); - if (pin->flags & CV1800_PIN_HAVE_MUX2) { - reg = cv1800_pinctrl_get_component_addr(pctrl, &pin->mux2); + if (pin->pin.flags & CV1800_PIN_HAVE_MUX2) { + reg = cv1800_pinctrl_get_component_addr(priv, &pin->mux2); value = readl(reg); seq_printf(seq, "mux2: 0x%08x ", value); } if (type == IO_TYPE_1V8_ONLY || type == IO_TYPE_1V8_OR_3V3) { - reg = cv1800_pinctrl_get_component_addr(pctrl, &pin->conf); + reg = cv1800_pinctrl_get_component_addr(priv, &pin->conf); value = readl(reg); seq_printf(seq, "conf: 0x%08x ", value); } } -static int cv1800_verify_pinmux_config(const struct cv1800_pin_mux_config *config) +static int cv1800_verify_pinmux_config(const struct sophgo_pin_mux_config *config) { + struct cv1800_pin *pin = sophgo_to_cv1800_pin(config->pin); unsigned int mux = cv1800_dt_get_pin_mux(config->config); unsigned int mux2 = cv1800_dt_get_pin_mux2(config->config); - if (mux > config->pin->mux.max) + if (mux > pin->mux.max) return -EINVAL; - if (config->pin->flags & CV1800_PIN_HAVE_MUX2) { - if (mux != config->pin->mux2.pfunc) + if (pin->pin.flags & CV1800_PIN_HAVE_MUX2) { + if (mux != pin->mux2.pfunc) return -EINVAL; - if (mux2 > config->pin->mux2.max) + if (mux2 > pin->mux2.max) return -EINVAL; } else { if (mux2 != PIN_MUX_INVALD) @@ -177,9 +147,10 @@ static int cv1800_verify_pinmux_config(const struct cv1800_pin_mux_config *confi return 0; } -static int cv1800_verify_pin_group(const struct cv1800_pin_mux_config *mux, - unsigned long npins) +static int cv1800_verify_pin_group(const struct sophgo_pin_mux_config *mux, + unsigned int npins) { + struct cv1800_pin *pin; enum cv1800_pin_io_type type; u8 power_domain; int i; @@ -187,232 +158,78 @@ static int cv1800_verify_pin_group(const struct cv1800_pin_mux_config *mux, if (npins == 1) return 0; - type = cv1800_pin_io_type(mux[0].pin); - power_domain = mux[0].pin->power_domain; + pin = sophgo_to_cv1800_pin(mux[0].pin); + type = cv1800_pin_io_type(pin); + power_domain = pin->power_domain; for (i = 0; i < npins; i++) { - if (type != cv1800_pin_io_type(mux[i].pin) || - power_domain != mux[i].pin->power_domain) + pin = sophgo_to_cv1800_pin(mux[i].pin); + + if (type != cv1800_pin_io_type(pin) || + power_domain != pin->power_domain) return -ENOTSUPP; } return 0; } -static int cv1800_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, - struct device_node *np, - struct pinctrl_map **maps, - unsigned int *num_maps) +static int cv1800_dt_node_to_map_post(struct device_node *cur, + struct sophgo_pinctrl *pctrl, + struct sophgo_pin_mux_config *pinmuxs, + unsigned int npins) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - struct device *dev = pctrl->dev; - struct device_node *child; - struct pinctrl_map *map; - const char **grpnames; - const char *grpname; - int ngroups = 0; - int nmaps = 0; + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(pinmuxs[0].pin); + u32 power; int ret; - for_each_available_child_of_node(np, child) - ngroups += 1; - - grpnames = devm_kcalloc(dev, ngroups, sizeof(*grpnames), GFP_KERNEL); - if (!grpnames) - return -ENOMEM; - - map = kcalloc(ngroups * 2, sizeof(*map), GFP_KERNEL); - if (!map) - return -ENOMEM; - - ngroups = 0; - mutex_lock(&pctrl->mutex); - for_each_available_child_of_node(np, child) { - int npins = of_property_count_u32_elems(child, "pinmux"); - unsigned int *pins; - struct cv1800_pin_mux_config *pinmuxs; - u32 config, power; - int i; - - if (npins < 1) { - dev_err(dev, "invalid pinctrl group %pOFn.%pOFn\n", - np, child); - ret = -EINVAL; - goto dt_failed; - } - - grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", - np, child); - if (!grpname) { - ret = -ENOMEM; - goto dt_failed; - } - - grpnames[ngroups++] = grpname; - - pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); - if (!pins) { - ret = -ENOMEM; - goto dt_failed; - } - - pinmuxs = devm_kcalloc(dev, npins, sizeof(*pinmuxs), GFP_KERNEL); - if (!pinmuxs) { - ret = -ENOMEM; - goto dt_failed; - } - - for (i = 0; i < npins; i++) { - ret = of_property_read_u32_index(child, "pinmux", - i, &config); - if (ret) - goto dt_failed; - - pins[i] = cv1800_dt_get_pin(config); - pinmuxs[i].config = config; - pinmuxs[i].pin = cv1800_get_pin(pctrl, pins[i]); - - if (!pinmuxs[i].pin) { - dev_err(dev, "failed to get pin %d\n", pins[i]); - ret = -ENODEV; - goto dt_failed; - } - - ret = cv1800_verify_pinmux_config(&pinmuxs[i]); - if (ret) { - dev_err(dev, "group %s pin %d is invalid\n", - grpname, i); - goto dt_failed; - } - } - - ret = cv1800_verify_pin_group(pinmuxs, npins); - if (ret) { - dev_err(dev, "group %s is invalid\n", grpname); - goto dt_failed; - } - - ret = of_property_read_u32(child, "power-source", &power); - if (ret) - goto dt_failed; - - if (!(power == PIN_POWER_STATE_3V3 || power == PIN_POWER_STATE_1V8)) { - dev_err(dev, "group %s have unsupported power: %u\n", - grpname, power); - ret = -ENOTSUPP; - goto dt_failed; - } - - ret = cv1800_set_power_cfg(pctrl, pinmuxs[0].pin->power_domain, - power); - if (ret) - goto dt_failed; - - map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP; - map[nmaps].data.mux.function = np->name; - map[nmaps].data.mux.group = grpname; - nmaps += 1; - - ret = pinconf_generic_parse_dt_config(child, pctldev, - &map[nmaps].data.configs.configs, - &map[nmaps].data.configs.num_configs); - if (ret) { - dev_err(dev, "failed to parse pin config of group %s: %d\n", - grpname, ret); - goto dt_failed; - } - - ret = pinctrl_generic_add_group(pctldev, grpname, - pins, npins, pinmuxs); - if (ret < 0) { - dev_err(dev, "failed to add group %s: %d\n", grpname, ret); - goto dt_failed; - } - - /* don't create a map if there are no pinconf settings */ - if (map[nmaps].data.configs.num_configs == 0) - continue; - - map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; - map[nmaps].data.configs.group_or_pin = grpname; - nmaps += 1; - } - - ret = pinmux_generic_add_function(pctldev, np->name, - grpnames, ngroups, NULL); - if (ret < 0) { - dev_err(dev, "error adding function %s: %d\n", np->name, ret); - goto function_failed; - } - - *maps = map; - *num_maps = nmaps; - mutex_unlock(&pctrl->mutex); + ret = of_property_read_u32(cur, "power-source", &power); + if (ret) + return ret; - return 0; + if (!(power == PIN_POWER_STATE_3V3 || power == PIN_POWER_STATE_1V8)) + return -ENOTSUPP; -dt_failed: - of_node_put(child); -function_failed: - pinctrl_utils_free_map(pctldev, map, nmaps); - mutex_unlock(&pctrl->mutex); - return ret; + return cv1800_set_power_cfg(pctrl, pin->power_domain, power); } -static const struct pinctrl_ops cv1800_pctrl_ops = { +const struct pinctrl_ops cv1800_pctrl_ops = { .get_groups_count = pinctrl_generic_get_group_count, .get_group_name = pinctrl_generic_get_group_name, .get_group_pins = pinctrl_generic_get_group_pins, .pin_dbg_show = cv1800_pctrl_dbg_show, - .dt_node_to_map = cv1800_pctrl_dt_node_to_map, + .dt_node_to_map = sophgo_pctrl_dt_node_to_map, .dt_free_map = pinctrl_utils_free_map, }; +EXPORT_SYMBOL_GPL(cv1800_pctrl_ops); -static int cv1800_pmx_set_mux(struct pinctrl_dev *pctldev, - unsigned int fsel, unsigned int gsel) +static void cv1800_set_pinmux_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, u32 config) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - const struct group_desc *group; - const struct cv1800_pin_mux_config *configs; - unsigned int i; - - group = pinctrl_generic_get_group(pctldev, gsel); - if (!group) - return -EINVAL; - - configs = group->data; - - for (i = 0; i < group->grp.npins; i++) { - const struct cv1800_pin *pin = configs[i].pin; - u32 value = configs[i].config; - void __iomem *reg_mux; - void __iomem *reg_mux2; - unsigned long flags; - u32 mux; - u32 mux2; - - reg_mux = cv1800_pinctrl_get_component_addr(pctrl, &pin->mux); - reg_mux2 = cv1800_pinctrl_get_component_addr(pctrl, &pin->mux2); - mux = cv1800_dt_get_pin_mux(value); - mux2 = cv1800_dt_get_pin_mux2(value); - - raw_spin_lock_irqsave(&pctrl->lock, flags); - writel_relaxed(mux, reg_mux); - if (mux2 != PIN_MUX_INVALD) - writel_relaxed(mux2, reg_mux2); - raw_spin_unlock_irqrestore(&pctrl->lock, flags); - } - - return 0; + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); + struct cv1800_priv *priv = pctrl->priv_ctrl; + void __iomem *reg_mux; + void __iomem *reg_mux2; + u32 mux; + u32 mux2; + + reg_mux = cv1800_pinctrl_get_component_addr(priv, &pin->mux); + reg_mux2 = cv1800_pinctrl_get_component_addr(priv, &pin->mux2); + mux = cv1800_dt_get_pin_mux(config); + mux2 = cv1800_dt_get_pin_mux2(config); + + writel_relaxed(mux, reg_mux); + if (mux2 != PIN_MUX_INVALD) + writel_relaxed(mux2, reg_mux2); } -static const struct pinmux_ops cv1800_pmx_ops = { +const struct pinmux_ops cv1800_pmx_ops = { .get_functions_count = pinmux_generic_get_function_count, .get_function_name = pinmux_generic_get_function_name, .get_function_groups = pinmux_generic_get_function_groups, - .set_mux = cv1800_pmx_set_mux, + .set_mux = sophgo_pmx_set_mux, .strict = true, }; +EXPORT_SYMBOL_GPL(cv1800_pmx_ops); #define PIN_IO_PULLUP BIT(2) #define PIN_IO_PULLDOWN BIT(3) @@ -421,94 +238,14 @@ static const struct pinmux_ops cv1800_pmx_ops = { #define PIN_IO_BUS_HOLD BIT(10) #define PIN_IO_OUT_FAST_SLEW BIT(11) -static u32 cv1800_pull_down_typical_resistor(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin) -{ - return pctrl->data->vddio_ops->get_pull_down(pin, pctrl->power_cfg); -} - -static u32 cv1800_pull_up_typical_resistor(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin) -{ - return pctrl->data->vddio_ops->get_pull_up(pin, pctrl->power_cfg); -} - -static int cv1800_pinctrl_oc2reg(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, u32 target) -{ - const u32 *map; - int i, len; - - len = pctrl->data->vddio_ops->get_oc_map(pin, pctrl->power_cfg, &map); - if (len < 0) - return len; - - for (i = 0; i < len; i++) { - if (map[i] >= target) - return i; - } - - return -EINVAL; -} - -static int cv1800_pinctrl_reg2oc(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, u32 reg) -{ - const u32 *map; - int len; - - len = pctrl->data->vddio_ops->get_oc_map(pin, pctrl->power_cfg, &map); - if (len < 0) - return len; - - if (reg >= len) - return -EINVAL; - - return map[reg]; -} - -static int cv1800_pinctrl_schmitt2reg(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, u32 target) -{ - const u32 *map; - int i, len; - - len = pctrl->data->vddio_ops->get_schmitt_map(pin, pctrl->power_cfg, - &map); - if (len < 0) - return len; - - for (i = 0; i < len; i++) { - if (map[i] == target) - return i; - } - - return -EINVAL; -} - -static int cv1800_pinctrl_reg2schmitt(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, u32 reg) -{ - const u32 *map; - int len; - - len = pctrl->data->vddio_ops->get_schmitt_map(pin, pctrl->power_cfg, - &map); - if (len < 0) - return len; - - if (reg >= len) - return -EINVAL; - - return map[reg]; -} - static int cv1800_pconf_get(struct pinctrl_dev *pctldev, unsigned int pin_id, unsigned long *config) { - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct cv1800_priv *priv = pctrl->priv_ctrl; int param = pinconf_to_config_param(*config); - struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); + const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id); + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); enum cv1800_pin_io_type type; u32 value; u32 arg; @@ -522,28 +259,28 @@ static int cv1800_pconf_get(struct pinctrl_dev *pctldev, if (type == IO_TYPE_ETH || type == IO_TYPE_AUDIO) return -ENOTSUPP; - value = readl(cv1800_pinctrl_get_component_addr(pctrl, &pin->conf)); + value = readl(cv1800_pinctrl_get_component_addr(priv, &pin->conf)); switch (param) { case PIN_CONFIG_BIAS_PULL_DOWN: enabled = FIELD_GET(PIN_IO_PULLDOWN, value); - arg = cv1800_pull_down_typical_resistor(pctrl, pin); + arg = sophgo_pinctrl_typical_pull_down(pctrl, sp, priv->power_cfg); break; case PIN_CONFIG_BIAS_PULL_UP: enabled = FIELD_GET(PIN_IO_PULLUP, value); - arg = cv1800_pull_up_typical_resistor(pctrl, pin); + arg = sophgo_pinctrl_typical_pull_up(pctrl, sp, priv->power_cfg); break; case PIN_CONFIG_DRIVE_STRENGTH_UA: enabled = true; arg = FIELD_GET(PIN_IO_DRIVE, value); - ret = cv1800_pinctrl_reg2oc(pctrl, pin, arg); + ret = sophgo_pinctrl_reg2oc(pctrl, sp, priv->power_cfg, arg); if (ret < 0) return ret; arg = ret; break; case PIN_CONFIG_INPUT_SCHMITT_UV: arg = FIELD_GET(PIN_IO_SCHMITT, value); - ret = cv1800_pinctrl_reg2schmitt(pctrl, pin, arg); + ret = sophgo_pinctrl_reg2schmitt(pctrl, sp, priv->power_cfg, arg); if (ret < 0) return ret; arg = ret; @@ -570,14 +307,16 @@ static int cv1800_pconf_get(struct pinctrl_dev *pctldev, return enabled ? 0 : -EINVAL; } -static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, - struct cv1800_pin *pin, +static int cv1800_pinconf_compute_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, unsigned long *configs, unsigned int num_configs, - u32 *value) + u32 *value, u32 *mask) { + struct cv1800_priv *priv = pctrl->priv_ctrl; + const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); int i; - u32 v = 0; + u32 v = 0, m = 0; enum cv1800_pin_io_type type; int ret; @@ -596,24 +335,30 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, case PIN_CONFIG_BIAS_PULL_DOWN: v &= ~PIN_IO_PULLDOWN; v |= FIELD_PREP(PIN_IO_PULLDOWN, arg); + m |= PIN_IO_PULLDOWN; break; case PIN_CONFIG_BIAS_PULL_UP: v &= ~PIN_IO_PULLUP; v |= FIELD_PREP(PIN_IO_PULLUP, arg); + m |= PIN_IO_PULLUP; break; case PIN_CONFIG_DRIVE_STRENGTH_UA: - ret = cv1800_pinctrl_oc2reg(pctrl, pin, arg); + ret = sophgo_pinctrl_oc2reg(pctrl, sp, + priv->power_cfg, arg); if (ret < 0) return ret; v &= ~PIN_IO_DRIVE; v |= FIELD_PREP(PIN_IO_DRIVE, ret); + m |= PIN_IO_DRIVE; break; case PIN_CONFIG_INPUT_SCHMITT_UV: - ret = cv1800_pinctrl_schmitt2reg(pctrl, pin, arg); + ret = sophgo_pinctrl_schmitt2reg(pctrl, sp, + priv->power_cfg, arg); if (ret < 0) return ret; v &= ~PIN_IO_SCHMITT; v |= FIELD_PREP(PIN_IO_SCHMITT, ret); + m |= PIN_IO_SCHMITT; break; case PIN_CONFIG_POWER_SOURCE: /* Ignore power source as it is always fixed */ @@ -621,10 +366,12 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, case PIN_CONFIG_SLEW_RATE: v &= ~PIN_IO_OUT_FAST_SLEW; v |= FIELD_PREP(PIN_IO_OUT_FAST_SLEW, arg); + m |= PIN_IO_OUT_FAST_SLEW; break; case PIN_CONFIG_BIAS_BUS_HOLD: v &= ~PIN_IO_BUS_HOLD; v |= FIELD_PREP(PIN_IO_BUS_HOLD, arg); + m |= PIN_IO_BUS_HOLD; break; default: return -ENOTSUPP; @@ -632,134 +379,73 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl, } *value = v; + *mask = m; return 0; } -static int cv1800_pin_set_config(struct cv1800_pinctrl *pctrl, - unsigned int pin_id, - u32 value) +static int cv1800_set_pinconf_config(struct sophgo_pinctrl *pctrl, + const struct sophgo_pin *sp, + u32 value, u32 mask) { - struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); - unsigned long flags; + struct cv1800_priv *priv = pctrl->priv_ctrl; + struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); void __iomem *addr; + u32 reg; - if (!pin) - return -EINVAL; - - addr = cv1800_pinctrl_get_component_addr(pctrl, &pin->conf); + addr = cv1800_pinctrl_get_component_addr(priv, &pin->conf); - raw_spin_lock_irqsave(&pctrl->lock, flags); - writel(value, addr); - raw_spin_unlock_irqrestore(&pctrl->lock, flags); + reg = readl(addr); + reg &= ~mask; + reg |= value; + writel(reg, addr); return 0; } -static int cv1800_pconf_set(struct pinctrl_dev *pctldev, - unsigned int pin_id, unsigned long *configs, - unsigned int num_configs) -{ - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id); - u32 value; - - if (!pin) - return -ENODEV; - - if (cv1800_pinconf_compute_config(pctrl, pin, - configs, num_configs, &value)) - return -ENOTSUPP; - - return cv1800_pin_set_config(pctrl, pin_id, value); -} - -static int cv1800_pconf_group_set(struct pinctrl_dev *pctldev, - unsigned int gsel, - unsigned long *configs, - unsigned int num_configs) -{ - struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - const struct group_desc *group; - const struct cv1800_pin_mux_config *pinmuxs; - u32 value; - int i; - - group = pinctrl_generic_get_group(pctldev, gsel); - if (!group) - return -EINVAL; - - pinmuxs = group->data; - - if (cv1800_pinconf_compute_config(pctrl, pinmuxs[0].pin, - configs, num_configs, &value)) - return -ENOTSUPP; - - for (i = 0; i < group->grp.npins; i++) - cv1800_pin_set_config(pctrl, group->grp.pins[i], value); - - return 0; -} - -static const struct pinconf_ops cv1800_pconf_ops = { +const struct pinconf_ops cv1800_pconf_ops = { .pin_config_get = cv1800_pconf_get, - .pin_config_set = cv1800_pconf_set, - .pin_config_group_set = cv1800_pconf_group_set, + .pin_config_set = sophgo_pconf_set, + .pin_config_group_set = sophgo_pconf_group_set, .is_generic = true, }; +EXPORT_SYMBOL_GPL(cv1800_pconf_ops); -int cv1800_pinctrl_probe(struct platform_device *pdev) +static int cv1800_pinctrl_init(struct platform_device *pdev, + struct sophgo_pinctrl *pctrl) { - struct device *dev = &pdev->dev; - struct cv1800_pinctrl *pctrl; - const struct cv1800_pinctrl_data *pctrl_data; - int ret; - - pctrl_data = device_get_match_data(dev); - if (!pctrl_data) - return -ENODEV; + const struct sophgo_pinctrl_data *pctrl_data = pctrl->data; + struct cv1800_priv *priv; - if (pctrl_data->npins == 0 || pctrl_data->npd == 0) - return dev_err_probe(dev, -EINVAL, "invalid pin data\n"); - - pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); - if (!pctrl) + priv = devm_kzalloc(&pdev->dev, sizeof(struct cv1800_priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - pctrl->power_cfg = devm_kcalloc(dev, pctrl_data->npd, - sizeof(u32), GFP_KERNEL); - if (!pctrl->power_cfg) + priv->power_cfg = devm_kcalloc(&pdev->dev, pctrl_data->npds, + sizeof(u32), GFP_KERNEL); + if (!priv->power_cfg) return -ENOMEM; - pctrl->regs[0] = devm_platform_ioremap_resource_byname(pdev, "sys"); - if (IS_ERR(pctrl->regs[0])) - return PTR_ERR(pctrl->regs[0]); - - pctrl->regs[1] = devm_platform_ioremap_resource_byname(pdev, "rtc"); - if (IS_ERR(pctrl->regs[1])) - return PTR_ERR(pctrl->regs[1]); - - pctrl->pdesc.name = dev_name(dev); - pctrl->pdesc.pins = pctrl_data->pins; - pctrl->pdesc.npins = pctrl_data->npins; - pctrl->pdesc.pctlops = &cv1800_pctrl_ops; - pctrl->pdesc.pmxops = &cv1800_pmx_ops; - pctrl->pdesc.confops = &cv1800_pconf_ops; - pctrl->pdesc.owner = THIS_MODULE; - - pctrl->data = pctrl_data; - pctrl->dev = dev; - raw_spin_lock_init(&pctrl->lock); - mutex_init(&pctrl->mutex); + priv->regs[0] = devm_platform_ioremap_resource_byname(pdev, "sys"); + if (IS_ERR(priv->regs[0])) + return PTR_ERR(priv->regs[0]); - platform_set_drvdata(pdev, pctrl); + priv->regs[1] = devm_platform_ioremap_resource_byname(pdev, "rtc"); + if (IS_ERR(priv->regs[1])) + return PTR_ERR(priv->regs[1]); - ret = devm_pinctrl_register_and_init(dev, &pctrl->pdesc, - pctrl, &pctrl->pctl_dev); - if (ret) - return dev_err_probe(dev, ret, - "fail to register pinctrl driver\n"); + pctrl->priv_ctrl = priv; - return pinctrl_enable(pctrl->pctl_dev); + return 0; } -EXPORT_SYMBOL_GPL(cv1800_pinctrl_probe); + +const struct sophgo_cfg_ops cv1800_cfg_ops = { + .pctrl_init = cv1800_pinctrl_init, + .verify_pinmux_config = cv1800_verify_pinmux_config, + .verify_pin_group = cv1800_verify_pin_group, + .dt_node_to_map_post = cv1800_dt_node_to_map_post, + .compute_pinconf_config = cv1800_pinconf_compute_config, + .set_pinconf_config = cv1800_set_pinconf_config, + .set_pinmux_config = cv1800_set_pinmux_config, +}; +EXPORT_SYMBOL_GPL(cv1800_cfg_ops); |