summaryrefslogtreecommitdiff
path: root/arch/arm/mach-ns9xxx/gpio.c
blob: 5503ca09c4aee4a1d2dc8e5a249ddb6e9c31814a (plain) (blame)
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * arch/arm/mach-ns9xxx/gpio.c
 *
 * Copyright (C) 2006,2007 by Digi International Inc.
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 */
#include <linux/kernel.h>
#include <linux/compiler.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/bitops.h>

#include <mach/gpio.h>
#include <mach/processor.h>
#include <mach/processor-ns9360.h>
#include <asm/bug.h>
#include <asm/types.h>

#include "gpio-ns9360.h"

#if defined(CONFIG_PROCESSOR_NS9360)
#define GPIO_MAX 72
#elif defined(CONFIG_PROCESSOR_NS9750)
#define GPIO_MAX 49
#endif

/* protects BBU_GCONFx and BBU_GCTRLx */
static spinlock_t gpio_lock = __SPIN_LOCK_UNLOCKED(gpio_lock);

/* only access gpiores with atomic ops */
static DECLARE_BITMAP(gpiores, GPIO_MAX + 1);

static inline int ns9xxx_valid_gpio(unsigned gpio)
{
#if defined(CONFIG_PROCESSOR_NS9360)
	if (processor_is_ns9360())
		return gpio <= 72;
	else
#endif
#if defined(CONFIG_PROCESSOR_NS9750)
	if (processor_is_ns9750())
		return gpio <= 49;
	else
#endif
	{
		BUG();
		return 0;
	}
}

int gpio_request(unsigned gpio, const char *label)
{
	if (likely(ns9xxx_valid_gpio(gpio)))
		return test_and_set_bit(gpio, gpiores) ? -EBUSY : 0;
	else
		return -EINVAL;
}
EXPORT_SYMBOL(gpio_request);

void gpio_free(unsigned gpio)
{
	might_sleep();
	clear_bit(gpio, gpiores);
	return;
}
EXPORT_SYMBOL(gpio_free);

int gpio_direction_input(unsigned gpio)
{
	if (likely(ns9xxx_valid_gpio(gpio))) {
		int ret = -EINVAL;
		unsigned long flags;

		spin_lock_irqsave(&gpio_lock, flags);
#if defined(CONFIG_PROCESSOR_NS9360)
		if (processor_is_ns9360())
			ret = __ns9360_gpio_configure(gpio, 0, 0, 3);
		else
#endif
			BUG();

		spin_unlock_irqrestore(&gpio_lock, flags);

		return ret;

	} else
		return -EINVAL;
}
EXPORT_SYMBOL(gpio_direction_input);

int gpio_direction_output(unsigned gpio, int value)
{
	if (likely(ns9xxx_valid_gpio(gpio))) {
		int ret = -EINVAL;
		unsigned long flags;

		gpio_set_value(gpio, value);

		spin_lock_irqsave(&gpio_lock, flags);
#if defined(CONFIG_PROCESSOR_NS9360)
		if (processor_is_ns9360())
			ret = __ns9360_gpio_configure(gpio, 1, 0, 3);
		else
#endif
			BUG();

		spin_unlock_irqrestore(&gpio_lock, flags);

		return ret;
	} else
		return -EINVAL;
}
EXPORT_SYMBOL(gpio_direction_output);

int gpio_get_value(unsigned gpio)
{
#if defined(CONFIG_PROCESSOR_NS9360)
	if (processor_is_ns9360())
		return ns9360_gpio_get_value(gpio);
	else
#endif
	{
		BUG();
		return -EINVAL;
	}
}
EXPORT_SYMBOL(gpio_get_value);

void gpio_set_value(unsigned gpio, int value)
{
	unsigned long flags;
	spin_lock_irqsave(&gpio_lock, flags);
#if defined(CONFIG_PROCESSOR_NS9360)
	if (processor_is_ns9360())
		ns9360_gpio_set_value(gpio, value);
	else
#endif
		BUG();

	spin_unlock_irqrestore(&gpio_lock, flags);
}
EXPORT_SYMBOL(gpio_set_value);