Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (c) 2019, Linaro Limited
0003 
0004 #include <linux/module.h>
0005 #include <linux/gpio/driver.h>
0006 #include <linux/regmap.h>
0007 #include <linux/slab.h>
0008 #include <linux/of_device.h>
0009 
0010 #define WCD_PIN_MASK(p) BIT(p)
0011 #define WCD_REG_DIR_CTL_OFFSET 0x42
0012 #define WCD_REG_VAL_CTL_OFFSET 0x43
0013 #define WCD934X_NPINS       5
0014 
0015 struct wcd_gpio_data {
0016     struct regmap *map;
0017     struct gpio_chip chip;
0018 };
0019 
0020 static int wcd_gpio_get_direction(struct gpio_chip *chip, unsigned int pin)
0021 {
0022     struct wcd_gpio_data *data = gpiochip_get_data(chip);
0023     unsigned int value;
0024     int ret;
0025 
0026     ret = regmap_read(data->map, WCD_REG_DIR_CTL_OFFSET, &value);
0027     if (ret < 0)
0028         return ret;
0029 
0030     if (value & WCD_PIN_MASK(pin))
0031         return GPIO_LINE_DIRECTION_OUT;
0032 
0033     return GPIO_LINE_DIRECTION_IN;
0034 }
0035 
0036 static int wcd_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
0037 {
0038     struct wcd_gpio_data *data = gpiochip_get_data(chip);
0039 
0040     return regmap_update_bits(data->map, WCD_REG_DIR_CTL_OFFSET,
0041                   WCD_PIN_MASK(pin), 0);
0042 }
0043 
0044 static int wcd_gpio_direction_output(struct gpio_chip *chip, unsigned int pin,
0045                      int val)
0046 {
0047     struct wcd_gpio_data *data = gpiochip_get_data(chip);
0048 
0049     regmap_update_bits(data->map, WCD_REG_DIR_CTL_OFFSET,
0050                WCD_PIN_MASK(pin), WCD_PIN_MASK(pin));
0051 
0052     return regmap_update_bits(data->map, WCD_REG_VAL_CTL_OFFSET,
0053                   WCD_PIN_MASK(pin),
0054                   val ? WCD_PIN_MASK(pin) : 0);
0055 }
0056 
0057 static int wcd_gpio_get(struct gpio_chip *chip, unsigned int pin)
0058 {
0059     struct wcd_gpio_data *data = gpiochip_get_data(chip);
0060     unsigned int value;
0061 
0062     regmap_read(data->map, WCD_REG_VAL_CTL_OFFSET, &value);
0063 
0064     return !!(value & WCD_PIN_MASK(pin));
0065 }
0066 
0067 static void wcd_gpio_set(struct gpio_chip *chip, unsigned int pin, int val)
0068 {
0069     struct wcd_gpio_data *data = gpiochip_get_data(chip);
0070 
0071     regmap_update_bits(data->map, WCD_REG_VAL_CTL_OFFSET,
0072                WCD_PIN_MASK(pin), val ? WCD_PIN_MASK(pin) : 0);
0073 }
0074 
0075 static int wcd_gpio_probe(struct platform_device *pdev)
0076 {
0077     struct device *dev = &pdev->dev;
0078     struct wcd_gpio_data *data;
0079     struct gpio_chip *chip;
0080 
0081     data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
0082     if (!data)
0083         return -ENOMEM;
0084 
0085     data->map = dev_get_regmap(dev->parent, NULL);
0086     if (!data->map) {
0087         dev_err(dev, "%s: failed to get regmap\n", __func__);
0088         return  -EINVAL;
0089     }
0090 
0091     chip = &data->chip;
0092     chip->direction_input  = wcd_gpio_direction_input;
0093     chip->direction_output = wcd_gpio_direction_output;
0094     chip->get_direction = wcd_gpio_get_direction;
0095     chip->get = wcd_gpio_get;
0096     chip->set = wcd_gpio_set;
0097     chip->parent = dev;
0098     chip->base = -1;
0099     chip->ngpio = WCD934X_NPINS;
0100     chip->label = dev_name(dev);
0101     chip->of_gpio_n_cells = 2;
0102     chip->can_sleep = false;
0103 
0104     return devm_gpiochip_add_data(dev, chip, data);
0105 }
0106 
0107 static const struct of_device_id wcd_gpio_of_match[] = {
0108     { .compatible = "qcom,wcd9340-gpio" },
0109     { .compatible = "qcom,wcd9341-gpio" },
0110     { }
0111 };
0112 MODULE_DEVICE_TABLE(of, wcd_gpio_of_match);
0113 
0114 static struct platform_driver wcd_gpio_driver = {
0115     .driver = {
0116            .name = "wcd934x-gpio",
0117            .of_match_table = wcd_gpio_of_match,
0118     },
0119     .probe = wcd_gpio_probe,
0120 };
0121 
0122 module_platform_driver(wcd_gpio_driver);
0123 MODULE_DESCRIPTION("Qualcomm Technologies, Inc WCD GPIO control driver");
0124 MODULE_LICENSE("GPL v2");