From 3c5148a04fbc50c3200efe8793b8850ca07e05c2 Mon Sep 17 00:00:00 2001 From: Jin Park Date: Mon, 26 Sep 2011 14:51:20 +0900 Subject: mfd: max77663: Add GPIO attributes into platform data For board specific configuration, adding GPIO attributes such as push-pull, pull-up, pull-down, direction, output level and alternate into platform data. Bug 849360 Change-Id: I85c8e6ad397adf317cbc7f6d4bace8629091bad5 Signed-off-by: Jin Park Reviewed-on: http://git-master/r/54429 Reviewed-by: Laxman Dewangan --- drivers/mfd/max77663-core.c | 195 +++++++++++++++++++++++++++++++------- include/linux/mfd/max77663-core.h | 53 ++++++++++- 2 files changed, 208 insertions(+), 40 deletions(-) diff --git a/drivers/mfd/max77663-core.c b/drivers/mfd/max77663-core.c index 8cc7a5b83893..13f84e202973 100644 --- a/drivers/mfd/max77663-core.c +++ b/drivers/mfd/max77663-core.c @@ -384,10 +384,47 @@ struct max77663_chip *max77663_chip_from_gpio(struct gpio_chip *gpio) return container_of(gpio, struct max77663_chip, gpio); } +static int max77663_gpio_set_pull_up(struct max77663_chip *chip, int offset, + int pull_up) +{ + u8 val = 0; + + if ((offset < MAX77663_GPIO0) || (MAX77663_GPIO7 < offset)) + return -EINVAL; + + if (pull_up == GPIO_PU_ENABLE) + val = (1 << offset); + + return max77663_cache_write(chip->dev, MAX77663_REG_GPIO_PU, + (1 << offset), val, &chip->cache_gpio_pu); +} + +static int max77663_gpio_set_pull_down(struct max77663_chip *chip, int offset, + int pull_down) +{ + u8 val = 0; + + if ((offset < MAX77663_GPIO0) || (MAX77663_GPIO7 < offset)) + return -EINVAL; + + if (pull_down == GPIO_PD_ENABLE) + val = (1 << offset); + + return max77663_cache_write(chip->dev, MAX77663_REG_GPIO_PD, + (1 << offset), val, &chip->cache_gpio_pd); +} + +static inline +int max77663_gpio_is_alternate(struct max77663_chip *chip, int offset) +{ + return (chip->cache_gpio_alt & (1 << offset)) ? 1 : 0; +} + int max77663_gpio_set_alternate(int gpio, int alternate) { struct max77663_chip *chip = max77663_chip; u8 val = 0; + int ret = 0; if (!chip) return -ENXIO; @@ -396,11 +433,21 @@ int max77663_gpio_set_alternate(int gpio, int alternate) if ((gpio < MAX77663_GPIO0) || (MAX77663_GPIO7 < gpio)) return -EINVAL; - if (alternate) + if (alternate == GPIO_ALT_ENABLE) { val = (1 << gpio); + if (gpio == MAX77663_GPIO7) { + ret = max77663_gpio_set_pull_up(chip, gpio, 0); + if (ret < 0) + return ret; + + ret = max77663_gpio_set_pull_down(chip, gpio, 0); + if (ret < 0) + return ret; + } + } - return max77663_set_bits(chip->dev, MAX77663_REG_GPIO_ALT, (1 << gpio), - val, 0); + return max77663_cache_write(chip->dev, MAX77663_REG_GPIO_ALT, + (1 << gpio), val, &chip->cache_gpio_alt); } EXPORT_SYMBOL(max77663_gpio_set_alternate); @@ -408,6 +455,12 @@ static int max77663_gpio_dir_input(struct gpio_chip *gpio, unsigned offset) { struct max77663_chip *chip = max77663_chip_from_gpio(gpio); + if (max77663_gpio_is_alternate(chip, offset)) { + dev_warn(chip->dev, "gpio_dir_input: " + "gpio%u is used as alternate mode\n", offset); + return 0; + } + return max77663_cache_write(chip->dev, GPIO_REG_ADDR(offset), GPIO_CTRL_DIR_MASK, GPIO_CTRL_DIR_MASK, &chip->cache_gpio_ctrl[offset]); @@ -419,6 +472,12 @@ static int max77663_gpio_get(struct gpio_chip *gpio, unsigned offset) u8 val; int ret; + if (max77663_gpio_is_alternate(chip, offset)) { + dev_warn(chip->dev, "gpio_get: " + "gpio%u is used as alternate mode\n", offset); + return 0; + } + ret = max77663_read(chip->dev, GPIO_REG_ADDR(offset), &val, 1, 0); if (ret < 0) return ret; @@ -434,6 +493,12 @@ static int max77663_gpio_dir_output(struct gpio_chip *gpio, unsigned offset, u8 mask = GPIO_CTRL_DIR_MASK | GPIO_CTRL_DOUT_MASK; u8 val = (value ? 1 : 0) << GPIO_CTRL_DOUT_SHIFT; + if (max77663_gpio_is_alternate(chip, offset)) { + dev_warn(chip->dev, "gpio_dir_output: " + "gpio%u is used as alternate mode\n", offset); + return 0; + } + return max77663_cache_write(chip->dev, GPIO_REG_ADDR(offset), mask, val, &chip->cache_gpio_ctrl[offset]); } @@ -445,6 +510,12 @@ static int max77663_gpio_set_debounce(struct gpio_chip *gpio, unsigned offset, u8 shift = GPIO_CTRL_DBNC_SHIFT; u8 val = 0; + if (max77663_gpio_is_alternate(chip, offset)) { + dev_warn(chip->dev, "gpio_set_debounce: " + "gpio%u is used as alternate mode\n", offset); + return 0; + } + if (debounce == 0) val = 0; else if ((0 < debounce) && (debounce <= 8)) @@ -467,6 +538,12 @@ static void max77663_gpio_set(struct gpio_chip *gpio, unsigned offset, struct max77663_chip *chip = max77663_chip_from_gpio(gpio); u8 val = (value ? 1 : 0) << GPIO_CTRL_DOUT_SHIFT; + if (max77663_gpio_is_alternate(chip, offset)) { + dev_warn(chip->dev, "gpio_set: " + "gpio%u is used as alternate mode\n", offset); + return; + } + max77663_cache_write(chip->dev, GPIO_REG_ADDR(offset), GPIO_CTRL_DOUT_MASK, val, &chip->cache_gpio_ctrl[offset]); @@ -486,7 +563,7 @@ static void max77663_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gpio) int i; for (i = 0; i < gpio->ngpio; i++) { - int ctrl_val, alt_val; + u8 ctrl_val; const char *label; int is_out; int ret; @@ -498,14 +575,7 @@ static void max77663_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gpio) seq_printf(s, " gpio-%-3d (%-20.20s) ", i + chip->gpio_base, label); - ret = max77663_read(chip->dev, MAX77663_REG_GPIO_ALT, &alt_val, - 1, 0); - if (ret < 0) { - seq_printf(s, "\n"); - continue; - } - - if (alt_val & (1 << i)) { + if (chip->cache_gpio_alt & (1 << i)) { seq_printf(s, "alt\n"); continue; } @@ -572,13 +642,74 @@ static void max77663_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gpio) static int max77663_gpio_set_config(struct max77663_chip *chip, struct max77663_gpio_config *gpio_cfg) { - return max77663_gpio_set_alternate(gpio_cfg->gpio + chip->gpio_base, - gpio_cfg->alternate); + int gpio = gpio_cfg->gpio; + u8 val = 0, mask = 0; + int ret = 0; + + if ((gpio < MAX77663_GPIO0) || (MAX77663_GPIO7 < gpio)) + return -EINVAL; + + if (gpio_cfg->pull_up != GPIO_PU_DEF) { + ret = max77663_gpio_set_pull_up(chip, gpio, gpio_cfg->pull_up); + if (ret < 0) { + dev_err(chip->dev, "gpio_set_config: " + "Failed to set gpio%d pull-up\n", gpio); + return ret; + } + } + + if (gpio_cfg->pull_down != GPIO_PD_DEF) { + ret = max77663_gpio_set_pull_down(chip, gpio, + gpio_cfg->pull_down); + if (ret < 0) { + dev_err(chip->dev, "gpio_set_config: " + "Failed to set gpio%d pull-down\n", gpio); + return ret; + } + } + + if (gpio_cfg->dir != GPIO_DIR_DEF) { + mask = GPIO_CTRL_DIR_MASK; + if (gpio_cfg->dir == GPIO_DIR_IN) { + val |= GPIO_CTRL_DIR_MASK; + } else { + if (gpio_cfg->dout != GPIO_DOUT_DEF) { + mask |= GPIO_CTRL_DOUT_MASK; + if (gpio_cfg->dout == GPIO_DOUT_HIGH) + val |= GPIO_CTRL_DOUT_MASK; + } + + if (gpio_cfg->out_drv != GPIO_OUT_DRV_DEF) { + mask |= GPIO_CTRL_OUT_DRV_MASK; + if (gpio_cfg->out_drv == GPIO_OUT_DRV_PUSH_PULL) + val |= GPIO_CTRL_OUT_DRV_MASK; + } + } + + ret = max77663_cache_write(chip->dev, GPIO_REG_ADDR(gpio), mask, + val, &chip->cache_gpio_ctrl[gpio]); + if (ret < 0) { + dev_err(chip->dev, "gpio_set_config: " + "Failed to set gpio%d control\n", gpio); + return ret; + } + } + + if (gpio_cfg->alternate != GPIO_ALT_DEF) { + ret = max77663_gpio_set_alternate(gpio + chip->gpio_base, + gpio_cfg->alternate); + if (ret < 0) { + dev_err(chip->dev, "gpio_set_config: " + "Failed to set gpio%d alternate\n", gpio); + return ret; + } + } + + return 0; } static int max77663_gpio_init(struct max77663_chip *chip) { - u8 val = 0; int i; int ret; @@ -606,32 +737,25 @@ static int max77663_gpio_init(struct max77663_chip *chip) return ret; } - /* - * FIXME: The GPIOs can controlled when disabled pu & pd and enabled - * output drive. - */ - ret = max77663_write(chip->dev, MAX77663_REG_GPIO_PU, &val, 1, 0); + ret = max77663_read(chip->dev, MAX77663_REG_GPIO_PU, + &chip->cache_gpio_pu, 1, 0); if (ret < 0) { - dev_err(chip->dev, "gpio_init: Failed to set gpio pull up\n"); + dev_err(chip->dev, "gpio_init: Failed to get gpio pull-up\n"); return ret; } - ret = max77663_write(chip->dev, MAX77663_REG_GPIO_PD, &val, 1, 0); + ret = max77663_read(chip->dev, MAX77663_REG_GPIO_PD, + &chip->cache_gpio_pd, 1, 0); if (ret < 0) { - dev_err(chip->dev, "gpio_init: Failed to set gpio pull down\n"); + dev_err(chip->dev, "gpio_init: Failed to get gpio pull-down\n"); return ret; } - for (i = 0; i < MAX77663_GPIO_NR; i++) { - ret = max77663_cache_write(chip->dev, GPIO_REG_ADDR(i), - GPIO_CTRL_OUT_DRV_MASK, - (1 << GPIO_CTRL_OUT_DRV_SHIFT), - &chip->cache_gpio_ctrl[i]); - if (ret < 0) { - dev_err(chip->dev, - "gpio_init: Failed to set gpio control\n"); - return ret; - } + ret = max77663_read(chip->dev, MAX77663_REG_GPIO_ALT, + &chip->cache_gpio_alt, 1, 0); + if (ret < 0) { + dev_err(chip->dev, "gpio_init: Failed to get gpio alternate\n"); + return ret; } ret = gpiochip_add(&chip->gpio); @@ -641,8 +765,9 @@ static int max77663_gpio_init(struct max77663_chip *chip) } chip->gpio_base = chip->gpio.base; - for (i = 0; i < chip->pdata->num_gpio_cfg; i++) { - ret = max77663_gpio_set_config(chip, &chip->pdata->gpio_cfg[i]); + for (i = 0; i < chip->pdata->num_gpio_cfgs; i++) { + ret = max77663_gpio_set_config(chip, + &chip->pdata->gpio_cfgs[i]); if (ret < 0) { dev_err(chip->dev, "gpio_init: Failed to set gpio config\n"); diff --git a/include/linux/mfd/max77663-core.h b/include/linux/mfd/max77663-core.h index 59f8dbecd502..919f1b305a09 100644 --- a/include/linux/mfd/max77663-core.h +++ b/include/linux/mfd/max77663-core.h @@ -68,21 +68,64 @@ enum { MAX77663_GPIO_NR, }; -enum max77663_gpio_alternate { - GPIO_ALT_DISABLE, +/* Direction */ +enum max77663_gpio_dir { + GPIO_DIR_DEF, + GPIO_DIR_IN, + GPIO_DIR_OUT, +}; + +/* Data output */ +enum max77663_gpio_data_out { + GPIO_DOUT_DEF, + GPIO_DOUT_HIGH, + GPIO_DOUT_LOW, +}; + +/* Output drive */ +enum max77663_gpio_out_drv { + GPIO_OUT_DRV_DEF, + GPIO_OUT_DRV_PUSH_PULL, + GPIO_OUT_DRV_OPEN_DRAIN, +}; + +/* Pull-up */ +enum max77663_gpio_pull_up { + GPIO_PU_DEF, + GPIO_PU_ENABLE, + GPIO_PU_DISABLE, +}; + +/* Pull-down */ +enum max77663_gpio_pull_down { + GPIO_PD_DEF, + GPIO_PD_ENABLE, + GPIO_PD_DISABLE, +}; + +/* Alternate */ +enum max77663_gpio_alt { + GPIO_ALT_DEF, GPIO_ALT_ENABLE, + GPIO_ALT_DISABLE, }; struct max77663_gpio_config { int gpio; /* gpio number */ - bool alternate; /* alternate mode */ + enum max77663_gpio_dir dir; + enum max77663_gpio_data_out dout; + enum max77663_gpio_out_drv out_drv; + enum max77663_gpio_pull_up pull_up; + enum max77663_gpio_pull_down pull_down; + enum max77663_gpio_alt alternate; }; struct max77663_platform_data { int irq_base; int gpio_base; - int num_gpio_cfg; - struct max77663_gpio_config *gpio_cfg; + + int num_gpio_cfgs; + struct max77663_gpio_config *gpio_cfgs; int num_subdevs; struct mfd_cell *sub_devices; -- cgit v1.2.3