gpio-wm8350.c 3.89 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0+
2
/*
Grant Likely's avatar
Grant Likely committed
3
 * gpiolib support for Wolfson WM835x PMICs
4 5 6 7 8 9 10 11
 *
 * Copyright 2009 Wolfson Microelectronics PLC.
 *
 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
 *
 */

#include <linux/kernel.h>
12
#include <linux/slab.h>
13
#include <linux/module.h>
14
#include <linux/gpio/driver.h>
15 16 17 18 19 20 21 22 23 24 25 26 27 28
#include <linux/mfd/core.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>

#include <linux/mfd/wm8350/core.h>
#include <linux/mfd/wm8350/gpio.h>

struct wm8350_gpio_data {
	struct wm8350 *wm8350;
	struct gpio_chip gpio_chip;
};

static int wm8350_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
29
	struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
30 31 32 33 34 35 36 37
	struct wm8350 *wm8350 = wm8350_gpio->wm8350;

	return wm8350_set_bits(wm8350, WM8350_GPIO_CONFIGURATION_I_O,
			       1 << offset);
}

static int wm8350_gpio_get(struct gpio_chip *chip, unsigned offset)
{
38
	struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
	struct wm8350 *wm8350 = wm8350_gpio->wm8350;
	int ret;

	ret = wm8350_reg_read(wm8350, WM8350_GPIO_LEVEL);
	if (ret < 0)
		return ret;

	if (ret & (1 << offset))
		return 1;
	else
		return 0;
}

static void wm8350_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
54
	struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
55 56 57 58 59 60 61 62 63 64 65
	struct wm8350 *wm8350 = wm8350_gpio->wm8350;

	if (value)
		wm8350_set_bits(wm8350, WM8350_GPIO_LEVEL, 1 << offset);
	else
		wm8350_clear_bits(wm8350, WM8350_GPIO_LEVEL, 1 << offset);
}

static int wm8350_gpio_direction_out(struct gpio_chip *chip,
				     unsigned offset, int value)
{
66
	struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
	struct wm8350 *wm8350 = wm8350_gpio->wm8350;
	int ret;

	ret = wm8350_clear_bits(wm8350, WM8350_GPIO_CONFIGURATION_I_O,
				1 << offset);
	if (ret < 0)
		return ret;

	/* Don't have an atomic direction/value setup */
	wm8350_gpio_set(chip, offset, value);

	return 0;
}

static int wm8350_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
83
	struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
84 85 86 87 88 89 90 91
	struct wm8350 *wm8350 = wm8350_gpio->wm8350;

	if (!wm8350->irq_base)
		return -EINVAL;

	return wm8350->irq_base + WM8350_IRQ_GPIO(offset);
}

92
static const struct gpio_chip template_chip = {
93 94 95 96 97 98 99
	.label			= "wm8350",
	.owner			= THIS_MODULE,
	.direction_input	= wm8350_gpio_direction_in,
	.get			= wm8350_gpio_get,
	.direction_output	= wm8350_gpio_direction_out,
	.set			= wm8350_gpio_set,
	.to_irq			= wm8350_gpio_to_irq,
100
	.can_sleep		= true,
101 102
};

103
static int wm8350_gpio_probe(struct platform_device *pdev)
104 105
{
	struct wm8350 *wm8350 = dev_get_drvdata(pdev->dev.parent);
106
	struct wm8350_platform_data *pdata = dev_get_platdata(wm8350->dev);
107 108 109
	struct wm8350_gpio_data *wm8350_gpio;
	int ret;

110 111
	wm8350_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm8350_gpio),
				   GFP_KERNEL);
112 113 114 115 116 117
	if (wm8350_gpio == NULL)
		return -ENOMEM;

	wm8350_gpio->wm8350 = wm8350;
	wm8350_gpio->gpio_chip = template_chip;
	wm8350_gpio->gpio_chip.ngpio = 13;
118
	wm8350_gpio->gpio_chip.parent = &pdev->dev;
119 120 121 122 123
	if (pdata && pdata->gpio_base)
		wm8350_gpio->gpio_chip.base = pdata->gpio_base;
	else
		wm8350_gpio->gpio_chip.base = -1;

124 125
	ret = devm_gpiochip_add_data(&pdev->dev, &wm8350_gpio->gpio_chip,
				     wm8350_gpio);
126
	if (ret < 0) {
127 128
		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
		return ret;
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
	}

	platform_set_drvdata(pdev, wm8350_gpio);

	return ret;
}

static struct platform_driver wm8350_gpio_driver = {
	.driver.name	= "wm8350-gpio",
	.probe		= wm8350_gpio_probe,
};

static int __init wm8350_gpio_init(void)
{
	return platform_driver_register(&wm8350_gpio_driver);
}
subsys_initcall(wm8350_gpio_init);

static void __exit wm8350_gpio_exit(void)
{
	platform_driver_unregister(&wm8350_gpio_driver);
}
module_exit(wm8350_gpio_exit);

MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("GPIO interface for WM8350 PMICs");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:wm8350-gpio");