|
@@ -66,6 +66,14 @@
|
|
|
#define GPIO_DRV_STRENGTH_BITS 3
|
|
|
#define GPIO_DRV_STRENGTH_BIT_MASK ((1 << GPIO_DRV_STRENGTH_BITS) - 1)
|
|
|
|
|
|
+enum iproc_pinconf_param {
|
|
|
+ IPROC_PINCONF_DRIVE_STRENGTH = 0,
|
|
|
+ IPROC_PINCONF_BIAS_DISABLE,
|
|
|
+ IPROC_PINCONF_BIAS_PULL_UP,
|
|
|
+ IPROC_PINCONF_BIAS_PULL_DOWN,
|
|
|
+ IPROC_PINCON_MAX,
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* Iproc GPIO core
|
|
|
*
|
|
@@ -78,6 +86,10 @@
|
|
|
* @num_banks: number of GPIO banks, each bank supports up to 32 GPIOs
|
|
|
* @pinmux_is_supported: flag to indicate this GPIO controller contains pins
|
|
|
* that can be individually muxed to GPIO
|
|
|
+ * @pinconf_disable: contains a list of PINCONF parameters that need to be
|
|
|
+ * disabled
|
|
|
+ * @nr_pinconf_disable: total number of PINCONF parameters that need to be
|
|
|
+ * disabled
|
|
|
* @pctl: pointer to pinctrl_dev
|
|
|
* @pctldesc: pinctrl descriptor
|
|
|
*/
|
|
@@ -94,6 +106,9 @@ struct iproc_gpio {
|
|
|
|
|
|
bool pinmux_is_supported;
|
|
|
|
|
|
+ enum pin_config_param *pinconf_disable;
|
|
|
+ unsigned int nr_pinconf_disable;
|
|
|
+
|
|
|
struct pinctrl_dev *pctl;
|
|
|
struct pinctrl_desc pctldesc;
|
|
|
};
|
|
@@ -360,6 +375,65 @@ static int iproc_gpio_get(struct gpio_chip *gc, unsigned gpio)
|
|
|
return !!(readl(chip->base + offset) & BIT(shift));
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Mapping of the iProc PINCONF parameters to the generic pin configuration
|
|
|
+ * parameters
|
|
|
+ */
|
|
|
+static const enum pin_config_param iproc_pinconf_disable_map[] = {
|
|
|
+ [IPROC_PINCONF_DRIVE_STRENGTH] = PIN_CONFIG_DRIVE_STRENGTH,
|
|
|
+ [IPROC_PINCONF_BIAS_DISABLE] = PIN_CONFIG_BIAS_DISABLE,
|
|
|
+ [IPROC_PINCONF_BIAS_PULL_UP] = PIN_CONFIG_BIAS_PULL_UP,
|
|
|
+ [IPROC_PINCONF_BIAS_PULL_DOWN] = PIN_CONFIG_BIAS_PULL_DOWN,
|
|
|
+};
|
|
|
+
|
|
|
+static bool iproc_pinconf_param_is_disabled(struct iproc_gpio *chip,
|
|
|
+ enum pin_config_param param)
|
|
|
+{
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ if (!chip->nr_pinconf_disable)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ for (i = 0; i < chip->nr_pinconf_disable; i++)
|
|
|
+ if (chip->pinconf_disable[i] == param)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static int iproc_pinconf_disable_map_create(struct iproc_gpio *chip,
|
|
|
+ unsigned long disable_mask)
|
|
|
+{
|
|
|
+ unsigned int map_size = ARRAY_SIZE(iproc_pinconf_disable_map);
|
|
|
+ unsigned int bit, nbits = 0;
|
|
|
+
|
|
|
+ /* figure out total number of PINCONF parameters to disable */
|
|
|
+ for_each_set_bit(bit, &disable_mask, map_size)
|
|
|
+ nbits++;
|
|
|
+
|
|
|
+ if (!nbits)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Allocate an array to store PINCONF parameters that need to be
|
|
|
+ * disabled
|
|
|
+ */
|
|
|
+ chip->pinconf_disable = devm_kcalloc(chip->dev, nbits,
|
|
|
+ sizeof(*chip->pinconf_disable),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!chip->pinconf_disable)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ chip->nr_pinconf_disable = nbits;
|
|
|
+
|
|
|
+ /* now store these parameters */
|
|
|
+ nbits = 0;
|
|
|
+ for_each_set_bit(bit, &disable_mask, map_size)
|
|
|
+ chip->pinconf_disable[nbits++] = iproc_pinconf_disable_map[bit];
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int iproc_get_groups_count(struct pinctrl_dev *pctldev)
|
|
|
{
|
|
|
return 1;
|
|
@@ -500,6 +574,9 @@ static int iproc_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
|
|
|
bool disable, pull_up;
|
|
|
int ret;
|
|
|
|
|
|
+ if (iproc_pinconf_param_is_disabled(chip, param))
|
|
|
+ return -ENOTSUPP;
|
|
|
+
|
|
|
switch (param) {
|
|
|
case PIN_CONFIG_BIAS_DISABLE:
|
|
|
iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
|
|
@@ -548,6 +625,10 @@ static int iproc_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
|
|
|
|
|
|
for (i = 0; i < num_configs; i++) {
|
|
|
param = pinconf_to_config_param(configs[i]);
|
|
|
+
|
|
|
+ if (iproc_pinconf_param_is_disabled(chip, param))
|
|
|
+ return -ENOTSUPP;
|
|
|
+
|
|
|
arg = pinconf_to_config_argument(configs[i]);
|
|
|
|
|
|
switch (param) {
|
|
@@ -633,11 +714,13 @@ static int iproc_gpio_register_pinconf(struct iproc_gpio *chip)
|
|
|
}
|
|
|
|
|
|
static const struct of_device_id iproc_gpio_of_match[] = {
|
|
|
+ { .compatible = "brcm,iproc-gpio" },
|
|
|
{ .compatible = "brcm,cygnus-ccm-gpio" },
|
|
|
{ .compatible = "brcm,cygnus-asiu-gpio" },
|
|
|
{ .compatible = "brcm,cygnus-crmu-gpio" },
|
|
|
- { .compatible = "brcm,iproc-gpio" },
|
|
|
- { }
|
|
|
+ { .compatible = "brcm,iproc-nsp-gpio" },
|
|
|
+ { .compatible = "brcm,iproc-stingray-gpio" },
|
|
|
+ { /* sentinel */ }
|
|
|
};
|
|
|
|
|
|
static int iproc_gpio_probe(struct platform_device *pdev)
|
|
@@ -646,8 +729,17 @@ static int iproc_gpio_probe(struct platform_device *pdev)
|
|
|
struct resource *res;
|
|
|
struct iproc_gpio *chip;
|
|
|
struct gpio_chip *gc;
|
|
|
- u32 ngpios;
|
|
|
+ u32 ngpios, pinconf_disable_mask = 0;
|
|
|
int irq, ret;
|
|
|
+ bool no_pinconf = false;
|
|
|
+
|
|
|
+ /* NSP does not support drive strength config */
|
|
|
+ if (of_device_is_compatible(dev->of_node, "brcm,iproc-nsp-gpio"))
|
|
|
+ pinconf_disable_mask = BIT(IPROC_PINCONF_DRIVE_STRENGTH);
|
|
|
+ /* Stingray does not support pinconf in this controller */
|
|
|
+ else if (of_device_is_compatible(dev->of_node,
|
|
|
+ "brcm,iproc-stingray-gpio"))
|
|
|
+ no_pinconf = true;
|
|
|
|
|
|
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
|
|
|
if (!chip)
|
|
@@ -702,10 +794,22 @@ static int iproc_gpio_probe(struct platform_device *pdev)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- ret = iproc_gpio_register_pinconf(chip);
|
|
|
- if (ret) {
|
|
|
- dev_err(dev, "unable to register pinconf\n");
|
|
|
- goto err_rm_gpiochip;
|
|
|
+ if (!no_pinconf) {
|
|
|
+ ret = iproc_gpio_register_pinconf(chip);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(dev, "unable to register pinconf\n");
|
|
|
+ goto err_rm_gpiochip;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pinconf_disable_mask) {
|
|
|
+ ret = iproc_pinconf_disable_map_create(chip,
|
|
|
+ pinconf_disable_mask);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(dev,
|
|
|
+ "unable to create pinconf disable map\n");
|
|
|
+ goto err_rm_gpiochip;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* optional GPIO interrupt support */
|