Date:2010-04-24 17:25:01 (9 years 27 days ago)
Author:Lars C.
Commit:41057ef044dcf189232bd6de25bb1df9bbe8f572
Message:Add n516 board support

Files: arch/mips/include/asm/mach-jz4740/board-n516.h (1 diff)
arch/mips/jz4740/Kconfig (1 diff)
arch/mips/jz4740/Makefile (1 diff)
arch/mips/jz4740/board-n516-display.c (1 diff)
arch/mips/jz4740/board-n516.c (1 diff)

Change Details

arch/mips/include/asm/mach-jz4740/board-n516.h
1/*
2 * linux/include/asm-mips/mach-jz4740/board-n516.h
3 *
4 * JZ4730-based N516 board definition.
5 *
6 * Copyright (C) 2009, Yauhen Kharuzhy <jekhor@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#ifndef __ASM_JZ4740_N516_H__
15#define __ASM_JZ4740_N516_H__
16
17#include <asm/mach-jz4740/gpio.h>
18
19/*
20 * GPIO
21 */
22#define GPIO_SD_VCC_EN_N JZ_GPIO_PORTD(17)
23#define GPIO_SD_CD_N JZ_GPIO_PORTD(7)
24#define GPIO_SD_WP JZ_GPIO_PORTD(15)
25#define GPIO_USB_DETECT JZ_GPIO_PORTD(19)
26#define GPIO_CHARG_STAT_N JZ_GPIO_PORTD(16)
27#define GPIO_LED_ENABLE JZ_GPIO_PORTD(28)
28#define GPIO_LPC_INT JZ_GPIO_PORTD(14)
29#define GPIO_HPHONE_DETECT JZ_GPIO_PORTD(20)
30#define GPIO_SPEAKER_ENABLE JZ_GPIO_PORTD(21)
31
32/* Display */
33#define GPIO_DISPLAY_RST_L JZ_GPIO_PORTB(18)
34#define GPIO_DISPLAY_RDY JZ_GPIO_PORTB(17)
35#define GPIO_DISPLAY_STBY JZ_GPIO_PORTC(22)
36#define GPIO_DISPLAY_ERR JZ_GPIO_PORTC(23)
37#define GPIO_DISPLAY_OFF_N JZ_GPIO_PORTD(1)
38
39#endif /* __ASM_JZ4740_N516_H__ */
arch/mips/jz4740/Kconfig
66config JZ4740_QI_LB60
77    bool "Qi Hardware Ben NanoNote"
88
9config JZ4740_N516
10    bool "Hanvon n516 eBook reader"
11    select SOC_JZ4740
12
913endchoice
1014
1115config HAVE_PWM
arch/mips/jz4740/Makefile
1212# board specific support
1313
1414obj-$(CONFIG_JZ4740_QI_LB60) += board-qi_lb60.o
15obj-$(CONFIG_JZ4740_N516) += board-n516.o board-n516-display.o
1516
1617# PM support
1718
arch/mips/jz4740/board-n516-display.c
1/*
2 * board-n516-display.c -- Platform device for N516 display
3 *
4 * Copyright (C) 2009, Yauhen Kharuzhy <jekhor@gmail.com>
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
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/errno.h>
14#include <linux/string.h>
15#include <linux/delay.h>
16#include <linux/interrupt.h>
17#include <linux/fb.h>
18#include <linux/init.h>
19#include <linux/platform_device.h>
20#include <linux/irq.h>
21#include <linux/gpio.h>
22
23#include <asm/mach-jz4740/jz4740_fb.h>
24
25#include <asm/mach-jz4740/platform.h>
26#include <asm/mach-jz4740/board-n516.h>
27
28#include <video/metronomefb.h>
29#include <linux/console.h>
30
31static struct fb_videomode n516_fb_modes[] = {
32    [0] = {
33        .name = "Metronome 800x600",
34        .refresh = 50,
35        .xres = 400,
36        .yres = 624,
37        .hsync_len = 31,
38        .vsync_len = 23,
39        .right_margin = 31,
40        .left_margin = 5,
41        .upper_margin = 1,
42        .lower_margin = 2,
43        .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
44    },
45};
46
47static struct jz4740_fb_platform_data n516_fb_pdata = {
48    .num_modes = ARRAY_SIZE(n516_fb_modes),
49    .modes = n516_fb_modes,
50    .bpp = 16,
51    .lcd_type = JZ_LCD_TYPE_GENERIC_16_BIT,
52};
53
54struct n516_board_info {
55    uint8_t *metromem;
56    size_t wfm_size;
57    struct fb_info *host_fbinfo; /* the host LCD controller's fbi */
58    unsigned int fw;
59    unsigned int fh;
60};
61
62static struct platform_device *n516_device;
63static struct n516_board_info n516_board_info;
64
65static int metronome_gpios[] = {
66    GPIO_DISPLAY_STBY,
67    GPIO_DISPLAY_RST_L,
68    GPIO_DISPLAY_RDY,
69    GPIO_DISPLAY_ERR,
70/* GPIO_DISPLAY_OFF_N,*/
71};
72
73static const char *metronome_gpio_names[] = {
74    "Metronome STDBY",
75    "Metronome RST",
76    "Metronome RDY",
77    "Metronome ERR",
78/* "Metronone OFF",*/
79};
80
81static int n516_enable_hostfb(bool enable)
82{
83    int ret;
84    int blank = enable ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
85
86    acquire_console_sem();
87    ret = fb_blank(n516_board_info.host_fbinfo, blank);
88    release_console_sem();
89
90    return ret;
91}
92
93static int n516_init_metronome_gpios(struct metronomefb_par *par)
94{
95    int i;
96    int ret;
97
98    for (i = 0; i < ARRAY_SIZE(metronome_gpios); ++i) {
99        ret = gpio_request(metronome_gpios[i], metronome_gpio_names[i]);
100        if (ret)
101            goto err;
102    }
103
104    gpio_direction_output(GPIO_DISPLAY_OFF_N, 0);
105    gpio_direction_output(GPIO_DISPLAY_RST_L, 0);
106    gpio_direction_output(GPIO_DISPLAY_STBY, 0);
107    gpio_direction_input(GPIO_DISPLAY_RDY);
108    gpio_direction_input(GPIO_DISPLAY_ERR);
109
110    return 0;
111err:
112    for (--i; i >= 0; --i)
113        gpio_free(metronome_gpios[i]);
114
115    return ret;
116}
117
118static int n516_share_video_mem(struct fb_info *info)
119{
120    int ret;
121
122    dev_dbg(&n516_device->dev, "ENTER %s\n", __func__);
123    dev_dbg(&n516_device->dev, "%s, info->var.xres = %u, info->var.yres = %u\n", __func__, info->var.xres, info->var.yres);
124    /* rough check if this is our desired fb and not something else */
125    if ((info->var.xres != n516_fb_pdata.modes[0].xres)
126        || (info->var.yres != n516_fb_pdata.modes[0].yres))
127        return 0;
128
129    /* we've now been notified that we have our new fb */
130    n516_board_info.metromem = info->screen_base;
131    n516_board_info.host_fbinfo = info;
132
133    n516_enable_hostfb(false);
134    /* try to refcount host drv since we are the consumer after this */
135    if (!try_module_get(info->fbops->owner))
136        return -ENODEV;
137
138    /* this _add binds metronomefb to n516. metronomefb refcounts n516 */
139    ret = platform_device_add(n516_device);
140
141    if (ret) {
142        platform_device_put(n516_device);
143        return ret;
144    }
145
146    /* request our platform independent driver */
147    request_module("metronomefb");
148
149    return 0;
150}
151
152static int n516_unshare_video_mem(struct fb_info *info)
153{
154    dev_dbg(&n516_device->dev, "ENTER %s\n", __func__);
155
156    if (info != n516_board_info.host_fbinfo)
157        return 0;
158
159    module_put(n516_board_info.host_fbinfo->fbops->owner);
160    return 0;
161}
162
163static int n516_fb_notifier_callback(struct notifier_block *self,
164                 unsigned long event, void *data)
165{
166    struct fb_event *evdata = data;
167    struct fb_info *info = evdata->info;
168
169    dev_dbg(&n516_device->dev, "ENTER %s\n", __func__);
170
171    if (event == FB_EVENT_FB_REGISTERED)
172        return n516_share_video_mem(info);
173    else if (event == FB_EVENT_FB_UNREGISTERED)
174        return n516_unshare_video_mem(info);
175
176    return 0;
177}
178
179static struct notifier_block n516_fb_notif = {
180    .notifier_call = n516_fb_notifier_callback,
181};
182
183/* this gets called as part of our init. these steps must be done now so
184 * that we can use set_pxa_fb_info */
185static void __init n516_presetup_fb(void)
186{
187    int padding_size;
188    int totalsize;
189
190    /* the frame buffer is divided as follows:
191    command | CRC | padding
192    16kb waveform data | CRC | padding
193    image data | CRC
194    */
195
196    n516_board_info.fw = 800;
197    n516_board_info.fh = 624;
198
199    /* waveform must be 16k + 2 for checksum */
200    n516_board_info.wfm_size = roundup(16*1024 + 2, n516_board_info.fw);
201
202    padding_size = PAGE_SIZE + (4 * n516_board_info.fw);
203
204    /* total is 1 cmd , 1 wfm, padding and image */
205    totalsize = n516_board_info.fw + n516_board_info.wfm_size;
206    totalsize += padding_size + (n516_board_info.fw*n516_board_info.fh);
207
208    /* save this off because we're manipulating fw after this and
209     * we'll need it when we're ready to setup the framebuffer */
210
211    /* the reason we do this adjustment is because we want to acquire
212     * more framebuffer memory without imposing custom awareness on the
213     * underlying driver */
214    n516_fb_pdata.modes[0].yres = DIV_ROUND_UP(totalsize, n516_board_info.fw);
215
216    jz4740_framebuffer_device.dev.platform_data = &n516_fb_pdata;
217    platform_device_register(&jz4740_framebuffer_device);
218}
219
220/* this gets called by metronomefb as part of its init, in our case, we
221 * have already completed initial framebuffer init in presetup_fb so we
222 * can just setup the fb access pointers */
223static int n516_setup_fb(struct metronomefb_par *par)
224{
225    /* metromem was set up by the notifier in share_video_mem so now
226     * we can use its value to calculate the other entries */
227    par->metromem_cmd = (struct metromem_cmd *) n516_board_info.metromem;
228    par->metromem_wfm = n516_board_info.metromem + n516_board_info.fw;
229    par->metromem_img = par->metromem_wfm + n516_board_info.wfm_size;
230    par->metromem_img_csum = (u16 *) (par->metromem_img + (n516_board_info.fw * n516_board_info.fh));
231    par->metromem_dma = n516_board_info.host_fbinfo->fix.smem_start;
232
233    return 0;
234}
235
236static int n516_get_panel_type(void)
237{
238    return 5;
239}
240
241static irqreturn_t n516_handle_irq(int irq, void *dev_id)
242{
243    struct metronomefb_par *par = dev_id;
244
245    dev_dbg(&par->pdev->dev, "Metronome IRQ! RDY=%d\n", gpio_get_value(GPIO_DISPLAY_RDY));
246    wake_up_all(&par->waitq);
247
248    return IRQ_HANDLED;
249}
250
251static void n516_power_ctl(struct metronomefb_par *par, int cmd)
252{
253    switch (cmd) {
254    case METRONOME_POWER_OFF:
255        gpio_set_value(GPIO_DISPLAY_OFF_N, 1);
256        n516_enable_hostfb(false);
257        break;
258    case METRONOME_POWER_ON:
259        gpio_set_value(GPIO_DISPLAY_OFF_N, 0);
260        n516_enable_hostfb(true);
261        break;
262    }
263}
264
265static int n516_get_rdy(struct metronomefb_par *par)
266{
267    return gpio_get_value(GPIO_DISPLAY_RDY);
268}
269
270static int n516_get_err(struct metronomefb_par *par)
271{
272    return gpio_get_value(GPIO_DISPLAY_ERR);
273}
274
275static int n516_setup_irq(struct fb_info *info)
276{
277    int ret;
278
279    dev_dbg(&n516_device->dev, "ENTER %s\n", __func__);
280
281    ret = request_irq(gpio_to_irq(GPIO_DISPLAY_RDY), n516_handle_irq,
282                IRQF_TRIGGER_RISING,
283                "n516", info->par);
284    if (ret)
285        dev_err(&n516_device->dev, "request_irq failed: %d\n", ret);
286
287    return ret;
288}
289
290static void n516_set_rst(struct metronomefb_par *par, int state)
291{
292    dev_dbg(&n516_device->dev, "ENTER %s, RDY=%d\n", __func__, gpio_get_value(GPIO_DISPLAY_RDY));
293    if (state)
294        gpio_set_value(GPIO_DISPLAY_RST_L, 1);
295    else
296        gpio_set_value(GPIO_DISPLAY_RST_L, 0);
297}
298
299static void n516_set_stdby(struct metronomefb_par *par, int state)
300{
301    dev_dbg(&n516_device->dev, "ENTER %s, RDY=%d\n", __func__, gpio_get_value(GPIO_DISPLAY_RDY));
302    if (state)
303        gpio_set_value(GPIO_DISPLAY_STBY, 1);
304    else
305        gpio_set_value(GPIO_DISPLAY_STBY, 0);
306}
307
308static int n516_wait_event(struct metronomefb_par *par)
309{
310    unsigned long timeout = jiffies + HZ / 20;
311
312    dev_dbg(&n516_device->dev, "ENTER1 %s, RDY=%d\n",
313            __func__, gpio_get_value(GPIO_DISPLAY_RDY));
314    while (n516_get_rdy(par) && time_before(jiffies, timeout))
315        schedule();
316
317    dev_dbg(&n516_device->dev, "ENTER2 %s, RDY=%d\n",
318            __func__, gpio_get_value(GPIO_DISPLAY_RDY));
319    return wait_event_timeout(par->waitq,
320            n516_get_rdy(par), HZ * 2) ? 0 : -EIO;
321}
322
323static int n516_wait_event_intr(struct metronomefb_par *par)
324{
325    unsigned long timeout = jiffies + HZ/20;
326
327    dev_dbg(&n516_device->dev, "ENTER1 %s, RDY=%d\n",
328            __func__, gpio_get_value(GPIO_DISPLAY_RDY));
329    while (n516_get_rdy(par) && time_before(jiffies, timeout))
330        schedule();
331
332    dev_dbg(&n516_device->dev, "ENTER2 %s, RDY=%d\n",
333            __func__, gpio_get_value(GPIO_DISPLAY_RDY));
334    return wait_event_interruptible_timeout(par->waitq,
335                    n516_get_rdy(par), HZ * 2) ? 0 : -EIO;
336}
337
338static void n516_cleanup(struct metronomefb_par *par)
339{
340    int i;
341
342    free_irq(gpio_to_irq(GPIO_DISPLAY_RDY), par);
343    for (i = 0; i < ARRAY_SIZE(metronome_gpios); ++i)
344        gpio_free(metronome_gpios[i]);
345}
346
347static struct metronome_board n516_board __initdata = {
348    .owner = THIS_MODULE,
349    .power_ctl = n516_power_ctl,
350    .setup_irq = n516_setup_irq,
351    .setup_io = n516_init_metronome_gpios,
352    .setup_fb = n516_setup_fb,
353    .set_rst = n516_set_rst,
354    .get_err = n516_get_err,
355    .get_rdy = n516_get_rdy,
356    .set_stdby = n516_set_stdby,
357    .met_wait_event = n516_wait_event,
358    .met_wait_event_intr = n516_wait_event_intr,
359    .get_panel_type = n516_get_panel_type,
360    .cleanup = n516_cleanup,
361};
362
363static int __init n516_init(void)
364{
365    int ret;
366
367    /* Keep the metronome off, until its driver is loaded */
368    ret = gpio_request(GPIO_DISPLAY_OFF_N, "Display off");
369    if (ret)
370        return ret;
371
372    gpio_direction_output(GPIO_DISPLAY_OFF_N, 1);
373
374    /* before anything else, we request notification for any fb
375     * creation events */
376    fb_register_client(&n516_fb_notif);
377
378    n516_device = platform_device_alloc("metronomefb", -1);
379    if (!n516_device)
380        return -ENOMEM;
381
382    /* the n516_board that will be seen by metronomefb is a copy */
383    platform_device_add_data(n516_device, &n516_board,
384                    sizeof(n516_board));
385
386    n516_presetup_fb();
387
388    return 0;
389}
390module_init(n516_init);
391
392MODULE_DESCRIPTION("board driver for n516 display");
393MODULE_AUTHOR("Yauhen Kharuzhy");
394MODULE_LICENSE("GPL");
arch/mips/jz4740/board-n516.c
1/*
2 * linux/arch/mips/jz4740/board-516.c
3 *
4 * JZ4740 n516 board setup routines.
5 *
6 * Copyright (c) 2009, Yauhen Kharuzhy <jekhor@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/init.h>
15#include <linux/sched.h>
16#include <linux/ioport.h>
17#include <linux/mm.h>
18#include <linux/console.h>
19#include <linux/delay.h>
20#include <linux/i2c.h>
21#include <linux/platform_device.h>
22#include <linux/mtd/mtd.h>
23#include <linux/leds.h>
24
25#include <linux/power_supply.h>
26#include <linux/power/gpio-charger.h>
27
28#include <linux/i2c.h>
29#include <linux/i2c-gpio.h>
30
31#include <asm/mach-jz4740/jz4740_mmc.h>
32#include <asm/mach-jz4740/jz4740_nand.h>
33
34#include <asm/mach-jz4740/board-n516.h>
35#include <asm/mach-jz4740/platform.h>
36
37#include "clock.h"
38
39static long n516_panic_blink(long time)
40{
41    gpio_set_value(GPIO_LED_ENABLE, 1);
42    mdelay(200);
43    gpio_set_value(GPIO_LED_ENABLE, 0);
44    mdelay(200);
45
46    return 400;
47}
48
49static void __init board_gpio_setup(void)
50{
51/* jz_gpio_enable_pullup(JZ_GPIO_PORTD(23));
52    jz_gpio_enable_pullup(JZ_GPIO_PORTD(24));*/
53}
54
55static struct i2c_gpio_platform_data n516_i2c_pdata = {
56    .sda_pin = JZ_GPIO_PORTD(23),
57    .scl_pin = JZ_GPIO_PORTD(24),
58    .udelay = 2,
59    .timeout = 3 * HZ,
60};
61
62static struct platform_device n516_i2c_device = {
63    .name = "i2c-gpio",
64    .id = -1,
65    .dev = {
66        .platform_data = &n516_i2c_pdata,
67    },
68};
69
70static const struct i2c_board_info n516_i2c_board_info[] = {
71    {
72        .type = "LPC524",
73        .addr = 0x54,
74    },
75    {
76        .type = "lm75a",
77        .addr = 0x48,
78    }
79};
80
81static struct jz4740_mmc_platform_data n516_mmc_pdata = {
82    .gpio_card_detect = GPIO_SD_CD_N,
83    .card_detect_active_low = 1,
84    .gpio_read_only = -1,
85    .gpio_power = GPIO_SD_VCC_EN_N,
86    .power_active_low = 1,
87};
88
89static struct gpio_led n516_leds[] = {
90    {
91        .name = "n516:blue:power",
92        .gpio = GPIO_LED_ENABLE,
93        .default_state = LEDS_GPIO_DEFSTATE_ON,
94        .default_trigger = "nand-disk",
95    }
96};
97
98static struct gpio_led_platform_data n516_leds_pdata = {
99    .leds = n516_leds,
100    .num_leds = ARRAY_SIZE(n516_leds),
101};
102
103static struct platform_device n516_leds_device = {
104    .name = "leds-gpio",
105    .id = -1,
106    .dev = {
107        .platform_data = &n516_leds_pdata,
108    },
109};
110
111static struct mtd_partition n516_partitions[] = {
112    { .name = "NAND BOOT partition",
113      .offset = 0 * 0x100000,
114      .size = 4 * 0x100000,
115    },
116    { .name = "NAND KERNEL partition",
117      .offset = 4 * 0x100000,
118      .size = 4 * 0x100000,
119     },
120    { .name = "NAND ROOTFS partition",
121      .offset = 8 * 0x100000,
122      .size = 504 * 0x100000,
123     },
124};
125
126static struct nand_ecclayout n516_ecclayout = {
127/* .eccbytes = 36,
128    .eccpos = {
129         6, 7, 8, 9, 10, 11, 12, 13, 14,
130        15, 16, 17, 18, 19, 20, 21, 22, 23,
131        24, 25, 26, 27, 28, 29, 30, 31, 32,
132        33, 34, 35, 36, 37, 38, 39, 40, 41,
133    },*/
134    .oobfree = {
135        {
136            .offset = 2,
137            .length = 4
138        },
139        {
140            .offset = 42,
141            .length = 22,
142        }
143    }
144};
145
146static struct jz_nand_platform_data n516_nand_pdata = {
147    .ecc_layout = &n516_ecclayout,
148    .partitions = n516_partitions,
149    .num_partitions = ARRAY_SIZE(n516_partitions),
150    .busy_gpio = 94,
151};
152
153static char *n516_batteries[] = {
154    "n516_battery",
155};
156
157static struct gpio_charger_platform_data n516_charger_pdata = {
158    .name = "usb",
159    .type = POWER_SUPPLY_TYPE_USB,
160    .gpio = GPIO_USB_DETECT,
161    .gpio_active_low = 1,
162    .batteries = n516_batteries,
163    .num_batteries = ARRAY_SIZE(n516_batteries),
164};
165
166static struct platform_device n516_charger_device = {
167    .name = "gpio-charger",
168    .dev = {
169        .platform_data = &n516_charger_pdata,
170    },
171};
172
173static struct platform_device *n516_devices[] __initdata = {
174    &jz4740_nand_device,
175    &n516_leds_device,
176    &jz4740_mmc_device,
177    &jz4740_i2s_device,
178    &jz4740_codec_device,
179    &jz4740_rtc_device,
180    &jz4740_udc_device,
181    &n516_i2c_device,
182    &n516_charger_device,
183};
184
185struct jz4740_clock_board_data jz4740_clock_bdata = {
186    .ext_rate = 12000000,
187    .rtc_rate = 32768,
188};
189
190extern int jz_gpiolib_init(void);
191
192static int n516_setup_platform(void)
193{
194    board_gpio_setup();
195
196    panic_blink = n516_panic_blink;
197    i2c_register_board_info(0, n516_i2c_board_info, ARRAY_SIZE(n516_i2c_board_info));
198    jz4740_mmc_device.dev.platform_data = &n516_mmc_pdata;
199    jz4740_nand_device.dev.platform_data = &n516_nand_pdata;
200
201    return platform_add_devices(n516_devices, ARRAY_SIZE(n516_devices));
202}
203arch_initcall(n516_setup_platform);

Archive Download the corresponding diff file



interactive