155682Smarkm// SPDX-License-Identifier: GPL-2.0+ 2233294Sstas/* 3233294Sstas * gpiolib support for Wolfson WM835x PMICs 4233294Sstas * 555682Smarkm * Copyright 2009 Wolfson Microelectronics PLC. 6233294Sstas * 755682Smarkm * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 8233294Sstas * 9233294Sstas */ 10233294Sstas 1155682Smarkm#include <linux/gpio/driver.h> 12233294Sstas#include <linux/kernel.h> 13233294Sstas#include <linux/mfd/core.h> 1455682Smarkm#include <linux/module.h> 15233294Sstas#include <linux/platform_device.h> 16233294Sstas#include <linux/slab.h> 17233294Sstas 1855682Smarkm#include <linux/mfd/wm8350/core.h> 19233294Sstas#include <linux/mfd/wm8350/gpio.h> 20233294Sstas 21233294Sstasstruct wm8350_gpio_data { 22233294Sstas struct wm8350 *wm8350; 23233294Sstas struct gpio_chip gpio_chip; 24233294Sstas}; 25233294Sstas 26233294Sstasstatic int wm8350_gpio_direction_in(struct gpio_chip *chip, unsigned offset) 27233294Sstas{ 28233294Sstas struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip); 29233294Sstas struct wm8350 *wm8350 = wm8350_gpio->wm8350; 30233294Sstas 31233294Sstas return wm8350_set_bits(wm8350, WM8350_GPIO_CONFIGURATION_I_O, 32233294Sstas 1 << offset); 33233294Sstas} 3455682Smarkm 3555682Smarkmstatic int wm8350_gpio_get(struct gpio_chip *chip, unsigned offset) 3655682Smarkm{ 37233294Sstas struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip); 38102644Snectar struct wm8350 *wm8350 = wm8350_gpio->wm8350; 3955682Smarkm int ret; 4055682Smarkm 4155682Smarkm ret = wm8350_reg_read(wm8350, WM8350_GPIO_LEVEL); 4255682Smarkm if (ret < 0) 4355682Smarkm return ret; 44178825Sdfr 45178825Sdfr if (ret & (1 << offset)) 46178825Sdfr return 1; 47178825Sdfr else 48178825Sdfr return 0; 49178825Sdfr} 50178825Sdfr 5155682Smarkmstatic void wm8350_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 5255682Smarkm{ 5355682Smarkm struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip); 5455682Smarkm struct wm8350 *wm8350 = wm8350_gpio->wm8350; 5555682Smarkm 5655682Smarkm if (value) 5755682Smarkm wm8350_set_bits(wm8350, WM8350_GPIO_LEVEL, 1 << offset); 5855682Smarkm else 5955682Smarkm wm8350_clear_bits(wm8350, WM8350_GPIO_LEVEL, 1 << offset); 6055682Smarkm} 6155682Smarkm 62102644Snectarstatic int wm8350_gpio_direction_out(struct gpio_chip *chip, 6355682Smarkm unsigned offset, int value) 64233294Sstas{ 6555682Smarkm struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip); 6655682Smarkm struct wm8350 *wm8350 = wm8350_gpio->wm8350; 6755682Smarkm int ret; 6855682Smarkm 6955682Smarkm ret = wm8350_clear_bits(wm8350, WM8350_GPIO_CONFIGURATION_I_O, 7055682Smarkm 1 << offset); 7155682Smarkm if (ret < 0) 72233294Sstas return ret; 7355682Smarkm 7455682Smarkm /* Don't have an atomic direction/value setup */ 7555682Smarkm wm8350_gpio_set(chip, offset, value); 76178825Sdfr 77178825Sdfr return 0; 78178825Sdfr} 79178825Sdfr 80178825Sdfrstatic int wm8350_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 81178825Sdfr{ 8255682Smarkm struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip); 8355682Smarkm struct wm8350 *wm8350 = wm8350_gpio->wm8350; 8455682Smarkm 85233294Sstas if (!wm8350->irq_base) 86102644Snectar return -EINVAL; 8755682Smarkm 8855682Smarkm return wm8350->irq_base + WM8350_IRQ_GPIO(offset); 8955682Smarkm} 9055682Smarkm 9155682Smarkmstatic const struct gpio_chip template_chip = { 9255682Smarkm .label = "wm8350", 9355682Smarkm .owner = THIS_MODULE, 9455682Smarkm .direction_input = wm8350_gpio_direction_in, 9555682Smarkm .get = wm8350_gpio_get, 9655682Smarkm .direction_output = wm8350_gpio_direction_out, 9790926Snectar .set = wm8350_gpio_set, 9855682Smarkm .to_irq = wm8350_gpio_to_irq, 99233294Sstas .can_sleep = true, 100102644Snectar}; 10190926Snectar 10255682Smarkmstatic int wm8350_gpio_probe(struct platform_device *pdev) 10355682Smarkm{ 10455682Smarkm struct wm8350 *wm8350 = dev_get_drvdata(pdev->dev.parent); 10555682Smarkm struct wm8350_platform_data *pdata = dev_get_platdata(wm8350->dev); 10672445Sassar struct wm8350_gpio_data *wm8350_gpio; 107233294Sstas 108233294Sstas wm8350_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm8350_gpio), 109233294Sstas GFP_KERNEL); 110233294Sstas if (wm8350_gpio == NULL) 111233294Sstas return -ENOMEM; 112233294Sstas 113233294Sstas wm8350_gpio->wm8350 = wm8350; 114233294Sstas wm8350_gpio->gpio_chip = template_chip; 115233294Sstas wm8350_gpio->gpio_chip.ngpio = 13; 116233294Sstas wm8350_gpio->gpio_chip.parent = &pdev->dev; 117233294Sstas if (pdata && pdata->gpio_base) 118233294Sstas wm8350_gpio->gpio_chip.base = pdata->gpio_base; 119233294Sstas else 120102644Snectar wm8350_gpio->gpio_chip.base = -1; 121102644Snectar 122102644Snectar return devm_gpiochip_add_data(&pdev->dev, &wm8350_gpio->gpio_chip, wm8350_gpio); 123102644Snectar} 124102644Snectar 125233294Sstasstatic struct platform_driver wm8350_gpio_driver = { 126102644Snectar .driver.name = "wm8350-gpio", 127102644Snectar .probe = wm8350_gpio_probe, 128102644Snectar}; 129102644Snectar 130102644Snectarstatic int __init wm8350_gpio_init(void) 13155682Smarkm{ 132233294Sstas return platform_driver_register(&wm8350_gpio_driver); 133233294Sstas} 134233294Sstassubsys_initcall(wm8350_gpio_init); 135233294Sstas 136233294Sstasstatic void __exit wm8350_gpio_exit(void) 137233294Sstas{ 138233294Sstas platform_driver_unregister(&wm8350_gpio_driver); 139233294Sstas} 140233294Sstasmodule_exit(wm8350_gpio_exit); 141233294Sstas 142233294SstasMODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 143233294SstasMODULE_DESCRIPTION("GPIO interface for WM8350 PMICs"); 144233294SstasMODULE_LICENSE("GPL"); 145233294SstasMODULE_ALIAS("platform:wm8350-gpio"); 146233294Sstas