mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-24 01:43:08 +02:00
[xburst] Add support for the n516
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@19987 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
parent
de2c2b0b71
commit
cde7986406
@ -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 DMA_NONCOHERENT
|
||||||
select SOC_JZ4740
|
select SOC_JZ4740
|
||||||
|
|
||||||
|
config JZ4740_N516
|
||||||
|
bool "Hanvon n516 eBook reader"
|
||||||
|
select DMA_NONCOHERENT
|
||||||
|
select SOC_JZ4740
|
||||||
|
|
||||||
config JZ4740_N526
|
config JZ4740_N526
|
||||||
bool "Hanvon n526 eBook reader"
|
bool "Hanvon n526 eBook reader"
|
||||||
select DMA_NONCOHERENT
|
select DMA_NONCOHERENT
|
||||||
|
@ -12,9 +12,10 @@ obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o
|
|||||||
# board specific support
|
# board specific support
|
||||||
|
|
||||||
obj-$(CONFIG_JZ4740_QI_LB60) += board-qi_lb60.o
|
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
|
obj-$(CONFIG_JZ4740_N526) += board-n526.o
|
||||||
|
|
||||||
# PM support
|
# 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
|
--- a/drivers/i2c/chips/Kconfig
|
||||||
+++ b/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
|
This driver can also be built as a module. If so, the module
|
||||||
will be called tsl2550.
|
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
|
+config N526_LPC
|
||||||
+ tristate "N526 LPC934 coprocessor"
|
+ tristate "N526 LPC934 coprocessor"
|
||||||
+ depends on JZ4740_N526
|
+ depends on JZ4740_N526
|
||||||
@ -26,10 +34,11 @@ Subject: [PATCH] /opt/Projects/openwrt/target/linux/xburst/patches-2.6.31/800-n5
|
|||||||
endmenu
|
endmenu
|
||||||
--- a/drivers/i2c/chips/Makefile
|
--- a/drivers/i2c/chips/Makefile
|
||||||
+++ b/drivers/i2c/chips/Makefile
|
+++ b/drivers/i2c/chips/Makefile
|
||||||
@@ -12,6 +12,7 @@
|
@@ -12,6 +12,8 @@
|
||||||
|
|
||||||
obj-$(CONFIG_DS1682) += ds1682.o
|
obj-$(CONFIG_DS1682) += ds1682.o
|
||||||
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
|
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
|
||||||
|
+obj-$(CONFIG_N516_LPC) += n516-lpc.o
|
||||||
+obj-$(CONFIG_N526_LPC) += n526-lpc.o
|
+obj-$(CONFIG_N526_LPC) += n526-lpc.o
|
||||||
|
|
||||||
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
|
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
|
Loading…
Reference in New Issue
Block a user