1/*
2 * am300epd.c -- Platform device for AM300 EPD kit
3 *
4 * Copyright (C) 2008, Jaya Kumar
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
8 * more details.
9 *
10 * This work was made possible by help and equipment support from E-Ink
11 * Corporation. http://support.eink.com/community
12 *
13 * This driver is written to be used with the Broadsheet display controller.
14 * on the AM300 EPD prototype kit/development kit with an E-Ink 800x600
15 * Vizplex EPD on a Gumstix board using the Broadsheet interface board.
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/kernel.h>
21#include <linux/errno.h>
22#include <linux/string.h>
23#include <linux/delay.h>
24#include <linux/interrupt.h>
25#include <linux/fb.h>
26#include <linux/init.h>
27#include <linux/platform_device.h>
28#include <linux/irq.h>
29#include <linux/gpio.h>
30
31#include "gumstix.h"
32#include "mfp-pxa25x.h"
33#include "irqs.h"
34#include <linux/platform_data/video-pxafb.h>
35
36#include "generic.h"
37
38#include <video/broadsheetfb.h>
39
40static unsigned int panel_type = 6;
41static struct platform_device *am300_device;
42static struct broadsheet_board am300_board;
43
44static unsigned long am300_pin_config[] __initdata = {
45 GPIO16_GPIO,
46 GPIO17_GPIO,
47 GPIO32_GPIO,
48 GPIO48_GPIO,
49 GPIO49_GPIO,
50 GPIO51_GPIO,
51 GPIO74_GPIO,
52 GPIO75_GPIO,
53 GPIO76_GPIO,
54 GPIO77_GPIO,
55
56 /* this is the 16-bit hdb bus 58-73 */
57 GPIO58_GPIO,
58 GPIO59_GPIO,
59 GPIO60_GPIO,
60 GPIO61_GPIO,
61
62 GPIO62_GPIO,
63 GPIO63_GPIO,
64 GPIO64_GPIO,
65 GPIO65_GPIO,
66
67 GPIO66_GPIO,
68 GPIO67_GPIO,
69 GPIO68_GPIO,
70 GPIO69_GPIO,
71
72 GPIO70_GPIO,
73 GPIO71_GPIO,
74 GPIO72_GPIO,
75 GPIO73_GPIO,
76};
77
78/* register offsets for gpio control */
79#define PWR_GPIO_PIN 16
80#define CFG_GPIO_PIN 17
81#define RDY_GPIO_PIN 32
82#define DC_GPIO_PIN 48
83#define RST_GPIO_PIN 49
84#define LED_GPIO_PIN 51
85#define RD_GPIO_PIN 74
86#define WR_GPIO_PIN 75
87#define CS_GPIO_PIN 76
88#define IRQ_GPIO_PIN 77
89
90/* hdb bus */
91#define DB0_GPIO_PIN 58
92#define DB15_GPIO_PIN 73
93
94static int gpios[] = { PWR_GPIO_PIN, CFG_GPIO_PIN, RDY_GPIO_PIN, DC_GPIO_PIN,
95 RST_GPIO_PIN, RD_GPIO_PIN, WR_GPIO_PIN, CS_GPIO_PIN,
96 IRQ_GPIO_PIN, LED_GPIO_PIN };
97static char *gpio_names[] = { "PWR", "CFG", "RDY", "DC", "RST", "RD", "WR",
98 "CS", "IRQ", "LED" };
99
100static int am300_wait_event(struct broadsheetfb_par *par)
101{
102 /* todo: improve err recovery */
103 wait_event(par->waitq, gpio_get_value(RDY_GPIO_PIN));
104 return 0;
105}
106
107static int am300_init_gpio_regs(struct broadsheetfb_par *par)
108{
109 int i;
110 int err;
111 char dbname[8];
112
113 for (i = 0; i < ARRAY_SIZE(gpios); i++) {
114 err = gpio_request(gpio: gpios[i], label: gpio_names[i]);
115 if (err) {
116 dev_err(&am300_device->dev, "failed requesting "
117 "gpio %s, err=%d\n", gpio_names[i], err);
118 goto err_req_gpio;
119 }
120 }
121
122 /* we also need to take care of the hdb bus */
123 for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++) {
124 sprintf(buf: dbname, fmt: "DB%d", i);
125 err = gpio_request(gpio: i, label: dbname);
126 if (err) {
127 dev_err(&am300_device->dev, "failed requesting "
128 "gpio %d, err=%d\n", i, err);
129 goto err_req_gpio2;
130 }
131 }
132
133 /* setup the outputs and init values */
134 gpio_direction_output(PWR_GPIO_PIN, value: 0);
135 gpio_direction_output(CFG_GPIO_PIN, value: 1);
136 gpio_direction_output(DC_GPIO_PIN, value: 0);
137 gpio_direction_output(RD_GPIO_PIN, value: 1);
138 gpio_direction_output(WR_GPIO_PIN, value: 1);
139 gpio_direction_output(CS_GPIO_PIN, value: 1);
140 gpio_direction_output(RST_GPIO_PIN, value: 0);
141
142 /* setup the inputs */
143 gpio_direction_input(RDY_GPIO_PIN);
144 gpio_direction_input(IRQ_GPIO_PIN);
145
146 /* start the hdb bus as an input */
147 for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++)
148 gpio_direction_output(gpio: i, value: 0);
149
150 /* go into command mode */
151 gpio_set_value(CFG_GPIO_PIN, value: 1);
152 gpio_set_value(RST_GPIO_PIN, value: 0);
153 msleep(msecs: 10);
154 gpio_set_value(RST_GPIO_PIN, value: 1);
155 msleep(msecs: 10);
156 am300_wait_event(par);
157
158 return 0;
159
160err_req_gpio2:
161 while (--i >= DB0_GPIO_PIN)
162 gpio_free(gpio: i);
163 i = ARRAY_SIZE(gpios);
164err_req_gpio:
165 while (--i >= 0)
166 gpio_free(gpio: gpios[i]);
167
168 return err;
169}
170
171static int am300_init_board(struct broadsheetfb_par *par)
172{
173 return am300_init_gpio_regs(par);
174}
175
176static void am300_cleanup(struct broadsheetfb_par *par)
177{
178 int i;
179
180 free_irq(PXA_GPIO_TO_IRQ(RDY_GPIO_PIN), par);
181
182 for (i = 0; i < ARRAY_SIZE(gpios); i++)
183 gpio_free(gpio: gpios[i]);
184
185 for (i = DB0_GPIO_PIN; i <= DB15_GPIO_PIN; i++)
186 gpio_free(gpio: i);
187
188}
189
190static u16 am300_get_hdb(struct broadsheetfb_par *par)
191{
192 u16 res = 0;
193 int i;
194
195 for (i = 0; i <= (DB15_GPIO_PIN - DB0_GPIO_PIN) ; i++)
196 res |= (gpio_get_value(DB0_GPIO_PIN + i)) ? (1 << i) : 0;
197
198 return res;
199}
200
201static void am300_set_hdb(struct broadsheetfb_par *par, u16 data)
202{
203 int i;
204
205 for (i = 0; i <= (DB15_GPIO_PIN - DB0_GPIO_PIN) ; i++)
206 gpio_set_value(DB0_GPIO_PIN + i, value: (data >> i) & 0x01);
207}
208
209
210static void am300_set_ctl(struct broadsheetfb_par *par, unsigned char bit,
211 u8 state)
212{
213 switch (bit) {
214 case BS_CS:
215 gpio_set_value(CS_GPIO_PIN, value: state);
216 break;
217 case BS_DC:
218 gpio_set_value(DC_GPIO_PIN, value: state);
219 break;
220 case BS_WR:
221 gpio_set_value(WR_GPIO_PIN, value: state);
222 break;
223 }
224}
225
226static int am300_get_panel_type(void)
227{
228 return panel_type;
229}
230
231static irqreturn_t am300_handle_irq(int irq, void *dev_id)
232{
233 struct broadsheetfb_par *par = dev_id;
234
235 wake_up(&par->waitq);
236 return IRQ_HANDLED;
237}
238
239static int am300_setup_irq(struct fb_info *info)
240{
241 int ret;
242 struct broadsheetfb_par *par = info->par;
243
244 ret = request_irq(PXA_GPIO_TO_IRQ(RDY_GPIO_PIN), handler: am300_handle_irq,
245 IRQF_TRIGGER_RISING, name: "AM300", dev: par);
246 if (ret)
247 dev_err(&am300_device->dev, "request_irq failed: %d\n", ret);
248
249 return ret;
250}
251
252static struct broadsheet_board am300_board = {
253 .owner = THIS_MODULE,
254 .init = am300_init_board,
255 .cleanup = am300_cleanup,
256 .set_hdb = am300_set_hdb,
257 .get_hdb = am300_get_hdb,
258 .set_ctl = am300_set_ctl,
259 .wait_for_rdy = am300_wait_event,
260 .get_panel_type = am300_get_panel_type,
261 .setup_irq = am300_setup_irq,
262};
263
264int __init am300_init(void)
265{
266 int ret;
267
268 pxa2xx_mfp_config(ARRAY_AND_SIZE(am300_pin_config));
269
270 /* request our platform independent driver */
271 request_module("broadsheetfb");
272
273 am300_device = platform_device_alloc(name: "broadsheetfb", id: -1);
274 if (!am300_device)
275 return -ENOMEM;
276
277 /* the am300_board that will be seen by broadsheetfb is a copy */
278 platform_device_add_data(pdev: am300_device, data: &am300_board,
279 size: sizeof(am300_board));
280
281 ret = platform_device_add(pdev: am300_device);
282
283 if (ret) {
284 platform_device_put(pdev: am300_device);
285 return ret;
286 }
287
288 return 0;
289}
290
291module_param(panel_type, uint, 0);
292MODULE_PARM_DESC(panel_type, "Select the panel type: 37, 6, 97");
293
294MODULE_DESCRIPTION("board driver for am300 epd kit");
295MODULE_AUTHOR("Jaya Kumar");
296MODULE_LICENSE("GPL");
297

source code of linux/arch/arm/mach-pxa/am300epd.c