1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2019, Linaro Limited 3 4 #include <linux/mod_devicetable.h> 5 #include <linux/module.h> 6 #include <linux/gpio/driver.h> 7 #include <linux/platform_device.h> 8 #include <linux/regmap.h> 9 #include <linux/slab.h> 10 11 #define WCD_PIN_MASK(p) BIT(p) 12 #define WCD_REG_DIR_CTL_OFFSET 0x42 13 #define WCD_REG_VAL_CTL_OFFSET 0x43 14 #define WCD934X_NPINS 5 15 16 struct wcd_gpio_data { 17 struct regmap *map; 18 struct gpio_chip chip; 19 }; 20 21 static int wcd_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) 22 { 23 struct wcd_gpio_data *data = gpiochip_get_data(chip); 24 unsigned int value; 25 int ret; 26 27 ret = regmap_read(data->map, WCD_REG_DIR_CTL_OFFSET, &value); 28 if (ret < 0) 29 return ret; 30 31 if (value & WCD_PIN_MASK(pin)) 32 return GPIO_LINE_DIRECTION_OUT; 33 34 return GPIO_LINE_DIRECTION_IN; 35 } 36 37 static int wcd_gpio_direction_input(struct gpio_chip *chip, unsigned int pin) 38 { 39 struct wcd_gpio_data *data = gpiochip_get_data(chip); 40 41 return regmap_update_bits(data->map, WCD_REG_DIR_CTL_OFFSET, 42 WCD_PIN_MASK(pin), 0); 43 } 44 45 static int wcd_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, 46 int val) 47 { 48 struct wcd_gpio_data *data = gpiochip_get_data(chip); 49 int ret; 50 51 ret = regmap_update_bits(data->map, WCD_REG_DIR_CTL_OFFSET, 52 WCD_PIN_MASK(pin), WCD_PIN_MASK(pin)); 53 if (ret) 54 return ret; 55 56 return regmap_update_bits(data->map, WCD_REG_VAL_CTL_OFFSET, 57 WCD_PIN_MASK(pin), 58 val ? WCD_PIN_MASK(pin) : 0); 59 } 60 61 static int wcd_gpio_get(struct gpio_chip *chip, unsigned int pin) 62 { 63 struct wcd_gpio_data *data = gpiochip_get_data(chip); 64 unsigned int value; 65 66 regmap_read(data->map, WCD_REG_VAL_CTL_OFFSET, &value); 67 68 return !!(value & WCD_PIN_MASK(pin)); 69 } 70 71 static int wcd_gpio_set(struct gpio_chip *chip, unsigned int pin, int val) 72 { 73 struct wcd_gpio_data *data = gpiochip_get_data(chip); 74 75 return regmap_update_bits(data->map, WCD_REG_VAL_CTL_OFFSET, 76 WCD_PIN_MASK(pin), 77 val ? WCD_PIN_MASK(pin) : 0); 78 } 79 80 static int wcd_gpio_probe(struct platform_device *pdev) 81 { 82 struct device *dev = &pdev->dev; 83 struct wcd_gpio_data *data; 84 struct gpio_chip *chip; 85 86 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 87 if (!data) 88 return -ENOMEM; 89 90 data->map = dev_get_regmap(dev->parent, NULL); 91 if (!data->map) { 92 dev_err(dev, "%s: failed to get regmap\n", __func__); 93 return -EINVAL; 94 } 95 96 chip = &data->chip; 97 chip->direction_input = wcd_gpio_direction_input; 98 chip->direction_output = wcd_gpio_direction_output; 99 chip->get_direction = wcd_gpio_get_direction; 100 chip->get = wcd_gpio_get; 101 chip->set_rv = wcd_gpio_set; 102 chip->parent = dev; 103 chip->base = -1; 104 chip->ngpio = WCD934X_NPINS; 105 chip->label = dev_name(dev); 106 chip->can_sleep = false; 107 108 return devm_gpiochip_add_data(dev, chip, data); 109 } 110 111 static const struct of_device_id wcd_gpio_of_match[] = { 112 { .compatible = "qcom,wcd9340-gpio" }, 113 { .compatible = "qcom,wcd9341-gpio" }, 114 { } 115 }; 116 MODULE_DEVICE_TABLE(of, wcd_gpio_of_match); 117 118 static struct platform_driver wcd_gpio_driver = { 119 .driver = { 120 .name = "wcd934x-gpio", 121 .of_match_table = wcd_gpio_of_match, 122 }, 123 .probe = wcd_gpio_probe, 124 }; 125 126 module_platform_driver(wcd_gpio_driver); 127 MODULE_DESCRIPTION("Qualcomm Technologies, Inc WCD GPIO control driver"); 128 MODULE_LICENSE("GPL v2"); 129