172edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek/*
272edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek * arch/arm/plat-iop/gpio.c
372edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek * GPIO handling for Intel IOP3xx processors.
472edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek *
572edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
672edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek *
772edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek * This program is free software; you can redistribute it and/or modify
872edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek * it under the terms of the GNU General Public License as published by
972edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek * the Free Software Foundation; either version 2 of the License, or (at
1072edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek * your option) any later version.
1172edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek */
1272edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek
1372edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek#include <linux/device.h>
1463f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard#include <linux/init.h>
1563f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard#include <linux/types.h>
1663f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard#include <linux/errno.h>
1763f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard#include <linux/gpio.h>
18dc28094b905a872f8884f1f1c48ca86b3b78583aPaul Gortmaker#include <linux/export.h>
197b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij#include <linux/platform_device.h>
20e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij#include <linux/bitops.h>
21e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij#include <linux/io.h>
22f6ffa5ee039cd0168d82e3edd712ebbb1de93a00Linus Walleij
23f6ffa5ee039cd0168d82e3edd712ebbb1de93a00Linus Walleij#define IOP3XX_N_GPIOS	8
2472edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek
257b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij#define GPIO_IN			0
267b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij#define GPIO_OUT		1
277b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij#define GPIO_LOW		0
287b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij#define GPIO_HIGH		1
297b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij
307b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij/* Memory base offset */
317b85b867b99044da93f83851c806d1e324d49ed5Linus Walleijstatic void __iomem *base;
327b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij
337b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij#define IOP3XX_GPIO_REG(reg)	(base + (reg))
34e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij#define IOP3XX_GPOE		IOP3XX_GPIO_REG(0x0000)
35e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij#define IOP3XX_GPID		IOP3XX_GPIO_REG(0x0004)
36e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij#define IOP3XX_GPOD		IOP3XX_GPIO_REG(0x0008)
377b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij
3851a97d829e32b7a1b960d3365e4c2546c9c792aaLinus Walleijstatic void gpio_line_config(int line, int direction)
3972edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek{
4072edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek	unsigned long flags;
41e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij	u32 val;
4272edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek
4372edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek	local_irq_save(flags);
44e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij	val = readl(IOP3XX_GPOE);
4572edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek	if (direction == GPIO_IN) {
46e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij		val |= BIT(line);
4772edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek	} else if (direction == GPIO_OUT) {
48e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij		val &= ~BIT(line);
4972edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek	}
50e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij	writel(val, IOP3XX_GPOE);
5172edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek	local_irq_restore(flags);
5272edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek}
5372edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek
5451a97d829e32b7a1b960d3365e4c2546c9c792aaLinus Walleijstatic int gpio_line_get(int line)
5572edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek{
56e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij	return !!(readl(IOP3XX_GPID) & BIT(line));
5772edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek}
5872edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek
5951a97d829e32b7a1b960d3365e4c2546c9c792aaLinus Walleijstatic void gpio_line_set(int line, int value)
6072edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek{
6172edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek	unsigned long flags;
62e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij	u32 val;
6372edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek
6472edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek	local_irq_save(flags);
65e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij	val = readl(IOP3XX_GPOD);
6672edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek	if (value == GPIO_LOW) {
67e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij		val &= ~BIT(line);
6872edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek	} else if (value == GPIO_HIGH) {
69e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij		val |= BIT(line);
7072edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek	}
71e3f94b385748c10b735f392b69f39f33f02ca3a5Linus Walleij	writel(val, IOP3XX_GPOD);
7272edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek	local_irq_restore(flags);
7372edd84a6b2db1a21d1ed07929cae560e276a0a6Lennert Buytenhek}
7463f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard
7563f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patardstatic int iop3xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
7663f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard{
7763f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	gpio_line_config(gpio, GPIO_IN);
7863f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	return 0;
7963f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard}
8063f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard
8163f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patardstatic int iop3xx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int level)
8263f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard{
8363f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	gpio_line_set(gpio, level);
8463f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	gpio_line_config(gpio, GPIO_OUT);
8563f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	return 0;
8663f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard}
8763f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard
8863f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patardstatic int iop3xx_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
8963f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard{
9063f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	return gpio_line_get(gpio);
9163f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard}
9263f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard
9363f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patardstatic void iop3xx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
9463f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard{
9563f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	gpio_line_set(gpio, value);
9663f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard}
9763f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard
9863f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patardstatic struct gpio_chip iop3xx_chip = {
9963f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	.label			= "iop3xx",
10063f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	.direction_input	= iop3xx_gpio_direction_input,
10163f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	.get			= iop3xx_gpio_get_value,
10263f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	.direction_output	= iop3xx_gpio_direction_output,
10363f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	.set			= iop3xx_gpio_set_value,
10463f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	.base			= 0,
10563f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	.ngpio			= IOP3XX_N_GPIOS,
10663f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard};
10763f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard
1087b85b867b99044da93f83851c806d1e324d49ed5Linus Walleijstatic int iop3xx_gpio_probe(struct platform_device *pdev)
10963f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard{
1107b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij	struct resource *res;
1117b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij
1127b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
113e34ca9de0b3575fc7e94b1f520169fc7024c6dd2Linus Walleij	base = devm_ioremap_resource(&pdev->dev, res);
114138d876e30353da34495e463d20c9bd7c0fd4ba0Bartlomiej Zolnierkiewicz	if (IS_ERR(base))
115138d876e30353da34495e463d20c9bd7c0fd4ba0Bartlomiej Zolnierkiewicz		return PTR_ERR(base);
1167b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij
11763f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard	return gpiochip_add(&iop3xx_chip);
11863f385cd1f649b3f4f2d59fc609e051981215fd7Arnaud Patard}
1197b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij
1207b85b867b99044da93f83851c806d1e324d49ed5Linus Walleijstatic struct platform_driver iop3xx_gpio_driver = {
1217b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij	.driver = {
1227b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij		.name = "gpio-iop",
1237b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij		.owner = THIS_MODULE,
1247b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij	},
1257b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij	.probe = iop3xx_gpio_probe,
1267b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij};
1277b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij
1287b85b867b99044da93f83851c806d1e324d49ed5Linus Walleijstatic int __init iop3xx_gpio_init(void)
1297b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij{
1307b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij	return platform_driver_register(&iop3xx_gpio_driver);
1317b85b867b99044da93f83851c806d1e324d49ed5Linus Walleij}
1327b85b867b99044da93f83851c806d1e324d49ed5Linus Walleijarch_initcall(iop3xx_gpio_init);
133