200 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * TI Palma series PMIC's GPIO driver.4 *5 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.6 *7 * Author: Laxman Dewangan <ldewangan@nvidia.com>8 */9 10#include <linux/gpio/driver.h>11#include <linux/kernel.h>12#include <linux/init.h>13#include <linux/mfd/palmas.h>14#include <linux/of.h>15#include <linux/platform_device.h>16 17struct palmas_gpio {18 struct gpio_chip gpio_chip;19 struct palmas *palmas;20};21 22struct palmas_device_data {23 int ngpio;24};25 26static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)27{28 struct palmas_gpio *pg = gpiochip_get_data(gc);29 struct palmas *palmas = pg->palmas;30 unsigned int val;31 int ret;32 unsigned int reg;33 int gpio16 = (offset/8);34 35 offset %= 8;36 reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;37 38 ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);39 if (ret < 0) {40 dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret);41 return ret;42 }43 44 if (val & BIT(offset))45 reg = (gpio16) ? PALMAS_GPIO_DATA_OUT2 : PALMAS_GPIO_DATA_OUT;46 else47 reg = (gpio16) ? PALMAS_GPIO_DATA_IN2 : PALMAS_GPIO_DATA_IN;48 49 ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);50 if (ret < 0) {51 dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret);52 return ret;53 }54 return !!(val & BIT(offset));55}56 57static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset,58 int value)59{60 struct palmas_gpio *pg = gpiochip_get_data(gc);61 struct palmas *palmas = pg->palmas;62 int ret;63 unsigned int reg;64 int gpio16 = (offset/8);65 66 offset %= 8;67 if (gpio16)68 reg = (value) ?69 PALMAS_GPIO_SET_DATA_OUT2 : PALMAS_GPIO_CLEAR_DATA_OUT2;70 else71 reg = (value) ?72 PALMAS_GPIO_SET_DATA_OUT : PALMAS_GPIO_CLEAR_DATA_OUT;73 74 ret = palmas_write(palmas, PALMAS_GPIO_BASE, reg, BIT(offset));75 if (ret < 0)76 dev_err(gc->parent, "Reg 0x%02x write failed, %d\n", reg, ret);77}78 79static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,80 int value)81{82 struct palmas_gpio *pg = gpiochip_get_data(gc);83 struct palmas *palmas = pg->palmas;84 int ret;85 unsigned int reg;86 int gpio16 = (offset/8);87 88 offset %= 8;89 reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;90 91 /* Set the initial value */92 palmas_gpio_set(gc, offset, value);93 94 ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg,95 BIT(offset), BIT(offset));96 if (ret < 0)97 dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg,98 ret);99 return ret;100}101 102static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)103{104 struct palmas_gpio *pg = gpiochip_get_data(gc);105 struct palmas *palmas = pg->palmas;106 int ret;107 unsigned int reg;108 int gpio16 = (offset/8);109 110 offset %= 8;111 reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;112 113 ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0);114 if (ret < 0)115 dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg,116 ret);117 return ret;118}119 120static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)121{122 struct palmas_gpio *pg = gpiochip_get_data(gc);123 struct palmas *palmas = pg->palmas;124 125 return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);126}127 128static const struct palmas_device_data palmas_dev_data = {129 .ngpio = 8,130};131 132static const struct palmas_device_data tps80036_dev_data = {133 .ngpio = 16,134};135 136static const struct of_device_id of_palmas_gpio_match[] = {137 { .compatible = "ti,palmas-gpio", .data = &palmas_dev_data,},138 { .compatible = "ti,tps65913-gpio", .data = &palmas_dev_data,},139 { .compatible = "ti,tps65914-gpio", .data = &palmas_dev_data,},140 { .compatible = "ti,tps80036-gpio", .data = &tps80036_dev_data,},141 { },142};143 144static int palmas_gpio_probe(struct platform_device *pdev)145{146 struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);147 struct palmas_platform_data *palmas_pdata;148 struct palmas_gpio *palmas_gpio;149 int ret;150 const struct palmas_device_data *dev_data;151 152 dev_data = of_device_get_match_data(&pdev->dev);153 if (!dev_data)154 dev_data = &palmas_dev_data;155 156 palmas_gpio = devm_kzalloc(&pdev->dev,157 sizeof(*palmas_gpio), GFP_KERNEL);158 if (!palmas_gpio)159 return -ENOMEM;160 161 palmas_gpio->palmas = palmas;162 palmas_gpio->gpio_chip.owner = THIS_MODULE;163 palmas_gpio->gpio_chip.label = dev_name(&pdev->dev);164 palmas_gpio->gpio_chip.ngpio = dev_data->ngpio;165 palmas_gpio->gpio_chip.can_sleep = true;166 palmas_gpio->gpio_chip.direction_input = palmas_gpio_input;167 palmas_gpio->gpio_chip.direction_output = palmas_gpio_output;168 palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq;169 palmas_gpio->gpio_chip.set = palmas_gpio_set;170 palmas_gpio->gpio_chip.get = palmas_gpio_get;171 palmas_gpio->gpio_chip.parent = &pdev->dev;172 173 palmas_pdata = dev_get_platdata(palmas->dev);174 if (palmas_pdata && palmas_pdata->gpio_base)175 palmas_gpio->gpio_chip.base = palmas_pdata->gpio_base;176 else177 palmas_gpio->gpio_chip.base = -1;178 179 ret = devm_gpiochip_add_data(&pdev->dev, &palmas_gpio->gpio_chip,180 palmas_gpio);181 if (ret < 0) {182 dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);183 return ret;184 }185 186 return ret;187}188 189static struct platform_driver palmas_gpio_driver = {190 .driver.name = "palmas-gpio",191 .driver.of_match_table = of_palmas_gpio_match,192 .probe = palmas_gpio_probe,193};194 195static int __init palmas_gpio_init(void)196{197 return platform_driver_register(&palmas_gpio_driver);198}199subsys_initcall(palmas_gpio_init);200