Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * gpiolib support for Wolfson WM8994
0004  *
0005  * Copyright 2009 Wolfson Microelectronics PLC.
0006  *
0007  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
0008  *
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/slab.h>
0013 #include <linux/module.h>
0014 #include <linux/gpio/driver.h>
0015 #include <linux/mfd/core.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/seq_file.h>
0018 #include <linux/regmap.h>
0019 
0020 #include <linux/mfd/wm8994/core.h>
0021 #include <linux/mfd/wm8994/pdata.h>
0022 #include <linux/mfd/wm8994/gpio.h>
0023 #include <linux/mfd/wm8994/registers.h>
0024 
0025 struct wm8994_gpio {
0026     struct wm8994 *wm8994;
0027     struct gpio_chip gpio_chip;
0028 };
0029 
0030 static int wm8994_gpio_request(struct gpio_chip *chip, unsigned offset)
0031 {
0032     struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
0033     struct wm8994 *wm8994 = wm8994_gpio->wm8994;
0034 
0035     switch (wm8994->type) {
0036     case WM8958:
0037         switch (offset) {
0038         case 1:
0039         case 2:
0040         case 3:
0041         case 4:
0042         case 6:
0043             return -EINVAL;
0044         }
0045         break;
0046     default:
0047         break;
0048     }
0049 
0050     return 0;
0051 }
0052 
0053 static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
0054 {
0055     struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
0056     struct wm8994 *wm8994 = wm8994_gpio->wm8994;
0057 
0058     return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
0059                    WM8994_GPN_DIR, WM8994_GPN_DIR);
0060 }
0061 
0062 static int wm8994_gpio_get(struct gpio_chip *chip, unsigned offset)
0063 {
0064     struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
0065     struct wm8994 *wm8994 = wm8994_gpio->wm8994;
0066     int ret;
0067 
0068     ret = wm8994_reg_read(wm8994, WM8994_GPIO_1 + offset);
0069     if (ret < 0)
0070         return ret;
0071 
0072     if (ret & WM8994_GPN_LVL)
0073         return 1;
0074     else
0075         return 0;
0076 }
0077 
0078 static int wm8994_gpio_direction_out(struct gpio_chip *chip,
0079                      unsigned offset, int value)
0080 {
0081     struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
0082     struct wm8994 *wm8994 = wm8994_gpio->wm8994;
0083 
0084     if (value)
0085         value = WM8994_GPN_LVL;
0086 
0087     return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
0088                    WM8994_GPN_DIR | WM8994_GPN_LVL, value);
0089 }
0090 
0091 static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
0092 {
0093     struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
0094     struct wm8994 *wm8994 = wm8994_gpio->wm8994;
0095 
0096     if (value)
0097         value = WM8994_GPN_LVL;
0098 
0099     wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, WM8994_GPN_LVL, value);
0100 }
0101 
0102 static int wm8994_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
0103                   unsigned long config)
0104 {
0105     struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
0106     struct wm8994 *wm8994 = wm8994_gpio->wm8994;
0107 
0108     switch (pinconf_to_config_param(config)) {
0109     case PIN_CONFIG_DRIVE_OPEN_DRAIN:
0110         return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
0111                        WM8994_GPN_OP_CFG_MASK,
0112                        WM8994_GPN_OP_CFG);
0113     case PIN_CONFIG_DRIVE_PUSH_PULL:
0114         return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
0115                        WM8994_GPN_OP_CFG_MASK, 0);
0116     default:
0117         break;
0118     }
0119 
0120     return -ENOTSUPP;
0121 }
0122 
0123 static int wm8994_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
0124 {
0125     struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
0126     struct wm8994 *wm8994 = wm8994_gpio->wm8994;
0127 
0128     return regmap_irq_get_virq(wm8994->irq_data, offset);
0129 }
0130 
0131 
0132 #ifdef CONFIG_DEBUG_FS
0133 static const char *wm8994_gpio_fn(u16 fn)
0134 {
0135     switch (fn) {
0136     case WM8994_GP_FN_PIN_SPECIFIC:
0137         return "pin-specific";
0138     case WM8994_GP_FN_GPIO:
0139         return "GPIO";
0140     case WM8994_GP_FN_SDOUT:
0141         return "SDOUT";
0142     case WM8994_GP_FN_IRQ:
0143         return "IRQ";
0144     case WM8994_GP_FN_TEMPERATURE:
0145         return "Temperature";
0146     case WM8994_GP_FN_MICBIAS1_DET:
0147         return "MICBIAS1 detect";
0148     case WM8994_GP_FN_MICBIAS1_SHORT:
0149         return "MICBIAS1 short";
0150     case WM8994_GP_FN_MICBIAS2_DET:
0151         return "MICBIAS2 detect";
0152     case WM8994_GP_FN_MICBIAS2_SHORT:
0153         return "MICBIAS2 short";
0154     case WM8994_GP_FN_FLL1_LOCK:
0155         return "FLL1 lock";
0156     case WM8994_GP_FN_FLL2_LOCK:
0157         return "FLL2 lock";
0158     case WM8994_GP_FN_SRC1_LOCK:
0159         return "SRC1 lock";
0160     case WM8994_GP_FN_SRC2_LOCK:
0161         return "SRC2 lock";
0162     case WM8994_GP_FN_DRC1_ACT:
0163         return "DRC1 activity";
0164     case WM8994_GP_FN_DRC2_ACT:
0165         return "DRC2 activity";
0166     case WM8994_GP_FN_DRC3_ACT:
0167         return "DRC3 activity";
0168     case WM8994_GP_FN_WSEQ_STATUS:
0169         return "Write sequencer";
0170     case WM8994_GP_FN_FIFO_ERROR:
0171         return "FIFO error";
0172     case WM8994_GP_FN_OPCLK:
0173         return "OPCLK";
0174     case WM8994_GP_FN_THW:
0175         return "Thermal warning";
0176     case WM8994_GP_FN_DCS_DONE:
0177         return "DC servo";
0178     case WM8994_GP_FN_FLL1_OUT:
0179         return "FLL1 output";
0180     case WM8994_GP_FN_FLL2_OUT:
0181         return "FLL1 output";
0182     default:
0183         return "Unknown";
0184     }
0185 }
0186 
0187 static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
0188 {
0189     struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
0190     struct wm8994 *wm8994 = wm8994_gpio->wm8994;
0191     int i;
0192 
0193     for (i = 0; i < chip->ngpio; i++) {
0194         int gpio = i + chip->base;
0195         int reg;
0196         const char *label;
0197 
0198         /* We report the GPIO even if it's not requested since
0199          * we're also reporting things like alternate
0200          * functions which apply even when the GPIO is not in
0201          * use as a GPIO.
0202          */
0203         label = gpiochip_is_requested(chip, i);
0204         if (!label)
0205             label = "Unrequested";
0206 
0207         seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label);
0208 
0209         reg = wm8994_reg_read(wm8994, WM8994_GPIO_1 + i);
0210         if (reg < 0) {
0211             dev_err(wm8994->dev,
0212                 "GPIO control %d read failed: %d\n",
0213                 gpio, reg);
0214             seq_printf(s, "\n");
0215             continue;
0216         }
0217 
0218         if (reg & WM8994_GPN_DIR)
0219             seq_printf(s, "in ");
0220         else
0221             seq_printf(s, "out ");
0222 
0223         if (reg & WM8994_GPN_PU)
0224             seq_printf(s, "pull up ");
0225 
0226         if (reg & WM8994_GPN_PD)
0227             seq_printf(s, "pull down ");
0228 
0229         if (reg & WM8994_GPN_POL)
0230             seq_printf(s, "inverted ");
0231         else
0232             seq_printf(s, "noninverted ");
0233 
0234         if (reg & WM8994_GPN_OP_CFG)
0235             seq_printf(s, "open drain ");
0236         else
0237             seq_printf(s, "push-pull ");
0238 
0239         seq_printf(s, "%s (%x)\n",
0240                wm8994_gpio_fn(reg & WM8994_GPN_FN_MASK), reg);
0241     }
0242 }
0243 #else
0244 #define wm8994_gpio_dbg_show NULL
0245 #endif
0246 
0247 static const struct gpio_chip template_chip = {
0248     .label          = "wm8994",
0249     .owner          = THIS_MODULE,
0250     .request        = wm8994_gpio_request,
0251     .direction_input    = wm8994_gpio_direction_in,
0252     .get            = wm8994_gpio_get,
0253     .direction_output   = wm8994_gpio_direction_out,
0254     .set            = wm8994_gpio_set,
0255     .set_config     = wm8994_gpio_set_config,
0256     .to_irq         = wm8994_gpio_to_irq,
0257     .dbg_show       = wm8994_gpio_dbg_show,
0258     .can_sleep      = true,
0259 };
0260 
0261 static int wm8994_gpio_probe(struct platform_device *pdev)
0262 {
0263     struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
0264     struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev);
0265     struct wm8994_gpio *wm8994_gpio;
0266 
0267     wm8994_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm8994_gpio),
0268                    GFP_KERNEL);
0269     if (wm8994_gpio == NULL)
0270         return -ENOMEM;
0271 
0272     wm8994_gpio->wm8994 = wm8994;
0273     wm8994_gpio->gpio_chip = template_chip;
0274     wm8994_gpio->gpio_chip.ngpio = WM8994_GPIO_MAX;
0275     wm8994_gpio->gpio_chip.parent = &pdev->dev;
0276     if (pdata && pdata->gpio_base)
0277         wm8994_gpio->gpio_chip.base = pdata->gpio_base;
0278     else
0279         wm8994_gpio->gpio_chip.base = -1;
0280 
0281     return devm_gpiochip_add_data(&pdev->dev, &wm8994_gpio->gpio_chip, wm8994_gpio);
0282 }
0283 
0284 static struct platform_driver wm8994_gpio_driver = {
0285     .driver.name    = "wm8994-gpio",
0286     .probe      = wm8994_gpio_probe,
0287 };
0288 
0289 static int __init wm8994_gpio_init(void)
0290 {
0291     return platform_driver_register(&wm8994_gpio_driver);
0292 }
0293 subsys_initcall(wm8994_gpio_init);
0294 
0295 static void __exit wm8994_gpio_exit(void)
0296 {
0297     platform_driver_unregister(&wm8994_gpio_driver);
0298 }
0299 module_exit(wm8994_gpio_exit);
0300 
0301 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
0302 MODULE_DESCRIPTION("GPIO interface for WM8994");
0303 MODULE_LICENSE("GPL");
0304 MODULE_ALIAS("platform:wm8994-gpio");