0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/slab.h>
0012 #include <linux/module.h>
0013 #include <linux/gpio/driver.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/pm_runtime.h>
0016 #include <linux/seq_file.h>
0017
0018 #include <linux/mfd/arizona/core.h>
0019 #include <linux/mfd/arizona/pdata.h>
0020 #include <linux/mfd/arizona/registers.h>
0021
0022 struct arizona_gpio {
0023 struct arizona *arizona;
0024 struct gpio_chip gpio_chip;
0025 };
0026
0027 static int arizona_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
0028 {
0029 struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
0030 struct arizona *arizona = arizona_gpio->arizona;
0031 bool persistent = gpiochip_line_is_persistent(chip, offset);
0032 bool change;
0033 int ret;
0034
0035 ret = regmap_update_bits_check(arizona->regmap,
0036 ARIZONA_GPIO1_CTRL + offset,
0037 ARIZONA_GPN_DIR, ARIZONA_GPN_DIR,
0038 &change);
0039 if (ret < 0)
0040 return ret;
0041
0042 if (change && persistent) {
0043 pm_runtime_mark_last_busy(chip->parent);
0044 pm_runtime_put_autosuspend(chip->parent);
0045 }
0046
0047 return 0;
0048 }
0049
0050 static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset)
0051 {
0052 struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
0053 struct arizona *arizona = arizona_gpio->arizona;
0054 unsigned int reg, val;
0055 int ret;
0056
0057 reg = ARIZONA_GPIO1_CTRL + offset;
0058 ret = regmap_read(arizona->regmap, reg, &val);
0059 if (ret < 0)
0060 return ret;
0061
0062
0063 if (val & ARIZONA_GPN_DIR) {
0064 ret = pm_runtime_get_sync(chip->parent);
0065 if (ret < 0) {
0066 dev_err(chip->parent, "Failed to resume: %d\n", ret);
0067 pm_runtime_put_autosuspend(chip->parent);
0068 return ret;
0069 }
0070
0071
0072 ret = regcache_drop_region(arizona->regmap, reg, reg);
0073 if (ret < 0) {
0074 dev_err(chip->parent, "Failed to drop cache: %d\n",
0075 ret);
0076 pm_runtime_put_autosuspend(chip->parent);
0077 return ret;
0078 }
0079
0080 ret = regmap_read(arizona->regmap, reg, &val);
0081 if (ret < 0) {
0082 pm_runtime_put_autosuspend(chip->parent);
0083 return ret;
0084 }
0085
0086 pm_runtime_mark_last_busy(chip->parent);
0087 pm_runtime_put_autosuspend(chip->parent);
0088 }
0089
0090 if (val & ARIZONA_GPN_LVL)
0091 return 1;
0092 else
0093 return 0;
0094 }
0095
0096 static int arizona_gpio_direction_out(struct gpio_chip *chip,
0097 unsigned offset, int value)
0098 {
0099 struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
0100 struct arizona *arizona = arizona_gpio->arizona;
0101 bool persistent = gpiochip_line_is_persistent(chip, offset);
0102 unsigned int val;
0103 int ret;
0104
0105 ret = regmap_read(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, &val);
0106 if (ret < 0)
0107 return ret;
0108
0109 if ((val & ARIZONA_GPN_DIR) && persistent) {
0110 ret = pm_runtime_get_sync(chip->parent);
0111 if (ret < 0) {
0112 dev_err(chip->parent, "Failed to resume: %d\n", ret);
0113 pm_runtime_put(chip->parent);
0114 return ret;
0115 }
0116 }
0117
0118 if (value)
0119 value = ARIZONA_GPN_LVL;
0120
0121 return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
0122 ARIZONA_GPN_DIR | ARIZONA_GPN_LVL, value);
0123 }
0124
0125 static void arizona_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
0126 {
0127 struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
0128 struct arizona *arizona = arizona_gpio->arizona;
0129
0130 if (value)
0131 value = ARIZONA_GPN_LVL;
0132
0133 regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
0134 ARIZONA_GPN_LVL, value);
0135 }
0136
0137 static const struct gpio_chip template_chip = {
0138 .label = "arizona",
0139 .owner = THIS_MODULE,
0140 .direction_input = arizona_gpio_direction_in,
0141 .get = arizona_gpio_get,
0142 .direction_output = arizona_gpio_direction_out,
0143 .set = arizona_gpio_set,
0144 .can_sleep = true,
0145 };
0146
0147 static int arizona_gpio_probe(struct platform_device *pdev)
0148 {
0149 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
0150 struct arizona_pdata *pdata = &arizona->pdata;
0151 struct arizona_gpio *arizona_gpio;
0152 int ret;
0153
0154 device_set_node(&pdev->dev, dev_fwnode(pdev->dev.parent));
0155
0156 arizona_gpio = devm_kzalloc(&pdev->dev, sizeof(*arizona_gpio),
0157 GFP_KERNEL);
0158 if (!arizona_gpio)
0159 return -ENOMEM;
0160
0161 arizona_gpio->arizona = arizona;
0162 arizona_gpio->gpio_chip = template_chip;
0163 arizona_gpio->gpio_chip.parent = &pdev->dev;
0164
0165 switch (arizona->type) {
0166 case WM5102:
0167 case WM5110:
0168 case WM8280:
0169 case WM8997:
0170 case WM8998:
0171 case WM1814:
0172 arizona_gpio->gpio_chip.ngpio = 5;
0173 break;
0174 case WM1831:
0175 case CS47L24:
0176 arizona_gpio->gpio_chip.ngpio = 2;
0177 break;
0178 default:
0179 dev_err(&pdev->dev, "Unknown chip variant %d\n",
0180 arizona->type);
0181 return -EINVAL;
0182 }
0183
0184 if (pdata->gpio_base)
0185 arizona_gpio->gpio_chip.base = pdata->gpio_base;
0186 else
0187 arizona_gpio->gpio_chip.base = -1;
0188
0189 pm_runtime_enable(&pdev->dev);
0190
0191 ret = devm_gpiochip_add_data(&pdev->dev, &arizona_gpio->gpio_chip,
0192 arizona_gpio);
0193 if (ret < 0) {
0194 pm_runtime_disable(&pdev->dev);
0195 dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
0196 ret);
0197 return ret;
0198 }
0199
0200 return 0;
0201 }
0202
0203 static struct platform_driver arizona_gpio_driver = {
0204 .driver.name = "arizona-gpio",
0205 .probe = arizona_gpio_probe,
0206 };
0207
0208 module_platform_driver(arizona_gpio_driver);
0209
0210 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
0211 MODULE_DESCRIPTION("GPIO interface for Arizona devices");
0212 MODULE_LICENSE("GPL");
0213 MODULE_ALIAS("platform:arizona-gpio");