18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * TI/National Semiconductor LP3943 GPIO driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2013 Texas Instruments 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Milo Kim <milo.kim@ti.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/bitops.h> 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 138c2ecf20Sopenharmony_ci#include <linux/i2c.h> 148c2ecf20Sopenharmony_ci#include <linux/mfd/lp3943.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cienum lp3943_gpios { 208c2ecf20Sopenharmony_ci LP3943_GPIO1, 218c2ecf20Sopenharmony_ci LP3943_GPIO2, 228c2ecf20Sopenharmony_ci LP3943_GPIO3, 238c2ecf20Sopenharmony_ci LP3943_GPIO4, 248c2ecf20Sopenharmony_ci LP3943_GPIO5, 258c2ecf20Sopenharmony_ci LP3943_GPIO6, 268c2ecf20Sopenharmony_ci LP3943_GPIO7, 278c2ecf20Sopenharmony_ci LP3943_GPIO8, 288c2ecf20Sopenharmony_ci LP3943_GPIO9, 298c2ecf20Sopenharmony_ci LP3943_GPIO10, 308c2ecf20Sopenharmony_ci LP3943_GPIO11, 318c2ecf20Sopenharmony_ci LP3943_GPIO12, 328c2ecf20Sopenharmony_ci LP3943_GPIO13, 338c2ecf20Sopenharmony_ci LP3943_GPIO14, 348c2ecf20Sopenharmony_ci LP3943_GPIO15, 358c2ecf20Sopenharmony_ci LP3943_GPIO16, 368c2ecf20Sopenharmony_ci LP3943_MAX_GPIO, 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct lp3943_gpio { 408c2ecf20Sopenharmony_ci struct gpio_chip chip; 418c2ecf20Sopenharmony_ci struct lp3943 *lp3943; 428c2ecf20Sopenharmony_ci u16 input_mask; /* 1 = GPIO is input direction, 0 = output */ 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); 488c2ecf20Sopenharmony_ci struct lp3943 *lp3943 = lp3943_gpio->lp3943; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* Return an error if the pin is already assigned */ 518c2ecf20Sopenharmony_ci if (test_and_set_bit(offset, &lp3943->pin_used)) 528c2ecf20Sopenharmony_ci return -EBUSY; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return 0; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void lp3943_gpio_free(struct gpio_chip *chip, unsigned offset) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); 608c2ecf20Sopenharmony_ci struct lp3943 *lp3943 = lp3943_gpio->lp3943; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci clear_bit(offset, &lp3943->pin_used); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int lp3943_gpio_set_mode(struct lp3943_gpio *lp3943_gpio, u8 offset, 668c2ecf20Sopenharmony_ci u8 val) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct lp3943 *lp3943 = lp3943_gpio->lp3943; 698c2ecf20Sopenharmony_ci const struct lp3943_reg_cfg *mux = lp3943->mux_cfg; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return lp3943_update_bits(lp3943, mux[offset].reg, mux[offset].mask, 728c2ecf20Sopenharmony_ci val << mux[offset].shift); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci lp3943_gpio->input_mask |= BIT(offset); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return lp3943_gpio_set_mode(lp3943_gpio, offset, LP3943_GPIO_IN); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int lp3943_get_gpio_in_status(struct lp3943_gpio *lp3943_gpio, 858c2ecf20Sopenharmony_ci struct gpio_chip *chip, unsigned offset) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci u8 addr, read; 888c2ecf20Sopenharmony_ci int err; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci switch (offset) { 918c2ecf20Sopenharmony_ci case LP3943_GPIO1 ... LP3943_GPIO8: 928c2ecf20Sopenharmony_ci addr = LP3943_REG_GPIO_A; 938c2ecf20Sopenharmony_ci break; 948c2ecf20Sopenharmony_ci case LP3943_GPIO9 ... LP3943_GPIO16: 958c2ecf20Sopenharmony_ci addr = LP3943_REG_GPIO_B; 968c2ecf20Sopenharmony_ci offset = offset - 8; 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci default: 998c2ecf20Sopenharmony_ci return -EINVAL; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci err = lp3943_read_byte(lp3943_gpio->lp3943, addr, &read); 1038c2ecf20Sopenharmony_ci if (err) 1048c2ecf20Sopenharmony_ci return err; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return !!(read & BIT(offset)); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int lp3943_get_gpio_out_status(struct lp3943_gpio *lp3943_gpio, 1108c2ecf20Sopenharmony_ci struct gpio_chip *chip, unsigned offset) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct lp3943 *lp3943 = lp3943_gpio->lp3943; 1138c2ecf20Sopenharmony_ci const struct lp3943_reg_cfg *mux = lp3943->mux_cfg; 1148c2ecf20Sopenharmony_ci u8 read; 1158c2ecf20Sopenharmony_ci int err; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci err = lp3943_read_byte(lp3943, mux[offset].reg, &read); 1188c2ecf20Sopenharmony_ci if (err) 1198c2ecf20Sopenharmony_ci return err; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci read = (read & mux[offset].mask) >> mux[offset].shift; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (read == LP3943_GPIO_OUT_HIGH) 1248c2ecf20Sopenharmony_ci return 1; 1258c2ecf20Sopenharmony_ci else if (read == LP3943_GPIO_OUT_LOW) 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci else 1288c2ecf20Sopenharmony_ci return -EINVAL; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* 1368c2ecf20Sopenharmony_ci * Limitation: 1378c2ecf20Sopenharmony_ci * LP3943 doesn't have the GPIO direction register. It provides 1388c2ecf20Sopenharmony_ci * only input and output status registers. 1398c2ecf20Sopenharmony_ci * So, direction info is required to handle the 'get' operation. 1408c2ecf20Sopenharmony_ci * This variable is updated whenever the direction is changed and 1418c2ecf20Sopenharmony_ci * it is used here. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (lp3943_gpio->input_mask & BIT(offset)) 1458c2ecf20Sopenharmony_ci return lp3943_get_gpio_in_status(lp3943_gpio, chip, offset); 1468c2ecf20Sopenharmony_ci else 1478c2ecf20Sopenharmony_ci return lp3943_get_gpio_out_status(lp3943_gpio, chip, offset); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); 1538c2ecf20Sopenharmony_ci u8 data; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (value) 1568c2ecf20Sopenharmony_ci data = LP3943_GPIO_OUT_HIGH; 1578c2ecf20Sopenharmony_ci else 1588c2ecf20Sopenharmony_ci data = LP3943_GPIO_OUT_LOW; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci lp3943_gpio_set_mode(lp3943_gpio, offset, data); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int lp3943_gpio_direction_output(struct gpio_chip *chip, unsigned offset, 1648c2ecf20Sopenharmony_ci int value) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci lp3943_gpio_set(chip, offset, value); 1698c2ecf20Sopenharmony_ci lp3943_gpio->input_mask &= ~BIT(offset); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci return 0; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic const struct gpio_chip lp3943_gpio_chip = { 1758c2ecf20Sopenharmony_ci .label = "lp3943", 1768c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1778c2ecf20Sopenharmony_ci .request = lp3943_gpio_request, 1788c2ecf20Sopenharmony_ci .free = lp3943_gpio_free, 1798c2ecf20Sopenharmony_ci .direction_input = lp3943_gpio_direction_input, 1808c2ecf20Sopenharmony_ci .get = lp3943_gpio_get, 1818c2ecf20Sopenharmony_ci .direction_output = lp3943_gpio_direction_output, 1828c2ecf20Sopenharmony_ci .set = lp3943_gpio_set, 1838c2ecf20Sopenharmony_ci .base = -1, 1848c2ecf20Sopenharmony_ci .ngpio = LP3943_MAX_GPIO, 1858c2ecf20Sopenharmony_ci .can_sleep = 1, 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int lp3943_gpio_probe(struct platform_device *pdev) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct lp3943 *lp3943 = dev_get_drvdata(pdev->dev.parent); 1918c2ecf20Sopenharmony_ci struct lp3943_gpio *lp3943_gpio; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci lp3943_gpio = devm_kzalloc(&pdev->dev, sizeof(*lp3943_gpio), 1948c2ecf20Sopenharmony_ci GFP_KERNEL); 1958c2ecf20Sopenharmony_ci if (!lp3943_gpio) 1968c2ecf20Sopenharmony_ci return -ENOMEM; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci lp3943_gpio->lp3943 = lp3943; 1998c2ecf20Sopenharmony_ci lp3943_gpio->chip = lp3943_gpio_chip; 2008c2ecf20Sopenharmony_ci lp3943_gpio->chip.parent = &pdev->dev; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, lp3943_gpio); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return devm_gpiochip_add_data(&pdev->dev, &lp3943_gpio->chip, 2058c2ecf20Sopenharmony_ci lp3943_gpio); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic const struct of_device_id lp3943_gpio_of_match[] = { 2098c2ecf20Sopenharmony_ci { .compatible = "ti,lp3943-gpio", }, 2108c2ecf20Sopenharmony_ci { } 2118c2ecf20Sopenharmony_ci}; 2128c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, lp3943_gpio_of_match); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic struct platform_driver lp3943_gpio_driver = { 2158c2ecf20Sopenharmony_ci .probe = lp3943_gpio_probe, 2168c2ecf20Sopenharmony_ci .driver = { 2178c2ecf20Sopenharmony_ci .name = "lp3943-gpio", 2188c2ecf20Sopenharmony_ci .of_match_table = lp3943_gpio_of_match, 2198c2ecf20Sopenharmony_ci }, 2208c2ecf20Sopenharmony_ci}; 2218c2ecf20Sopenharmony_cimodule_platform_driver(lp3943_gpio_driver); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LP3943 GPIO driver"); 2248c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:lp3943-gpio"); 2258c2ecf20Sopenharmony_ciMODULE_AUTHOR("Milo Kim"); 2268c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 227