0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #include <linux/module.h>
0022 #include <linux/kernel.h>
0023 #include <linux/errno.h>
0024 #include <linux/string.h>
0025 #include <linux/delay.h>
0026 #include <linux/interrupt.h>
0027 #include <linux/fb.h>
0028 #include <linux/init.h>
0029 #include <linux/platform_device.h>
0030 #include <linux/irq.h>
0031 #include <linux/gpio.h>
0032
0033 #include "pxa25x.h"
0034 #include "gumstix.h"
0035 #include <linux/platform_data/video-pxafb.h>
0036
0037 #include "generic.h"
0038
0039 #include <video/metronomefb.h>
0040
0041 static unsigned int panel_type = 6;
0042 static struct platform_device *am200_device;
0043 static struct metronome_board am200_board;
0044
0045 static struct pxafb_mode_info am200_fb_mode_9inch7 = {
0046 .pixclock = 40000,
0047 .xres = 1200,
0048 .yres = 842,
0049 .bpp = 16,
0050 .hsync_len = 2,
0051 .left_margin = 2,
0052 .right_margin = 2,
0053 .vsync_len = 1,
0054 .upper_margin = 2,
0055 .lower_margin = 25,
0056 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
0057 };
0058
0059 static struct pxafb_mode_info am200_fb_mode_8inch = {
0060 .pixclock = 40000,
0061 .xres = 1088,
0062 .yres = 791,
0063 .bpp = 16,
0064 .hsync_len = 28,
0065 .left_margin = 8,
0066 .right_margin = 30,
0067 .vsync_len = 8,
0068 .upper_margin = 10,
0069 .lower_margin = 8,
0070 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
0071 };
0072
0073 static struct pxafb_mode_info am200_fb_mode_6inch = {
0074 .pixclock = 40189,
0075 .xres = 832,
0076 .yres = 622,
0077 .bpp = 16,
0078 .hsync_len = 28,
0079 .left_margin = 34,
0080 .right_margin = 34,
0081 .vsync_len = 25,
0082 .upper_margin = 0,
0083 .lower_margin = 2,
0084 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
0085 };
0086
0087 static struct pxafb_mach_info am200_fb_info = {
0088 .modes = &am200_fb_mode_6inch,
0089 .num_modes = 1,
0090 .lcd_conn = LCD_TYPE_COLOR_TFT | LCD_PCLK_EDGE_FALL |
0091 LCD_AC_BIAS_FREQ(24),
0092 };
0093
0094
0095 #define LED_GPIO_PIN 51
0096 #define STDBY_GPIO_PIN 48
0097 #define RST_GPIO_PIN 49
0098 #define RDY_GPIO_PIN 32
0099 #define ERR_GPIO_PIN 17
0100 #define PCBPWR_GPIO_PIN 16
0101 static int gpios[] = { LED_GPIO_PIN , STDBY_GPIO_PIN , RST_GPIO_PIN,
0102 RDY_GPIO_PIN, ERR_GPIO_PIN, PCBPWR_GPIO_PIN };
0103 static char *gpio_names[] = { "LED" , "STDBY" , "RST", "RDY", "ERR", "PCBPWR" };
0104
0105 static int am200_init_gpio_regs(struct metronomefb_par *par)
0106 {
0107 int i;
0108 int err;
0109
0110 for (i = 0; i < ARRAY_SIZE(gpios); i++) {
0111 err = gpio_request(gpios[i], gpio_names[i]);
0112 if (err) {
0113 dev_err(&am200_device->dev, "failed requesting "
0114 "gpio %s, err=%d\n", gpio_names[i], err);
0115 goto err_req_gpio;
0116 }
0117 }
0118
0119 gpio_direction_output(LED_GPIO_PIN, 0);
0120 gpio_direction_output(STDBY_GPIO_PIN, 0);
0121 gpio_direction_output(RST_GPIO_PIN, 0);
0122
0123 gpio_direction_input(RDY_GPIO_PIN);
0124 gpio_direction_input(ERR_GPIO_PIN);
0125
0126 gpio_direction_output(PCBPWR_GPIO_PIN, 0);
0127
0128 return 0;
0129
0130 err_req_gpio:
0131 while (--i >= 0)
0132 gpio_free(gpios[i]);
0133
0134 return err;
0135 }
0136
0137 static void am200_cleanup(struct metronomefb_par *par)
0138 {
0139 int i;
0140
0141 free_irq(PXA_GPIO_TO_IRQ(RDY_GPIO_PIN), par);
0142
0143 for (i = 0; i < ARRAY_SIZE(gpios); i++)
0144 gpio_free(gpios[i]);
0145 }
0146
0147 static int am200_share_video_mem(struct fb_info *info)
0148 {
0149
0150 if ((info->var.xres != am200_fb_info.modes->xres)
0151 || (info->var.yres != am200_fb_info.modes->yres))
0152 return 0;
0153
0154
0155 am200_board.metromem = info->screen_base;
0156 am200_board.host_fbinfo = info;
0157
0158
0159 if (!try_module_get(info->fbops->owner))
0160 return -ENODEV;
0161
0162 return 0;
0163 }
0164
0165 static int am200_unshare_video_mem(struct fb_info *info)
0166 {
0167 dev_dbg(&am200_device->dev, "ENTER %s\n", __func__);
0168
0169 if (info != am200_board.host_fbinfo)
0170 return 0;
0171
0172 module_put(am200_board.host_fbinfo->fbops->owner);
0173 return 0;
0174 }
0175
0176 static int am200_fb_notifier_callback(struct notifier_block *self,
0177 unsigned long event, void *data)
0178 {
0179 struct fb_event *evdata = data;
0180 struct fb_info *info = evdata->info;
0181
0182 dev_dbg(&am200_device->dev, "ENTER %s\n", __func__);
0183
0184 if (event == FB_EVENT_FB_REGISTERED)
0185 return am200_share_video_mem(info);
0186 else if (event == FB_EVENT_FB_UNREGISTERED)
0187 return am200_unshare_video_mem(info);
0188
0189 return 0;
0190 }
0191
0192 static struct notifier_block am200_fb_notif = {
0193 .notifier_call = am200_fb_notifier_callback,
0194 };
0195
0196
0197
0198 static void __init am200_presetup_fb(void)
0199 {
0200 int fw;
0201 int fh;
0202 int padding_size;
0203 int totalsize;
0204
0205 switch (panel_type) {
0206 case 6:
0207 am200_fb_info.modes = &am200_fb_mode_6inch;
0208 break;
0209 case 8:
0210 am200_fb_info.modes = &am200_fb_mode_8inch;
0211 break;
0212 case 97:
0213 am200_fb_info.modes = &am200_fb_mode_9inch7;
0214 break;
0215 default:
0216 dev_err(&am200_device->dev, "invalid panel_type selection,"
0217 " setting to 6\n");
0218 am200_fb_info.modes = &am200_fb_mode_6inch;
0219 break;
0220 }
0221
0222
0223
0224
0225
0226
0227
0228 fw = am200_fb_info.modes->xres;
0229 fh = am200_fb_info.modes->yres;
0230
0231
0232 am200_board.wfm_size = roundup(16*1024 + 2, fw);
0233
0234 padding_size = PAGE_SIZE + (4 * fw);
0235
0236
0237 totalsize = fw + am200_board.wfm_size + padding_size + (fw*fh);
0238
0239
0240
0241 am200_board.fw = fw;
0242 am200_board.fh = fh;
0243
0244
0245
0246
0247 am200_fb_info.modes->yres = DIV_ROUND_UP(totalsize, fw);
0248
0249
0250 am200_fb_info.modes->xres /= 2;
0251
0252 pxa_set_fb_info(NULL, &am200_fb_info);
0253
0254 }
0255
0256
0257
0258
0259 static int am200_setup_fb(struct metronomefb_par *par)
0260 {
0261 int fw;
0262 int fh;
0263
0264 fw = am200_board.fw;
0265 fh = am200_board.fh;
0266
0267
0268
0269 par->metromem_cmd = (struct metromem_cmd *) am200_board.metromem;
0270 par->metromem_wfm = am200_board.metromem + fw;
0271 par->metromem_img = par->metromem_wfm + am200_board.wfm_size;
0272 par->metromem_img_csum = (u16 *) (par->metromem_img + (fw * fh));
0273 par->metromem_dma = am200_board.host_fbinfo->fix.smem_start;
0274
0275 return 0;
0276 }
0277
0278 static int am200_get_panel_type(void)
0279 {
0280 return panel_type;
0281 }
0282
0283 static irqreturn_t am200_handle_irq(int irq, void *dev_id)
0284 {
0285 struct metronomefb_par *par = dev_id;
0286
0287 wake_up_interruptible(&par->waitq);
0288 return IRQ_HANDLED;
0289 }
0290
0291 static int am200_setup_irq(struct fb_info *info)
0292 {
0293 int ret;
0294
0295 ret = request_irq(PXA_GPIO_TO_IRQ(RDY_GPIO_PIN), am200_handle_irq,
0296 IRQF_TRIGGER_FALLING, "AM200", info->par);
0297 if (ret)
0298 dev_err(&am200_device->dev, "request_irq failed: %d\n", ret);
0299
0300 return ret;
0301 }
0302
0303 static void am200_set_rst(struct metronomefb_par *par, int state)
0304 {
0305 gpio_set_value(RST_GPIO_PIN, state);
0306 }
0307
0308 static void am200_set_stdby(struct metronomefb_par *par, int state)
0309 {
0310 gpio_set_value(STDBY_GPIO_PIN, state);
0311 }
0312
0313 static int am200_wait_event(struct metronomefb_par *par)
0314 {
0315 return wait_event_timeout(par->waitq, gpio_get_value(RDY_GPIO_PIN), HZ);
0316 }
0317
0318 static int am200_wait_event_intr(struct metronomefb_par *par)
0319 {
0320 return wait_event_interruptible_timeout(par->waitq,
0321 gpio_get_value(RDY_GPIO_PIN), HZ);
0322 }
0323
0324 static struct metronome_board am200_board = {
0325 .owner = THIS_MODULE,
0326 .setup_irq = am200_setup_irq,
0327 .setup_io = am200_init_gpio_regs,
0328 .setup_fb = am200_setup_fb,
0329 .set_rst = am200_set_rst,
0330 .set_stdby = am200_set_stdby,
0331 .met_wait_event = am200_wait_event,
0332 .met_wait_event_intr = am200_wait_event_intr,
0333 .get_panel_type = am200_get_panel_type,
0334 .cleanup = am200_cleanup,
0335 };
0336
0337 static unsigned long am200_pin_config[] __initdata = {
0338 GPIO51_GPIO,
0339 GPIO49_GPIO,
0340 GPIO48_GPIO,
0341 GPIO32_GPIO,
0342 GPIO17_GPIO,
0343 GPIO16_GPIO,
0344 };
0345
0346 int __init am200_init(void)
0347 {
0348 int ret;
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361 fb_register_client(&am200_fb_notif);
0362
0363 pxa2xx_mfp_config(ARRAY_AND_SIZE(am200_pin_config));
0364
0365
0366 request_module("metronomefb");
0367
0368 am200_device = platform_device_alloc("metronomefb", -1);
0369 if (!am200_device)
0370 return -ENOMEM;
0371
0372
0373 platform_device_add_data(am200_device, &am200_board,
0374 sizeof(am200_board));
0375
0376
0377 ret = platform_device_add(am200_device);
0378
0379 if (ret) {
0380 platform_device_put(am200_device);
0381 fb_unregister_client(&am200_fb_notif);
0382 return ret;
0383 }
0384
0385 am200_presetup_fb();
0386
0387 return 0;
0388 }
0389
0390 module_param(panel_type, uint, 0);
0391 MODULE_PARM_DESC(panel_type, "Select the panel type: 6, 8, 97");
0392
0393 MODULE_DESCRIPTION("board driver for am200 metronome epd kit");
0394 MODULE_AUTHOR("Jaya Kumar");
0395 MODULE_LICENSE("GPL");