aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorJonathan Corbet <corbet@lwn.net>2009-12-01 22:39:57 -0500
committerJonathan Corbet <corbet@lwn.net>2010-05-07 19:16:02 -0400
commit7e0de022680f7899d33141f3ab5724a704f5669a (patch)
tree237054ee8d0676b9a327f0e3cdd1a6773cb3eb2d /drivers/video
parent24b4d82e4715841848a499534ed5cb7db3d6bca3 (diff)
viafb: add a driver for GPIO lines
This is a simple gpiolib driver giving access to the GPIO lines in the VIA framebuffer system. A simple mechanism exists for switching lines between GPIO and I2C, but it's only compile-time for now. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte <laforge@gnumonks.org> Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de> Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/via/Makefile5
-rw-r--r--drivers/video/via/via-core.c7
-rw-r--r--drivers/video/via/via-gpio.c268
-rw-r--r--drivers/video/via/via-gpio.h15
5 files changed, 296 insertions, 1 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6e16244f3ed1..22c1662de964 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1511,6 +1511,7 @@ config FB_VIA
1511 select FB_CFB_IMAGEBLIT 1511 select FB_CFB_IMAGEBLIT
1512 select I2C_ALGOBIT 1512 select I2C_ALGOBIT
1513 select I2C 1513 select I2C
1514 select GPIOLIB
1514 help 1515 help
1515 This is the frame buffer device driver for Graphics chips of VIA 1516 This is the frame buffer device driver for Graphics chips of VIA
1516 UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/ 1517 UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/
@@ -1520,6 +1521,7 @@ config FB_VIA
1520 1521
1521 To compile this driver as a module, choose M here: the 1522 To compile this driver as a module, choose M here: the
1522 module will be called viafb. 1523 module will be called viafb.
1524
1523config FB_NEOMAGIC 1525config FB_NEOMAGIC
1524 tristate "NeoMagic display support" 1526 tristate "NeoMagic display support"
1525 depends on FB && PCI 1527 depends on FB && PCI
diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile
index aec3f8b24a96..8c42a42c3dbb 100644
--- a/drivers/video/via/Makefile
+++ b/drivers/video/via/Makefile
@@ -4,4 +4,7 @@
4 4
5obj-$(CONFIG_FB_VIA) += viafb.o 5obj-$(CONFIG_FB_VIA) += viafb.o
6 6
7viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o via-core.o 7viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o \
8 via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o \
9 via-core.o via-gpio.o
10
diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
index b77cd5c2fc96..806237e8b4a4 100644
--- a/drivers/video/via/via-core.c
+++ b/drivers/video/via/via-core.c
@@ -9,6 +9,7 @@
9 */ 9 */
10#include "via-core.h" 10#include "via-core.h"
11#include "via_i2c.h" 11#include "via_i2c.h"
12#include "via-gpio.h"
12#include "global.h" 13#include "global.h"
13 14
14#include <linux/module.h> 15#include <linux/module.h>
@@ -221,6 +222,11 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
221 ret = via_fb_pci_probe(&global_dev); 222 ret = via_fb_pci_probe(&global_dev);
222 if (ret) 223 if (ret)
223 goto out_i2c; 224 goto out_i2c;
225 /*
226 * Create the GPIOs. We continue whether or not this succeeds;
227 * the framebuffer might be useful even without GPIO ports.
228 */
229 ret = viafb_create_gpios(&global_dev, adap_configs);
224 return 0; 230 return 0;
225 231
226out_i2c: 232out_i2c:
@@ -234,6 +240,7 @@ out_disable:
234 240
235static void __devexit via_pci_remove(struct pci_dev *pdev) 241static void __devexit via_pci_remove(struct pci_dev *pdev)
236{ 242{
243 viafb_destroy_gpios();
237 viafb_delete_i2c_busses(); 244 viafb_delete_i2c_busses();
238 via_fb_pci_remove(pdev); 245 via_fb_pci_remove(pdev);
239 via_pci_teardown_mmio(&global_dev); 246 via_pci_teardown_mmio(&global_dev);
diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c
new file mode 100644
index 000000000000..e119d2103730
--- /dev/null
+++ b/drivers/video/via/via-gpio.c
@@ -0,0 +1,268 @@
1/*
2 * Support for viafb GPIO ports.
3 *
4 * Copyright 2009 Jonathan Corbet <corbet@lwn.net>
5 * Distributable under version 2 of the GNU General Public License.
6 */
7
8#include <linux/spinlock.h>
9#include <linux/gpio.h>
10#include "via-core.h"
11#include "via-gpio.h"
12#include "global.h"
13
14/*
15 * The ports we know about. Note that the port-25 gpios are not
16 * mentioned in the datasheet.
17 */
18
19struct viafb_gpio {
20 char *vg_name; /* Data sheet name */
21 u16 vg_io_port;
22 u8 vg_port_index;
23 int vg_mask_shift;
24};
25
26static struct viafb_gpio viafb_all_gpios[] = {
27 {
28 .vg_name = "VGPIO0", /* Guess - not in datasheet */
29 .vg_io_port = VIASR,
30 .vg_port_index = 0x25,
31 .vg_mask_shift = 1
32 },
33 {
34 .vg_name = "VGPIO1",
35 .vg_io_port = VIASR,
36 .vg_port_index = 0x25,
37 .vg_mask_shift = 0
38 },
39 {
40 .vg_name = "VGPIO2", /* aka DISPCLKI0 */
41 .vg_io_port = VIASR,
42 .vg_port_index = 0x2c,
43 .vg_mask_shift = 1
44 },
45 {
46 .vg_name = "VGPIO3", /* aka DISPCLKO0 */
47 .vg_io_port = VIASR,
48 .vg_port_index = 0x2c,
49 .vg_mask_shift = 0
50 },
51 {
52 .vg_name = "VGPIO4", /* DISPCLKI1 */
53 .vg_io_port = VIASR,
54 .vg_port_index = 0x3d,
55 .vg_mask_shift = 1
56 },
57 {
58 .vg_name = "VGPIO5", /* DISPCLKO1 */
59 .vg_io_port = VIASR,
60 .vg_port_index = 0x3d,
61 .vg_mask_shift = 0
62 },
63};
64
65#define VIAFB_NUM_GPIOS ARRAY_SIZE(viafb_all_gpios)
66
67/*
68 * This structure controls the active GPIOs, which may be a subset
69 * of those which are known.
70 */
71
72struct viafb_gpio_cfg {
73 struct gpio_chip gpio_chip;
74 struct viafb_dev *vdev;
75 struct viafb_gpio *active_gpios[VIAFB_NUM_GPIOS];
76 char *gpio_names[VIAFB_NUM_GPIOS];
77};
78
79/*
80 * GPIO access functions
81 */
82static void via_gpio_set(struct gpio_chip *chip, unsigned int nr,
83 int value)
84{
85 struct viafb_gpio_cfg *cfg = container_of(chip,
86 struct viafb_gpio_cfg,
87 gpio_chip);
88 u8 reg;
89 struct viafb_gpio *gpio;
90 unsigned long flags;
91
92 spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
93 gpio = cfg->active_gpios[nr];
94 reg = viafb_read_reg(VIASR, gpio->vg_port_index);
95 reg |= 0x40 << gpio->vg_mask_shift; /* output enable */
96 if (value)
97 reg |= 0x10 << gpio->vg_mask_shift;
98 else
99 reg &= ~(0x10 << gpio->vg_mask_shift);
100 viafb_write_reg(gpio->vg_port_index, VIASR, reg);
101 spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
102}
103
104static int via_gpio_dir_out(struct gpio_chip *chip, unsigned int nr,
105 int value)
106{
107 via_gpio_set(chip, nr, value);
108 return 0;
109}
110
111/*
112 * Set the input direction. I'm not sure this is right; we should
113 * be able to do input without disabling output.
114 */
115static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr)
116{
117 struct viafb_gpio_cfg *cfg = container_of(chip,
118 struct viafb_gpio_cfg,
119 gpio_chip);
120 struct viafb_gpio *gpio;
121 unsigned long flags;
122
123 spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
124 gpio = cfg->active_gpios[nr];
125 viafb_write_reg_mask(gpio->vg_port_index, VIASR, 0,
126 0x40 << gpio->vg_mask_shift);
127 spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
128 return 0;
129}
130
131static int via_gpio_get(struct gpio_chip *chip, unsigned int nr)
132{
133 struct viafb_gpio_cfg *cfg = container_of(chip,
134 struct viafb_gpio_cfg,
135 gpio_chip);
136 u8 reg;
137 struct viafb_gpio *gpio;
138 unsigned long flags;
139
140 spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
141 gpio = cfg->active_gpios[nr];
142 reg = viafb_read_reg(VIASR, gpio->vg_port_index);
143 spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
144 return reg & (0x04 << gpio->vg_mask_shift);
145}
146
147
148static struct viafb_gpio_cfg gpio_config = {
149 .gpio_chip = {
150 .label = "VIAFB onboard GPIO",
151 .owner = THIS_MODULE,
152 .direction_output = via_gpio_dir_out,
153 .set = via_gpio_set,
154 .direction_input = via_gpio_dir_input,
155 .get = via_gpio_get,
156 .base = -1,
157 .ngpio = 0,
158 .can_sleep = 0
159 }
160};
161
162/*
163 * Manage the software enable bit.
164 */
165static void viafb_gpio_enable(struct viafb_gpio *gpio)
166{
167 viafb_write_reg_mask(gpio->vg_port_index, VIASR, 0x02, 0x02);
168}
169
170static void viafb_gpio_disable(struct viafb_gpio *gpio)
171{
172 viafb_write_reg_mask(gpio->vg_port_index, VIASR, 0, 0x02);
173}
174
175
176
177
178int viafb_create_gpios(struct viafb_dev *vdev,
179 const struct via_port_cfg *port_cfg)
180{
181 int i, ngpio = 0, ret;
182 struct viafb_gpio *gpio;
183 unsigned long flags;
184
185 /*
186 * Set up entries for all GPIOs which have been configured to
187 * operate as such (as opposed to as i2c ports).
188 */
189 for (i = 0; i < VIAFB_NUM_PORTS; i++) {
190 if (port_cfg[i].mode != VIA_MODE_GPIO)
191 continue;
192 for (gpio = viafb_all_gpios;
193 gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++)
194 if (gpio->vg_port_index == port_cfg[i].ioport_index) {
195 gpio_config.active_gpios[ngpio] = gpio;
196 gpio_config.gpio_names[ngpio] = gpio->vg_name;
197 ngpio++;
198 }
199 }
200 gpio_config.gpio_chip.ngpio = ngpio;
201 gpio_config.gpio_chip.names = gpio_config.gpio_names;
202 gpio_config.vdev = vdev;
203 if (ngpio == 0) {
204 printk(KERN_INFO "viafb: no GPIOs configured\n");
205 return 0;
206 }
207 /*
208 * Enable the ports. They come in pairs, with a single
209 * enable bit for both.
210 */
211 spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags);
212 for (i = 0; i < ngpio; i += 2)
213 viafb_gpio_enable(gpio_config.active_gpios[i]);
214 spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags);
215 /*
216 * Get registered.
217 */
218 gpio_config.gpio_chip.base = -1; /* Dynamic */
219 ret = gpiochip_add(&gpio_config.gpio_chip);
220 if (ret) {
221 printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
222 gpio_config.gpio_chip.ngpio = 0;
223 }
224 return ret;
225/* Port enable ? */
226}
227
228
229int viafb_destroy_gpios(void)
230{
231 unsigned long flags;
232 int ret = 0, i;
233
234 spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags);
235 /*
236 * Get unregistered.
237 */
238 if (gpio_config.gpio_chip.ngpio > 0) {
239 ret = gpiochip_remove(&gpio_config.gpio_chip);
240 if (ret) { /* Somebody still using it? */
241 printk(KERN_ERR "Viafb: GPIO remove failed\n");
242 goto out;
243 }
244 }
245 /*
246 * Disable the ports.
247 */
248 for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2)
249 viafb_gpio_disable(gpio_config.active_gpios[i]);
250 gpio_config.gpio_chip.ngpio = 0;
251out:
252 spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags);
253 return ret;
254}
255
256/*
257 * Look up a specific gpio and return the number it was assigned.
258 */
259int viafb_gpio_lookup(const char *name)
260{
261 int i;
262
263 for (i = 0; i < gpio_config.gpio_chip.ngpio; i++)
264 if (!strcmp(name, gpio_config.active_gpios[i]->vg_name))
265 return gpio_config.gpio_chip.base + i;
266 return -1;
267}
268EXPORT_SYMBOL_GPL(viafb_gpio_lookup);
diff --git a/drivers/video/via/via-gpio.h b/drivers/video/via/via-gpio.h
new file mode 100644
index 000000000000..7b53f966eb4b
--- /dev/null
+++ b/drivers/video/via/via-gpio.h
@@ -0,0 +1,15 @@
1/*
2 * Support for viafb GPIO ports.
3 *
4 * Copyright 2009 Jonathan Corbet <corbet@lwn.net>
5 * Distributable under version 2 of the GNU General Public License.
6 */
7
8#ifndef __VIA_GPIO_H__
9#define __VIA_GPIO_H__
10
11extern int viafb_create_gpios(struct viafb_dev *vdev,
12 const struct via_port_cfg *port_cfg);
13extern int viafb_destroy_gpios(void);
14extern int viafb_gpio_lookup(const char *name);
15#endif