Add support for the n516
SVN-Revision: 19987
This commit is contained in:
		| @@ -0,0 +1,39 @@ | ||||
| /* | ||||
|  *  linux/include/asm-mips/mach-jz4740/board-n516.h | ||||
|  * | ||||
|  *  JZ4730-based N516 board definition. | ||||
|  * | ||||
|  *  Copyright (C) 2009, Yauhen Kharuzhy <jekhor@gmail.com> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  */ | ||||
|  | ||||
| #ifndef __ASM_JZ4740_N516_H__ | ||||
| #define __ASM_JZ4740_N516_H__ | ||||
|  | ||||
| #include <asm/mach-jz4740/gpio.h> | ||||
|  | ||||
| /* | ||||
|  * GPIO | ||||
|  */ | ||||
| #define GPIO_SD_VCC_EN_N	JZ_GPIO_PORTD(17) | ||||
| #define GPIO_SD_CD_N		JZ_GPIO_PORTD(7) | ||||
| #define GPIO_SD_WP		JZ_GPIO_PORTD(15) | ||||
| #define GPIO_USB_DETECT		JZ_GPIO_PORTD(19) | ||||
| #define GPIO_CHARG_STAT_N	JZ_GPIO_PORTD(16) | ||||
| #define GPIO_LED_ENABLE       	JZ_GPIO_PORTD(28) | ||||
| #define GPIO_LPC_INT		JZ_GPIO_PORTD(14) | ||||
| #define GPIO_HPHONE_DETECT	JZ_GPIO_PORTD(20) | ||||
| #define GPIO_SPEAKER_ENABLE	JZ_GPIO_PORTD(21) | ||||
|  | ||||
| /* Display */ | ||||
| #define GPIO_DISPLAY_RST_L	JZ_GPIO_PORTB(18) | ||||
| #define GPIO_DISPLAY_RDY	JZ_GPIO_PORTB(17) | ||||
| #define GPIO_DISPLAY_STBY	JZ_GPIO_PORTC(22) | ||||
| #define GPIO_DISPLAY_ERR	JZ_GPIO_PORTC(23) | ||||
| #define GPIO_DISPLAY_OFF_N	JZ_GPIO_PORTD(1) | ||||
|  | ||||
| #endif /* __ASM_JZ4740_N516_H__ */ | ||||
| @@ -8,6 +8,11 @@ config JZ4740_QI_LB60 | ||||
| 	select DMA_NONCOHERENT | ||||
| 	select SOC_JZ4740 | ||||
|  | ||||
| config JZ4740_N516 | ||||
| 	bool "Hanvon n516 eBook reader" | ||||
| 	select DMA_NONCOHERENT | ||||
| 	select SOC_JZ4740 | ||||
|  | ||||
| config JZ4740_N526 | ||||
| 	bool "Hanvon n526 eBook reader" | ||||
| 	select DMA_NONCOHERENT | ||||
|   | ||||
| @@ -12,9 +12,10 @@ obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o | ||||
| # board specific support | ||||
|  | ||||
| obj-$(CONFIG_JZ4740_QI_LB60)	+= board-qi_lb60.o | ||||
| obj-$(CONFIG_JZ4740_N516)	+= board-n516.o board-n516-display.o | ||||
| obj-$(CONFIG_JZ4740_N526)	+= board-n526.o | ||||
|  | ||||
| # PM support | ||||
|  | ||||
| obj-$(CONFIG_PM)         +=pm.o | ||||
| obj-$(CONFIG_PM)         += pm.o | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,395 @@ | ||||
| /* | ||||
|  * board-n516-display.c -- Platform device for N516 display | ||||
|  * | ||||
|  * Copyright (C) 2009, Yauhen Kharuzhy <jekhor@gmail.com> | ||||
|  * | ||||
|  * This file is subject to the terms and conditions of the GNU General Public | ||||
|  * License. See the file COPYING in the main directory of this archive for | ||||
|  * more details. | ||||
|  */ | ||||
|  | ||||
| #include <linux/module.h> | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/errno.h> | ||||
| #include <linux/string.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/fb.h> | ||||
| #include <linux/init.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/irq.h> | ||||
| #include <linux/gpio.h> | ||||
| #include <linux/jz4740_fb.h> | ||||
|  | ||||
| #include <asm/mach-jz4740/platform.h> | ||||
| #include <asm/mach-jz4740/board-n516.h> | ||||
|  | ||||
| #include <video/metronomefb.h> | ||||
| #include <linux/console.h> | ||||
|  | ||||
| extern struct platform_device jz_lcd_device; | ||||
|  | ||||
| static struct fb_videomode n516_fb_modes[] = { | ||||
| 	[0] = { | ||||
| 		.name		= "Metronome 800x600", | ||||
| 		.refresh	= 50, | ||||
| 		.xres		= 400, | ||||
| 		.yres		= 624, | ||||
| 		.hsync_len	= 31, | ||||
| 		.vsync_len	= 23, | ||||
| 		.right_margin	= 31, | ||||
| 		.left_margin	= 5, | ||||
| 		.upper_margin	= 1, | ||||
| 		.lower_margin	= 2, | ||||
| 		.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| static struct jz4740_fb_platform_data n516_fb_pdata = { | ||||
| 	.num_modes	= ARRAY_SIZE(n516_fb_modes), | ||||
| 	.modes		= n516_fb_modes, | ||||
| 	.bpp		= 16, | ||||
| 	.lcd_type	= JZ_LCD_TYPE_GENERIC_16_BIT, | ||||
| }; | ||||
|  | ||||
| struct n516_board_info { | ||||
| 	uint8_t *metromem; | ||||
| 	size_t wfm_size; | ||||
| 	struct fb_info *host_fbinfo; /* the host LCD controller's fbi */ | ||||
| 	unsigned int fw; | ||||
| 	unsigned int fh; | ||||
| }; | ||||
|  | ||||
| static struct platform_device *n516_device; | ||||
| static struct n516_board_info n516_board_info; | ||||
|  | ||||
| static int metronome_gpios[] = { | ||||
| 	GPIO_DISPLAY_STBY, | ||||
| 	GPIO_DISPLAY_RST_L, | ||||
| 	GPIO_DISPLAY_RDY, | ||||
| 	GPIO_DISPLAY_ERR, | ||||
| /*	GPIO_DISPLAY_OFF,*/ | ||||
| }; | ||||
|  | ||||
| static const char *metronome_gpio_names[] = { | ||||
| 	"Metronome STDBY", | ||||
| 	"Metronome RST", | ||||
| 	"Metronome RDY", | ||||
| 	"Metronome ERR", | ||||
| /*	"Metronone OFF",*/ | ||||
| }; | ||||
|  | ||||
| static int n516_enable_hostfb(bool enable) | ||||
| { | ||||
| 	int ret; | ||||
| 	int blank = enable ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; | ||||
|  | ||||
| 	acquire_console_sem(); | ||||
| 	ret = fb_blank(n516_board_info.host_fbinfo, blank); | ||||
| 	release_console_sem(); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static int n516_init_metronome_gpios(struct metronomefb_par *par) | ||||
| { | ||||
| 	int i; | ||||
| 	int ret; | ||||
|  | ||||
| 	for (i = 0; i < ARRAY_SIZE(metronome_gpios); ++i) { | ||||
| 		ret = gpio_request(metronome_gpios[i], metronome_gpio_names[i]); | ||||
| 		if (ret) | ||||
| 			goto err; | ||||
| 	} | ||||
|  | ||||
| 	gpio_direction_output(GPIO_DISPLAY_OFF, 0); | ||||
| 	gpio_direction_output(GPIO_DISPLAY_RST_L, 0); | ||||
| 	gpio_direction_output(GPIO_DISPLAY_STBY, 0); | ||||
| 	gpio_direction_input(GPIO_DISPLAY_RDY); | ||||
| 	gpio_direction_input(GPIO_DISPLAY_ERR); | ||||
|  | ||||
| 	return 0; | ||||
| err: | ||||
| 	for (--i; i >= 0; --i) | ||||
| 		gpio_free(metronome_gpios[i]); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static int n516_share_video_mem(struct fb_info *info) | ||||
| { | ||||
| 	int ret; | ||||
|  | ||||
| 	dev_dbg(&n516_device->dev, "ENTER %s\n", __func__); | ||||
| 	dev_dbg(&n516_device->dev, "%s, info->var.xres = %u, info->var.yres = %u\n", __func__, info->var.xres, info->var.yres); | ||||
| 	/* rough check if this is our desired fb and not something else */ | ||||
| 	if ((info->var.xres != n516_fb_pdata.modes[0].xres) | ||||
| 		|| (info->var.yres != n516_fb_pdata.modes[0].yres)) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* we've now been notified that we have our new fb */ | ||||
| 	n516_board_info.metromem = info->screen_base; | ||||
| 	n516_board_info.host_fbinfo = info; | ||||
|  | ||||
| 	n516_enable_hostfb(false); | ||||
| 	/* try to refcount host drv since we are the consumer after this */ | ||||
| 	if (!try_module_get(info->fbops->owner)) | ||||
| 		return -ENODEV; | ||||
|  | ||||
| 	/* this _add binds metronomefb to n516. metronomefb refcounts n516 */ | ||||
| 	ret = platform_device_add(n516_device); | ||||
|  | ||||
| 	if (ret) { | ||||
| 		platform_device_put(n516_device); | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	/* request our platform independent driver */ | ||||
| 	request_module("metronomefb"); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int n516_unshare_video_mem(struct fb_info *info) | ||||
| { | ||||
| 	dev_dbg(&n516_device->dev, "ENTER %s\n", __func__); | ||||
|  | ||||
| 	if (info != n516_board_info.host_fbinfo) | ||||
| 		return 0; | ||||
|  | ||||
| 	module_put(n516_board_info.host_fbinfo->fbops->owner); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int n516_fb_notifier_callback(struct notifier_block *self, | ||||
| 				 unsigned long event, void *data) | ||||
| { | ||||
| 	struct fb_event *evdata = data; | ||||
| 	struct fb_info *info = evdata->info; | ||||
|  | ||||
| 	dev_dbg(&n516_device->dev, "ENTER %s\n", __func__); | ||||
|  | ||||
| 	if (event == FB_EVENT_FB_REGISTERED) | ||||
| 		return n516_share_video_mem(info); | ||||
| 	else if (event == FB_EVENT_FB_UNREGISTERED) | ||||
| 		return n516_unshare_video_mem(info); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static struct notifier_block n516_fb_notif = { | ||||
| 	.notifier_call = n516_fb_notifier_callback, | ||||
| }; | ||||
|  | ||||
| /* this gets called as part of our init. these steps must be done now so | ||||
|  * that we can use set_pxa_fb_info */ | ||||
| static void __init n516_presetup_fb(void) | ||||
| { | ||||
| 	int padding_size; | ||||
| 	int totalsize; | ||||
|  | ||||
| 	/* the frame buffer is divided as follows: | ||||
| 	command | CRC | padding | ||||
| 	16kb waveform data | CRC | padding | ||||
| 	image data | CRC | ||||
| 	*/ | ||||
|  | ||||
| 	n516_board_info.fw = 800; | ||||
| 	n516_board_info.fh = 624; | ||||
|  | ||||
| 	/* waveform must be 16k + 2 for checksum */ | ||||
| 	n516_board_info.wfm_size = roundup(16*1024 + 2, n516_board_info.fw); | ||||
|  | ||||
| 	padding_size = PAGE_SIZE + (4 * n516_board_info.fw); | ||||
|  | ||||
| 	/* total is 1 cmd , 1 wfm, padding and image */ | ||||
| 	totalsize = n516_board_info.fw + n516_board_info.wfm_size; | ||||
| 	totalsize += padding_size + (n516_board_info.fw*n516_board_info.fh); | ||||
|  | ||||
| 	/* save this off because we're manipulating fw after this and | ||||
| 	 * we'll need it when we're ready to setup the framebuffer */ | ||||
|  | ||||
| 	/* the reason we do this adjustment is because we want to acquire | ||||
| 	 * more framebuffer memory without imposing custom awareness on the | ||||
| 	 * underlying driver */ | ||||
| 	n516_fb_pdata.modes[0].yres = DIV_ROUND_UP(totalsize, n516_board_info.fw); | ||||
|  | ||||
| 	jz4740_framebuffer_device.dev.platform_data = &n516_fb_pdata; | ||||
| 	platform_device_register(&jz4740_framebuffer_device); | ||||
| } | ||||
|  | ||||
| /* this gets called by metronomefb as part of its init, in our case, we | ||||
|  * have already completed initial framebuffer init in presetup_fb so we | ||||
|  * can just setup the fb access pointers */ | ||||
| static int n516_setup_fb(struct metronomefb_par *par) | ||||
| { | ||||
| 	/* metromem was set up by the notifier in share_video_mem so now | ||||
| 	 * we can use its value to calculate the other entries */ | ||||
| 	par->metromem_cmd = (struct metromem_cmd *) n516_board_info.metromem; | ||||
| 	par->metromem_wfm = n516_board_info.metromem + n516_board_info.fw; | ||||
| 	par->metromem_img = par->metromem_wfm + n516_board_info.wfm_size; | ||||
| 	par->metromem_img_csum = (u16 *) (par->metromem_img + (n516_board_info.fw * n516_board_info.fh)); | ||||
| 	par->metromem_dma = n516_board_info.host_fbinfo->fix.smem_start; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int n516_get_panel_type(void) | ||||
| { | ||||
| 	return 5; | ||||
| } | ||||
|  | ||||
| static irqreturn_t n516_handle_irq(int irq, void *dev_id) | ||||
| { | ||||
| 	struct metronomefb_par *par = dev_id; | ||||
|  | ||||
| 	dev_dbg(&par->pdev->dev, "Metronome IRQ! RDY=%d\n", 	gpio_get_value(GPIO_DISPLAY_RDY)); | ||||
| 	wake_up_all(&par->waitq); | ||||
|  | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
|  | ||||
| static void n516_power_ctl(struct metronomefb_par *par, int cmd) | ||||
| { | ||||
| 	switch (cmd) { | ||||
| 	case METRONOME_POWER_OFF: | ||||
| 		gpio_set_value(GPIO_DISPLAY_OFF, 1); | ||||
| 		n516_enable_hostfb(false); | ||||
| 		break; | ||||
| 	case METRONOME_POWER_ON: | ||||
| 		gpio_set_value(GPIO_DISPLAY_OFF, 0); | ||||
| 		n516_enable_hostfb(true); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int n516_get_rdy(struct metronomefb_par *par) | ||||
| { | ||||
| 	return gpio_get_value(GPIO_DISPLAY_RDY); | ||||
| } | ||||
|  | ||||
| static int n516_get_err(struct metronomefb_par *par) | ||||
| { | ||||
| 	return gpio_get_value(GPIO_DISPLAY_ERR); | ||||
| } | ||||
|  | ||||
| static int n516_setup_irq(struct fb_info *info) | ||||
| { | ||||
| 	int ret; | ||||
|  | ||||
| 	dev_dbg(&n516_device->dev, "ENTER %s\n", __func__); | ||||
|  | ||||
| 	ret = request_irq(gpio_to_irq(GPIO_DISPLAY_RDY), n516_handle_irq, | ||||
| 				IRQF_TRIGGER_RISING, | ||||
| 				"n516", info->par); | ||||
| 	if (ret) | ||||
| 		dev_err(&n516_device->dev, "request_irq failed: %d\n", ret); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static void n516_set_rst(struct metronomefb_par *par, int state) | ||||
| { | ||||
| 	dev_dbg(&n516_device->dev, "ENTER %s, RDY=%d\n", __func__, gpio_get_value(GPIO_DISPLAY_RDY)); | ||||
| 	if (state) | ||||
| 		gpio_set_value(GPIO_DISPLAY_RST_L, 1); | ||||
| 	else | ||||
| 		gpio_set_value(GPIO_DISPLAY_RST_L, 0); | ||||
| } | ||||
|  | ||||
| static void n516_set_stdby(struct metronomefb_par *par, int state) | ||||
| { | ||||
| 	dev_dbg(&n516_device->dev, "ENTER %s, RDY=%d\n", __func__, gpio_get_value(GPIO_DISPLAY_RDY)); | ||||
| 	if (state) | ||||
| 		gpio_set_value(GPIO_DISPLAY_STBY, 1); | ||||
| 	else | ||||
| 		gpio_set_value(GPIO_DISPLAY_STBY, 0); | ||||
| } | ||||
|  | ||||
| static int n516_wait_event(struct metronomefb_par *par) | ||||
| { | ||||
| 	unsigned long timeout = jiffies + HZ / 20; | ||||
|  | ||||
| 	dev_dbg(&n516_device->dev, "ENTER1 %s, RDY=%d\n", | ||||
| 			__func__, gpio_get_value(GPIO_DISPLAY_RDY)); | ||||
| 	while (n516_get_rdy(par) && time_before(jiffies, timeout)) | ||||
| 		schedule(); | ||||
|  | ||||
| 	dev_dbg(&n516_device->dev, "ENTER2 %s, RDY=%d\n", | ||||
| 			__func__, gpio_get_value(GPIO_DISPLAY_RDY)); | ||||
| 	return wait_event_timeout(par->waitq, | ||||
| 			n516_get_rdy(par), HZ * 2) ? 0 : -EIO; | ||||
| } | ||||
|  | ||||
| static int n516_wait_event_intr(struct metronomefb_par *par) | ||||
| { | ||||
| 	unsigned long timeout = jiffies + HZ/20; | ||||
|  | ||||
| 	dev_dbg(&n516_device->dev, "ENTER1 %s, RDY=%d\n", | ||||
| 			__func__, gpio_get_value(GPIO_DISPLAY_RDY)); | ||||
| 	while (n516_get_rdy(par) && time_before(jiffies, timeout)) | ||||
| 		schedule(); | ||||
|  | ||||
| 	dev_dbg(&n516_device->dev, "ENTER2 %s, RDY=%d\n", | ||||
| 			__func__, gpio_get_value(GPIO_DISPLAY_RDY)); | ||||
| 	return wait_event_interruptible_timeout(par->waitq, | ||||
| 					n516_get_rdy(par), HZ * 2) ? 0 : -EIO; | ||||
| } | ||||
|  | ||||
| static void n516_cleanup(struct metronomefb_par *par) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	free_irq(gpio_to_irq(GPIO_DISPLAY_RDY), par); | ||||
| 	for (i = 0; i < ARRAY_SIZE(metronome_gpios); ++i) | ||||
| 		gpio_free(metronome_gpios[i]); | ||||
| } | ||||
|  | ||||
| static struct metronome_board n516_board __initdata = { | ||||
| 	.owner			= THIS_MODULE, | ||||
| 	.power_ctl		= n516_power_ctl, | ||||
| 	.setup_irq		= n516_setup_irq, | ||||
| 	.setup_io		= n516_init_metronome_gpios, | ||||
| 	.setup_fb		= n516_setup_fb, | ||||
| 	.set_rst		= n516_set_rst, | ||||
| 	.get_err		= n516_get_err, | ||||
| 	.get_rdy		= n516_get_rdy, | ||||
| 	.set_stdby		= n516_set_stdby, | ||||
| 	.met_wait_event		= n516_wait_event, | ||||
| 	.met_wait_event_intr	= n516_wait_event_intr, | ||||
| 	.get_panel_type		= n516_get_panel_type, | ||||
| 	.cleanup		= n516_cleanup, | ||||
| }; | ||||
|  | ||||
| static int __init n516_init(void) | ||||
| { | ||||
| 	int ret; | ||||
|  | ||||
| 	/* Keep the metronome off, until its driver is loaded */ | ||||
| 	ret = gpio_request(GPIO_DISPLAY_OFF, "Display off"); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
|  | ||||
| 	gpio_direction_output(GPIO_DISPLAY_OFF, 1); | ||||
|  | ||||
| 	/* before anything else, we request notification for any fb | ||||
| 	 * creation events */ | ||||
| 	fb_register_client(&n516_fb_notif); | ||||
|  | ||||
| 	n516_device = platform_device_alloc("metronomefb", -1); | ||||
| 	if (!n516_device) | ||||
| 		return -ENOMEM; | ||||
|  | ||||
| 	/* the n516_board that will be seen by metronomefb is a copy */ | ||||
| 	platform_device_add_data(n516_device, &n516_board, | ||||
| 					sizeof(n516_board)); | ||||
|  | ||||
| 	n516_presetup_fb(); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| module_init(n516_init); | ||||
|  | ||||
| MODULE_DESCRIPTION("board driver for n516 display"); | ||||
| MODULE_AUTHOR("Yauhen Kharuzhy"); | ||||
| MODULE_LICENSE("GPL"); | ||||
							
								
								
									
										201
									
								
								target/linux/xburst/files-2.6.32/arch/mips/jz4740/board-n516.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								target/linux/xburst/files-2.6.32/arch/mips/jz4740/board-n516.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,201 @@ | ||||
| /* | ||||
|  * linux/arch/mips/jz4740/board-516.c | ||||
|  * | ||||
|  * JZ4740 n516 board setup routines. | ||||
|  * | ||||
|  * Copyright (c) 2009, Yauhen Kharuzhy <jekhor@gmail.com> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  */ | ||||
|  | ||||
| #include <linux/init.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/ioport.h> | ||||
| #include <linux/mm.h> | ||||
| #include <linux/console.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/i2c.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/mtd/mtd.h> | ||||
| #include <linux/mmc/jz4740_mmc.h> | ||||
| #include <linux/mtd/jz4740_nand.h> | ||||
| #include <linux/leds.h> | ||||
|  | ||||
| #include <linux/power_supply.h> | ||||
| #include <linux/power/gpio-charger.h> | ||||
|  | ||||
| #include <linux/i2c.h> | ||||
| #include <linux/i2c-gpio.h> | ||||
|  | ||||
| #include <asm/mach-jz4740/board-n516.h> | ||||
| #include <asm/mach-jz4740/platform.h> | ||||
|  | ||||
| #include "clock.h" | ||||
|  | ||||
| static long n516_panic_blink(long time) | ||||
| { | ||||
| 	gpio_set_value(GPIO_LED_ENABLE, 1); | ||||
| 	mdelay(200); | ||||
| 	gpio_set_value(GPIO_LED_ENABLE, 0); | ||||
| 	mdelay(200); | ||||
|  | ||||
| 	return 400; | ||||
| } | ||||
|  | ||||
| static void __init board_gpio_setup(void) | ||||
| { | ||||
| /*	jz_gpio_enable_pullup(JZ_GPIO_PORTD(23)); | ||||
| 	jz_gpio_enable_pullup(JZ_GPIO_PORTD(24));*/ | ||||
| } | ||||
|  | ||||
| static struct i2c_gpio_platform_data n516_i2c_pdata = { | ||||
| 	.sda_pin = JZ_GPIO_PORTD(23), | ||||
| 	.scl_pin = JZ_GPIO_PORTD(24), | ||||
| 	.udelay = 2, | ||||
| 	.timeout = 3 * HZ, | ||||
| }; | ||||
|  | ||||
| static struct platform_device n516_i2c_device = { | ||||
| 	.name = "i2c-gpio", | ||||
| 	.id = -1, | ||||
| 	.dev = { | ||||
| 		.platform_data = &n516_i2c_pdata, | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| static const struct i2c_board_info n516_i2c_board_info[] = { | ||||
| 	{ | ||||
| 		.type		= "LPC524", | ||||
| 		.addr		= 0x54, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.type		= "lm75a", | ||||
| 		.addr		= 0x48, | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| static struct jz4740_mmc_platform_data n516_mmc_pdata = { | ||||
| 	.gpio_card_detect	= GPIO_SD_CD_N, | ||||
| 	.card_detect_active_low = 1, | ||||
| 	.gpio_read_only		= -1, | ||||
| 	.gpio_power		= GPIO_SD_VCC_EN_N, | ||||
| 	.power_active_low = 1, | ||||
| }; | ||||
|  | ||||
| static struct gpio_led n516_leds[] = { | ||||
| 	{ | ||||
| 		.name = "n516:blue:power", | ||||
| 		.gpio = GPIO_LED_ENABLE, | ||||
| 		.default_state = LEDS_GPIO_DEFSTATE_ON, | ||||
| 		.default_trigger = "nand-disk", | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| static struct gpio_led_platform_data n516_leds_pdata = { | ||||
| 	.leds = n516_leds, | ||||
| 	.num_leds = ARRAY_SIZE(n516_leds), | ||||
| }; | ||||
|  | ||||
| static struct platform_device n516_leds_device = { | ||||
| 	.name = "leds-gpio", | ||||
| 	.id = -1, | ||||
| 	.dev = { | ||||
| 		.platform_data = &n516_leds_pdata, | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| static struct mtd_partition n516_partitions[] = { | ||||
| 	{ .name = "NAND BOOT partition", | ||||
| 	  .offset = 0 * 0x100000, | ||||
| 	  .size = 4 * 0x100000, | ||||
|  	}, | ||||
| 	{ .name = "NAND KERNEL partition", | ||||
| 	  .offset = 4 * 0x100000, | ||||
| 	  .size = 4 * 0x100000, | ||||
|  	}, | ||||
| 	{ .name = "NAND ROOTFS partition", | ||||
| 	  .offset = 8 * 0x100000, | ||||
| 	  .size = 504 * 0x100000, | ||||
|  	}, | ||||
| }; | ||||
|  | ||||
| static struct nand_ecclayout n516_ecclayout = { | ||||
| 	.eccbytes = 36, | ||||
| 	.eccpos = { | ||||
| 		 6,  7,  8,  9, 10, 11, 12, 13, 14, | ||||
| 		15, 16, 17, 18, 19, 20, 21, 22, 23, | ||||
| 		24, 25, 26, 27, 28, 29, 30, 31, 32, | ||||
| 		33, 34, 35, 36, 37, 38, 39, 40, 41, | ||||
| 	}, | ||||
| 	.oobfree = { | ||||
| 		{.offset = 2, | ||||
| 		 .length = 4}, | ||||
| 		{.offset = 42, | ||||
| 		 .length = 22}} | ||||
| }; | ||||
|  | ||||
| static struct jz_nand_platform_data n516_nand_pdata = { | ||||
| 	.ecc_layout = &n516_ecclayout, | ||||
| 	.partitions = n516_partitions, | ||||
| 	.num_partitions = ARRAY_SIZE(n516_partitions), | ||||
| 	.busy_gpio = 94, | ||||
| }; | ||||
|  | ||||
| static char *n516_batteries[] = { | ||||
| 	"n516_battery", | ||||
| }; | ||||
|  | ||||
| static struct gpio_charger_platform_data n516_charger_pdata = { | ||||
| 	.name = "usb", | ||||
| 	.type = POWER_SUPPLY_TYPE_USB, | ||||
| 	.gpio = GPIO_USB_DETECT, | ||||
| 	.gpio_active_low = 1, | ||||
| 	.batteries = n516_batteries, | ||||
| 	.num_batteries = ARRAY_SIZE(n516_batteries), | ||||
| }; | ||||
|  | ||||
| static struct platform_device n516_charger_device = { | ||||
| 	.name = "gpio-charger", | ||||
| 	.dev = { | ||||
| 		.platform_data = &n516_charger_pdata, | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| static struct platform_device *n516_devices[] __initdata = { | ||||
| 	&jz4740_nand_device, | ||||
| 	&n516_leds_device, | ||||
| 	&jz4740_mmc_device, | ||||
| 	&jz4740_i2s_device, | ||||
| 	&jz4740_codec_device, | ||||
| 	&jz4740_rtc_device, | ||||
| 	&jz4740_usb_gdt_device, | ||||
| 	&n516_i2c_device, | ||||
| 	&n516_charger_device, | ||||
| }; | ||||
|  | ||||
| struct jz4740_clock_board_data jz4740_clock_bdata = { | ||||
| 	.ext_rate = 12000000, | ||||
| 	.rtc_rate = 32768, | ||||
| }; | ||||
|  | ||||
| extern int jz_gpiolib_init(void); | ||||
|  | ||||
| static int n516_setup_platform(void) | ||||
| { | ||||
| 	if (jz_gpiolib_init()) | ||||
| 		panic("Failed to initalize jz gpio\n"); | ||||
|  | ||||
| 	jz4740_clock_init(); | ||||
| 	board_gpio_setup(); | ||||
|  | ||||
| 	panic_blink = n516_panic_blink; | ||||
| 	i2c_register_board_info(0, n516_i2c_board_info, ARRAY_SIZE(n516_i2c_board_info)); | ||||
| 	jz4740_mmc_device.dev.platform_data = &n516_mmc_pdata; | ||||
| 	jz4740_nand_device.dev.platform_data = &n516_nand_pdata; | ||||
|  | ||||
| 	return platform_add_devices(n516_devices, ARRAY_SIZE(n516_devices)); | ||||
| } | ||||
| arch_initcall(n516_setup_platform); | ||||
							
								
								
									
										491
									
								
								target/linux/xburst/files-2.6.32/drivers/i2c/chips/n516-lpc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										491
									
								
								target/linux/xburst/files-2.6.32/drivers/i2c/chips/n516-lpc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,491 @@ | ||||
| /* | ||||
|  * board-n516-display.c -- Platform device for N516 display | ||||
|  * | ||||
|  * Copyright (C) 2009, Yauhen Kharuzhy <jekhor@gmail.com> | ||||
|  * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> | ||||
|  * | ||||
|  * This file is subject to the terms and conditions of the GNU General Public | ||||
|  * License. See the file COPYING in the main directory of this archive for | ||||
|  * more details. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #include <linux/module.h> | ||||
| #include <linux/version.h> | ||||
| #include <linux/init.h> | ||||
| #include <linux/fs.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/irq.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/pm.h> | ||||
| #include <linux/sysctl.h> | ||||
| #include <linux/proc_fs.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/input.h> | ||||
| #include <linux/power_supply.h> | ||||
| #include <linux/suspend.h> | ||||
|  | ||||
| #include <linux/i2c.h> | ||||
|  | ||||
| #include <asm/mach-jz4740/irq.h> | ||||
| #include <asm/mach-jz4740/gpio.h> | ||||
| #include <asm/mach-jz4740/board-n516.h> | ||||
|  | ||||
|  | ||||
| static int batt_level=0; | ||||
| module_param(batt_level, int, 0); | ||||
|  | ||||
| struct n516_lpc_chip { | ||||
| 	struct i2c_client	*i2c_client; | ||||
| 	struct input_dev	*input; | ||||
| 	unsigned int		battery_level; | ||||
| 	unsigned int		suspending:1, can_sleep:1; | ||||
| }; | ||||
|  | ||||
| static struct n516_lpc_chip *the_lpc; | ||||
|  | ||||
| struct i2c_device_id n516_lpc_i2c_ids[] = { | ||||
| 	{"LPC524", 0}, | ||||
| 	{}, | ||||
| }; | ||||
|  | ||||
| MODULE_DEVICE_TABLE(i2c, n516_lpc_i2c_ids); | ||||
|  | ||||
| static const unsigned short normal_i2c[] = {0x54, I2C_CLIENT_END}; | ||||
|  | ||||
| static const unsigned int n516_lpc_keymap[] = { | ||||
| 	[0x01] = KEY_4, | ||||
| 	[0x02] = KEY_3, | ||||
| 	[0x03] = KEY_2, | ||||
| 	[0x04] = KEY_1, | ||||
| 	[0x05] = KEY_0, | ||||
| 	[0x07] = KEY_9, | ||||
| 	[0x08] = KEY_8, | ||||
| 	[0x09] = KEY_7, | ||||
| 	[0x0a] = KEY_6, | ||||
| 	[0x0b] = KEY_5, | ||||
| 	[0x0d] = KEY_PLAYPAUSE, | ||||
| 	[0x0e] = KEY_MENU, | ||||
| 	[0x0f] = KEY_SEARCH, | ||||
| 	[0x10] = KEY_DIRECTION, | ||||
| 	[0x11] = KEY_SPACE, | ||||
| 	[0x13] = KEY_ENTER, | ||||
| 	[0x14] = KEY_UP, | ||||
| 	[0x15] = KEY_DOWN, | ||||
| 	[0x16] = KEY_RIGHT, | ||||
| 	[0x17] = KEY_LEFT, | ||||
| 	[0x19] = KEY_PAGEDOWN, | ||||
| 	[0x1a] = KEY_PAGEUP, | ||||
| 	[0x1c] = KEY_POWER, | ||||
| 	[0x1d] = KEY_ESC, | ||||
| 	[0x1e] = KEY_SLEEP, | ||||
| /*	[0x1f] = KEY_WAKEUP,*/ | ||||
| }; | ||||
|  | ||||
| static const unsigned int batt_charge[] = {0, 7, 20, 45, 65, 80, 100}; | ||||
| #define MAX_BAT_LEVEL (ARRAY_SIZE(batt_charge) - 1) | ||||
|  | ||||
| /* Insmod parameters */ | ||||
| I2C_CLIENT_INSMOD_1(n516_lpc); | ||||
|  | ||||
| static inline int n516_bat_usb_connected(void) | ||||
| { | ||||
| 	return !gpio_get_value(GPIO_USB_DETECT); | ||||
| } | ||||
|  | ||||
| static inline int n516_bat_charging(void) | ||||
| { | ||||
| 	return !gpio_get_value(GPIO_CHARG_STAT_N); | ||||
| } | ||||
|  | ||||
| static int n516_bat_get_status(struct power_supply *b) | ||||
| { | ||||
| 	if (n516_bat_usb_connected()) { | ||||
| 		if (n516_bat_charging()) | ||||
| 			return POWER_SUPPLY_STATUS_CHARGING; | ||||
| 		else | ||||
| 			return POWER_SUPPLY_STATUS_FULL; | ||||
| 	} else { | ||||
| 		return POWER_SUPPLY_STATUS_DISCHARGING; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int n516_bat_get_charge(struct power_supply *b) | ||||
| { | ||||
| 	return batt_charge[the_lpc->battery_level]; | ||||
| } | ||||
|  | ||||
| static int n516_bat_get_property(struct power_supply *b, | ||||
| 		enum power_supply_property psp, | ||||
| 		union power_supply_propval *val) | ||||
| { | ||||
| 	switch (psp) { | ||||
| 	case POWER_SUPPLY_PROP_STATUS: | ||||
| 		val->intval = n516_bat_get_status(b); | ||||
| 		break; | ||||
| 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||||
| 		val->intval = 100; | ||||
| 		break; | ||||
| 	case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN: | ||||
| 		val->intval = 0; | ||||
| 		break; | ||||
| 	case POWER_SUPPLY_PROP_CHARGE_NOW: | ||||
| 		val->intval = n516_bat_get_charge(b); | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void n516_bat_power_changed(struct power_supply *p) | ||||
| { | ||||
| 	power_supply_changed(p); | ||||
| } | ||||
|  | ||||
| static enum power_supply_property n516_bat_properties[] = { | ||||
| 	POWER_SUPPLY_PROP_STATUS, | ||||
| 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||||
| 	POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN, | ||||
| 	POWER_SUPPLY_PROP_CHARGE_NOW, | ||||
| }; | ||||
|  | ||||
| static struct power_supply n516_battery = { | ||||
| 	.name		= "n516-battery", | ||||
| 	.get_property	= n516_bat_get_property, | ||||
| 	.properties	= n516_bat_properties, | ||||
| 	.num_properties	= ARRAY_SIZE(n516_bat_properties), | ||||
| 	.external_power_changed = n516_bat_power_changed, | ||||
| }; | ||||
|  | ||||
| static irqreturn_t n516_bat_charge_irq(int irq, void *dev) | ||||
| { | ||||
| 	struct power_supply *psy = dev; | ||||
|  | ||||
| 	dev_dbg(psy->dev, "Battery charging IRQ\n"); | ||||
|  | ||||
| 	if (n516_bat_usb_connected() && !n516_bat_charging()) | ||||
| 		the_lpc->battery_level = MAX_BAT_LEVEL; | ||||
|  | ||||
| 	power_supply_changed(psy); | ||||
|  | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
|  | ||||
| static int n516_lpc_set_normal_mode(struct n516_lpc_chip *chip) | ||||
| { | ||||
| 	struct i2c_client *client = chip->i2c_client; | ||||
| 	unsigned char val = 0x02; | ||||
| 	struct i2c_msg msg = {client->addr, client->flags, 1, &val}; | ||||
| 	int ret = 0; | ||||
|  | ||||
| 	ret = i2c_transfer(client->adapter, &msg, 1); | ||||
| 	return ret > 0 ? 0 : ret; | ||||
| } | ||||
|  | ||||
| static void n516_key_event(struct n516_lpc_chip *chip, unsigned char keycode) | ||||
| { | ||||
| 	struct i2c_client *client = chip->i2c_client; | ||||
| 	bool long_press = false; | ||||
|  | ||||
| 	if (keycode & 0x40) { | ||||
| 		keycode &= ~0x40; | ||||
| 		long_press = true; | ||||
| 	} | ||||
|  | ||||
| 	dev_dbg(&client->dev, "keycode: 0x%02x, long_press: 0x%02x\n", keycode, (unsigned int)long_press); | ||||
|  | ||||
| 	if (keycode >= ARRAY_SIZE(n516_lpc_keymap) || n516_lpc_keymap[keycode] == 0) | ||||
| 		return; | ||||
|  | ||||
| 	if (long_press) | ||||
| 		input_report_key(chip->input, KEY_LEFTALT, 1); | ||||
|  | ||||
| 	input_report_key(chip->input, n516_lpc_keymap[keycode], 1); | ||||
| 	input_sync(chip->input); | ||||
| 	input_report_key(chip->input, n516_lpc_keymap[keycode], 0); | ||||
|  | ||||
| 	if (long_press) | ||||
| 		input_report_key(chip->input, KEY_LEFTALT, 0); | ||||
| 	input_sync(chip->input); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void n516_battery_event(struct n516_lpc_chip *chip, unsigned char battery_level) | ||||
| { | ||||
| 	if (battery_level != chip->battery_level) { | ||||
| 		chip->battery_level = battery_level; | ||||
| 		power_supply_changed(&n516_battery); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static irqreturn_t n516_lpc_irq(int irq, void *devid) | ||||
| { | ||||
| 	struct n516_lpc_chip *chip = (struct n516_lpc_chip*)devid; | ||||
| 	int ret; | ||||
| 	unsigned char raw_msg; | ||||
| 	struct i2c_client *client = chip->i2c_client; | ||||
| 	struct i2c_msg msg = {client->addr, client->flags | I2C_M_RD, 1, &raw_msg}; | ||||
|  | ||||
| 	ret = i2c_transfer(client->adapter, &msg, 1); | ||||
| 	if (ret != 1) { | ||||
| 		dev_dbg(&client->dev, "I2C error: %d\n", ret); | ||||
| 		return IRQ_HANDLED; | ||||
| 	} | ||||
|  | ||||
| 	dev_dbg(&client->dev, "msg: 0x%02x\n", raw_msg); | ||||
|  | ||||
| 	if ((raw_msg & 0x40) < ARRAY_SIZE(n516_lpc_keymap)) { | ||||
| 		n516_key_event(chip, raw_msg); | ||||
| 	} else if ((raw_msg >= 0x81) && (raw_msg <= 0x87)) { | ||||
| 		n516_battery_event(chip, raw_msg - 0x81); | ||||
| 	} else { | ||||
| 		n516_lpc_set_normal_mode(chip); | ||||
| 		dev_warn(&client->dev, "Unkown message: %x\n", raw_msg); | ||||
| 		ret = i2c_transfer(client->adapter, &msg, 1); | ||||
| 		if (ret != 1) { | ||||
| 			dev_dbg(&client->dev, "I2C error: %d\n", ret); | ||||
| 		} else { | ||||
| 			dev_warn(&client->dev, "Unkown message part 2: %x\n", raw_msg); | ||||
| 		} | ||||
|  | ||||
| } | ||||
|  | ||||
| 	if (chip->suspending) | ||||
| 		chip->can_sleep = 0; | ||||
|  | ||||
| 	printk("foobar\n"); | ||||
|  | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
|  | ||||
| static void n516_lpc_power_off(void) | ||||
| { | ||||
| 	struct i2c_client *client = the_lpc->i2c_client; | ||||
| 	unsigned char val = 0x01; | ||||
| 	struct i2c_msg msg = {client->addr, client->flags, 1, &val}; | ||||
|  | ||||
| 	printk("Issue LPC POWEROFF command...\n"); | ||||
| 	while (1) | ||||
| 		i2c_transfer(client->adapter, &msg, 1); | ||||
| } | ||||
|  | ||||
| static int n516_lpc_detect(struct i2c_client *client, int kind, struct i2c_board_info *info) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int n516_lpc_suspend_notifier(struct notifier_block *nb, | ||||
| 		                                unsigned long event, | ||||
| 						void *dummy) | ||||
| { | ||||
| 	switch(event) { | ||||
| 	case PM_SUSPEND_PREPARE: | ||||
| 		the_lpc->suspending = 1; | ||||
| 		the_lpc->can_sleep = 1; | ||||
| 		break; | ||||
| 	case PM_POST_SUSPEND: | ||||
| 		the_lpc->suspending = 0; | ||||
| 		the_lpc->can_sleep = 1; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return NOTIFY_DONE; | ||||
| 	} | ||||
| 	return NOTIFY_OK; | ||||
| } | ||||
|  | ||||
| static struct notifier_block n516_lpc_notif_block = { | ||||
| 	.notifier_call = n516_lpc_suspend_notifier, | ||||
| }; | ||||
|  | ||||
| static int n516_lpc_probe(struct i2c_client *client, const struct i2c_device_id *id) | ||||
| { | ||||
| 	struct n516_lpc_chip *chip; | ||||
| 	struct input_dev *input; | ||||
| 	int ret = 0; | ||||
| 	int i; | ||||
|  | ||||
| 	chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||||
| 	if (!chip) | ||||
| 		return -ENOMEM; | ||||
|  | ||||
| 	the_lpc = chip; | ||||
| 	chip->i2c_client = client; | ||||
| 	if ((batt_level > 0) && (batt_level < ARRAY_SIZE(batt_charge))) | ||||
| 		chip->battery_level = batt_level; | ||||
| 	i2c_set_clientdata(client, chip); | ||||
|  | ||||
| 	ret = gpio_request(GPIO_LPC_INT, "LPC interrupt request"); | ||||
| 	if (ret) { | ||||
| 		dev_err(&client->dev, "Unable to reguest LPC INT GPIO\n"); | ||||
| 		goto err_gpio_req_lpcint; | ||||
| 	} | ||||
|  | ||||
| 	ret = gpio_request(GPIO_CHARG_STAT_N, "LPC interrupt request"); | ||||
| 	if (ret) { | ||||
| 		dev_err(&client->dev, "Unable to reguest CHARG STAT GPIO\n"); | ||||
| 		goto err_gpio_req_chargstat; | ||||
| 	} | ||||
|  | ||||
| 	n516_lpc_set_normal_mode(chip); | ||||
|  | ||||
| 	input = input_allocate_device(); | ||||
| 	if (!input) { | ||||
| 		dev_err(&client->dev, "Unable to allocate input device\n"); | ||||
| 		ret = -ENOMEM; | ||||
| 		goto err_input_alloc; | ||||
| 	} | ||||
|  | ||||
| 	chip->input = input; | ||||
|  | ||||
| 	__set_bit(EV_KEY, input->evbit); | ||||
|  | ||||
| 	for (i = 0; i < ARRAY_SIZE(n516_lpc_keymap); i++) | ||||
| 		__set_bit(n516_lpc_keymap[i], input->keybit); | ||||
|  | ||||
| 	__set_bit(KEY_LEFTALT, input->keybit); | ||||
|  | ||||
| 	input->name = "n516-keys"; | ||||
| 	input->phys = "n516-keys/input0"; | ||||
| 	input->dev.parent = &client->dev; | ||||
| 	input->id.bustype = BUS_I2C; | ||||
| 	input->id.vendor = 0x0001; | ||||
| 	input->id.product = 0x0001; | ||||
| 	input->id.version = 0x0100; | ||||
|  | ||||
| 	ret = input_register_device(input); | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(&client->dev, "Unable to register input device\n"); | ||||
| 		goto err_input_register; | ||||
| 	} | ||||
|  | ||||
| 	ret = power_supply_register(NULL, &n516_battery); | ||||
| 	if (ret) { | ||||
| 		dev_err(&client->dev, "Unable to register N516 battery\n"); | ||||
| 		goto err_bat_reg; | ||||
| 	} | ||||
|  | ||||
| 	if (n516_bat_usb_connected() && !n516_bat_charging()) | ||||
| 		the_lpc->battery_level = MAX_BAT_LEVEL; | ||||
|  | ||||
| 	ret = request_threaded_irq(gpio_to_irq(GPIO_LPC_INT), NULL, n516_lpc_irq, | ||||
| 			IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lpc", chip); | ||||
| 	if (ret) { | ||||
| 		dev_err(&client->dev, "request_irq failed: %d\n", ret); | ||||
| 		goto err_request_lpc_irq; | ||||
| 	} | ||||
|  | ||||
| 	ret = request_irq(gpio_to_irq(GPIO_CHARG_STAT_N), n516_bat_charge_irq, | ||||
| 				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "battery charging", &n516_battery); | ||||
| 	if (ret) { | ||||
| 		dev_err(&client->dev, "Unable to claim battery charging IRQ\n"); | ||||
| 		goto err_request_chrg_irq; | ||||
| 	} | ||||
|  | ||||
| 	pm_power_off = n516_lpc_power_off; | ||||
| 	ret = register_pm_notifier(&n516_lpc_notif_block); | ||||
| 	if (ret) { | ||||
| 		dev_err(&client->dev, "Unable to register PM notify block\n"); | ||||
| 		goto err_reg_pm_notifier; | ||||
| 	} | ||||
|  | ||||
| 	device_init_wakeup(&client->dev, 1); | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| 	unregister_pm_notifier(&n516_lpc_notif_block); | ||||
| err_reg_pm_notifier: | ||||
| 	free_irq(gpio_to_irq(GPIO_CHARG_STAT_N), &n516_battery); | ||||
| err_request_chrg_irq: | ||||
| 	free_irq(gpio_to_irq(GPIO_LPC_INT), chip); | ||||
| err_request_lpc_irq: | ||||
| 	power_supply_unregister(&n516_battery); | ||||
| err_bat_reg: | ||||
| 	input_unregister_device(input); | ||||
| err_input_register: | ||||
| 	input_free_device(input); | ||||
| err_input_alloc: | ||||
| 	gpio_free(GPIO_CHARG_STAT_N); | ||||
| err_gpio_req_chargstat: | ||||
| 	gpio_free(GPIO_LPC_INT); | ||||
| err_gpio_req_lpcint: | ||||
| 	i2c_set_clientdata(client, NULL); | ||||
| 	kfree(chip); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static int n516_lpc_remove(struct i2c_client *client) | ||||
| { | ||||
| 	struct n516_lpc_chip *chip = i2c_get_clientdata(client); | ||||
|  | ||||
| 	unregister_pm_notifier(&n516_lpc_notif_block); | ||||
| 	pm_power_off = NULL; | ||||
| 	free_irq(gpio_to_irq(GPIO_CHARG_STAT_N), &n516_battery); | ||||
| 	free_irq(gpio_to_irq(GPIO_LPC_INT), chip); | ||||
| 	power_supply_unregister(&n516_battery); | ||||
| 	input_unregister_device(chip->input); | ||||
| 	gpio_free(GPIO_CHARG_STAT_N); | ||||
| 	gpio_free(GPIO_LPC_INT); | ||||
| 	i2c_set_clientdata(client, NULL); | ||||
| 	kfree(chip); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #if CONFIG_PM | ||||
| static int n516_lpc_suspend(struct i2c_client *client, pm_message_t msg) | ||||
| { | ||||
| 	if (!the_lpc->can_sleep) | ||||
| 		return -EBUSY; | ||||
|  | ||||
| 	if (device_may_wakeup(&client->dev)) | ||||
| 		enable_irq_wake(gpio_to_irq(GPIO_LPC_INT)); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int n516_lpc_resume(struct i2c_client *client) | ||||
| { | ||||
| 	if (device_may_wakeup(&client->dev)) | ||||
| 		disable_irq_wake(gpio_to_irq(GPIO_LPC_INT)); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| #else | ||||
| #define n516_lpc_suspend NULL | ||||
| #define n516_lpc_resume NULL | ||||
| #endif | ||||
|  | ||||
| static struct i2c_driver n516_lpc_driver = { | ||||
| 	.class		= I2C_CLASS_HWMON, | ||||
| 	.driver		= { | ||||
| 		.name	= "n516-keys", | ||||
| 		.owner	= THIS_MODULE, | ||||
| 	}, | ||||
| 	.probe		= n516_lpc_probe, | ||||
| 	.remove		= __devexit_p(n516_lpc_remove), | ||||
| 	.detect		= n516_lpc_detect, | ||||
| 	.id_table	= n516_lpc_i2c_ids, | ||||
| 	.address_data	= &addr_data, | ||||
| 	.suspend	= n516_lpc_suspend, | ||||
| 	.resume		= n516_lpc_resume, | ||||
| }; | ||||
|  | ||||
| static int n516_lpc_init(void) | ||||
| { | ||||
| 	return i2c_add_driver(&n516_lpc_driver); | ||||
| } | ||||
| module_init(n516_lpc_init); | ||||
|  | ||||
| static void n516_lpc_exit(void) | ||||
| { | ||||
| 	i2c_del_driver(&n516_lpc_driver); | ||||
| } | ||||
| module_exit(n516_lpc_exit); | ||||
|  | ||||
| MODULE_AUTHOR("Yauhen Kharuzhy"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| MODULE_DESCRIPTION("Keys and power controller driver for N516"); | ||||
| MODULE_ALIAS("platform:n516-keys"); | ||||
							
								
								
									
										1229
									
								
								target/linux/xburst/files-2.6.32/drivers/video/metronomefb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1229
									
								
								target/linux/xburst/files-2.6.32/drivers/video/metronomefb.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										67
									
								
								target/linux/xburst/files-2.6.32/include/video/metronomefb.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								target/linux/xburst/files-2.6.32/include/video/metronomefb.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| /* | ||||
|  * metronomefb.h - definitions for the metronome framebuffer driver | ||||
|  * | ||||
|  * Copyright (C) 2008 by Jaya Kumar | ||||
|  * | ||||
|  * This file is subject to the terms and conditions of the GNU General Public | ||||
|  * License. See the file COPYING in the main directory of this archive for | ||||
|  * more details. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef _LINUX_METRONOMEFB_H_ | ||||
| #define _LINUX_METRONOMEFB_H_ | ||||
|  | ||||
| /* command structure used by metronome controller */ | ||||
| struct metromem_cmd { | ||||
| 	u16 opcode; | ||||
| 	u16 args[((64-2)/2)]; | ||||
| 	u16 csum; | ||||
| } __attribute__(packed); | ||||
|  | ||||
| /* struct used by metronome. board specific stuff comes from *board */ | ||||
| struct metronomefb_par { | ||||
| 	struct metromem_cmd *metromem_cmd; | ||||
| 	unsigned char *metromem_wfm; | ||||
| 	unsigned char *metromem_img; | ||||
| 	u16 *metromem_img_csum; | ||||
| 	u16 *csum_table; | ||||
| 	dma_addr_t metromem_dma; | ||||
| 	const struct firmware *firmware; | ||||
| 	struct fb_info *info; | ||||
| 	struct metronome_board *board; | ||||
| 	struct platform_device *pdev; | ||||
| 	wait_queue_head_t waitq; | ||||
| 	u8 frame_count; | ||||
| 	int extra_size; | ||||
| 	int current_wf_mode; | ||||
| 	int current_wf_temp; | ||||
| 	unsigned int manual_refresh_threshold; | ||||
| 	unsigned int partial_autorefresh_interval; | ||||
| 	int dt; | ||||
| 	u32 *fxbuckets; | ||||
| 	u32 *fybuckets; | ||||
| 	struct mutex lock; | ||||
| }; | ||||
|  | ||||
| #define METRONOME_POWER_OFF	0 | ||||
| #define METRONOME_POWER_ON	1 | ||||
|  | ||||
| /* board specific routines and data */ | ||||
| struct metronome_board { | ||||
| 	struct module *owner; /* the platform device */ | ||||
| 	void (*power_ctl)(struct metronomefb_par *, int); | ||||
| 	void (*set_rst)(struct metronomefb_par *, int); | ||||
| 	void (*set_stdby)(struct metronomefb_par *, int); | ||||
| 	int (*get_err)(struct metronomefb_par *); | ||||
| 	int (*get_rdy)(struct metronomefb_par *); | ||||
| 	void (*cleanup)(struct metronomefb_par *); | ||||
| 	int (*met_wait_event)(struct metronomefb_par *); | ||||
| 	int (*met_wait_event_intr)(struct metronomefb_par *); | ||||
| 	int (*setup_irq)(struct fb_info *); | ||||
| 	int (*setup_fb)(struct metronomefb_par *); | ||||
| 	int (*setup_io)(struct metronomefb_par *); | ||||
| 	int (*get_panel_type)(void); | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										25
									
								
								target/linux/xburst/n516/config-2.6.32
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								target/linux/xburst/n516/config-2.6.32
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| CONFIG_FB_DEFERRED_IO=y | ||||
| CONFIG_FB_JZ4740=y | ||||
| CONFIG_FB_METRONOME=m | ||||
| CONFIG_FB_SYS_FOPS=m | ||||
| # CONFIG_FRAMEBUFFER_CONSOLE is not set | ||||
| CONFIG_HWMON=y | ||||
| # CONFIG_HWMON_DEBUG_CHIP is not set | ||||
| CONFIG_I2C=y | ||||
| CONFIG_I2C_ALGOBIT=y | ||||
| CONFIG_I2C_BOARDINFO=y | ||||
| CONFIG_I2C_GPIO=y | ||||
| CONFIG_JZ4740_N516=y | ||||
| # CONFIG_KEYBOARD_GPIO is not set | ||||
| CONFIG_LEDS_GPIO=y | ||||
| CONFIG_MTD_CMDLINE_PARTS=y | ||||
| CONFIG_N516_LPC=y | ||||
| CONFIG_NEW_LEDS=y | ||||
| # CONFIG_REGULATOR_FIXED_VOLTAGE is not set | ||||
| # CONFIG_REGULATOR_LP3971 is not set | ||||
| # CONFIG_REGULATOR_MAX1586 is not set | ||||
| # CONFIG_REGULATOR_TPS65023 is not set | ||||
| # CONFIG_REGULATOR_TPS6507X is not set | ||||
| CONFIG_SENSORS_LM75=y | ||||
| # CONFIG_USB_ARCH_HAS_HCD is not set | ||||
| # CONFIG_USB_ARCH_HAS_OHCI is not set | ||||
							
								
								
									
										2
									
								
								target/linux/xburst/n516/target.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								target/linux/xburst/n516/target.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| BOARDNAME:=Hanvon N516 e-book reader | ||||
| #DEFAULT_PACKAGES += uboot-xburst-n516 | ||||
| @@ -10,10 +10,18 @@ Subject: [PATCH] /opt/Projects/openwrt/target/linux/xburst/patches-2.6.31/800-n5 | ||||
| 
 | ||||
| --- a/drivers/i2c/chips/Kconfig
 | ||||
| +++ b/drivers/i2c/chips/Kconfig
 | ||||
| @@ -26,4 +26,13 @@ config SENSORS_TSL2550
 | ||||
| @@ -26,4 +26,21 @@ config SENSORS_TSL2550
 | ||||
|  	  This driver can also be built as a module.  If so, the module | ||||
|  	  will be called tsl2550. | ||||
|   | ||||
| +config N516_LPC
 | ||||
| +	tristate "N516 keys & power controller"
 | ||||
| +	depends on I2C
 | ||||
| +	depends on INPUT
 | ||||
| +	depends on POWER_SUPPLY
 | ||||
| +	help
 | ||||
| +	  N516 keyboard & power controller driver
 | ||||
| +
 | ||||
| +config N526_LPC
 | ||||
| +	tristate "N526 LPC934 coprocessor"
 | ||||
| +	depends on JZ4740_N526
 | ||||
| @@ -26,10 +34,11 @@ Subject: [PATCH] /opt/Projects/openwrt/target/linux/xburst/patches-2.6.31/800-n5 | ||||
|  endmenu | ||||
| --- a/drivers/i2c/chips/Makefile
 | ||||
| +++ b/drivers/i2c/chips/Makefile
 | ||||
| @@ -12,6 +12,7 @@
 | ||||
| @@ -12,6 +12,8 @@
 | ||||
|   | ||||
|  obj-$(CONFIG_DS1682)		+= ds1682.o | ||||
|  obj-$(CONFIG_SENSORS_TSL2550)	+= tsl2550.o | ||||
| +obj-$(CONFIG_N516_LPC)		+= n516-lpc.o
 | ||||
| +obj-$(CONFIG_N526_LPC)		+= n526-lpc.o
 | ||||
|   | ||||
|  ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) | ||||
		Reference in New Issue
	
	Block a user
	 Lars-Peter Clausen
					Lars-Peter Clausen