125 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (c) 2019, Linaro Limited3 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 0x4213#define WCD_REG_VAL_CTL_OFFSET 0x4314#define WCD934X_NPINS 515 16struct wcd_gpio_data {17 struct regmap *map;18 struct gpio_chip chip;19};20 21static 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 37static 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 45static 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 50 regmap_update_bits(data->map, WCD_REG_DIR_CTL_OFFSET,51 WCD_PIN_MASK(pin), WCD_PIN_MASK(pin));52 53 return regmap_update_bits(data->map, WCD_REG_VAL_CTL_OFFSET,54 WCD_PIN_MASK(pin),55 val ? WCD_PIN_MASK(pin) : 0);56}57 58static int wcd_gpio_get(struct gpio_chip *chip, unsigned int pin)59{60 struct wcd_gpio_data *data = gpiochip_get_data(chip);61 unsigned int value;62 63 regmap_read(data->map, WCD_REG_VAL_CTL_OFFSET, &value);64 65 return !!(value & WCD_PIN_MASK(pin));66}67 68static void wcd_gpio_set(struct gpio_chip *chip, unsigned int pin, int val)69{70 struct wcd_gpio_data *data = gpiochip_get_data(chip);71 72 regmap_update_bits(data->map, WCD_REG_VAL_CTL_OFFSET,73 WCD_PIN_MASK(pin), val ? WCD_PIN_MASK(pin) : 0);74}75 76static int wcd_gpio_probe(struct platform_device *pdev)77{78 struct device *dev = &pdev->dev;79 struct wcd_gpio_data *data;80 struct gpio_chip *chip;81 82 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);83 if (!data)84 return -ENOMEM;85 86 data->map = dev_get_regmap(dev->parent, NULL);87 if (!data->map) {88 dev_err(dev, "%s: failed to get regmap\n", __func__);89 return -EINVAL;90 }91 92 chip = &data->chip;93 chip->direction_input = wcd_gpio_direction_input;94 chip->direction_output = wcd_gpio_direction_output;95 chip->get_direction = wcd_gpio_get_direction;96 chip->get = wcd_gpio_get;97 chip->set = wcd_gpio_set;98 chip->parent = dev;99 chip->base = -1;100 chip->ngpio = WCD934X_NPINS;101 chip->label = dev_name(dev);102 chip->can_sleep = false;103 104 return devm_gpiochip_add_data(dev, chip, data);105}106 107static const struct of_device_id wcd_gpio_of_match[] = {108 { .compatible = "qcom,wcd9340-gpio" },109 { .compatible = "qcom,wcd9341-gpio" },110 { }111};112MODULE_DEVICE_TABLE(of, wcd_gpio_of_match);113 114static struct platform_driver wcd_gpio_driver = {115 .driver = {116 .name = "wcd934x-gpio",117 .of_match_table = wcd_gpio_of_match,118 },119 .probe = wcd_gpio_probe,120};121 122module_platform_driver(wcd_gpio_driver);123MODULE_DESCRIPTION("Qualcomm Technologies, Inc WCD GPIO control driver");124MODULE_LICENSE("GPL v2");125