summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-iop.c
blob: fb65e5850e0c1f67a31b00a678fb1a4b35ccf3de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * arch/arm/plat-iop/gpio.c
 * GPIO handling for Intel IOP3xx processors.
 *
 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 */

#include <linux/device.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/export.h>
#include <linux/platform_device.h>
#include <linux/bitops.h>
#include <linux/io.h>

#define IOP3XX_N_GPIOS	8

#define GPIO_IN			0
#define GPIO_OUT		1
#define GPIO_LOW		0
#define GPIO_HIGH		1

/* Memory base offset */
static void __iomem *base;

#define IOP3XX_GPIO_REG(reg)	(base + (reg))
#define IOP3XX_GPOE		IOP3XX_GPIO_REG(0x0000)
#define IOP3XX_GPID		IOP3XX_GPIO_REG(0x0004)
#define IOP3XX_GPOD		IOP3XX_GPIO_REG(0x0008)

static void gpio_line_config(int line, int direction)
{
	unsigned long flags;
	u32 val;

	local_irq_save(flags);
	val = readl(IOP3XX_GPOE);
	if (direction == GPIO_IN) {
		val |= BIT(line);
	} else if (direction == GPIO_OUT) {
		val &= ~BIT(line);
	}
	writel(val, IOP3XX_GPOE);
	local_irq_restore(flags);
}

static int gpio_line_get(int line)
{
	return !!(readl(IOP3XX_GPID) & BIT(line));
}

static void gpio_line_set(int line, int value)
{
	unsigned long flags;
	u32 val;

	local_irq_save(flags);
	val = readl(IOP3XX_GPOD);
	if (value == GPIO_LOW) {
		val &= ~BIT(line);
	} else if (value == GPIO_HIGH) {
		val |= BIT(line);
	}
	writel(val, IOP3XX_GPOD);
	local_irq_restore(flags);
}

static int iop3xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
	gpio_line_config(gpio, GPIO_IN);
	return 0;
}

static int iop3xx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int level)
{
	gpio_line_set(gpio, level);
	gpio_line_config(gpio, GPIO_OUT);
	return 0;
}

static int iop3xx_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{
	return gpio_line_get(gpio);
}

static void iop3xx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
{
	gpio_line_set(gpio, value);
}

static struct gpio_chip iop3xx_chip = {
	.label			= "iop3xx",
	.direction_input	= iop3xx_gpio_direction_input,
	.get			= iop3xx_gpio_get_value,
	.direction_output	= iop3xx_gpio_direction_output,
	.set			= iop3xx_gpio_set_value,
	.base			= 0,
	.ngpio			= IOP3XX_N_GPIOS,
};

static int iop3xx_gpio_probe(struct platform_device *pdev)
{
	struct resource *res;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(base))
		return PTR_ERR(base);

	return gpiochip_add_data(&iop3xx_chip, NULL);
}

static struct platform_driver iop3xx_gpio_driver = {
	.driver = {
		.name = "gpio-iop",
	},
	.probe = iop3xx_gpio_probe,
};

static int __init iop3xx_gpio_init(void)
{
	return platform_driver_register(&iop3xx_gpio_driver);
}
arch_initcall(iop3xx_gpio_init);