1/*
2 *  STLS2F GPIO Support
3 *
4 *  Copyright (c) 2008 Richard Liu,  STMicroelectronics  <richard.liu@st.com>
5 *  Copyright (c) 2008-2010 Arnaud Patard <apatard@mandriva.com>
6 *
7 *  This program is free software; you can redistribute it and/or modify
8 *  it under the terms of the GNU General Public License as published by
9 *  the Free Software Foundation; either version 2 of the License, or
10 *  (at your option) any later version.
11 */
12
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/spinlock.h>
17#include <linux/err.h>
18#include <asm/types.h>
19#include <loongson.h>
20#include <linux/gpio.h>
21
22#define STLS2F_N_GPIO		4
23#define STLS2F_GPIO_IN_OFFSET	16
24
25static DEFINE_SPINLOCK(gpio_lock);
26
27int gpio_get_value(unsigned gpio)
28{
29	u32 val;
30	u32 mask;
31
32	if (gpio >= STLS2F_N_GPIO)
33		return __gpio_get_value(gpio);
34
35	mask = 1 << (gpio + STLS2F_GPIO_IN_OFFSET);
36	spin_lock(&gpio_lock);
37	val = LOONGSON_GPIODATA;
38	spin_unlock(&gpio_lock);
39
40	return ((val & mask) != 0);
41}
42EXPORT_SYMBOL(gpio_get_value);
43
44void gpio_set_value(unsigned gpio, int state)
45{
46	u32 val;
47	u32 mask;
48
49	if (gpio >= STLS2F_N_GPIO) {
50		__gpio_set_value(gpio, state);
51		return ;
52	}
53
54	mask = 1 << gpio;
55
56	spin_lock(&gpio_lock);
57	val = LOONGSON_GPIODATA;
58	if (state)
59		val |= mask;
60	else
61		val &= (~mask);
62	LOONGSON_GPIODATA = val;
63	spin_unlock(&gpio_lock);
64}
65EXPORT_SYMBOL(gpio_set_value);
66
67int gpio_cansleep(unsigned gpio)
68{
69	if (gpio < STLS2F_N_GPIO)
70		return 0;
71	else
72		return __gpio_cansleep(gpio);
73}
74EXPORT_SYMBOL(gpio_cansleep);
75
76static int ls2f_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
77{
78	u32 temp;
79	u32 mask;
80
81	if (gpio >= STLS2F_N_GPIO)
82		return -EINVAL;
83
84	spin_lock(&gpio_lock);
85	mask = 1 << gpio;
86	temp = LOONGSON_GPIOIE;
87	temp |= mask;
88	LOONGSON_GPIOIE = temp;
89	spin_unlock(&gpio_lock);
90
91	return 0;
92}
93
94static int ls2f_gpio_direction_output(struct gpio_chip *chip,
95		unsigned gpio, int level)
96{
97	u32 temp;
98	u32 mask;
99
100	if (gpio >= STLS2F_N_GPIO)
101		return -EINVAL;
102
103	gpio_set_value(gpio, level);
104	spin_lock(&gpio_lock);
105	mask = 1 << gpio;
106	temp = LOONGSON_GPIOIE;
107	temp &= (~mask);
108	LOONGSON_GPIOIE = temp;
109	spin_unlock(&gpio_lock);
110
111	return 0;
112}
113
114static int ls2f_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
115{
116	return gpio_get_value(gpio);
117}
118
119static void ls2f_gpio_set_value(struct gpio_chip *chip,
120		unsigned gpio, int value)
121{
122	gpio_set_value(gpio, value);
123}
124
125static struct gpio_chip ls2f_chip = {
126	.label                  = "ls2f",
127	.direction_input        = ls2f_gpio_direction_input,
128	.get                    = ls2f_gpio_get_value,
129	.direction_output       = ls2f_gpio_direction_output,
130	.set                    = ls2f_gpio_set_value,
131	.base                   = 0,
132	.ngpio                  = STLS2F_N_GPIO,
133};
134
135static int __init ls2f_gpio_setup(void)
136{
137	return gpiochip_add(&ls2f_chip);
138}
139arch_initcall(ls2f_gpio_setup);
140