mirror of
https://github.com/genesi/linux-legacy.git
synced 2026-07-08 17:56:11 +00:00
EfikaMX Smartbook Kernel support, initial
This commit is contained in:
1946
arch/arm/configs/mx51_efikasb_defconfig
Normal file
1946
arch/arm/configs/mx51_efikasb_defconfig
Normal file
File diff suppressed because it is too large
Load Diff
@@ -47,6 +47,13 @@ config MACH_MX51_EFIKAMX
|
||||
help
|
||||
Include support for Genesi Efika MX platforms.
|
||||
|
||||
config MACH_MX51_EFIKASB
|
||||
bool "Support Genesi Efika MX Smartbook"
|
||||
select ARCH_MX51
|
||||
help
|
||||
Include support for Genesi Efika MX Smartbook. This includes specific
|
||||
configurations for the board and its peripherals.
|
||||
|
||||
config MACH_MX53_EVK
|
||||
bool "Support MX53 EVK platform"
|
||||
select ARCH_MX53
|
||||
|
||||
@@ -22,3 +22,6 @@ obj-$(CONFIG_MACH_MX51_EFIKAMX) += mx51_efikamx.o mx51_efikamx_io.o mx51_efikamx
|
||||
mx51_efikamx_spi.o mx51_efikamx_nor.o mx51_efikamx_pmic.o \
|
||||
mx51_efikamx_mmc.o mx51_efikamx_ata.o mx51_efikamx_powerkey.o \
|
||||
mx51_efikamx_audio.o mx51_efikamx_display.o early_setup.o
|
||||
obj-$(CONFIG_MACH_MX51_EFIKASB) += mx51_efikasb.o mx51_efikasb_gpio.o mx51_efikasb_pmic.o \
|
||||
mx51_efikasb_idle_timer.o mx51_efikasb_input.o \
|
||||
mx51_efikasb_lid.o mx51_efikasb_powerkey.o
|
||||
|
||||
833
arch/arm/mach-mx5/mx51_efikasb.c
Normal file
833
arch/arm/mach-mx5/mx51_efikasb.c
Normal file
@@ -0,0 +1,833 @@
|
||||
/*
|
||||
* Copyright 2009-2010 Pegatron Corporation. All Rights Reserved.
|
||||
* Copyright 2009-2010 Genesi USA, Inc. All Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/fsl_devices.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/map.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pmic_external.h>
|
||||
#include <linux/pmic_status.h>
|
||||
#include <linux/ipu.h>
|
||||
#include <linux/mxcfb.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/ata.h>
|
||||
#include <mach/common.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/time.h>
|
||||
#include <asm/mach/keypad.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/mmc.h>
|
||||
#include <mach/mxc_dvfs.h>
|
||||
#include <mach/mxc_edid.h>
|
||||
|
||||
#include "devices.h"
|
||||
#include "mx51_efikasb.h"
|
||||
#include "iomux.h"
|
||||
#include "mx51_pins.h"
|
||||
#include "crm_regs.h"
|
||||
#include "usb.h"
|
||||
#include <mach/clock.h>
|
||||
|
||||
/*!
|
||||
* @file mach-mx51/mx51_efikasb.c
|
||||
*
|
||||
* @brief This file contains the board specific initialization routines.
|
||||
*
|
||||
* @ingroup MSL_MX51
|
||||
*/
|
||||
extern void __init mx51_efikasb_io_init(void);
|
||||
extern struct cpu_wp *(*get_cpu_wp)(int *wp);
|
||||
extern void (*set_num_cpu_wp)(int num);
|
||||
static int num_cpu_wp = 3;
|
||||
static int lvds_en_dir = 0;
|
||||
|
||||
extern int mxc_get_battery_insertion_status(void);
|
||||
extern int mxc_get_ac_adapter_insertion_status(void);
|
||||
extern int mxc_get_batt_low_status(void);
|
||||
/* extern void mxc_turn_on_batt_low_led(int); */
|
||||
|
||||
extern int mxc_get_memory_id(void);
|
||||
extern unsigned int mxc_get_pcb_id(void);
|
||||
|
||||
/* working point(wp): 0 - 800MHz; 1 - 166.25MHz; */
|
||||
static struct cpu_wp cpu_wp_auto[] = {
|
||||
{
|
||||
.pll_rate = 1000000000,
|
||||
.cpu_rate = 1000000000,
|
||||
.pdf = 0,
|
||||
.mfi = 10,
|
||||
.mfd = 11,
|
||||
.mfn = 5,
|
||||
.cpu_podf = 0,
|
||||
.cpu_voltage = 1175000,},
|
||||
{
|
||||
.pll_rate = 800000000,
|
||||
.cpu_rate = 800000000,
|
||||
.pdf = 0,
|
||||
.mfi = 8,
|
||||
.mfd = 2,
|
||||
.mfn = 1,
|
||||
.cpu_podf = 0,
|
||||
.cpu_voltage = 1100000,},
|
||||
{
|
||||
.pll_rate = 800000000,
|
||||
.cpu_rate = 166250000,
|
||||
.pdf = 4,
|
||||
.mfi = 8,
|
||||
.mfd = 2,
|
||||
.mfn = 1,
|
||||
.cpu_podf = 4,
|
||||
.cpu_voltage = 850000,},
|
||||
|
||||
};
|
||||
|
||||
struct cpu_wp *mx51_efikasb_get_cpu_wp(int *wp)
|
||||
{
|
||||
*wp = num_cpu_wp;
|
||||
return cpu_wp_auto;
|
||||
}
|
||||
|
||||
void mx51_efikasb_set_num_cpu_wp(int num)
|
||||
{
|
||||
num_cpu_wp = num;
|
||||
return;
|
||||
}
|
||||
|
||||
static struct mxc_w1_config mxc_w1_data = {
|
||||
.search_rom_accelerator = 1,
|
||||
};
|
||||
|
||||
|
||||
static struct platform_pwm_backlight_data mxc_pwm_backlight_data = {
|
||||
.pwm_id = 0,
|
||||
.max_brightness = 255,
|
||||
.dft_brightness = 128,
|
||||
.pwm_period_ns = 78770,
|
||||
};
|
||||
|
||||
extern void mx5_ipu_reset(void); /* eric 20100521 */
|
||||
static struct mxc_ipu_config mxc_ipu_data = {
|
||||
.rev = 2,
|
||||
.reset = mx5_ipu_reset, /* eric 20100521*/
|
||||
};
|
||||
|
||||
extern void mx5_vpu_reset(void);
|
||||
static struct mxc_vpu_platform_data mxc_vpu_data = {
|
||||
.reset = mx5_vpu_reset,
|
||||
};
|
||||
|
||||
extern void mx51_efikasb_gpio_spi_chipselect_active(int cspi_mode, int status,
|
||||
int chipselect);
|
||||
extern void mx51_efikasb_gpio_spi_chipselect_inactive(int cspi_mode, int status,
|
||||
int chipselect);
|
||||
static struct mxc_spi_master mxcspi1_data = {
|
||||
.maxchipselect = 4,
|
||||
.spi_version = 23,
|
||||
.chipselect_active = mx51_efikasb_gpio_spi_chipselect_active,
|
||||
.chipselect_inactive = mx51_efikasb_gpio_spi_chipselect_inactive,
|
||||
};
|
||||
|
||||
static struct mxc_i2c_platform_data mxci2c_data = {
|
||||
.i2c_clk = 100000,
|
||||
};
|
||||
|
||||
static struct mxc_srtc_platform_data srtc_data = {
|
||||
.srtc_sec_mode_addr = 0x83F98840,
|
||||
};
|
||||
|
||||
static struct tve_platform_data tve_data = {
|
||||
.dac_reg = "VVIDEO",
|
||||
};
|
||||
|
||||
static struct mxc_dvfs_platform_data dvfs_core_data = {
|
||||
.reg_id = "SW1",
|
||||
.clk1_id = "cpu_clk",
|
||||
.clk2_id = "gpc_dvfs_clk",
|
||||
.gpc_cntr_reg_addr = MXC_GPC_CNTR,
|
||||
.gpc_vcr_reg_addr = MXC_GPC_VCR,
|
||||
.ccm_cdcr_reg_addr = MXC_CCM_CDCR,
|
||||
.ccm_cacrr_reg_addr = MXC_CCM_CACRR,
|
||||
.ccm_cdhipr_reg_addr = MXC_CCM_CDHIPR,
|
||||
// .dvfs_thrs_reg_addr = MXC_DVFSTHRS,
|
||||
//.dvfs_coun_reg_addr = MXC_DVFSCOUN,
|
||||
//.dvfs_emac_reg_addr = MXC_DVFSEMAC,
|
||||
//.dvfs_cntr_reg_addr = MXC_DVFSCNTR,
|
||||
.prediv_mask = 0x1F800,
|
||||
.prediv_offset = 11,
|
||||
.prediv_val = 3,
|
||||
.div3ck_mask = 0xE0000000,
|
||||
.div3ck_offset = 29,
|
||||
.div3ck_val = 2,
|
||||
.emac_val = 0x08,
|
||||
.upthr_val = 25,
|
||||
.dnthr_val = 9,
|
||||
.pncthr_val = 33,
|
||||
.upcnt_val = 10,
|
||||
.dncnt_val = 10,
|
||||
.delay_time = 30,
|
||||
.num_wp = 3,
|
||||
};
|
||||
|
||||
static struct mxc_dvfsper_data dvfs_per_data = {
|
||||
.reg_id = "SW2",
|
||||
.clk_id = "gpc_dvfs_clk",
|
||||
.gpc_cntr_reg_addr = MXC_GPC_CNTR,
|
||||
.gpc_vcr_reg_addr = MXC_GPC_VCR,
|
||||
.gpc_adu = 0x0,
|
||||
.vai_mask = MXC_DVFSPMCR0_FSVAI_MASK,
|
||||
.vai_offset = MXC_DVFSPMCR0_FSVAI_OFFSET,
|
||||
.dvfs_enable_bit = MXC_DVFSPMCR0_DVFEN,
|
||||
.irq_mask = MXC_DVFSPMCR0_FSVAIM,
|
||||
.div3_offset = 0,
|
||||
.div3_mask = 0x7,
|
||||
.div3_div = 2,
|
||||
.lp_high = 1200000,
|
||||
.lp_low = 1200000,
|
||||
};
|
||||
|
||||
static struct mxc_spdif_platform_data mxc_spdif_data = {
|
||||
.spdif_tx = 1,
|
||||
.spdif_rx = 0,
|
||||
.spdif_clk_44100 = 0, /* spdif_ext_clk source for 44.1KHz */
|
||||
.spdif_clk_48000 = 7, /* audio osc source */
|
||||
.spdif_clkid = 0,
|
||||
.spdif_clk = NULL, /* spdif bus clk */
|
||||
};
|
||||
|
||||
#if defined(CONFIG_FB_MXC_SYNC_PANEL) || \
|
||||
defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE)
|
||||
static struct resource mxcfb_resources[] = {
|
||||
[0] = {
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mxc_fb_platform_data fb_data[] = {
|
||||
{
|
||||
.interface_pix_fmt = IPU_PIX_FMT_RGB24,
|
||||
.mode_str = "1280x720MR-16@60", /* ron: TBD */
|
||||
},
|
||||
{
|
||||
.interface_pix_fmt = IPU_PIX_FMT_RGB565,
|
||||
.mode_str = "1024x768M-16@60", /* ron: TBD */
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
static void __init mxc_init_fb(void)
|
||||
{
|
||||
mxc_fb_devices[1].num_resources = ARRAY_SIZE(mxcfb_resources);
|
||||
mxc_fb_devices[1].resource = mxcfb_resources;
|
||||
mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); /* ron: LVDS LCD */
|
||||
mxc_register_device(&mxc_fb_devices[2], NULL); // Overlay for VPU
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __initdata enable_ddr2max = { 0 };
|
||||
|
||||
static void mxc_power_on_lcd(int on)
|
||||
{
|
||||
if(on) {
|
||||
gpio_set_value(IOMUX_TO_GPIO(LCD_PWRON_PIN), 1); /* LCD Power On */
|
||||
} else {
|
||||
gpio_set_value(IOMUX_TO_GPIO(LCD_PWRON_PIN), 0); /* LCD Power Off */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void mxc_lvds_enable(int on)
|
||||
{
|
||||
if(on == -1) {
|
||||
gpio_direction_input(IOMUX_TO_GPIO(LCD_LVDS_EN_PIN));
|
||||
lvds_en_dir = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
lvds_en_dir = 0;
|
||||
if(on) {
|
||||
gpio_set_value(IOMUX_TO_GPIO(LCD_LVDS_EN_PIN), 1); /* LVDS_EN On */
|
||||
} else {
|
||||
gpio_set_value(IOMUX_TO_GPIO(LCD_LVDS_EN_PIN), 0); /* LVDS_EN Off */
|
||||
}
|
||||
}
|
||||
|
||||
static void mxc_turn_on_lcd_backlight(int on)
|
||||
{
|
||||
if(on) {
|
||||
mxc_free_iomux(LCD_BL_PWM_PIN, IOMUX_CONFIG_GPIO);
|
||||
mxc_request_iomux(LCD_BL_PWM_PIN, IOMUX_CONFIG_ALT1);
|
||||
|
||||
msleep(10);
|
||||
|
||||
gpio_set_value(IOMUX_TO_GPIO(LCD_BL_PWRON_PIN), 0); /* Backlight Power On */
|
||||
} else {
|
||||
gpio_set_value(IOMUX_TO_GPIO(LCD_BL_PWRON_PIN), 1); /* Backlight Power Off */
|
||||
|
||||
msleep(10);
|
||||
|
||||
mxc_free_iomux(LCD_BL_PWM_PIN, IOMUX_CONFIG_ALT1);
|
||||
mxc_request_iomux(LCD_BL_PWM_PIN, IOMUX_CONFIG_GPIO);
|
||||
gpio_direction_output(IOMUX_TO_GPIO(LCD_BL_PWM_PIN), 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void mxc_reset_lvds(void)
|
||||
{
|
||||
gpio_set_value(IOMUX_TO_GPIO(LVDS_RESET_PIN), 0);
|
||||
msleep(50);
|
||||
gpio_set_value(IOMUX_TO_GPIO(LVDS_RESET_PIN), 1);
|
||||
msleep(10);
|
||||
gpio_set_value(IOMUX_TO_GPIO(LVDS_RESET_PIN), 0);
|
||||
|
||||
}
|
||||
|
||||
static void mxc_power_on_lvds(int on)
|
||||
{
|
||||
if(on)
|
||||
gpio_set_value(IOMUX_TO_GPIO(LVDS_PWRCTL_PIN), 1);
|
||||
else
|
||||
gpio_set_value(IOMUX_TO_GPIO(LVDS_PWRCTL_PIN), 0);
|
||||
}
|
||||
|
||||
static struct mxc_lcd_platform_data lvds_data = {
|
||||
.core_reg = "VCAM",
|
||||
.io_reg = "VGEN3",
|
||||
.analog_reg = "VAUDIO",
|
||||
.reset = mxc_reset_lvds,
|
||||
.power_on_lcd = mxc_power_on_lcd,
|
||||
.turn_on_backlight = mxc_turn_on_lcd_backlight,
|
||||
.power_on_lvds = mxc_power_on_lvds,
|
||||
.lvds_enable = mxc_lvds_enable,
|
||||
};
|
||||
|
||||
static struct platform_device mxcbl_device = {
|
||||
.name = "mxc_efikasb_bl",
|
||||
};
|
||||
|
||||
static struct platform_device mxc_led_device = {
|
||||
.name = "efikasb_leds",
|
||||
.id = 1,
|
||||
};
|
||||
|
||||
static struct mxc_battery_platform_data efikasb_batt_data = {
|
||||
.batt_in_irq = IOMUX_TO_IRQ(BATT_INS_PIN),
|
||||
.ac_in_irq = IOMUX_TO_IRQ(AC_ADAP_INS_PIN),
|
||||
.batt_low_irq = IOMUX_TO_IRQ(BATT_LOW_PIN),
|
||||
.get_batt_in_status = mxc_get_battery_insertion_status,
|
||||
.get_ac_in_status = mxc_get_ac_adapter_insertion_status,
|
||||
.get_batt_low_status = mxc_get_batt_low_status,
|
||||
.set_batt_low_led = NULL/* mxc_turn_on_batt_low_led */,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_I2C_MXC) || defined(CONFIG_I2C_MXC_MODULE)
|
||||
static struct i2c_board_info mxc_i2c1_board_info[] __initdata = {
|
||||
{
|
||||
.type = "sgtl5000-i2c",
|
||||
.addr = 0x0a,
|
||||
},
|
||||
{ /* ron: LVDS Controller */
|
||||
.type = "mtl017",
|
||||
.addr = 0x3a,
|
||||
.platform_data = &lvds_data,
|
||||
},
|
||||
{
|
||||
.type = "efikasb-battery",
|
||||
.addr = 0x0b,
|
||||
.platform_data = &efikasb_batt_data,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE)
|
||||
static struct mtd_partition mxc_spi_flash_partitions[] = {
|
||||
{
|
||||
.name = "redboot",
|
||||
.offset = 0,
|
||||
.size = 0x00040000,
|
||||
.mask_flags = MTD_CAP_ROM,
|
||||
},
|
||||
{
|
||||
.name = "fis-dir",
|
||||
.offset = MTDPART_OFS_APPEND,
|
||||
.size = 0x0000F000,
|
||||
.mask_flags = MTD_CAP_ROM,
|
||||
},
|
||||
{
|
||||
.name = "rb-config",
|
||||
.offset = MTDPART_OFS_APPEND,
|
||||
.size = 0x00001000,
|
||||
.mask_flags = MTD_CAP_ROM,
|
||||
},
|
||||
{
|
||||
.name = "kernel",
|
||||
.offset = 0x00100000,
|
||||
.size = MTDPART_SIZ_FULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct flash_platform_data mxc_spi_flash_data = {
|
||||
.name = "mxc_spi_nor",
|
||||
.parts = mxc_spi_flash_partitions,
|
||||
.nr_parts = ARRAY_SIZE(mxc_spi_flash_partitions),
|
||||
/* .type = "sst25vf032b", */
|
||||
/* ron: also support MXIC MX25L3205D, use jedec_probe to detect */
|
||||
.type = NULL,
|
||||
};
|
||||
|
||||
static struct spi_board_info mxc_spi_board_info[] __initdata = {
|
||||
{
|
||||
.modalias = "sst25vf",
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 1,
|
||||
.platform_data = &mxc_spi_flash_data,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE)
|
||||
static int sdhc_write_protect(struct device *dev)
|
||||
{
|
||||
unsigned short rc = 0;
|
||||
|
||||
if (to_platform_device(dev)->id == 0)
|
||||
rc = gpio_get_value(IOMUX_TO_GPIO(SDHC1_WP_PIN));
|
||||
else
|
||||
rc = gpio_get_value(IOMUX_TO_GPIO(SDHC2_WP_PIN));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static unsigned int sdhc_get_card_det_status(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (to_platform_device(dev)->id == 0) {
|
||||
ret = gpio_get_value(IOMUX_TO_GPIO(SDHC1_CD_PIN));
|
||||
return ret;
|
||||
} else { /* config the det pin for SDHC2 */
|
||||
//ron: SDHC2 CD gpio
|
||||
ret = gpio_get_value(IOMUX_TO_GPIO(SDHC2_CD_PIN));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static struct mxc_mmc_platform_data mmc1_data = {
|
||||
.ocr_mask = MMC_VDD_31_32,
|
||||
.caps = MMC_CAP_4_BIT_DATA,
|
||||
.min_clk = 400000,
|
||||
.max_clk = 52000000,
|
||||
.card_inserted_state = 1,
|
||||
.status = sdhc_get_card_det_status,
|
||||
.wp_status = sdhc_write_protect,
|
||||
.clock_mmc = "esdhc_clk",
|
||||
.power_mmc = NULL,
|
||||
};
|
||||
|
||||
static struct mxc_mmc_platform_data mmc2_data = {
|
||||
.ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 |
|
||||
MMC_VDD_31_32,
|
||||
.caps = MMC_CAP_4_BIT_DATA,
|
||||
.min_clk = 150000,
|
||||
.max_clk = 50000000,
|
||||
.card_inserted_state = 0,
|
||||
.status = sdhc_get_card_det_status,
|
||||
.wp_status = sdhc_write_protect,
|
||||
.clock_mmc = "esdhc_clk",
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_SOC_IMX_3STACK_SGTL5000) \
|
||||
|| defined(CONFIG_SND_SOC_IMX_3STACK_SGTL5000_MODULE)
|
||||
static int mxc_sgtl5000_amp_enable(int enable)
|
||||
{
|
||||
gpio_set_value(IOMUX_TO_GPIO(AUD_MUTE_PIN), enable ? 1 : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int headphone_det_status(void)
|
||||
{
|
||||
return gpio_get_value(IOMUX_TO_GPIO(HPJACK_INS_PIN));
|
||||
}
|
||||
|
||||
static struct mxc_audio_platform_data sgtl5000_data = {
|
||||
.ssi_num = 1,
|
||||
.src_port = 2,
|
||||
.ext_port = 3,
|
||||
.hp_irq = IOMUX_TO_IRQ(HPJACK_INS_PIN),
|
||||
.hp_status = headphone_det_status,
|
||||
.amp_enable = mxc_sgtl5000_amp_enable,
|
||||
.sysclk = 12288000,
|
||||
};
|
||||
|
||||
static struct platform_device mxc_sgtl5000_device = {
|
||||
.name = "imx-3stack-sgtl5000",
|
||||
};
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Board specific fixup function. It is called by \b setup_arch() in
|
||||
* setup.c file very early on during kernel starts. It allows the user to
|
||||
* statically fill in the proper values for the passed-in parameters. None of
|
||||
* the parameters is used currently.
|
||||
*
|
||||
* @param desc pointer to \b struct \b machine_desc
|
||||
* @param tags pointer to \b struct \b tag
|
||||
* @param cmdline pointer to the command line
|
||||
* @param mi pointer to \b struct \b meminfo
|
||||
*/
|
||||
static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags,
|
||||
char **cmdline, struct meminfo *mi)
|
||||
{
|
||||
char *str;
|
||||
int size = SZ_512M - SZ_32M;
|
||||
struct tag *t;
|
||||
|
||||
mxc_set_cpu_type(MXC_CPU_MX51);
|
||||
|
||||
get_cpu_wp = mx51_efikasb_get_cpu_wp;
|
||||
set_num_cpu_wp = mx51_efikasb_set_num_cpu_wp;
|
||||
|
||||
for_each_tag(t, tags) {
|
||||
if (t->hdr.tag != ATAG_CMDLINE)
|
||||
continue;
|
||||
str = t->u.cmdline.cmdline;
|
||||
str = strstr(str, "mem=");
|
||||
if (str != NULL) {
|
||||
str += 4;
|
||||
size = memparse(str, &str);
|
||||
if (size == 0 || size == SZ_512M)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for_each_tag(t, tags) {
|
||||
if (t->hdr.tag != ATAG_MEM)
|
||||
continue;
|
||||
|
||||
t->u.mem.size = size;
|
||||
#if defined(CONFIG_FB_MXC_SYNC_PANEL) || \
|
||||
defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE)
|
||||
mxcfb_resources[0].start = t->u.mem.start + size;
|
||||
mxcfb_resources[0].end = t->u.mem.start + SZ_512M - 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#define PWGT1SPIEN (1<<15)
|
||||
#define PWGT2SPIEN (1<<16)
|
||||
#define USEROFFSPI (1<<3)
|
||||
|
||||
static void mxc_power_off(void)
|
||||
{
|
||||
mxc_turn_on_lcd_backlight(0);
|
||||
|
||||
msleep(200);
|
||||
|
||||
if(lvds_en_dir == 0) {
|
||||
mxc_lvds_enable(0);
|
||||
}
|
||||
|
||||
mxc_power_on_lvds(0);
|
||||
|
||||
msleep(5);
|
||||
|
||||
mxc_power_on_lcd(0);
|
||||
|
||||
/* We can do power down one of two ways:
|
||||
Set the power gating
|
||||
Set USEROFFSPI */
|
||||
gpio_set_value(IOMUX_TO_GPIO(USB_PHY_RESET_PIN), 0);
|
||||
msleep(10);
|
||||
/* Set the power gate bits to power down */
|
||||
pmic_write_reg(REG_POWER_MISC, (PWGT1SPIEN|PWGT2SPIEN),
|
||||
(PWGT1SPIEN|PWGT2SPIEN));
|
||||
|
||||
mxc_wd_reset();
|
||||
|
||||
//robin: CLR_DFF
|
||||
mxc_request_iomux(SYS_PWROFF_PIN, IOMUX_CONFIG_GPIO);
|
||||
gpio_direction_output(IOMUX_TO_GPIO(SYS_PWROFF_PIN), 0);
|
||||
gpio_set_value(IOMUX_TO_GPIO(SYS_PWROFF_PIN), 0);
|
||||
msleep(10);
|
||||
gpio_set_value(IOMUX_TO_GPIO(SYS_PWROFF_PIN), 1);
|
||||
}
|
||||
|
||||
static irqreturn_t wwan_wakeup_int(int irq, void *dev_id)
|
||||
{
|
||||
if(gpio_get_value(IOMUX_TO_GPIO(WWAN_WAKEUP_PIN)))
|
||||
set_irq_type(irq, IRQF_TRIGGER_FALLING);
|
||||
else
|
||||
set_irq_type(irq, IRQF_TRIGGER_RISING);
|
||||
|
||||
pr_info("WWAN wakeup event\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init mxc_init_wwan_wakeup(void)
|
||||
{
|
||||
int irq, ret;
|
||||
|
||||
irq = IOMUX_TO_IRQ(WWAN_WAKEUP_PIN);
|
||||
|
||||
if(gpio_get_value(IOMUX_TO_GPIO(WWAN_WAKEUP_PIN)))
|
||||
set_irq_type(irq, IRQF_TRIGGER_FALLING);
|
||||
else
|
||||
set_irq_type(irq, IRQF_TRIGGER_RISING);
|
||||
|
||||
ret = request_irq(irq, wwan_wakeup_int, 0, "wwan-wakeup", 0);
|
||||
if(ret)
|
||||
pr_info("register WWAN wakeup interrupt failed\n");
|
||||
else
|
||||
enable_irq_wake(irq);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
late_initcall(mxc_init_wwan_wakeup);
|
||||
|
||||
extern void gpio_ata_active(void);
|
||||
extern void gpio_ata_inactive(void);
|
||||
|
||||
static int ata_init(struct platform_device *pdev)
|
||||
{
|
||||
/* Configure the pins */
|
||||
gpio_ata_active();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ata_exit(void)
|
||||
{
|
||||
/* Free the pins */
|
||||
gpio_ata_inactive();
|
||||
}
|
||||
|
||||
static struct fsl_ata_platform_data ata_data = {
|
||||
.udma_mask = ATA_UDMA3,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.fifo_alarm = MXC_IDE_DMA_WATERMARK / 2,
|
||||
.max_sg = MXC_IDE_DMA_BD_NR,
|
||||
.init = ata_init,
|
||||
.exit = ata_exit,
|
||||
.core_reg = NULL,
|
||||
.io_reg = NULL,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_GPS_IOCTRL) || defined(CONFIG_GPS_IOCTRL_MODULE)
|
||||
static struct mxc_gps_platform_data gps_data = {
|
||||
.core_reg = "VIOHI",
|
||||
.analog_reg = "SW4",
|
||||
};
|
||||
|
||||
static struct platform_device mxc_gps_device = {
|
||||
.name = "gps_ioctrl",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &gps_data,
|
||||
},
|
||||
};
|
||||
|
||||
int gpio_gps_access(int para)
|
||||
{
|
||||
iomux_pin_name_t pin;
|
||||
pin = (para & 0x1) ? AGPS_PWRON_PIN : AGPS_RESET_PIN;
|
||||
|
||||
if (para & 0x4) /* Read GPIO */
|
||||
return gpio_get_value(IOMUX_TO_GPIO(pin));
|
||||
else if (para & 0x2) /* Write GPIO */
|
||||
gpio_set_value(IOMUX_TO_GPIO(pin), 1);
|
||||
else
|
||||
gpio_set_value(IOMUX_TO_GPIO(pin), 0);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_gps_access);
|
||||
#endif
|
||||
|
||||
static void __init mxc_board_init(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
// printk(" [VV] mxc_board_init.\n");
|
||||
|
||||
mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk");
|
||||
mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk");
|
||||
|
||||
#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE)
|
||||
/* SD card detect irqs */
|
||||
mxcsdhc2_device.resource[2].start = IOMUX_TO_IRQ(SDHC2_CD_PIN);
|
||||
mxcsdhc2_device.resource[2].end = IOMUX_TO_IRQ(SDHC2_CD_PIN);
|
||||
mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(SDHC1_CD_PIN);
|
||||
mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(SDHC1_CD_PIN);
|
||||
#endif
|
||||
|
||||
mxc_cpu_common_init();
|
||||
|
||||
mxc_register_gpios();
|
||||
mx51_efikasb_io_init();
|
||||
|
||||
clk = clk_get(&(mxc_fb_devices[0].dev), "axi_b_clk");
|
||||
clk_set_rate(clk, 133000000);
|
||||
|
||||
mxc_register_device(&mxc_dma_device, NULL);
|
||||
mxc_register_device(&mxc_wdt_device, NULL);
|
||||
mxc_register_device(&mxcspi1_device, &mxcspi1_data);
|
||||
#if defined(CONFIG_I2C_MXC) || defined(CONFIG_I2C_MXC_MODULE)
|
||||
mxc_register_device(&mxci2c_devices[1], &mxci2c_data);
|
||||
#endif
|
||||
#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE)
|
||||
mxc_register_device(&mxcsdhc1_device, &mmc1_data);
|
||||
mxc_register_device(&mxcsdhc2_device, &mmc2_data);
|
||||
#endif
|
||||
mxc_register_device(&mxc_rtc_device, &srtc_data);
|
||||
mxc_register_device(&mxc_w1_master_device, &mxc_w1_data);
|
||||
mxc_register_device(&mxc_ipu_device, &mxc_ipu_data);
|
||||
mxc_register_device(&mxc_tve_device, &tve_data);
|
||||
mxc_register_device(&mxcvpu_device, &mxc_vpu_data);
|
||||
mxc_register_device(&gpu_device, NULL);
|
||||
mxc_register_device(&mxcscc_device, NULL); /* eric 20100521: SCC support */
|
||||
mxc_register_device(&mx51_lpmode_device, NULL);
|
||||
mxc_register_device(&busfreq_device, NULL);
|
||||
mxc_register_device(&sdram_autogating_device, NULL);
|
||||
mxc_register_device(&mxc_dvfs_core_device, &dvfs_core_data);
|
||||
mxc_register_device(&mxc_dvfs_per_device, &dvfs_per_data);
|
||||
mxc_register_device(&mxc_iim_device, NULL);
|
||||
mxc_register_device(&mxc_pwm1_device, NULL);
|
||||
mxc_register_device(&mxc_pwm_backlight_device, &mxc_pwm_backlight_data);
|
||||
mxc_register_device(&mxc_ssi1_device, NULL);
|
||||
mxc_register_device(&mxc_ssi2_device, NULL);
|
||||
mxc_register_device(&pata_fsl_device, &ata_data);
|
||||
mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data);
|
||||
mxc_register_device(&mxc_fec_device, NULL);
|
||||
|
||||
mxc_init_fb();
|
||||
mxc_register_device(&mxcbl_device, NULL);
|
||||
mxc_register_device(&mxc_led_device, NULL);
|
||||
// printk(" [VV] invoking mx51_efikasb_init_mc13892.\n");
|
||||
mx51_efikasb_init_mc13892();
|
||||
|
||||
#if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE)
|
||||
spi_register_board_info(mxc_spi_board_info,
|
||||
ARRAY_SIZE(mxc_spi_board_info));
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_I2C_MXC) || defined(CONFIG_I2C_MXC_MODULE)
|
||||
i2c_register_board_info(1, mxc_i2c1_board_info,
|
||||
ARRAY_SIZE(mxc_i2c1_board_info));
|
||||
#endif
|
||||
|
||||
pm_power_off = mxc_power_off;
|
||||
|
||||
#if defined(CONFIG_SND_SOC_IMX_3STACK_SGTL5000) \
|
||||
|| defined(CONFIG_SND_SOC_IMX_3STACK_SGTL5000_MODULE)
|
||||
if (cpu_is_mx51_rev(CHIP_REV_1_1) == 2) {
|
||||
sgtl5000_data.sysclk = 26000000;
|
||||
}
|
||||
|
||||
gpio_direction_output(IOMUX_TO_GPIO(AUD_MUTE_PIN), 0);
|
||||
mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data);
|
||||
#endif
|
||||
|
||||
mx5_usb_dr_init();
|
||||
mx5_usbh1_init();
|
||||
mx51_usbh2_init();
|
||||
|
||||
#if defined(CONFIG_GPS_IOCTRL) || defined(CONFIG_GPS_IOCTRL_MODULE)
|
||||
mxc_register_device(&mxc_gps_device, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __init mx51_efikasb_timer_init(void)
|
||||
{
|
||||
struct clk *uart_clk;
|
||||
|
||||
/* Change the CPU voltages for TO2*/
|
||||
if (cpu_is_mx51_rev(CHIP_REV_2_0) <= 1) {
|
||||
cpu_wp_auto[0].cpu_voltage = 1175000;
|
||||
cpu_wp_auto[1].cpu_voltage = 1100000;
|
||||
cpu_wp_auto[2].cpu_voltage = 1000000;
|
||||
}
|
||||
|
||||
mx51_clocks_init(32768, 24000000, 22579200, 24576000);
|
||||
|
||||
uart_clk = clk_get(NULL, "uart_clk.0");
|
||||
early_console_setup(UART1_BASE_ADDR, uart_clk);
|
||||
}
|
||||
|
||||
static struct sys_timer mxc_timer = {
|
||||
.init = mx51_efikasb_timer_init,
|
||||
};
|
||||
|
||||
/*
|
||||
* The following uses standard kernel macros define in arch.h in order to
|
||||
* initialize __mach_desc_MX51_EFIKASB data structure.
|
||||
*/
|
||||
/* *INDENT-OFF* */
|
||||
MACHINE_START(MX51_EFIKASB, "Freescale MX51 Efikasb Board")
|
||||
/* Maintainer: Genesi, Inc. */
|
||||
.fixup = fixup_mxc_board,
|
||||
.map_io = mx5_map_io,
|
||||
.init_irq = mx5_init_irq,
|
||||
.init_machine = mxc_board_init,
|
||||
.timer = &mxc_timer,
|
||||
MACHINE_END
|
||||
|
||||
static int __init ddr2max_setup(char *__unused)
|
||||
{
|
||||
enable_ddr2max = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("ddr2max", ddr2max_setup);
|
||||
|
||||
/*
|
||||
* Workaround to solve the black screen on warm reboot aging test
|
||||
* This requires to set DDR2 rate to 160MHz before booting kernel
|
||||
*/
|
||||
static int __init ddr2_set_max_rate(void)
|
||||
{
|
||||
struct clk *tclk;
|
||||
unsigned long rate;
|
||||
|
||||
/*Change the DDR freq to 200MHz*/
|
||||
if (enable_ddr2max) {
|
||||
tclk = clk_get(NULL, "ddr_hf_clk");
|
||||
rate = clk_round_rate(tclk, 200000000);
|
||||
if (clk_get_rate(tclk) != rate)
|
||||
clk_set_rate(tclk, rate);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
late_initcall(ddr2_set_max_rate);
|
||||
153
arch/arm/mach-mx5/mx51_efikasb.h
Normal file
153
arch/arm/mach-mx5/mx51_efikasb.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARCH_MXC_BOARD_MX51_EFIKASB_H__
|
||||
#define __ASM_ARCH_MXC_BOARD_MX51_EFIKASB_H__
|
||||
|
||||
/*!
|
||||
* @defgroup BRDCFG_MX51 Board Configuration Options
|
||||
* @ingroup MSL_MX51
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file mach-mx51/board-mx51_efikasb.h
|
||||
*
|
||||
* @brief This file contains all the board level configuration options.
|
||||
*
|
||||
* It currently hold the options defined for Genesi MX51 Efikasb Platform.
|
||||
*
|
||||
* @ingroup BRDCFG_MX51
|
||||
*/
|
||||
|
||||
/*
|
||||
* Include Files
|
||||
*/
|
||||
#include <mach/mxc_uart.h>
|
||||
|
||||
/*!
|
||||
* @name MXC UART board level configurations
|
||||
*/
|
||||
/*! @{ */
|
||||
/*!
|
||||
* Specifies if the Irda transmit path is inverting
|
||||
*/
|
||||
#define MXC_IRDA_TX_INV 0
|
||||
/*!
|
||||
* Specifies if the Irda receive path is inverting
|
||||
*/
|
||||
#define MXC_IRDA_RX_INV 0
|
||||
|
||||
/* UART 1 configuration */
|
||||
/*!
|
||||
* This define specifies if the UART port is configured to be in DTE or
|
||||
* DCE mode. There exists a define like this for each UART port. Valid
|
||||
* values that can be used are \b MODE_DTE or \b MODE_DCE.
|
||||
*/
|
||||
#define UART1_MODE MODE_DCE
|
||||
/*!
|
||||
* This define specifies if the UART is to be used for IRDA. There exists a
|
||||
* define like this for each UART port. Valid values that can be used are
|
||||
* \b IRDA or \b NO_IRDA.
|
||||
*/
|
||||
#define UART1_IR NO_IRDA
|
||||
/*!
|
||||
* This define is used to enable or disable a particular UART port. If
|
||||
* disabled, the UART will not be registered in the file system and the user
|
||||
* will not be able to access it. There exists a define like this for each UART
|
||||
* port. Specify a value of 1 to enable the UART and 0 to disable it.
|
||||
*/
|
||||
#define UART1_ENABLED 1
|
||||
/*! @} */
|
||||
/* UART 2 configuration */
|
||||
#define UART2_MODE MODE_DCE
|
||||
#define UART2_IR NO_IRDA
|
||||
#define UART2_ENABLED 1
|
||||
/* UART 3 configuration */
|
||||
#define UART3_MODE MODE_DTE
|
||||
#define UART3_IR NO_IRDA
|
||||
#define UART3_ENABLED 1
|
||||
/* UART 4 configuration */
|
||||
#define UART4_MODE MODE_DCE
|
||||
#define UART4_IR NO_IRDA
|
||||
#define UART4_ENABLED 0
|
||||
/* UART 5 configuration */
|
||||
#define UART5_MODE MODE_DCE
|
||||
#define UART5_IR NO_IRDA
|
||||
#define UART5_ENABLED 0
|
||||
|
||||
#define MXC_LL_UART_PADDR UART1_BASE_ADDR
|
||||
#define MXC_LL_UART_VADDR AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
|
||||
|
||||
/* ron: Efikasb GPIO Pin Definition */
|
||||
#define SDHC1_CD_PIN MX51_PIN_EIM_CS2 /* MX51_PIN_GPIO1_0 */
|
||||
#define SDHC1_WP_PIN MX51_PIN_GPIO1_1
|
||||
#define SDHC2_CD_PIN MX51_PIN_GPIO1_8
|
||||
#define SDHC2_WP_PIN MX51_PIN_GPIO1_7
|
||||
|
||||
#define HUB_RESET_PIN MX51_PIN_GPIO1_5
|
||||
#define PMIC_INT_PIN MX51_PIN_GPIO1_6
|
||||
#define USB_PHY_RESET_PIN MX51_PIN_EIM_D27
|
||||
|
||||
#define WIRELESS_SW_PIN MX51_PIN_DI1_PIN12
|
||||
#define WLAN_PWRON_PIN MX51_PIN_EIM_A22
|
||||
#define WLAN_RESET_PIN MX51_PIN_EIM_A16
|
||||
#define BT_PWRON_PIN MX51_PIN_EIM_A17
|
||||
#define WWAN_PWRON_PIN MX51_PIN_CSI2_D13
|
||||
|
||||
#define LCD_LVDS_EN_PIN MX51_PIN_CSI1_D8
|
||||
#define LCD_PWRON_PIN MX51_PIN_CSI1_D9
|
||||
#define LCD_BL_PWM_PIN MX51_PIN_GPIO1_2
|
||||
#define LCD_BL_PWRON_PIN MX51_PIN_CSI2_D19
|
||||
#define LVDS_RESET_PIN MX51_PIN_DISPB2_SER_DIN
|
||||
#define LVDS_PWRCTL_PIN MX51_PIN_DISPB2_SER_CLK
|
||||
|
||||
#define CAM_PWRON_PIN MX51_PIN_NANDF_CS0
|
||||
|
||||
#define BATT_LOW_PIN MX51_PIN_DI1_PIN11
|
||||
#define BATT_INS_PIN MX51_PIN_DISPB2_SER_DIO
|
||||
#define AC_ADAP_INS_PIN MX51_PIN_DI1_D0_CS /* MX51_PIN_CSI1_D8 */
|
||||
|
||||
#define AUD_MUTE_PIN MX51_PIN_EIM_A23
|
||||
#define HPJACK_INS_PIN MX51_PIN_DISPB2_SER_RS
|
||||
|
||||
#define LID_SW_PIN MX51_PIN_CSI1_VSYNC /* Low: close, High: open */
|
||||
|
||||
#define POWER_BTN_PIN MX51_PIN_EIM_DTACK
|
||||
#define SYS_PWROFF_PIN MX51_PIN_CSI2_VSYNC
|
||||
#define SYS_PWRGD_PIN MX51_PIN_CSI2_PIXCLK
|
||||
|
||||
/* ron: Efikasb LED Pin Definition */
|
||||
#define CAPS_LED_PIN MX51_PIN_EIM_CS0
|
||||
#define ALARM_LED_PIN MX51_PIN_GPIO1_3
|
||||
|
||||
/* ron: R1.2 borad GPIO definition */
|
||||
#define MEM_ID0_PIN MX51_PIN_EIM_LBA /* MX51_PIN_GPIO1_4 */
|
||||
#define MEM_ID1_PIN MX51_PIN_EIM_CRE
|
||||
|
||||
#define SIM_CD_PIN MX51_PIN_EIM_CS1
|
||||
#define WWAN_WAKEUP_PIN MX51_PIN_CSI1_HSYNC
|
||||
#define AGPS_PWRON_PIN MX51_PIN_CSI2_D12
|
||||
#define AGPS_RESET_PIN MX51_PIN_CSI2_D18
|
||||
#define AGPS_PWRSW_PIN MX51_PIN_NANDF_CS1 /* ron: R1.3 add AGPS_PWRSW */
|
||||
|
||||
/* ron: R1.3 board GPIO definition */
|
||||
#define PCB_ID0_PIN MX51_PIN_EIM_CS3
|
||||
#define PCB_ID1_PIN MX51_PIN_EIM_CS4
|
||||
|
||||
#define WDOG_PIN MX51_PIN_GPIO1_4
|
||||
|
||||
/* #define BATT_LOW_LED_PIN MX51_PIN_DI1_PIN13 */
|
||||
|
||||
extern int __init mx51_efikasb_init_mc13892(void);
|
||||
|
||||
#endif /* __ASM_ARCH_MXC_BOARD_MX51_LANGE51_H__ */
|
||||
1107
arch/arm/mach-mx5/mx51_efikasb_gpio.c
Normal file
1107
arch/arm/mach-mx5/mx51_efikasb_gpio.c
Normal file
File diff suppressed because it is too large
Load Diff
251
arch/arm/mach-mx5/mx51_efikasb_idle_timer.c
Normal file
251
arch/arm/mach-mx5/mx51_efikasb_idle_timer.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright 2009-2010 Pegatron Corporation. All Rights Reserved.
|
||||
* Copyright 2009-2010 Genesi USA, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/keyboard.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include "mx51_efikasb.h"
|
||||
#include "iomux.h"
|
||||
|
||||
#define DEFAULT_PERIOD 60
|
||||
#define IDLE_EVENT 1
|
||||
|
||||
void mxc_reset_idle_timer(void);
|
||||
|
||||
struct efikasb_idle_timer {
|
||||
int enable;
|
||||
int timeout;
|
||||
spinlock_t lock;
|
||||
struct timer_list timer;
|
||||
unsigned long period; /* in second */
|
||||
};
|
||||
|
||||
static struct efikasb_idle_timer *idle_timer = NULL;
|
||||
|
||||
static BLOCKING_NOTIFIER_HEAD(idle_notifier_list);
|
||||
|
||||
int register_idle_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_register(&idle_notifier_list, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_idle_notifier);
|
||||
|
||||
int unregister_idle_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_unregister(&idle_notifier_list, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_idle_notifier);
|
||||
|
||||
static int key_event_call(struct notifier_block *blk, unsigned long code, void *_param)
|
||||
{
|
||||
|
||||
switch (code) {
|
||||
case KBD_KEYCODE:
|
||||
mxc_reset_idle_timer();
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block key_nb = {
|
||||
.notifier_call = key_event_call,
|
||||
};
|
||||
|
||||
static void idle_timeout_fn(unsigned long data)
|
||||
{
|
||||
struct efikasb_idle_timer *efikasb_timer = (struct efikasb_idle_timer *)data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&efikasb_timer->lock, flags);
|
||||
|
||||
efikasb_timer->timeout = 1;
|
||||
efikasb_timer->enable = 0;
|
||||
|
||||
spin_unlock_irqrestore(&efikasb_timer->lock, flags);
|
||||
|
||||
blocking_notifier_call_chain(&idle_notifier_list, IDLE_EVENT, 1);
|
||||
|
||||
}
|
||||
|
||||
static void idle_timer_enable(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if(idle_timer->enable && timer_pending(&idle_timer->timer))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&idle_timer->lock, flags);
|
||||
|
||||
idle_timer->timer.data = (unsigned long)idle_timer;
|
||||
idle_timer->timer.function = idle_timeout_fn;
|
||||
if(idle_timer->period == 0)
|
||||
idle_timer->period = DEFAULT_PERIOD;
|
||||
|
||||
idle_timer->timer.expires = jiffies + idle_timer->period * HZ;
|
||||
|
||||
add_timer(&idle_timer->timer);
|
||||
idle_timer->enable = 1;
|
||||
idle_timer->timeout = 0;
|
||||
|
||||
spin_unlock_irqrestore(&idle_timer->lock, flags);
|
||||
}
|
||||
|
||||
static void idle_timer_disable(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if(!idle_timer->enable && !timer_pending(&idle_timer->timer))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&idle_timer->lock, flags);
|
||||
|
||||
del_timer(&idle_timer->timer);
|
||||
idle_timer->enable = 0;
|
||||
idle_timer->timeout = 0;
|
||||
|
||||
spin_unlock_irqrestore(&idle_timer->lock, flags);
|
||||
}
|
||||
|
||||
static void idle_timer_reset(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if(!idle_timer->enable && !timer_pending(&idle_timer->timer))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&idle_timer->lock, flags);
|
||||
|
||||
mod_timer(&idle_timer->timer, jiffies + idle_timer->period * HZ);
|
||||
idle_timer->timeout = 0;
|
||||
|
||||
spin_unlock_irqrestore(&idle_timer->lock, flags);
|
||||
}
|
||||
|
||||
static ssize_t timer_enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", idle_timer->enable);
|
||||
}
|
||||
|
||||
static ssize_t timer_enable_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
if(strncmp(buf, "1", 1) == 0)
|
||||
idle_timer_enable();
|
||||
else if(strncmp(buf, "0", 1) == 0)
|
||||
idle_timer_disable();
|
||||
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
static ssize_t timer_period_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", (unsigned int) idle_timer->period);
|
||||
}
|
||||
|
||||
static ssize_t timer_period_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *end;
|
||||
int arg;
|
||||
|
||||
arg = simple_strtoul(buf, &end, 10);
|
||||
if(arg < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
idle_timer->period = arg;
|
||||
idle_timer_reset();
|
||||
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
static ssize_t timer_timeout_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
|
||||
if (!idle_timer->enable)
|
||||
return sprintf(buf, "0\n");
|
||||
else
|
||||
return sprintf(buf, "%d\n",
|
||||
jiffies_to_msecs(idle_timer->timer.expires - jiffies) / 1000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct kobj_attribute timer_enable_attribute =
|
||||
__ATTR(enable, 0666, timer_enable_show, timer_enable_store);
|
||||
static struct kobj_attribute timer_period_attribute =
|
||||
__ATTR(period, 0666, timer_period_show, timer_period_store);
|
||||
static struct kobj_attribute timer_timeout_attribute =
|
||||
__ATTR(timeout, S_IFREG | S_IRUGO, timer_timeout_show, NULL);
|
||||
|
||||
static struct attribute *idle_attrs[] = {
|
||||
&timer_enable_attribute.attr,
|
||||
&timer_period_attribute.attr,
|
||||
&timer_timeout_attribute.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group idle_attr_group = {
|
||||
.attrs = idle_attrs,
|
||||
};
|
||||
|
||||
static struct platform_device mxc_idle_timer_dev = {
|
||||
.name = "mxc_idle_timer",
|
||||
};
|
||||
|
||||
static int __init mxc_init_idle_timer(void)
|
||||
{
|
||||
int retval;
|
||||
static struct kobject *idle_timer_kobj;
|
||||
|
||||
platform_device_register(&mxc_idle_timer_dev);
|
||||
|
||||
idle_timer_kobj = kobject_create_and_add("setting", &mxc_idle_timer_dev.dev.kobj);
|
||||
if(!idle_timer_kobj)
|
||||
return -ENOMEM;
|
||||
|
||||
retval = sysfs_create_group(idle_timer_kobj, &idle_attr_group);
|
||||
if(retval) {
|
||||
kobject_put(idle_timer_kobj);
|
||||
return retval;
|
||||
}
|
||||
|
||||
idle_timer = kzalloc(sizeof(*idle_timer), GFP_KERNEL);
|
||||
if(!idle_timer) {
|
||||
sysfs_remove_group(idle_timer_kobj, &idle_attr_group);
|
||||
kobject_put(idle_timer_kobj);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
init_timer(&idle_timer->timer);
|
||||
idle_timer->lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
register_keyboard_notifier(&key_nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
late_initcall(mxc_init_idle_timer);
|
||||
|
||||
void mxc_reset_idle_timer(void)
|
||||
{
|
||||
if(idle_timer->timeout) {
|
||||
blocking_notifier_call_chain(&idle_notifier_list, IDLE_EVENT, 0);
|
||||
} else {
|
||||
idle_timer_reset();
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(mxc_reset_idle_timer);
|
||||
|
||||
471
arch/arm/mach-mx5/mx51_efikasb_input.c
Normal file
471
arch/arm/mach-mx5/mx51_efikasb_input.c
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright 2009-2010 Pegatron Corporation. All Rights Reserved.
|
||||
* Copyright 2009-2010 Genesi USA, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <mach/gpio.h>
|
||||
|
||||
#include "mx51_efikasb.h"
|
||||
#include "mx51_pins.h"
|
||||
#include "iomux.h"
|
||||
|
||||
int wireless_sw_state;
|
||||
|
||||
extern int mxc_get_battery_insertion_status(void);
|
||||
extern int mxc_get_batt_low_status(void);
|
||||
extern int mxc_get_ac_adapter_insertion_status(void);
|
||||
extern int mxc_get_wireless_sw_status(void);
|
||||
extern int mxc_get_sim_card_status(void);
|
||||
|
||||
extern void mxc_power_on_wlan(int on);
|
||||
extern void efikasb_power_on_wwan(int val);
|
||||
extern void efikasb_power_on_bt(int val);
|
||||
|
||||
extern int register_idle_notifier(struct notifier_block *);
|
||||
extern int unregister_idle_notifier(struct notifier_block *);
|
||||
extern void mxc_reset_idle_timer(void);
|
||||
|
||||
extern int lid_wake_enable;
|
||||
extern int mxc_get_lid_sw_status(void);
|
||||
|
||||
extern void kernel_power_off(void);
|
||||
|
||||
static struct input_dev *efikasb_inputdev;
|
||||
static int system_is_resuming = 0;
|
||||
|
||||
#ifdef CONFIG_EFIKASB_EXPERIMENTAL_OS
|
||||
static void power_off_worker(struct work_struct *work);
|
||||
static DECLARE_DELAYED_WORK(power_off_work, power_off_worker);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Power Key interrupt handler.
|
||||
*/
|
||||
static irqreturn_t power_key_int(int irq, void *dev_id)
|
||||
{
|
||||
static int key_pressed = 0;
|
||||
int pk_pressed;
|
||||
|
||||
/* ron: Don't report power key event if system is resuming */
|
||||
if(system_is_resuming)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
pk_pressed = !gpio_get_value(IOMUX_TO_GPIO(POWER_BTN_PIN));
|
||||
if (pk_pressed) {
|
||||
if (key_pressed)
|
||||
return 0;
|
||||
key_pressed = 1;
|
||||
pr_info("PWR key pressed\n");
|
||||
/* ron: input_report_key(pk_dev, KEY_POWER, pk_pressed); */
|
||||
set_irq_type(irq, IRQF_TRIGGER_RISING); /* ron: detect falling edge */
|
||||
|
||||
if(lid_wake_enable)
|
||||
enable_irq_wake(IOMUX_TO_IRQ(LID_SW_PIN));
|
||||
|
||||
input_report_key(efikasb_inputdev, KEY_POWER, 1);
|
||||
input_sync(efikasb_inputdev);
|
||||
} else {
|
||||
if (!key_pressed)
|
||||
return 0;
|
||||
key_pressed = 0;
|
||||
pr_info("PWR Key released\n");
|
||||
/* ron: input_report_key(pk_dev, KEY_POWER, pk_released); */
|
||||
set_irq_type(irq, IRQF_TRIGGER_FALLING); /* ron: detect falling edge */
|
||||
input_report_key(efikasb_inputdev, KEY_POWER, 0);
|
||||
input_sync(efikasb_inputdev);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mxc_init_power_key(void)
|
||||
{
|
||||
int ret;
|
||||
int irq;
|
||||
|
||||
/* ron: set power key as wakeup source */
|
||||
gpio_request(IOMUX_TO_GPIO(POWER_BTN_PIN), "power_btn");
|
||||
gpio_direction_input(IOMUX_TO_GPIO(POWER_BTN_PIN));
|
||||
irq = IOMUX_TO_IRQ(POWER_BTN_PIN);
|
||||
set_irq_type(irq, IRQF_TRIGGER_FALLING); /* ron: detect rising & falling edge */
|
||||
|
||||
ret = request_irq(irq, power_key_int, 0, "power_key", 0);
|
||||
if (ret)
|
||||
pr_info("register on-off key interrupt failed\n");
|
||||
else
|
||||
enable_irq_wake(irq);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
#define KEY_RESUME KEY_WAKEUP
|
||||
|
||||
static int pm_notifier_call(struct notifier_block *nb, unsigned long event, void *dummy)
|
||||
{
|
||||
switch (event) {
|
||||
case PM_SUSPEND_PREPARE:
|
||||
printk("System Suspending .....\n");
|
||||
system_is_resuming = 1;
|
||||
return NOTIFY_OK;
|
||||
|
||||
case PM_POST_SUSPEND:
|
||||
printk("System Resumed\n");
|
||||
system_is_resuming = 0;
|
||||
input_event(efikasb_inputdev, EV_PWR, KEY_RESUME, 1);
|
||||
input_sync(efikasb_inputdev);
|
||||
|
||||
return NOTIFY_OK;
|
||||
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
|
||||
static struct notifier_block pm_nb = {
|
||||
.notifier_call = pm_notifier_call,
|
||||
};
|
||||
|
||||
|
||||
#define EVENT_IDLE 1
|
||||
static int idle_notifier_call(struct notifier_block *nb, unsigned long event, void *v)
|
||||
{
|
||||
int value = (int) v;
|
||||
|
||||
switch(event) {
|
||||
case EVENT_IDLE:
|
||||
input_event(efikasb_inputdev, EV_PWR, KEY_SUSPEND, value);
|
||||
input_sync(efikasb_inputdev);
|
||||
return NOTIFY_OK;
|
||||
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
|
||||
}
|
||||
|
||||
static struct notifier_block idle_nb = {
|
||||
.notifier_call = idle_notifier_call,
|
||||
};
|
||||
|
||||
|
||||
static irqreturn_t wireless_sw_int(int irq, void *dev_id)
|
||||
{
|
||||
wireless_sw_state = gpio_get_value(IOMUX_TO_GPIO(WIRELESS_SW_PIN));
|
||||
|
||||
if (wireless_sw_state) {
|
||||
pr_info("Wireless SW Off\n");
|
||||
set_irq_type(irq, IRQF_TRIGGER_FALLING);
|
||||
input_report_switch(efikasb_inputdev, SW_RFKILL_ALL, 0);
|
||||
input_sync(efikasb_inputdev);
|
||||
// power off WLAN, WWAN and BT by H/W
|
||||
} else {
|
||||
pr_info("Wireless SW On\n");
|
||||
set_irq_type(irq, IRQF_TRIGGER_RISING);
|
||||
input_report_switch(efikasb_inputdev, SW_RFKILL_ALL, 1);
|
||||
input_sync(efikasb_inputdev);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mxc_init_wireless_sw(void)
|
||||
{
|
||||
int irq, ret;
|
||||
|
||||
gpio_request(IOMUX_TO_GPIO(WIRELESS_SW_PIN), "wireless_sw");
|
||||
gpio_direction_input(IOMUX_TO_GPIO(WIRELESS_SW_PIN));
|
||||
irq = IOMUX_TO_IRQ(WIRELESS_SW_PIN);
|
||||
|
||||
if (gpio_get_value(IOMUX_TO_GPIO(WIRELESS_SW_PIN)))
|
||||
set_irq_type(irq, IRQF_TRIGGER_FALLING);
|
||||
else
|
||||
set_irq_type(irq, IRQF_TRIGGER_RISING);
|
||||
|
||||
ret = request_irq(irq, wireless_sw_int, 0, "wireless-sw", 0);
|
||||
|
||||
if (ret)
|
||||
pr_info("register wireless switch interrupt failed\n");
|
||||
|
||||
wireless_sw_state = gpio_get_value(IOMUX_TO_GPIO(WIRELESS_SW_PIN));
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static irqreturn_t sim_detect_int(int irq, void *dev_id)
|
||||
{
|
||||
if(mxc_get_sim_card_status()) { /* ron: low active */
|
||||
set_irq_type(irq, IRQF_TRIGGER_RISING);
|
||||
pr_info("SIM card inserted\n");
|
||||
} else {
|
||||
set_irq_type(irq, IRQF_TRIGGER_FALLING);
|
||||
pr_info("SIM card removed\n");
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mxc_init_sim_detect(void)
|
||||
{
|
||||
int irq, ret;
|
||||
|
||||
irq = IOMUX_TO_IRQ(SIM_CD_PIN);
|
||||
|
||||
if(mxc_get_sim_card_status()) /* ron: low active */
|
||||
set_irq_type(irq, IRQF_TRIGGER_RISING);
|
||||
else
|
||||
set_irq_type(irq, IRQF_TRIGGER_FALLING);
|
||||
|
||||
ret = request_irq(irq, sim_detect_int, 0, "sim-detect", 0);
|
||||
if(ret)
|
||||
pr_info("register SIM card detect interrupt failed\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
/* late_initcall(mxc_init_sim_detect); */
|
||||
|
||||
#ifdef CONFIG_EFIKASB_EXPERIMENTAL_OS
|
||||
static irqreturn_t efikasb_battery_detect_handler(int irq, void *data)
|
||||
{
|
||||
int batt_in;
|
||||
|
||||
batt_in = mxc_get_battery_insertion_status();
|
||||
printk("efikasb_battery: Battery %s\n",
|
||||
batt_in ? "Inserted" : "Removed");
|
||||
|
||||
input_report_switch(efikasb_inputdev, SW_BATT_IN, batt_in);
|
||||
input_sync(efikasb_inputdev);
|
||||
|
||||
if (batt_in)
|
||||
set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
|
||||
else
|
||||
set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static irqreturn_t efikasb_ac_charger_detect_handler(int irq, void *data)
|
||||
{
|
||||
int ac_in;
|
||||
|
||||
ac_in = mxc_get_ac_adapter_insertion_status();
|
||||
printk("efikasb_ac_charger: AC %s\n",
|
||||
ac_in ? "Inserted" : "Removed");
|
||||
|
||||
input_report_switch(efikasb_inputdev, SW_AC_INSERT, ac_in);
|
||||
input_sync(efikasb_inputdev);
|
||||
|
||||
if (ac_in)
|
||||
set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
|
||||
else
|
||||
set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void power_off_worker(struct work_struct *work)
|
||||
{
|
||||
if(!mxc_get_ac_adapter_insertion_status() &&
|
||||
mxc_get_batt_low_status()) {
|
||||
sys_sync();
|
||||
kernel_power_off();
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t efikasb_batt_low_handler(int irq, void *data)
|
||||
{
|
||||
int batt_low;
|
||||
|
||||
batt_low = mxc_get_batt_low_status();
|
||||
printk("efikasb_batter: Battery %s\n",
|
||||
batt_low ? "Low" : "Normal");
|
||||
|
||||
input_event(efikasb_inputdev, EV_PWR, KEY_BATTERY, batt_low);
|
||||
input_sync(efikasb_inputdev);
|
||||
|
||||
if (batt_low) {
|
||||
set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH/* IRQ_TYPE_EDGE_RISING */);
|
||||
printk("Battery critical low, shutdown now....\n");
|
||||
schedule_delayed_work(&power_off_work, msecs_to_jiffies(1000));
|
||||
} else {
|
||||
set_irq_type(irq, IRQ_TYPE_LEVEL_LOW/* IRQ_TYPE_EDGE_FALLING */);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mxc_init_battery(void)
|
||||
{
|
||||
int ret;
|
||||
int batt_low;
|
||||
int batt_in, ac_in;
|
||||
batt_in = mxc_get_battery_insertion_status();
|
||||
if(batt_in) {
|
||||
ret = request_irq(IOMUX_TO_IRQ(BATT_INS_PIN),
|
||||
efikasb_battery_detect_handler,
|
||||
IRQ_TYPE_EDGE_RISING, "efikasb_battery", NULL);
|
||||
} else {
|
||||
ret = request_irq(IOMUX_TO_IRQ(BATT_INS_PIN),
|
||||
efikasb_battery_detect_handler,
|
||||
IRQ_TYPE_EDGE_FALLING, "efikasb_battery", NULL);
|
||||
}
|
||||
|
||||
ac_in = mxc_get_ac_adapter_insertion_status();
|
||||
if(ac_in) {
|
||||
ret = request_irq(IOMUX_TO_IRQ(AC_ADAP_INS_PIN),
|
||||
efikasb_ac_charger_detect_handler,
|
||||
IRQ_TYPE_EDGE_RISING, "efikasb_ac_charger", NULL);
|
||||
} else {
|
||||
ret = request_irq(IOMUX_TO_IRQ(AC_ADAP_INS_PIN),
|
||||
efikasb_ac_charger_detect_handler,
|
||||
IRQ_TYPE_EDGE_FALLING, "efikasb_ac_charger", NULL);
|
||||
}
|
||||
|
||||
|
||||
batt_low = mxc_get_batt_low_status();
|
||||
if(batt_low) {
|
||||
ret = request_irq(IOMUX_TO_IRQ(BATT_LOW_PIN),
|
||||
efikasb_batt_low_handler,
|
||||
IRQ_TYPE_LEVEL_HIGH, "efikasb_batt_low", NULL);
|
||||
} else {
|
||||
ret = request_irq(IOMUX_TO_IRQ(BATT_LOW_PIN),
|
||||
efikasb_batt_low_handler,
|
||||
IRQ_TYPE_LEVEL_LOW, "efikasb_batt_low", NULL);
|
||||
}
|
||||
enable_irq_wake(IOMUX_TO_IRQ(BATT_LOW_PIN));
|
||||
|
||||
/* ron: if battery critical low, shutdown immediately */
|
||||
if(!mxc_get_ac_adapter_insertion_status() && batt_low) {
|
||||
printk("Battery critical low, shutdown now....\n");
|
||||
schedule_delayed_work(&power_off_work, msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_EFIKASB_EXPERIMENTAL_OS */
|
||||
|
||||
static ssize_t sim_status_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", mxc_get_sim_card_status());
|
||||
}
|
||||
|
||||
static ssize_t wireless_sw_status_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", mxc_get_wireless_sw_status());
|
||||
}
|
||||
|
||||
static ssize_t batt_low_status_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", mxc_get_batt_low_status());
|
||||
}
|
||||
|
||||
static struct kobj_attribute sim_status_attribute =
|
||||
__ATTR(sim, S_IFREG | S_IRUGO, sim_status_show, NULL);
|
||||
static struct kobj_attribute wireless_sw_status_attribute =
|
||||
__ATTR(wireless_sw, S_IFREG | S_IRUGO, wireless_sw_status_show, NULL);
|
||||
static struct kobj_attribute batt_low_status_attribute =
|
||||
__ATTR(battery_low, S_IFREG | S_IRUGO, batt_low_status_show, NULL);
|
||||
|
||||
static struct attribute *status_attrs[] = {
|
||||
&sim_status_attribute.attr,
|
||||
&wireless_sw_status_attribute.attr,
|
||||
&batt_low_status_attribute.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group status_attr_group = {
|
||||
.attrs = status_attrs,
|
||||
};
|
||||
|
||||
static struct platform_device mxc_efikasb_input_dev = {
|
||||
.name = "efikasb_input",
|
||||
};
|
||||
|
||||
static int __init mxc_init_efikasb_inputdev(void)
|
||||
{
|
||||
int ret;
|
||||
struct kobject *efikasb_input_kobj;
|
||||
|
||||
platform_device_register(&mxc_efikasb_input_dev);
|
||||
|
||||
efikasb_input_kobj = kobject_create_and_add("status", &mxc_efikasb_input_dev.dev.kobj);
|
||||
if(!efikasb_input_kobj)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = sysfs_create_group(efikasb_input_kobj, &status_attr_group);
|
||||
if(ret) {
|
||||
kobject_put(efikasb_input_kobj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
efikasb_inputdev = input_allocate_device();
|
||||
if (!efikasb_inputdev) {
|
||||
pr_err("Failed to allocate hotkey input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
efikasb_inputdev->name = "Genesi Efikasb Extra Buttons";
|
||||
efikasb_inputdev->phys = "genesi-efikasb/input0";
|
||||
efikasb_inputdev->uniq = "genesi-efikasb";
|
||||
efikasb_inputdev->id.bustype = BUS_HOST;
|
||||
efikasb_inputdev->id.vendor = PCI_VENDOR_ID_FREESCALE;
|
||||
set_bit(KEY_POWER, efikasb_inputdev->keybit);
|
||||
set_bit(KEY_SLEEP, efikasb_inputdev->keybit);
|
||||
set_bit(KEY_WAKEUP, efikasb_inputdev->keybit);
|
||||
set_bit(EV_KEY, efikasb_inputdev->evbit);
|
||||
set_bit(EV_PWR, efikasb_inputdev->evbit);
|
||||
|
||||
set_bit(SW_RFKILL_ALL, efikasb_inputdev->swbit);
|
||||
if(mxc_get_wireless_sw_status())
|
||||
set_bit(SW_RFKILL_ALL, efikasb_inputdev->sw);
|
||||
|
||||
/* ron: I known this is not a regular approach,
|
||||
but Lenovo requests, I can't resist*/
|
||||
#ifdef CONFIG_EFIKASB_EXPERIMENTAL_OS
|
||||
set_bit(SW_AC_INSERT, efikasb_inputdev->swbit);
|
||||
if(mxc_get_ac_adapter_insertion_status())
|
||||
set_bit(SW_AC_INSERT, efikasb_inputdev->sw);
|
||||
|
||||
set_bit(SW_BATT_IN, efikasb_inputdev->swbit);
|
||||
if(mxc_get_battery_insertion_status())
|
||||
set_bit(SW_BATT_IN, efikasb_inputdev->sw);
|
||||
#endif
|
||||
|
||||
ret = input_register_device(efikasb_inputdev);
|
||||
if (ret) {
|
||||
input_free_device(efikasb_inputdev);
|
||||
pr_err("Failed to register hotkey input device\n");
|
||||
sysfs_remove_group(efikasb_input_kobj, &status_attr_group);
|
||||
kobject_put(efikasb_input_kobj);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mxc_init_power_key();
|
||||
|
||||
#ifdef CONFIG_EFIKASB_EXPERIMENTAL_OS
|
||||
mxc_init_battery();
|
||||
#endif
|
||||
mxc_init_sim_detect();
|
||||
mxc_init_wireless_sw();
|
||||
|
||||
register_pm_notifier(&pm_nb);
|
||||
register_idle_notifier(&idle_nb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
late_initcall(mxc_init_efikasb_inputdev);
|
||||
|
||||
195
arch/arm/mach-mx5/mx51_efikasb_lid.c
Normal file
195
arch/arm/mach-mx5/mx51_efikasb_lid.c
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 2009-2010 Pegatron Corporation. All Rights Reserved.
|
||||
* Copyright 2009-2010 Genesi USA, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
#include "mx51_efikasb.h"
|
||||
#include "mx51_pins.h"
|
||||
#include "iomux.h"
|
||||
|
||||
int lid_wake_enable = 0;
|
||||
extern int mxc_get_lid_sw_status(void);
|
||||
extern void mxc_reset_idle_timer(void);
|
||||
|
||||
static struct input_dev *efikasb_lid_inputdev;
|
||||
|
||||
static struct platform_device efikasb_lid_dev = {
|
||||
.name = "efikasb_lid",
|
||||
};
|
||||
|
||||
static irqreturn_t lid_sw_int(int irq, void *dev_id)
|
||||
{
|
||||
int lid_close;
|
||||
|
||||
mxc_reset_idle_timer();
|
||||
lid_close = mxc_get_lid_sw_status();
|
||||
if(lid_close) {
|
||||
pr_info("Lid Switch Close\n");
|
||||
set_irq_type(irq, IRQF_TRIGGER_RISING);
|
||||
|
||||
if(lid_wake_enable)
|
||||
enable_irq_wake(irq);
|
||||
|
||||
input_report_switch(efikasb_lid_inputdev, SW_LID, lid_close);
|
||||
input_sync(efikasb_lid_inputdev);
|
||||
|
||||
} else {
|
||||
pr_info("Lid Switch Open\n");
|
||||
set_irq_type(irq, IRQF_TRIGGER_FALLING);
|
||||
|
||||
input_report_switch(efikasb_lid_inputdev, SW_LID, lid_close);
|
||||
input_sync(efikasb_lid_inputdev);
|
||||
|
||||
if(lid_wake_enable)
|
||||
disable_irq_wake(irq);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mxc_init_lid_sw(void)
|
||||
{
|
||||
int irq, ret;
|
||||
|
||||
gpio_request(IOMUX_TO_GPIO(LID_SW_PIN), "lid_sw");
|
||||
gpio_direction_input(IOMUX_TO_GPIO(LID_SW_PIN));
|
||||
irq = IOMUX_TO_IRQ(LID_SW_PIN);
|
||||
|
||||
if(mxc_get_lid_sw_status()) {
|
||||
pr_info("Lid Switch Close\n");
|
||||
set_irq_type(irq, IRQF_TRIGGER_RISING);
|
||||
} else {
|
||||
pr_info("Lid Switch Open\n");
|
||||
set_irq_type(irq, IRQF_TRIGGER_FALLING);
|
||||
}
|
||||
|
||||
ret = request_irq(irq, lid_sw_int, 0, "lid-sw", 0);
|
||||
if(ret)
|
||||
pr_info("register lid switch interrupt failed\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t lid_status_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", mxc_get_lid_sw_status());
|
||||
}
|
||||
|
||||
static ssize_t lid_wake_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", lid_wake_enable ? "on": "off");
|
||||
}
|
||||
|
||||
static ssize_t lid_wake_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
if(strncmp(buf, "on", 2) == 0)
|
||||
lid_wake_enable = 1;
|
||||
else if (strncmp(buf, "off", 3) == 0)
|
||||
lid_wake_enable = 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct kobj_attribute lid_status_attribute =
|
||||
__ATTR(lid, S_IFREG | S_IRUGO, lid_status_show, NULL);
|
||||
static struct kobj_attribute lid_wake_attribute =
|
||||
__ATTR(lid_wake, 0666, lid_wake_show, lid_wake_store);
|
||||
|
||||
static struct attribute *status_attrs[] = {
|
||||
&lid_status_attribute.attr,
|
||||
&lid_wake_attribute.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group status_attr_group = {
|
||||
.attrs = status_attrs,
|
||||
};
|
||||
|
||||
static void __init lid_wake_setup(char **p)
|
||||
{
|
||||
if(memcmp(*p, "on", 2) == 0) {
|
||||
lid_wake_enable = 1;
|
||||
*p += 2;
|
||||
} else if(memcmp(*p, "off", 3) == 0) {
|
||||
lid_wake_enable = 0;
|
||||
*p += 3;
|
||||
}
|
||||
}
|
||||
|
||||
__early_param("lid_wake=", lid_wake_setup);
|
||||
|
||||
static int __init mxc_init_efikasb_lid(void)
|
||||
{
|
||||
int ret ;
|
||||
struct kobject *lid_kobj;
|
||||
|
||||
platform_device_register(&efikasb_lid_dev);
|
||||
|
||||
lid_kobj = kobject_create_and_add("status", &efikasb_lid_dev.dev.kobj);
|
||||
if(!lid_kobj) {
|
||||
ret = -ENOMEM;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
ret = sysfs_create_group(lid_kobj, &status_attr_group);
|
||||
if(ret) {
|
||||
goto err2;
|
||||
}
|
||||
|
||||
efikasb_lid_inputdev = input_allocate_device();
|
||||
if(!efikasb_lid_inputdev) {
|
||||
pr_err("Failed to allocate lid input device\n");
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
efikasb_lid_inputdev->name = "Efikasb Lid Switch";
|
||||
efikasb_lid_inputdev->phys = "Efikasb/input1";
|
||||
efikasb_lid_inputdev->uniq = "Efikasb";
|
||||
efikasb_lid_inputdev->id.bustype = BUS_HOST;
|
||||
efikasb_lid_inputdev->id.vendor = PCI_VENDOR_ID_FREESCALE;
|
||||
|
||||
set_bit(EV_SW, efikasb_lid_inputdev->evbit);
|
||||
set_bit(SW_LID, efikasb_lid_inputdev->swbit);
|
||||
|
||||
/* ron: 0:open 1:close */
|
||||
if(mxc_get_lid_sw_status())
|
||||
set_bit(SW_LID, efikasb_lid_inputdev->sw);
|
||||
|
||||
ret = input_register_device(efikasb_lid_inputdev);
|
||||
if(ret) {
|
||||
pr_err("Failed to register Efikasb lid input device\n");
|
||||
ret = -ENODEV;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
mxc_init_lid_sw();
|
||||
|
||||
return ret;
|
||||
|
||||
err1:
|
||||
input_free_device(efikasb_lid_inputdev);
|
||||
err2:
|
||||
kobject_put(lid_kobj);
|
||||
err3:
|
||||
platform_device_unregister(&efikasb_lid_dev);
|
||||
|
||||
return ret;
|
||||
|
||||
|
||||
}
|
||||
|
||||
late_initcall(mxc_init_efikasb_lid);
|
||||
419
arch/arm/mach-mx5/mx51_efikasb_pmic.c
Normal file
419
arch/arm/mach-mx5/mx51_efikasb_pmic.c
Normal file
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* mx51-efikasb-pmic-mc13892.c -- i.MX51 Efikasb Driver for Atlas MC13892 PMIC
|
||||
*/
|
||||
/*
|
||||
* Copyright 2009-2010 Pegatron Corporation. All Rights Reserved.
|
||||
* Copyright 2009-2010 Genesi USA, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/pmic_external.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/mfd/mc13892/core.h>
|
||||
#include <mach/irqs.h>
|
||||
#include "iomux.h"
|
||||
#include "mx51_pins.h"
|
||||
|
||||
/*
|
||||
* Convenience conversion.
|
||||
* Here atm, maybe there is somewhere better for this.
|
||||
*/
|
||||
#define mV_to_uV(mV) (mV * 1000)
|
||||
#define uV_to_mV(uV) (uV / 1000)
|
||||
#define V_to_uV(V) (mV_to_uV(V * 1000))
|
||||
#define uV_to_V(uV) (uV_to_mV(uV) / 1000)
|
||||
|
||||
/* Coin cell charger enable */
|
||||
#define COINCHEN_LSH 23
|
||||
#define COINCHEN_WID 1
|
||||
/* Coin cell charger voltage setting */
|
||||
#define VCOIN_LSH 20
|
||||
#define VCOIN_WID 3
|
||||
|
||||
/* Coin Charger voltage */
|
||||
#define VCOIN_2_5V 0x0
|
||||
#define VCOIN_2_7V 0x1
|
||||
#define VCOIN_2_8V 0x2
|
||||
#define VCOIN_2_9V 0x3
|
||||
#define VCOIN_3_0V 0x4
|
||||
#define VCOIN_3_1V 0x5
|
||||
#define VCOIN_3_2V 0x6
|
||||
#define VCOIN_3_3V 0x7
|
||||
|
||||
/* regulator standby mask */
|
||||
#define GEN1_STBY_MASK (1 << 1)
|
||||
#define IOHI_STBY_MASK (1 << 4)
|
||||
#define DIG_STBY_MASK (1 << 10)
|
||||
#define GEN2_STBY_MASK (1 << 13)
|
||||
#define PLL_STBY_MASK (1 << 16)
|
||||
#define USB2_STBY_MASK (1 << 19)
|
||||
|
||||
#define GEN3_STBY_MASK (1 << 1)
|
||||
#define CAM_STBY_MASK (1 << 7)
|
||||
#define VIDEO_STBY_MASK (1 << 13)
|
||||
#define AUDIO_STBY_MASK (1 << 16)
|
||||
#define SD_STBY_MASK (1 << 19)
|
||||
|
||||
/* 0x92412 */
|
||||
#define REG_MODE_0_ALL_MASK (GEN1_STBY_MASK |\
|
||||
DIG_STBY_MASK | GEN2_STBY_MASK |\
|
||||
PLL_STBY_MASK)
|
||||
/* 0x92082 */
|
||||
#define REG_MODE_1_ALL_MASK (CAM_STBY_MASK | VIDEO_STBY_MASK |\
|
||||
AUDIO_STBY_MASK | SD_STBY_MASK)
|
||||
|
||||
/* switch mode setting */
|
||||
#define SW1MODE_LSB 0
|
||||
#define SW2MODE_LSB 10
|
||||
#define SW3MODE_LSB 0
|
||||
#define SW4MODE_LSB 8
|
||||
|
||||
#define SWMODE_MASK 0xF
|
||||
#define SWMODE_AUTO 0x8
|
||||
|
||||
#define PWGT1SPIEN (1 << 15)
|
||||
#define PWGT2SPIEN (1 << 16)
|
||||
|
||||
/* CPU */
|
||||
static struct regulator_consumer_supply sw1_consumers[] = {
|
||||
{
|
||||
.supply = "cpu_vcc",
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_consumer_supply vdig_consumers[] = {
|
||||
{
|
||||
/* sgtl5000 */
|
||||
.supply = "VDDA",
|
||||
.dev_name = "1-000a",
|
||||
},
|
||||
};
|
||||
|
||||
static struct regulator_consumer_supply vvideo_consumers[] = {
|
||||
{
|
||||
/* sgtl5000 */
|
||||
.supply = "VDDIO",
|
||||
.dev_name = "1-000a",
|
||||
},
|
||||
};
|
||||
|
||||
struct mc13892;
|
||||
|
||||
static struct regulator_init_data sw1_init = {
|
||||
.constraints = {
|
||||
.name = "SW1",
|
||||
.min_uV = mV_to_uV(600),
|
||||
.max_uV = mV_to_uV(1375),
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
|
||||
.valid_modes_mask = 0,
|
||||
.always_on = 1,
|
||||
.boot_on = 1,
|
||||
.initial_state = PM_SUSPEND_MEM,
|
||||
.state_mem = {
|
||||
.uV = 850000,
|
||||
.mode = REGULATOR_MODE_NORMAL,
|
||||
.enabled = 1,
|
||||
},
|
||||
},
|
||||
.num_consumer_supplies = ARRAY_SIZE(sw1_consumers),
|
||||
.consumer_supplies = sw1_consumers,
|
||||
};
|
||||
|
||||
static struct regulator_init_data sw2_init = {
|
||||
.constraints = {
|
||||
.name = "SW2",
|
||||
.min_uV = mV_to_uV(900),
|
||||
.max_uV = mV_to_uV(1850),
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
|
||||
.always_on = 1,
|
||||
.boot_on = 1,
|
||||
.initial_state = PM_SUSPEND_MEM,
|
||||
.state_mem = {
|
||||
.uV = 950000,
|
||||
.mode = REGULATOR_MODE_NORMAL,
|
||||
.enabled = 1,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data sw3_init = {
|
||||
.constraints = {
|
||||
.name = "SW3",
|
||||
.min_uV = mV_to_uV(1100),
|
||||
.max_uV = mV_to_uV(1850),
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
|
||||
.always_on = 1,
|
||||
.boot_on = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data sw4_init = {
|
||||
.constraints = {
|
||||
.name = "SW4",
|
||||
.min_uV = mV_to_uV(1100),
|
||||
.max_uV = mV_to_uV(1850),
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
|
||||
.always_on = 1,
|
||||
.boot_on = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data viohi_init = {
|
||||
.constraints = {
|
||||
.name = "VIOHI",
|
||||
.always_on = 1,
|
||||
.boot_on = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data vusb_init = {
|
||||
.constraints = {
|
||||
.name = "VUSB",
|
||||
.boot_on = 1,
|
||||
.always_on = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data swbst_init = {
|
||||
.constraints = {
|
||||
.name = "SWBST",
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data vdig_init = {
|
||||
.constraints = {
|
||||
.name = "VDIG",
|
||||
.min_uV = mV_to_uV(1650),
|
||||
.max_uV = mV_to_uV(1650),
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
|
||||
.boot_on = 1,
|
||||
},
|
||||
.num_consumer_supplies = ARRAY_SIZE(vdig_consumers),
|
||||
.consumer_supplies = vdig_consumers,
|
||||
};
|
||||
|
||||
static struct regulator_init_data vpll_init = {
|
||||
.constraints = {
|
||||
.name = "VPLL",
|
||||
.min_uV = mV_to_uV(1050),
|
||||
.max_uV = mV_to_uV(1800),
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
|
||||
.boot_on = 1,
|
||||
.always_on = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data vusb2_init = {
|
||||
.constraints = {
|
||||
.name = "VUSB2",
|
||||
.min_uV = mV_to_uV(2400),
|
||||
.max_uV = mV_to_uV(2775),
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
|
||||
.boot_on = 1,
|
||||
.always_on = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data vvideo_init = {
|
||||
.constraints = {
|
||||
.name = "VVIDEO",
|
||||
.min_uV = mV_to_uV(2775),
|
||||
.max_uV = mV_to_uV(2775),
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
|
||||
.apply_uV =1,
|
||||
},
|
||||
.num_consumer_supplies = ARRAY_SIZE(vvideo_consumers),
|
||||
.consumer_supplies = vvideo_consumers,
|
||||
};
|
||||
|
||||
static struct regulator_init_data vaudio_init = {
|
||||
.constraints = {
|
||||
.name = "VAUDIO",
|
||||
.min_uV = mV_to_uV(2300),
|
||||
.max_uV = mV_to_uV(3000),
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data vsd_init = {
|
||||
.constraints = {
|
||||
.name = "VSD",
|
||||
.min_uV = mV_to_uV(1800),
|
||||
.max_uV = mV_to_uV(3150),
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data vcam_init = {
|
||||
.constraints = {
|
||||
.name = "VCAM",
|
||||
.min_uV = mV_to_uV(2500),
|
||||
.max_uV = mV_to_uV(3000),
|
||||
.valid_ops_mask =
|
||||
REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
|
||||
.valid_modes_mask = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data vgen1_init = {
|
||||
.constraints = {
|
||||
.name = "VGEN1",
|
||||
.min_uV = mV_to_uV(1200),
|
||||
.max_uV = mV_to_uV(1200),
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data vgen2_init = {
|
||||
.constraints = {
|
||||
.name = "VGEN2",
|
||||
.min_uV = mV_to_uV(1200),
|
||||
.max_uV = mV_to_uV(3150),
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
|
||||
.always_on = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data vgen3_init = {
|
||||
.constraints = {
|
||||
.name = "VGEN3",
|
||||
.min_uV = mV_to_uV(1800),
|
||||
.max_uV = mV_to_uV(2900),
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
|
||||
.always_on = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data gpo1_init = {
|
||||
.constraints = {
|
||||
.name = "GPO1",
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data gpo2_init = {
|
||||
.constraints = {
|
||||
.name = "GPO2",
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data gpo3_init = {
|
||||
.constraints = {
|
||||
.name = "GPO3",
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data gpo4_init = {
|
||||
.constraints = {
|
||||
.name = "GPO4",
|
||||
}
|
||||
};
|
||||
|
||||
static int mc13892_regulator_init(struct mc13892 *mc13892)
|
||||
{
|
||||
unsigned int value, register_mask;
|
||||
|
||||
printk("Initializing regulators for Efikasb 5.1.\n");
|
||||
if (mxc_cpu_is_rev(CHIP_REV_2_0) < 0)
|
||||
sw2_init.constraints.state_mem.uV = 1100000;
|
||||
else if (mxc_cpu_is_rev(CHIP_REV_2_0) == 1) {
|
||||
sw2_init.constraints.state_mem.uV = 1250000;
|
||||
sw1_init.constraints.state_mem.uV = 1000000;
|
||||
}
|
||||
|
||||
/* enable standby controll for all regulators */
|
||||
pmic_read_reg(REG_MODE_0, &value, 0xffffff);
|
||||
value |= REG_MODE_0_ALL_MASK;
|
||||
pmic_write_reg(REG_MODE_0, value, 0xffffff);
|
||||
|
||||
pmic_read_reg(REG_MODE_1, &value, 0xffffff);
|
||||
value |= REG_MODE_1_ALL_MASK;
|
||||
pmic_write_reg(REG_MODE_1, value, 0xffffff);
|
||||
|
||||
/* enable switch audo mode */
|
||||
pmic_read_reg(REG_IDENTIFICATION, &value, 0xffffff);
|
||||
/* only for mc13892 2.0A */
|
||||
if ((value & 0x0000FFFF) == 0x45d0) {
|
||||
pmic_read_reg(REG_SW_4, &value, 0xffffff);
|
||||
register_mask = (SWMODE_MASK << SW1MODE_LSB) |
|
||||
(SWMODE_MASK << SW2MODE_LSB);
|
||||
value &= ~register_mask;
|
||||
value |= (SWMODE_AUTO << SW1MODE_LSB) |
|
||||
(SWMODE_AUTO << SW2MODE_LSB);
|
||||
pmic_write_reg(REG_SW_4, value, 0xffffff);
|
||||
|
||||
pmic_read_reg(REG_SW_5, &value, 0xffffff);
|
||||
register_mask = (SWMODE_MASK << SW3MODE_LSB) |
|
||||
(SWMODE_MASK << SW4MODE_LSB);
|
||||
value &= ~register_mask;
|
||||
value |= (SWMODE_AUTO << SW3MODE_LSB) |
|
||||
(SWMODE_AUTO << SW4MODE_LSB);
|
||||
pmic_write_reg(REG_SW_5, value, 0xffffff);
|
||||
}
|
||||
|
||||
mc13892_register_regulator(mc13892, MC13892_SW1, &sw1_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_SW2, &sw2_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_SW3, &sw3_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_SW4, &sw4_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_SWBST, &swbst_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_VIOHI, &viohi_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_VPLL, &vpll_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_VDIG, &vdig_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_VSD, &vsd_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_VUSB2, &vusb2_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_VVIDEO, &vvideo_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_VAUDIO, &vaudio_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_VCAM, &vcam_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_VGEN1, &vgen1_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_VGEN2, &vgen2_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_VGEN3, &vgen3_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_VUSB, &vusb_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_GPO1, &gpo1_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_GPO2, &gpo2_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_GPO3, &gpo3_init);
|
||||
mc13892_register_regulator(mc13892, MC13892_GPO4, &gpo4_init);
|
||||
|
||||
regulator_has_full_constraints();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mc13892_platform_data mc13892_plat = {
|
||||
.init = mc13892_regulator_init,
|
||||
};
|
||||
|
||||
static struct spi_board_info __initdata mc13892_spi_device = {
|
||||
.modalias = "pmic_spi",
|
||||
/*
|
||||
.irq = IOMUX_TO_IRQ(MX51_PIN_GPIO1_8),
|
||||
*/
|
||||
.irq = IOMUX_TO_IRQ(MX51_PIN_GPIO1_6),
|
||||
.max_speed_hz = 1000000, /* max spi SCK clock speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 0,
|
||||
.platform_data = &mc13892_plat,
|
||||
};
|
||||
|
||||
|
||||
int __init mx51_efikasb_init_mc13892(void)
|
||||
{
|
||||
/* ron: disable power gate */
|
||||
printk(" [VV] mx51_efikasb_init_mc13892.\n");
|
||||
pmic_write_reg(REG_POWER_MISC, ~(PWGT1SPIEN|PWGT2SPIEN),
|
||||
(PWGT1SPIEN|PWGT2SPIEN));
|
||||
|
||||
return spi_register_board_info(&mc13892_spi_device, 1);
|
||||
}
|
||||
|
||||
352
arch/arm/mach-mx5/mx51_efikasb_powerkey.c
Normal file
352
arch/arm/mach-mx5/mx51_efikasb_powerkey.c
Normal file
@@ -0,0 +1,352 @@
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include "mx51_efikasb.h"
|
||||
#include "mx51_pins.h"
|
||||
#include "iomux.h"
|
||||
|
||||
extern int mxc_get_power_status(iomux_pin_name_t pin);
|
||||
extern void mxc_power_on_wlan(int on);
|
||||
extern void mxc_power_on_wwan(int on);
|
||||
extern void mxc_power_on_bt(int on);
|
||||
extern void mxc_power_on_camera(int on);
|
||||
extern void mxc_power_on_agps(int on);
|
||||
extern void mxc_reset_agps(void);
|
||||
|
||||
extern int suspend_device_by_name(char *dev_name, pm_message_t state);
|
||||
extern int resume_device_by_name(char *dev_name, pm_message_t state);
|
||||
|
||||
static void suspend_usbh2_wq_handler(struct work_struct *work);
|
||||
|
||||
static DECLARE_MUTEX(usbh2_mx);
|
||||
static DECLARE_DELAYED_WORK(suspend_usbh2_work, suspend_usbh2_wq_handler);
|
||||
|
||||
#define BIT_BT_PWRON 1
|
||||
#define BIT_WWAN_PWRON 2
|
||||
#define BIT_CAM_PWRON 3
|
||||
|
||||
extern int wireless_sw_state;
|
||||
|
||||
static int usbh2_dev_power = 0;
|
||||
static int usbh2_is_suspend = 0;
|
||||
|
||||
static void suspend_usbh2_wq_handler(struct work_struct *work)
|
||||
{
|
||||
int error;
|
||||
|
||||
down(&usbh2_mx);
|
||||
|
||||
if (usbh2_dev_power == 0) {
|
||||
error = suspend_device_by_name("fsl-ehci.1", PMSG_SUSPEND);
|
||||
if (error == 0)
|
||||
usbh2_is_suspend = 1;
|
||||
};
|
||||
|
||||
up(&usbh2_mx);
|
||||
}
|
||||
|
||||
static ssize_t wlan_pwr_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = mxc_get_power_status(WLAN_PWRON_PIN);
|
||||
return sprintf(buf, "%s\n", val ? "on" : "off");
|
||||
}
|
||||
|
||||
static ssize_t wlan_pwr_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int val;
|
||||
|
||||
if (strncmp(buf, "on", 2) == 0) {
|
||||
val = 1;
|
||||
} else if (strncmp(buf, "off", 3) == 0)
|
||||
val = 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
mxc_power_on_wlan(val);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t wwan_pwr_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = mxc_get_power_status(WWAN_PWRON_PIN);
|
||||
return sprintf(buf, "%s\n", val ? "on" : "off");
|
||||
}
|
||||
|
||||
static ssize_t wwan_pwr_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int old_usbh2_dev_power = usbh2_dev_power;
|
||||
int error;
|
||||
int val;
|
||||
|
||||
if (strncmp(buf, "on", 2) == 0) {
|
||||
val = 1;
|
||||
} else if (strncmp(buf, "off", 3) == 0)
|
||||
val = 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
down(&usbh2_mx);
|
||||
|
||||
if (usbh2_dev_power == 0 && val == 1 && usbh2_is_suspend == 1) {
|
||||
error = resume_device_by_name("fsl-ehci.1", PMSG_RESUME);
|
||||
if (error == 0)
|
||||
usbh2_is_suspend = 0;
|
||||
}
|
||||
|
||||
mxc_power_on_wwan(val);
|
||||
|
||||
if (val)
|
||||
usbh2_dev_power |= (1 << BIT_WWAN_PWRON);
|
||||
else
|
||||
usbh2_dev_power &= ~(1 << BIT_WWAN_PWRON);
|
||||
|
||||
up(&usbh2_mx);
|
||||
|
||||
printk("usbh2_dev_power=%x\n", usbh2_dev_power);
|
||||
|
||||
if (old_usbh2_dev_power != 0 && usbh2_dev_power == 0)
|
||||
schedule_delayed_work(&suspend_usbh2_work, msecs_to_jiffies(4000));
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t bt_pwr_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = mxc_get_power_status(BT_PWRON_PIN);
|
||||
return sprintf(buf, "%s\n", val ? "on" : "off");
|
||||
}
|
||||
|
||||
static ssize_t bt_pwr_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int old_usbh2_dev_power = usbh2_dev_power;
|
||||
int error;
|
||||
int val;
|
||||
|
||||
if (strncmp(buf, "on", 2) == 0) {
|
||||
val = 1;
|
||||
} else if (strncmp(buf, "off", 3) == 0)
|
||||
val = 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
down(&usbh2_mx);
|
||||
|
||||
if (usbh2_dev_power == 0 && val == 1 && usbh2_is_suspend == 1) {
|
||||
error = resume_device_by_name("fsl-ehci.1", PMSG_RESUME);
|
||||
if (error == 0)
|
||||
usbh2_is_suspend = 0;
|
||||
}
|
||||
|
||||
mxc_power_on_bt(val);
|
||||
|
||||
if (val)
|
||||
usbh2_dev_power |= (1 << BIT_BT_PWRON);
|
||||
else
|
||||
usbh2_dev_power &= ~(1 << BIT_BT_PWRON);
|
||||
|
||||
up(&usbh2_mx);
|
||||
|
||||
printk("usbh2_dev_power=%x\n", usbh2_dev_power);
|
||||
|
||||
if (old_usbh2_dev_power != 0 && usbh2_dev_power == 0)
|
||||
schedule_delayed_work(&suspend_usbh2_work, msecs_to_jiffies(4000));
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t camera_pwr_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = mxc_get_power_status(CAM_PWRON_PIN);
|
||||
return sprintf(buf, "%s\n", val ? "on" : "off");
|
||||
}
|
||||
|
||||
static ssize_t camera_pwr_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int val;
|
||||
int old_usbh2_dev_power = usbh2_dev_power;
|
||||
int error;
|
||||
|
||||
if (strncmp(buf, "on", 2) == 0)
|
||||
val = 1;
|
||||
else if (strncmp(buf, "off", 3) == 0)
|
||||
val = 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
down(&usbh2_mx);
|
||||
|
||||
if (usbh2_dev_power == 0 && val == 1 && usbh2_is_suspend == 1) {
|
||||
error = resume_device_by_name("fsl-ehci.1", PMSG_RESUME);
|
||||
if (error == 0)
|
||||
usbh2_is_suspend = 0;
|
||||
}
|
||||
|
||||
mxc_power_on_camera(val);
|
||||
|
||||
if (val)
|
||||
usbh2_dev_power |= (1 << BIT_CAM_PWRON);
|
||||
else
|
||||
usbh2_dev_power &= ~(1 << BIT_CAM_PWRON);
|
||||
|
||||
up(&usbh2_mx);
|
||||
|
||||
printk("usbh2_dev_power=%x\n", usbh2_dev_power);
|
||||
|
||||
if (old_usbh2_dev_power != 0 && usbh2_dev_power == 0)
|
||||
schedule_delayed_work(&suspend_usbh2_work, msecs_to_jiffies(4000));
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t agps_pwr_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = mxc_get_power_status(AGPS_PWRON_PIN);
|
||||
return sprintf(buf, "%s\n", val ? "on" : "off");
|
||||
}
|
||||
|
||||
static ssize_t agps_pwr_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int val;
|
||||
|
||||
if (strncmp(buf, "on", 2) == 0)
|
||||
val = 1;
|
||||
else if (strncmp(buf, "off", 3) == 0)
|
||||
val = 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
mxc_power_on_agps(val);
|
||||
if (val == 1)
|
||||
mxc_reset_agps();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#define DISABLE_POWER_DOWN 0
|
||||
#define PRECHARGE_POWER_DOWN 1
|
||||
#define ACTIVE_POWER_DOWN_64 2
|
||||
#define ACTIVE_POWER_DOWN_128 3
|
||||
|
||||
static void mxc_set_ddr2_power_down(int arg)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = __raw_readl(IO_ADDRESS(ESDCTL_BASE_ADDR + 0x08));
|
||||
value |= (arg & 0x03) << 12;
|
||||
__raw_writel(value, IO_ADDRESS(ESDCTL_BASE_ADDR + 0x08));
|
||||
|
||||
value = __raw_readl(IO_ADDRESS(ESDCTL_BASE_ADDR + 0x00));
|
||||
value |= (arg & 0x03) << 12;
|
||||
__raw_writel(value, IO_ADDRESS(ESDCTL_BASE_ADDR + 0x00));
|
||||
}
|
||||
|
||||
static ssize_t ddr2_pd_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = __raw_readl(IO_ADDRESS(ESDCTL_BASE_ADDR + 0x08));
|
||||
value = (value & 0x3000) >> 12;
|
||||
|
||||
return sprintf(buf, "%d\n", value);
|
||||
}
|
||||
static ssize_t ddr2_pd_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *end;
|
||||
int arg;
|
||||
|
||||
arg = simple_strtoul(buf, &end, 10);
|
||||
if (arg >= 4 || arg < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mxc_set_ddr2_power_down(arg);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct kobj_attribute wlan_pwr_attribute =
|
||||
__ATTR(wlan_power, 0666, wlan_pwr_show, wlan_pwr_store);
|
||||
static struct kobj_attribute wwan_pwr_attribute =
|
||||
__ATTR(wwan_power, 0666, wwan_pwr_show, wwan_pwr_store);
|
||||
static struct kobj_attribute bt_pwr_attribute =
|
||||
__ATTR(bt_power, 0666, bt_pwr_show, bt_pwr_store);
|
||||
static struct kobj_attribute camera_pwr_attribute =
|
||||
__ATTR(camera_power, 0666, camera_pwr_show, camera_pwr_store);
|
||||
static struct kobj_attribute agps_pwr_attribute =
|
||||
__ATTR(agps_power, 0666, agps_pwr_show, agps_pwr_store);
|
||||
static struct kobj_attribute ddr2_pd_attribute =
|
||||
__ATTR(ddr2_pd, 0666, ddr2_pd_show, ddr2_pd_store);
|
||||
|
||||
static struct attribute *pwr_attrs[] = {
|
||||
&wlan_pwr_attribute.attr,
|
||||
&wwan_pwr_attribute.attr,
|
||||
&bt_pwr_attribute.attr,
|
||||
&camera_pwr_attribute.attr,
|
||||
&agps_pwr_attribute.attr,
|
||||
&ddr2_pd_attribute.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group pwr_attr_group = {
|
||||
.attrs = pwr_attrs,
|
||||
};
|
||||
|
||||
static struct platform_device mxc_pwr_sw_device = {
|
||||
.name = "mxc_pwr_sw",
|
||||
};
|
||||
|
||||
static int __init mxc_init_pwr_sw(void)
|
||||
{
|
||||
int retval;
|
||||
static struct kobject *pwr_sw_kobj;
|
||||
|
||||
init_MUTEX(&usbh2_mx);
|
||||
|
||||
usbh2_dev_power |= mxc_get_power_status(BT_PWRON_PIN) << BIT_BT_PWRON;
|
||||
usbh2_dev_power |= mxc_get_power_status(WWAN_PWRON_PIN) << BIT_WWAN_PWRON;
|
||||
usbh2_dev_power |= mxc_get_power_status(CAM_PWRON_PIN) << BIT_CAM_PWRON;
|
||||
if (usbh2_dev_power == 0)
|
||||
suspend_device_by_name("fsl-ehci.1", PMSG_SUSPEND);
|
||||
|
||||
mxc_set_ddr2_power_down(ACTIVE_POWER_DOWN_64); /* ron: set DDR2 power down */
|
||||
|
||||
platform_device_register(&mxc_pwr_sw_device);
|
||||
|
||||
pwr_sw_kobj = kobject_create_and_add("power_control",
|
||||
&mxc_pwr_sw_device.dev.kobj);
|
||||
if (!pwr_sw_kobj)
|
||||
return -ENOMEM;
|
||||
|
||||
retval = sysfs_create_group(pwr_sw_kobj, &pwr_attr_group);
|
||||
if (retval) {
|
||||
kobject_put(pwr_sw_kobj);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
late_initcall(mxc_init_pwr_sw);
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/mxc_uart.h>
|
||||
#include "serial.h"
|
||||
#include "mx51_efikasb.h"
|
||||
|
||||
#if defined(CONFIG_SERIAL_MXC) || defined(CONFIG_SERIAL_MXC_MODULE)
|
||||
|
||||
@@ -36,16 +37,22 @@
|
||||
static uart_mxc_port mxc_ports[] = {
|
||||
[0] = {
|
||||
.port = {
|
||||
.membase = (void *)IO_ADDRESS(UART1_BASE_ADDR),
|
||||
.mapbase = UART1_BASE_ADDR,
|
||||
.iotype = SERIAL_IO_MEM,
|
||||
.irq = UART1_INT1,
|
||||
.fifosize = 32,
|
||||
.flags = ASYNC_BOOT_AUTOCONF,
|
||||
.line = 0,
|
||||
},
|
||||
.ints_muxed = 1,
|
||||
.mode = MODE_DCE,
|
||||
.ir_mode = NO_IRDA,
|
||||
.enabled = 1,
|
||||
.ints_muxed = UART1_MUX_INTS,
|
||||
.irqs = {UART1_INT2, UART1_INT3},
|
||||
.mode = UART1_MODE,
|
||||
.ir_mode = UART1_IR,
|
||||
.enabled = UART1_ENABLED,
|
||||
.hardware_flow = UART1_HW_FLOW,
|
||||
.cts_threshold = UART1_UCR4_CTSTL,
|
||||
.dma_enabled = UART1_DMA_ENABLE,
|
||||
.dma_rxbuf_size = UART1_DMA_RXBUFSIZE,
|
||||
.rx_threshold = UART1_UFCR_RXTL,
|
||||
.tx_threshold = UART1_UFCR_TXTL,
|
||||
@@ -55,16 +62,22 @@ static uart_mxc_port mxc_ports[] = {
|
||||
},
|
||||
[1] = {
|
||||
.port = {
|
||||
.membase = (void *)IO_ADDRESS(UART2_BASE_ADDR),
|
||||
.mapbase = UART2_BASE_ADDR,
|
||||
.iotype = SERIAL_IO_MEM,
|
||||
.irq = UART2_INT1,
|
||||
.fifosize = 32,
|
||||
.flags = ASYNC_BOOT_AUTOCONF,
|
||||
.line = 1,
|
||||
},
|
||||
.ints_muxed = 1,
|
||||
.mode = MODE_DCE,
|
||||
.ir_mode = NO_IRDA,
|
||||
.enabled = 1,
|
||||
.ints_muxed = UART2_MUX_INTS,
|
||||
.irqs = {UART2_INT2, UART2_INT3},
|
||||
.mode = UART2_MODE,
|
||||
.ir_mode = UART2_IR,
|
||||
.enabled = UART2_ENABLED,
|
||||
.hardware_flow = UART2_HW_FLOW,
|
||||
.cts_threshold = UART2_UCR4_CTSTL,
|
||||
.dma_enabled = UART2_DMA_ENABLE,
|
||||
.dma_rxbuf_size = UART2_DMA_RXBUFSIZE,
|
||||
.rx_threshold = UART2_UFCR_RXTL,
|
||||
.tx_threshold = UART2_UFCR_TXTL,
|
||||
@@ -74,17 +87,22 @@ static uart_mxc_port mxc_ports[] = {
|
||||
},
|
||||
[2] = {
|
||||
.port = {
|
||||
.membase = (void *)IO_ADDRESS(UART3_BASE_ADDR),
|
||||
.mapbase = UART3_BASE_ADDR,
|
||||
.iotype = SERIAL_IO_MEM,
|
||||
.irq = UART3_INT1,
|
||||
.fifosize = 32,
|
||||
.flags = ASYNC_BOOT_AUTOCONF,
|
||||
.line = 2,
|
||||
},
|
||||
.ints_muxed = 1,
|
||||
.mode = MODE_DCE,
|
||||
.ir_mode = NO_IRDA,
|
||||
.enabled = 1,
|
||||
.ints_muxed = UART3_MUX_INTS,
|
||||
.irqs = {UART3_INT2, UART3_INT3},
|
||||
.mode = UART3_MODE,
|
||||
.ir_mode = UART3_IR,
|
||||
.enabled = UART3_ENABLED,
|
||||
.hardware_flow = UART3_HW_FLOW,
|
||||
.cts_threshold = UART3_UCR4_CTSTL,
|
||||
.dma_enabled = 1,
|
||||
.dma_enabled = UART3_DMA_ENABLE,
|
||||
.dma_rxbuf_size = UART3_DMA_RXBUFSIZE,
|
||||
.rx_threshold = UART3_UFCR_RXTL,
|
||||
.tx_threshold = UART3_UFCR_TXTL,
|
||||
@@ -94,16 +112,22 @@ static uart_mxc_port mxc_ports[] = {
|
||||
},
|
||||
[3] = {
|
||||
.port = {
|
||||
.membase = (void *)IO_ADDRESS(UART4_BASE_ADDR),
|
||||
.mapbase = UART4_BASE_ADDR,
|
||||
.iotype = SERIAL_IO_MEM,
|
||||
.irq = UART4_INT1,
|
||||
.fifosize = 32,
|
||||
.flags = ASYNC_BOOT_AUTOCONF,
|
||||
.line = 3,
|
||||
},
|
||||
.ints_muxed = 1,
|
||||
.mode = MODE_DCE,
|
||||
.ir_mode = NO_IRDA,
|
||||
.enabled = 1,
|
||||
.ints_muxed = UART4_MUX_INTS,
|
||||
.irqs = {UART4_INT2, UART4_INT3},
|
||||
.mode = UART4_MODE,
|
||||
.ir_mode = UART4_IR,
|
||||
.enabled = UART4_ENABLED,
|
||||
.hardware_flow = UART4_HW_FLOW,
|
||||
.cts_threshold = UART4_UCR4_CTSTL,
|
||||
.dma_enabled = UART4_DMA_ENABLE,
|
||||
.dma_rxbuf_size = UART4_DMA_RXBUFSIZE,
|
||||
.rx_threshold = UART4_UFCR_RXTL,
|
||||
.tx_threshold = UART4_UFCR_TXTL,
|
||||
@@ -113,16 +137,22 @@ static uart_mxc_port mxc_ports[] = {
|
||||
},
|
||||
[4] = {
|
||||
.port = {
|
||||
.membase = (void *)IO_ADDRESS(UART5_BASE_ADDR),
|
||||
.mapbase = UART5_BASE_ADDR,
|
||||
.iotype = SERIAL_IO_MEM,
|
||||
.irq = UART5_INT1,
|
||||
.fifosize = 32,
|
||||
.flags = ASYNC_BOOT_AUTOCONF,
|
||||
.line = 4,
|
||||
},
|
||||
.ints_muxed = 1,
|
||||
.mode = MODE_DCE,
|
||||
.ir_mode = NO_IRDA,
|
||||
.enabled = 1,
|
||||
.ints_muxed = UART5_MUX_INTS,
|
||||
.irqs = {UART5_INT2, UART5_INT3},
|
||||
.mode = UART5_MODE,
|
||||
.ir_mode = UART5_IR,
|
||||
.enabled = UART5_ENABLED,
|
||||
.hardware_flow = UART5_HW_FLOW,
|
||||
.cts_threshold = UART5_UCR4_CTSTL,
|
||||
.dma_enabled = UART5_DMA_ENABLE,
|
||||
.dma_rxbuf_size = UART5_DMA_RXBUFSIZE,
|
||||
.rx_threshold = UART5_UFCR_RXTL,
|
||||
.tx_threshold = UART5_UFCR_TXTL,
|
||||
@@ -132,111 +162,41 @@ static uart_mxc_port mxc_ports[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource mxc_uart_resources1[] = {
|
||||
{
|
||||
.start = UART1_BASE_ADDR,
|
||||
.end = UART1_BASE_ADDR + 0x0B5,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = MXC_INT_UART1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device mxc_uart_device1 = {
|
||||
.name = "mxcintuart",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(mxc_uart_resources1),
|
||||
.resource = mxc_uart_resources1,
|
||||
.dev = {
|
||||
.platform_data = &mxc_ports[0],
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource mxc_uart_resources2[] = {
|
||||
{
|
||||
.start = UART2_BASE_ADDR,
|
||||
.end = UART2_BASE_ADDR + 0x0B5,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = MXC_INT_UART2,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device mxc_uart_device2 = {
|
||||
.name = "mxcintuart",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(mxc_uart_resources2),
|
||||
.resource = mxc_uart_resources2,
|
||||
.dev = {
|
||||
.platform_data = &mxc_ports[1],
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource mxc_uart_resources3[] = {
|
||||
{
|
||||
.start = UART3_BASE_ADDR,
|
||||
.end = UART3_BASE_ADDR + 0x0B5,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = MXC_INT_UART3,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device mxc_uart_device3 = {
|
||||
.name = "mxcintuart",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(mxc_uart_resources3),
|
||||
.resource = mxc_uart_resources3,
|
||||
.dev = {
|
||||
.platform_data = &mxc_ports[2],
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource mxc_uart_resources4[] = {
|
||||
{
|
||||
.start = UART4_BASE_ADDR,
|
||||
.end = UART4_BASE_ADDR + 0x0B5,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = MXC_INT_UART4,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device mxc_uart_device4 = {
|
||||
.name = "mxcintuart",
|
||||
.id = 3,
|
||||
.num_resources = ARRAY_SIZE(mxc_uart_resources4),
|
||||
.resource = mxc_uart_resources4,
|
||||
.dev = {
|
||||
.platform_data = &mxc_ports[3],
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource mxc_uart_resources5[] = {
|
||||
{
|
||||
.start = UART5_BASE_ADDR,
|
||||
.end = UART5_BASE_ADDR + 0x0B5,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = MXC_INT_UART5,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device mxc_uart_device5 = {
|
||||
.name = "mxcintuart",
|
||||
.id = 4,
|
||||
.num_resources = ARRAY_SIZE(mxc_uart_resources5),
|
||||
.resource = mxc_uart_resources5,
|
||||
.dev = {
|
||||
.platform_data = &mxc_ports[4],
|
||||
},
|
||||
@@ -244,26 +204,27 @@ static struct platform_device mxc_uart_device5 = {
|
||||
|
||||
static int __init mxc_init_uart(void)
|
||||
{
|
||||
if (cpu_is_mx53() || cpu_is_mx50()) {
|
||||
mxc_uart_resources1[0].start -= 0x20000000;
|
||||
mxc_uart_resources1[0].end -= 0x20000000;
|
||||
mxc_uart_resources2[0].start -= 0x20000000;
|
||||
mxc_uart_resources2[0].end -= 0x20000000;
|
||||
mxc_uart_resources3[0].start -= 0x20000000;
|
||||
mxc_uart_resources3[0].end -= 0x20000000;
|
||||
mxc_uart_resources4[0].start -= 0x20000000;
|
||||
mxc_uart_resources4[0].end -= 0x20000000;
|
||||
mxc_uart_resources5[0].start -= 0x20000000;
|
||||
mxc_uart_resources5[0].end -= 0x20000000;
|
||||
int i;
|
||||
|
||||
if (cpu_is_mx53()) {
|
||||
for (i = 0; i < ARRAY_SIZE(mxc_ports); i++) {
|
||||
mxc_ports[i].port.mapbase -= 0x20000000;
|
||||
}
|
||||
}
|
||||
|
||||
/* Register all the MXC UART platform device structures */
|
||||
platform_device_register(&mxc_uart_device1);
|
||||
platform_device_register(&mxc_uart_device2);
|
||||
#if UART3_ENABLED == 1
|
||||
platform_device_register(&mxc_uart_device3);
|
||||
#endif /* UART3_ENABLED */
|
||||
if (cpu_is_mx53()) {
|
||||
#if UART4_ENABLED == 1
|
||||
platform_device_register(&mxc_uart_device4);
|
||||
#endif /* UART4_ENABLED */
|
||||
#if UART5_ENABLED == 1
|
||||
platform_device_register(&mxc_uart_device5);
|
||||
#endif /* UART5_ENABLED */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,16 @@
|
||||
#ifndef __ARCH_ARM_MACH_MX51_SERIAL_H__
|
||||
#define __ARCH_ARM_MACH_MX51_SERIAL_H__
|
||||
|
||||
#include <mach/mxc_uart.h>
|
||||
|
||||
/* UART 1 configuration */
|
||||
/*!
|
||||
* This option allows to choose either an interrupt-driven software controlled
|
||||
* hardware flow control (set this option to 0) or hardware-driven hardware
|
||||
* flow control (set this option to 1).
|
||||
*/
|
||||
/* UART used as wakeup source */
|
||||
#define UART1_HW_FLOW 0
|
||||
/*!
|
||||
* This specifies the threshold at which the CTS pin is deasserted by the
|
||||
* RXFIFO. Set this value in Decimal to anything from 0 to 32 for
|
||||
@@ -23,6 +32,10 @@
|
||||
* flow control set this option to -1.
|
||||
*/
|
||||
#define UART1_UCR4_CTSTL 16
|
||||
/*!
|
||||
* This is option to enable (set this option to 1) or disable DMA data transfer
|
||||
*/
|
||||
#define UART1_DMA_ENABLE 0
|
||||
/*!
|
||||
* Specify the size of the DMA receive buffer. The minimum buffer size is 512
|
||||
* bytes. The buffer size should be a multiple of 256.
|
||||
@@ -43,24 +56,88 @@
|
||||
*/
|
||||
#define UART1_UFCR_TXTL 16
|
||||
/* UART 2 configuration */
|
||||
#define UART2_UCR4_CTSTL -1
|
||||
#define UART2_HW_FLOW 1 /* 0 */ /*ron: Enable H/W flow control for AGPS */
|
||||
#define UART2_UCR4_CTSTL 16 /* -1 */
|
||||
#define UART2_DMA_ENABLE 1 /* 0 */
|
||||
#define UART2_DMA_RXBUFSIZE 512
|
||||
#define UART2_UFCR_RXTL 16
|
||||
#define UART2_UFCR_TXTL 16
|
||||
/* UART 3 configuration */
|
||||
#define UART3_HW_FLOW 1
|
||||
#define UART3_UCR4_CTSTL 16
|
||||
#define UART3_DMA_ENABLE 1
|
||||
#define UART3_DMA_RXBUFSIZE 1024
|
||||
#define UART3_UFCR_RXTL 16
|
||||
#define UART3_UFCR_TXTL 16
|
||||
/* UART 4 configuration */
|
||||
#define UART4_HW_FLOW 0
|
||||
#define UART4_UCR4_CTSTL -1
|
||||
#define UART4_DMA_ENABLE 0
|
||||
#define UART4_DMA_RXBUFSIZE 512
|
||||
#define UART4_UFCR_RXTL 16
|
||||
#define UART4_UFCR_TXTL 16
|
||||
/* UART 5 configuration */
|
||||
#define UART5_HW_FLOW 0
|
||||
#define UART5_UCR4_CTSTL -1
|
||||
#define UART5_DMA_ENABLE 0
|
||||
#define UART5_DMA_RXBUFSIZE 512
|
||||
#define UART5_UFCR_RXTL 16
|
||||
#define UART5_UFCR_TXTL 16
|
||||
/*
|
||||
* UART Chip level Configuration that a user may not have to edit. These
|
||||
* configuration vary depending on how the UART module is integrated with
|
||||
* the ARM core
|
||||
*/
|
||||
/*
|
||||
* Is the MUXED interrupt output sent to the ARM core
|
||||
*/
|
||||
#define INTS_NOTMUXED 0
|
||||
#define INTS_MUXED 1
|
||||
/* UART 1 configuration */
|
||||
/*!
|
||||
* This define specifies whether the muxed ANDed interrupt line or the
|
||||
* individual interrupts from the UART port is integrated with the ARM core.
|
||||
* There exists a define like this for each UART port. Valid values that can
|
||||
* be used are \b INTS_NOTMUXED or \b INTS_MUXED.
|
||||
*/
|
||||
#define UART1_MUX_INTS INTS_MUXED
|
||||
/*!
|
||||
* This define specifies the transmitter interrupt number or the interrupt
|
||||
* number of the ANDed interrupt in case the interrupts are muxed. There exists
|
||||
* a define like this for each UART port.
|
||||
*/
|
||||
#define UART1_INT1 MXC_INT_UART1
|
||||
/*!
|
||||
* This define specifies the receiver interrupt number. If the interrupts of
|
||||
* the UART are muxed, then we specify here a dummy value -1. There exists a
|
||||
* define like this for each UART port.
|
||||
*/
|
||||
#define UART1_INT2 -1
|
||||
/*!
|
||||
* This specifies the master interrupt number. If the interrupts of the UART
|
||||
* are muxed, then we specify here a dummy value of -1. There exists a define
|
||||
* like this for each UART port.
|
||||
*/
|
||||
#define UART1_INT3 -1
|
||||
/* UART 2 configuration */
|
||||
#define UART2_MUX_INTS INTS_MUXED
|
||||
#define UART2_INT1 MXC_INT_UART2
|
||||
#define UART2_INT2 -1
|
||||
#define UART2_INT3 -1
|
||||
/* UART 3 configuration */
|
||||
#define UART3_MUX_INTS INTS_MUXED
|
||||
#define UART3_INT1 MXC_INT_UART3
|
||||
#define UART3_INT2 -1
|
||||
#define UART3_INT3 -1
|
||||
/* UART 4 configuration */
|
||||
#define UART4_MUX_INTS INTS_MUXED
|
||||
#define UART4_INT1 MXC_INT_UART4
|
||||
#define UART4_INT2 -1
|
||||
#define UART4_INT3 -1
|
||||
/* UART 5 configuration */
|
||||
#define UART5_MUX_INTS INTS_MUXED
|
||||
#define UART5_INT1 MXC_INT_UART5
|
||||
#define UART5_INT2 -1
|
||||
#define UART5_INT3 -1
|
||||
|
||||
#endif /* __ARCH_ARM_MACH_MX51_SERIAL_H__ */
|
||||
|
||||
@@ -29,7 +29,8 @@ extern void gpio_usbotg_utmi_inactive(void);
|
||||
extern void __init mx5_usb_dr_init(void);
|
||||
extern void __init mx5_usbh1_init(void);
|
||||
extern void __init mx5_usbh2_init(void);
|
||||
|
||||
// micken: name clash with efikamx mainline ?
|
||||
extern void __init mx51_usbh2_init(void);
|
||||
typedef void (*driver_vbus_func)(bool);
|
||||
extern void mx5_set_host1_vbus_func(driver_vbus_func);
|
||||
extern void mx5_set_otghost_vbus_func(driver_vbus_func);
|
||||
|
||||
@@ -209,6 +209,24 @@ struct mxc_w1_config {
|
||||
* data. It includes the SPI bus number and the maximum number of
|
||||
* slaves/chips it supports.
|
||||
*/
|
||||
|
||||
|
||||
/* micken: added battery support */
|
||||
|
||||
struct mxc_battery_platform_data {
|
||||
int batt_in_irq;
|
||||
int ac_in_irq;
|
||||
int batt_low_irq;
|
||||
int (*get_batt_in_status) (void);
|
||||
int (*get_ac_in_status) (void);
|
||||
int (*get_batt_low_status) (void);
|
||||
void (*set_batt_low_led) (int);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct mxc_spi_master {
|
||||
/*!
|
||||
* SPI Master's bus number.
|
||||
@@ -314,6 +332,11 @@ struct mxc_lcd_platform_data {
|
||||
char *io_reg;
|
||||
char *core_reg;
|
||||
char *analog_reg;
|
||||
// micken: backlight etc for efikasb
|
||||
void (*power_on_lcd) (int);
|
||||
void (*power_on_lvds) (int);
|
||||
void (*turn_on_backlight) (int);
|
||||
void (*lvds_enable) (int);
|
||||
void (*reset) (void);
|
||||
};
|
||||
|
||||
|
||||
@@ -696,6 +696,98 @@ static int dpm_suspend(pm_message_t state)
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* ron: suspend the USB Host if all device are disconnected */
|
||||
// Inherited Ron's added, Byron 2010.03.10 // micken : added to efikasb kernel 2010.09.03
|
||||
int suspend_device_by_name(char *dev_name, pm_message_t state)
|
||||
{
|
||||
struct list_head list;
|
||||
int error = 0;
|
||||
|
||||
INIT_LIST_HEAD(&list);
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
while (!list_empty(&dpm_list)) {
|
||||
struct device *dev = to_device(dpm_list.prev);
|
||||
|
||||
get_device(dev);
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
|
||||
if(strcmp(dev_name, dev->kobj.name) == 0) {
|
||||
|
||||
//error = suspend_device(dev, state);
|
||||
error= device_suspend(dev,state);//2010.03.10 ,Byron
|
||||
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
if (error) {
|
||||
pm_dev_err(dev, state, "", error);
|
||||
put_device(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
dev->power.status = DPM_OFF;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!list_empty(&dev->power.entry))
|
||||
list_move(&dev->power.entry, &list);
|
||||
put_device(dev);
|
||||
|
||||
}
|
||||
list_splice(&list, dpm_list.prev);
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(suspend_device_by_name);
|
||||
|
||||
|
||||
// inheriated V28 Byron 2010.03.10 // micken: added to efikasb 2010.09.03
|
||||
int resume_device_by_name(char *dev_name, pm_message_t state)
|
||||
{
|
||||
struct list_head list;
|
||||
int error = 0;
|
||||
|
||||
INIT_LIST_HEAD(&list);
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
transition_started = false;
|
||||
while (!list_empty(&dpm_list)) {
|
||||
struct device *dev = to_device(dpm_list.next);
|
||||
|
||||
get_device(dev);
|
||||
|
||||
if(strcmp(dev_name, dev->kobj.name) == 0) {
|
||||
|
||||
if (dev->power.status >= DPM_OFF) {
|
||||
|
||||
dev->power.status = DPM_RESUMING;
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
|
||||
//error = resume_device(dev, state);
|
||||
error=device_resume(dev,state); //2010.03.10 Byron
|
||||
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
if (error)
|
||||
pm_dev_err(dev, state, "", error);
|
||||
} else if (dev->power.status == DPM_SUSPENDING) {
|
||||
/* Allow new children of the device to be registered */
|
||||
dev->power.status = DPM_RESUMING;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!list_empty(&dev->power.entry))
|
||||
list_move_tail(&dev->power.entry, &list);
|
||||
put_device(dev);
|
||||
}
|
||||
list_splice(&list, &dpm_list);
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(resume_device_by_name);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* device_prepare - Execute the ->prepare() callback(s) for given device.
|
||||
* @dev: Device.
|
||||
|
||||
@@ -51,6 +51,13 @@ MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data
|
||||
EXPORT_SYMBOL_GPL(hid_debug);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//inherited V28 ,2010.03.10 Byron
|
||||
#ifdef CONFIG_MACH_MX51_EFIKASB
|
||||
extern void mxc_reset_idle_timer(void);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Register a new report for a device.
|
||||
*/
|
||||
@@ -917,6 +924,11 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ron: add kunlun custom Fn + XX key */
|
||||
//inherited Ron's code, Byron 2010.03.10
|
||||
if((field->usage[n].hid & HID_USAGE_PAGE) == HID_UP_CUSTOM)
|
||||
hid_process_event(hid, field, &field->usage[n], value[n], interrupt);
|
||||
|
||||
if (field->value[n] >= min && field->value[n] <= max
|
||||
&& field->usage[field->value[n] - min].hid
|
||||
&& search(value, field->value[n], count))
|
||||
|
||||
@@ -296,6 +296,8 @@
|
||||
#define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215
|
||||
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218
|
||||
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219
|
||||
//micken: #define USB_DEVICE_ID_LOGITECH_G15_GAMEPANEL 0xc227 define
|
||||
#define USB_DEVICE_ID_LOGITECH_G15_GAMEPANEL 0xc227
|
||||
#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283
|
||||
#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286
|
||||
#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include <linux/hid-debug.h>
|
||||
#include <linux/hidraw.h>
|
||||
#include "usbhid.h"
|
||||
|
||||
#include "../hid-ids.h" // micken: for logitech id
|
||||
/*
|
||||
* Version Information
|
||||
*/
|
||||
@@ -552,6 +552,12 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usbhid_submit_report);
|
||||
|
||||
|
||||
#ifdef CONFIG_MACH_MX51_EFIKASB
|
||||
extern void mxc_turn_on_caps_led(int on);
|
||||
#endif
|
||||
|
||||
|
||||
static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
struct hid_device *hid = input_get_drvdata(dev);
|
||||
@@ -583,6 +589,14 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un
|
||||
}
|
||||
usbhid_submit_report(hid, field->report, USB_DIR_OUT);
|
||||
|
||||
#ifdef CONFIG_MACH_MX51_EFIKASB
|
||||
/* ron: Caps Lock LED */
|
||||
if(code == 0x01) {
|
||||
mxc_turn_on_caps_led(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1130,6 +1144,18 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
hid->bus = BUS_USB;
|
||||
hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
|
||||
hid->product = le16_to_cpu(dev->descriptor.idProduct);
|
||||
|
||||
#ifdef CONFIG_MACH_MX51_EFIKASB
|
||||
/* ron: skip the Logitech G15 GamePanel LCD */
|
||||
// inherited Ron's code , Byron 2010.03.10
|
||||
if(hid->vendor == USB_VENDOR_ID_LOGITECH &&
|
||||
hid->product == USB_DEVICE_ID_LOGITECH_G15_GAMEPANEL) {
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
hid->name[0] = 0;
|
||||
if (intf->cur_altsetting->desc.bInterfaceProtocol ==
|
||||
USB_INTERFACE_PROTOCOL_MOUSE)
|
||||
|
||||
@@ -36,6 +36,15 @@ config LEDS_MC13892
|
||||
tristate "LED Support for mc13892 pmic"
|
||||
depends on LEDS_CLASS && MXC_MC13892_LIGHT
|
||||
|
||||
|
||||
config LEDS_EFIKASB
|
||||
tristate "LED Support for Efikasb Platform"
|
||||
depends on LEDS_CLASS && MACH_MX51_EFIKASB
|
||||
help
|
||||
This option enable support for the LEDs on Efikasb Platform.
|
||||
|
||||
|
||||
|
||||
config LEDS_LOCOMO
|
||||
tristate "LED Support for Locomo device"
|
||||
depends on LEDS_CLASS && SHARP_LOCOMO
|
||||
|
||||
@@ -8,6 +8,7 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
|
||||
obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o
|
||||
obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
|
||||
obj-$(CONFIG_LEDS_MC13892) += leds-mc13892.o
|
||||
obj-$(CONFIG_LEDS_EFIKASB) += leds-efikasb.o
|
||||
obj-$(CONFIG_LEDS_STMP378X) += leds-stmp378x-pwm.o
|
||||
obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
|
||||
obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o
|
||||
|
||||
102
drivers/leds/leds-efikasb.c
Normal file
102
drivers/leds/leds-efikasb.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2009 Pegatron Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
extern void mxc_turn_on_alarm_led(int on);
|
||||
|
||||
static void msg_alarm_led_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
mxc_turn_on_alarm_led(value ? 1 : 0);
|
||||
}
|
||||
|
||||
static struct led_classdev msg_alarm_led = {
|
||||
.name = "msg-alarm-led",
|
||||
.brightness_set = msg_alarm_led_set,
|
||||
};
|
||||
|
||||
static int efikasb_led_remove(struct platform_device *dev)
|
||||
{
|
||||
|
||||
led_classdev_unregister(&msg_alarm_led);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efikasb_led_probe(struct platform_device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = led_classdev_register(&dev->dev, &msg_alarm_led);
|
||||
if (ret < 0) {
|
||||
dev_err(&dev->dev, "Register Message Alarm LED failed\n");
|
||||
return -ENODEV;
|
||||
|
||||
}
|
||||
|
||||
printk(KERN_INFO "Registered Efikasb Message Alarm LED\n");
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int efikasb_led_suspend(struct platform_device *dev, pm_message_t state)
|
||||
{
|
||||
|
||||
led_classdev_suspend(&msg_alarm_led);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efikasb_led_resume(struct platform_device *dev)
|
||||
{
|
||||
|
||||
led_classdev_resume(&msg_alarm_led);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define efikasb_led_suspend NULL
|
||||
#define efikasb_led_resume NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver efikasb_led_driver = {
|
||||
.probe = efikasb_led_probe,
|
||||
.remove = efikasb_led_remove,
|
||||
.suspend = efikasb_led_suspend,
|
||||
.resume = efikasb_led_resume,
|
||||
.driver = {
|
||||
.name = "efikasb_leds",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init efikasb_led_init(void)
|
||||
{
|
||||
return platform_driver_register(&efikasb_led_driver);
|
||||
}
|
||||
|
||||
static void __exit efikasb_led_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&efikasb_led_driver);
|
||||
}
|
||||
|
||||
module_init(efikasb_led_init);
|
||||
module_exit(efikasb_led_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Led driver for Efikasb LEDs");
|
||||
MODULE_AUTHOR("Ron Lee <ron1_lee@pegatroncorp.com> Pegatron Inc.");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -238,6 +238,15 @@ config MXS_PERSISTENT
|
||||
depends on ARCH_MXS
|
||||
default y
|
||||
|
||||
|
||||
config MX51_EFIKASB_DEBUG
|
||||
tristate "MX51 Efikasb Debug Driver"
|
||||
depends on MACH_MX51_EFIKASB
|
||||
default n
|
||||
---help---
|
||||
MX51 debug driver of Efikasb board for Engineer.
|
||||
|
||||
|
||||
source "drivers/misc/c2port/Kconfig"
|
||||
source "drivers/misc/eeprom/Kconfig"
|
||||
source "drivers/misc/cb710/Kconfig"
|
||||
|
||||
@@ -21,5 +21,6 @@ obj-$(CONFIG_HP_ILO) += hpilo.o
|
||||
obj-$(CONFIG_ISL29003) += isl29003.o
|
||||
obj-$(CONFIG_C2PORT) += c2port/
|
||||
obj-$(CONFIG_MXS_PERSISTENT) += mxs-persistent.o
|
||||
obj-$(CONFIG_MX51_EFIKASB_DEBUG) += mx51_efikasb_debug.o
|
||||
obj-y += eeprom/
|
||||
obj-y += cb710/
|
||||
|
||||
657
drivers/misc/mx51_efikasb_debug.c
Normal file
657
drivers/misc/mx51_efikasb_debug.c
Normal file
@@ -0,0 +1,657 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/pmic_external.h>
|
||||
#include <linux/pmic_status.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
static ssize_t reg_dump_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t reg_dump_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *end;
|
||||
char *token;
|
||||
char *running;
|
||||
const char delimiters[] = " ";
|
||||
u32 addr, value;
|
||||
int len = 1;
|
||||
int i;
|
||||
|
||||
running = (char *)buf;
|
||||
|
||||
token = strsep(&running, delimiters);
|
||||
addr = simple_strtoul(token, &end, 16);
|
||||
token = strsep(&running, delimiters);
|
||||
if(token != NULL)
|
||||
len = simple_strtoul(token, &end, 10);
|
||||
|
||||
if(len <= 1)
|
||||
len = 1;
|
||||
|
||||
for (i = 0; i < len; i ++) {
|
||||
value = __raw_readl(IO_ADDRESS(addr));
|
||||
printk("[0x%08x] = 0x%08x\n", addr, value);
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t reg_write_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t reg_write_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *end;
|
||||
char *token;
|
||||
char *running;
|
||||
const char delimiters[] = "=";
|
||||
u32 addr, value;
|
||||
|
||||
running = (char *)buf;
|
||||
|
||||
token = strsep(&running, delimiters);
|
||||
addr = simple_strtoul(token, &end, 16);
|
||||
token = strsep(&running, delimiters);
|
||||
if(token != NULL) {
|
||||
value = simple_strtoul(token, &end, 16);
|
||||
} else {
|
||||
value = __raw_readl(IO_ADDRESS(addr));
|
||||
printk("[0x%08x] = 0x%08x\n", addr, value);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
__raw_writel(value, IO_ADDRESS(addr));
|
||||
value = __raw_readl(IO_ADDRESS(addr));
|
||||
|
||||
printk("[0x%08x] = 0x%08x\n", addr, value);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
struct pmic_reg_tbl {
|
||||
char *name;
|
||||
int reg_addr;
|
||||
};
|
||||
|
||||
struct pmic_reg_tbl pmic_reg_tbl[] = {
|
||||
{"INT_STATUS0",REG_INT_STATUS0},
|
||||
{"INT_MASK0",REG_INT_MASK0},
|
||||
{"INT_SENSE0",REG_INT_SENSE0},
|
||||
{"INT_STATUS1",REG_INT_STATUS1},
|
||||
{"INT_MASK1",REG_INT_MASK1},
|
||||
{"INT_SENSE1",REG_INT_SENSE1},
|
||||
{"PU_MODE_S",REG_PU_MODE_S},
|
||||
{"ID",REG_IDENTIFICATION},
|
||||
{"UNUSED0",REG_UNUSED0},
|
||||
{"ACC0",REG_ACC0},
|
||||
{"ACC1",REG_ACC1},
|
||||
{"UNUSED1",REG_UNUSED1},
|
||||
{"UNUSED2",REG_UNUSED2},
|
||||
{"POWER_CTL0",REG_POWER_CTL0},
|
||||
{"POWER_CTL1",REG_POWER_CTL1},
|
||||
{"POWER_CTL2",REG_POWER_CTL2},
|
||||
{"REGEN_ASSIGN",REG_REGEN_ASSIGN},
|
||||
{"UNUSED3",REG_UNUSED3},
|
||||
{"MEM_A",REG_MEM_A},
|
||||
{"MEM_B",REG_MEM_B},
|
||||
{"RTC_TIME",REG_RTC_TIME},
|
||||
{"RTC_ALARM",REG_RTC_ALARM},
|
||||
{"RTC_DAY",REG_RTC_DAY},
|
||||
{"RTC_DAY_ALARM",REG_RTC_DAY_ALARM},
|
||||
{"SW0",REG_SW_0},
|
||||
{"SW1",REG_SW_1},
|
||||
{"SW2",REG_SW_2},
|
||||
{"SW3",REG_SW_3},
|
||||
{"SW4",REG_SW_4},
|
||||
{"SW5",REG_SW_5},
|
||||
{"SETTING0",REG_SETTING_0},
|
||||
{"SETTING1",REG_SETTING_1},
|
||||
{"MODE_0",REG_MODE_0},
|
||||
{"MODE_1",REG_MODE_1},
|
||||
{"POWER_MISC",REG_POWER_MISC},
|
||||
{"UNUSED4",REG_UNUSED4},
|
||||
{"UNUSED5",REG_UNUSED5},
|
||||
{"UNUSED6",REG_UNUSED6},
|
||||
{"UNUSED7",REG_UNUSED7},
|
||||
{"UNUSED8",REG_UNUSED8},
|
||||
{"UNUSED9",REG_UNUSED9},
|
||||
{"UNUSED10",REG_UNUSED10},
|
||||
{"UNUSED11",REG_UNUSED11},
|
||||
{"ADC0",REG_ADC0},
|
||||
{"ADC1",REG_ADC1},
|
||||
{"ADC2",REG_ADC2},
|
||||
{"ADC3",REG_ADC3},
|
||||
{"ADC4",REG_ADC4},
|
||||
{"CHARGE",REG_CHARGE},
|
||||
{"USB0",REG_USB0},
|
||||
{"USB1",REG_USB1},
|
||||
{"LED_CTL0",REG_LED_CTL0},
|
||||
{"LED_CTL1",REG_LED_CTL1},
|
||||
{"LED_CTL2",REG_LED_CTL2},
|
||||
{"LED_CTL3",REG_LED_CTL3},
|
||||
{"UNUSED12",REG_UNUSED12},
|
||||
{"UNUSED13",REG_UNUSED13},
|
||||
{"TRIM0",REG_TRIM0},
|
||||
{"TRIM1",REG_TRIM1},
|
||||
{"TEST0",REG_TEST0},
|
||||
{"TEST1",REG_TEST1},
|
||||
{"TEST2",REG_TEST2},
|
||||
{"TEST3",REG_TEST3},
|
||||
{"TEST4",REG_TEST4},
|
||||
|
||||
};
|
||||
|
||||
static ssize_t pmic_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
u32 value;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < ARRAY_SIZE(pmic_reg_tbl); i++) {
|
||||
pmic_read(i, &value);
|
||||
printk("%s: [%d] = 0x%08x\n", pmic_reg_tbl[i].name, i, value);
|
||||
};
|
||||
|
||||
return 0/* strlen(buf) */;
|
||||
|
||||
}
|
||||
|
||||
static ssize_t pmic_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *end;
|
||||
char *token;
|
||||
char *running;
|
||||
const char delimiters[] = "=";
|
||||
u32 addr, value;
|
||||
|
||||
running = (char *)buf;
|
||||
|
||||
token = strsep(&running, delimiters);
|
||||
addr = simple_strtoul(token, &end, 10);
|
||||
if(addr > 63) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
token = strsep(&running, delimiters);
|
||||
if(token != NULL) {
|
||||
value = simple_strtoul(token, &end, 16);
|
||||
} else {
|
||||
value = pmic_read(addr, &value);
|
||||
printk("[%d] = 0x%08x\n", addr, value);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pmic_write(addr, value);
|
||||
pmic_read(addr, &value);
|
||||
|
||||
printk("[%d] = 0x%08x\n", addr, value);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t edid_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
u8 buf0[2] = {0, 0};
|
||||
int data = 0;
|
||||
u16 addr = 0x50;
|
||||
u8 edid[128];
|
||||
int i;
|
||||
struct i2c_adapter *adp;
|
||||
struct i2c_msg msg[2] = {
|
||||
{
|
||||
.addr = addr,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = buf0,
|
||||
}, {
|
||||
.addr = addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = 128,
|
||||
.buf = edid,
|
||||
},
|
||||
};
|
||||
|
||||
adp = i2c_get_adapter(1);
|
||||
|
||||
data = i2c_transfer(adp, msg, 2);
|
||||
if(data <= 0)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < 128; i ++) {
|
||||
printk("[%x]=%x\n", i, edid[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SBS_MFG_ACCESS 0x00
|
||||
#define SBS_REMAIN_CAPACITY_ALARM 0x01
|
||||
#define SBS_REMNAIN_TIME_ALARM 0x02
|
||||
#define SBS_BATTERY_MODE 0x03
|
||||
#define SBS_AT_RATE 0x04
|
||||
#define SBS_AT_RATE_TIME_TO_FULL 0x05
|
||||
#define SBS_AT_RATE_TIME_TO_EMPTY 0x06
|
||||
#define SBS_AT_RATE_OK 0x07
|
||||
#define SBS_TEMP 0x08
|
||||
#define SBS_VOLTAGE 0x09
|
||||
#define SBS_CURRENT 0x0A
|
||||
#define SBS_AVG_CURRENT 0x0B
|
||||
#define SBS_MAX_ERROR 0x0C
|
||||
#define SBS_REL_STATE_OF_CHARGE 0x0D
|
||||
#define SBS_ABS_STATE_OF_CHARGE 0x0E
|
||||
#define SBS_REMAIN_CAPABILITY 0x0F
|
||||
#define SBS_FULL_CHARGE_CAPACITY 0x10
|
||||
#define SBS_RUN_TIME_TO_EMPTY 0x11
|
||||
#define SBS_AVG_TIME_TO_EMPTY 0x12
|
||||
#define SBS_AVG_TIME_TO_FULL 0x13
|
||||
#define SBS_CHARGE_CURRENT 0x14
|
||||
#define SBS_CHARGE_VOLTAGE 0x15
|
||||
#define SBS_BATTERY_STATUS 0x16
|
||||
#define SBS_CYCLE_COUNT 0x17
|
||||
#define SBS_DESIGN_CAPACITY 0x18
|
||||
#define SBS_DESIGN_VOLTAGE 0x19
|
||||
#define SBS_SPEC_INFO 0x1A
|
||||
#define SBS_MFG_DATE 0x1B
|
||||
#define SBS_SERIAL_NO 0x1C
|
||||
#define SBS_MFG_NAME 0x20
|
||||
#define SBS_DEV_NAME 0x21
|
||||
#define SBS_DEV_CHEMISTRY 0x22
|
||||
#define SBS_MFG_DATA 0x23
|
||||
#define SBS_BATTERY_USAGE 0x30
|
||||
#define SBS_PERMANENT_FAILURE 0x31
|
||||
#define SBS_BATTERY_LOG1 0x32
|
||||
#define SBS_BATTERY_LOG2 0x33
|
||||
#define SBS_FET_TEMP 0x3B
|
||||
#define SBS_OPTION_MFG_FUNC5 0x2F
|
||||
#define SBS_OPTION_MFG_FUNC4 0x3C
|
||||
#define SBS_OPTION_MFG_FUNC3 0x3D
|
||||
#define SBS_OPTION_MFG_FUNC2 0x3E
|
||||
#define SBS_OPTION_MFG_FUNC1 0x3F
|
||||
|
||||
struct sbs_reg_tbl {
|
||||
char *name;
|
||||
unsigned char reg_offset;
|
||||
};
|
||||
|
||||
static struct sbs_reg_tbl reg_tbl[] = {
|
||||
{"Manufacture Access", SBS_MFG_ACCESS},
|
||||
{"Remain Capacity Alarm", SBS_REMAIN_CAPACITY_ALARM },
|
||||
{"Remain Time Alarm", SBS_REMNAIN_TIME_ALARM},
|
||||
{"Battery Mode", SBS_BATTERY_MODE},
|
||||
{"AT Rate", SBS_AT_RATE},
|
||||
{"AT Rate Time To Full", SBS_AT_RATE_TIME_TO_FULL},
|
||||
{"AT Rate Time To Empty", SBS_AT_RATE_TIME_TO_EMPTY},
|
||||
{"AT Rate OK", SBS_AT_RATE_OK},
|
||||
{"Temperature", SBS_TEMP},
|
||||
{"Voltage", SBS_VOLTAGE},
|
||||
{"Current", SBS_CURRENT},
|
||||
{"Average Current", SBS_AVG_CURRENT},
|
||||
{"Maximum Error", SBS_MAX_ERROR},
|
||||
{"Relative State of Charge", SBS_REL_STATE_OF_CHARGE},
|
||||
{"Absolute State of Charge", SBS_ABS_STATE_OF_CHARGE},
|
||||
{"Remain Capacity", SBS_REMAIN_CAPABILITY},
|
||||
{"Full Charge Capacity", SBS_FULL_CHARGE_CAPACITY},
|
||||
{"Run Time To Empty", SBS_RUN_TIME_TO_EMPTY},
|
||||
{"Average Time To Empty", SBS_AVG_TIME_TO_EMPTY},
|
||||
{"Average Time To Full", SBS_AVG_TIME_TO_FULL},
|
||||
{"Charge Current", SBS_CHARGE_CURRENT},
|
||||
{"Charge Voltage", SBS_CHARGE_VOLTAGE},
|
||||
{"Battery Status", SBS_BATTERY_STATUS},
|
||||
{"Cycle Count", SBS_CYCLE_COUNT},
|
||||
{"Design Capacity", SBS_DESIGN_CAPACITY},
|
||||
{"Design Voltage", SBS_DESIGN_VOLTAGE},
|
||||
{"Spec Info", SBS_SPEC_INFO},
|
||||
{"Manufacture Date", SBS_MFG_DATE},
|
||||
{"Serial Number", SBS_SERIAL_NO},
|
||||
{"Manufacture Name", SBS_MFG_NAME},
|
||||
{"Device Name", SBS_DEV_NAME},
|
||||
{"Device Chemistry", SBS_DEV_CHEMISTRY},
|
||||
{"Manufacture Date", SBS_MFG_DATA},
|
||||
{"Battery Usage", SBS_BATTERY_USAGE},
|
||||
{"Permanent Failure", SBS_PERMANENT_FAILURE},
|
||||
{"Battery Log1", SBS_BATTERY_LOG1},
|
||||
{"Battery Log2", SBS_BATTERY_LOG2},
|
||||
{"FET Temperature", SBS_FET_TEMP},
|
||||
{"Optional Mfg Func5", SBS_OPTION_MFG_FUNC5},
|
||||
{"Optional Mfg Func4", SBS_OPTION_MFG_FUNC4},
|
||||
{"Optional Mfg Func3", SBS_OPTION_MFG_FUNC3},
|
||||
{"Optional Mfg Func2", SBS_OPTION_MFG_FUNC2},
|
||||
{"Optional Mfg Func1", SBS_OPTION_MFG_FUNC1},
|
||||
|
||||
};
|
||||
|
||||
static ssize_t battery_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_adapter *adp;
|
||||
union i2c_smbus_data data;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
adp = i2c_get_adapter(1);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(reg_tbl); i++) {
|
||||
status = i2c_smbus_xfer(adp, 0x0b, 0,
|
||||
I2C_SMBUS_READ, reg_tbl[i].reg_offset,
|
||||
I2C_SMBUS_WORD_DATA, &data);
|
||||
if(status < 0)
|
||||
return -ENODEV;
|
||||
printk("%s: 0x%04x\n", reg_tbl[i].name, data.word);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t mtl017_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_adapter *adp;
|
||||
union i2c_smbus_data data;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
adp = i2c_get_adapter(1);
|
||||
|
||||
for (i = 0; i < 0xff; i++) {
|
||||
status = i2c_smbus_xfer(adp, 0x3a, 0,
|
||||
I2C_SMBUS_READ, i,
|
||||
I2C_SMBUS_BYTE_DATA, &data);
|
||||
if(status < 0)
|
||||
return -ENODEV;
|
||||
printk("[0x%x]: 0x%02x\n", i, data.byte);
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static ssize_t mtl017_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
#define SGTL5000_CHIP_ID 0x0000
|
||||
#define SGTL5000_CHIP_DIG_POWER 0x0002
|
||||
#define SGTL5000_CHIP_CLK_CTRL 0x0004
|
||||
#define SGTL5000_CHIP_I2S_CTRL 0x0006
|
||||
#define SGTL5000_CHIP_SSS_CTRL 0x000a
|
||||
#define SGTL5000_CHIP_ADCDAC_CTRL 0x000e
|
||||
#define SGTL5000_CHIP_DAC_VOL 0x0010
|
||||
#define SGTL5000_CHIP_PAD_STRENGTH 0x0014
|
||||
#define SGTL5000_CHIP_ANA_ADC_CTRL 0x0020
|
||||
#define SGTL5000_CHIP_ANA_HP_CTRL 0x0022
|
||||
#define SGTL5000_CHIP_ANA_CTRL 0x0024
|
||||
#define SGTL5000_CHIP_LINREG_CTRL 0x0026
|
||||
#define SGTL5000_CHIP_REF_CTRL 0x0028
|
||||
#define SGTL5000_CHIP_MIC_CTRL 0x002a
|
||||
#define SGTL5000_CHIP_LINE_OUT_CTRL 0x002c
|
||||
#define SGTL5000_CHIP_LINE_OUT_VOL 0x002e
|
||||
#define SGTL5000_CHIP_ANA_POWER 0x0030
|
||||
#define SGTL5000_CHIP_PLL_CTRL 0x0032
|
||||
#define SGTL5000_CHIP_CLK_TOP_CTRL 0x0034
|
||||
#define SGTL5000_CHIP_ANA_STATUS 0x0036
|
||||
#define SGTL5000_CHIP_SHORT_CTRL 0x003c
|
||||
#define SGTL5000_CHIP_ANA_TEST2 0x003a
|
||||
#define SGTL5000_DAP_CTRL 0x0100
|
||||
#define SGTL5000_DAP_PEQ 0x0102
|
||||
#define SGTL5000_DAP_BASS_ENHANCE 0x0104
|
||||
#define SGTL5000_DAP_BASS_ENHANCE_CTRL 0x0106
|
||||
#define SGTL5000_DAP_AUDIO_EQ 0x0108
|
||||
#define SGTL5000_DAP_SURROUND 0x010a
|
||||
#define SGTL5000_DAP_FLT_COEF_ACCESS 0x010c
|
||||
#define SGTL5000_DAP_COEF_WR_B0_MSB 0x010e
|
||||
#define SGTL5000_DAP_COEF_WR_B0_LSB 0x0110
|
||||
#define SGTL5000_DAP_EQ_BASS_BAND0 0x0116
|
||||
#define SGTL5000_DAP_EQ_BASS_BAND1 0x0118
|
||||
#define SGTL5000_DAP_EQ_BASS_BAND2 0x011a
|
||||
#define SGTL5000_DAP_EQ_BASS_BAND3 0x011c
|
||||
#define SGTL5000_DAP_EQ_BASS_BAND4 0x011e
|
||||
#define SGTL5000_DAP_MAIN_CHAN 0x0120
|
||||
#define SGTL5000_DAP_MIX_CHAN 0x0122
|
||||
#define SGTL5000_DAP_AVC_CTRL 0x0124
|
||||
#define SGTL5000_DAP_AVC_THRESHOLD 0x0126
|
||||
#define SGTL5000_DAP_AVC_ATTACK 0x0128
|
||||
#define SGTL5000_DAP_AVC_DECAY 0x012a
|
||||
#define SGTL5000_DAP_COEF_WR_B1_MSB 0x012c
|
||||
#define SGTL5000_DAP_COEF_WR_B1_LSB 0x012e
|
||||
#define SGTL5000_DAP_COEF_WR_B2_MSB 0x0130
|
||||
#define SGTL5000_DAP_COEF_WR_B2_LSB 0x0132
|
||||
#define SGTL5000_DAP_COEF_WR_A1_MSB 0x0134
|
||||
#define SGTL5000_DAP_COEF_WR_A1_LSB 0x0136
|
||||
#define SGTL5000_DAP_COEF_WR_A2_MSB 0x0138
|
||||
#define SGTL5000_DAP_COEF_WR_A2_LSB 0x013a
|
||||
|
||||
struct sgtl_reg_tbl {
|
||||
char *name;
|
||||
unsigned int reg_addr;
|
||||
};
|
||||
|
||||
struct sgtl_reg_tbl sgtl_tbl[] = {
|
||||
{"ID", SGTL5000_CHIP_ID},
|
||||
{"POWER", SGTL5000_CHIP_DIG_POWER},
|
||||
{"CLK_CTRL", SGTL5000_CHIP_CLK_CTRL},
|
||||
{"I2S_CTRL", SGTL5000_CHIP_I2S_CTRL},
|
||||
{"SSS_CTRL", SGTL5000_CHIP_SSS_CTRL},
|
||||
{"ADCDAC_CTRL", SGTL5000_CHIP_ADCDAC_CTRL},
|
||||
{"DAC_VOL", SGTL5000_CHIP_DAC_VOL},
|
||||
{"PAD_STRENGTH", SGTL5000_CHIP_PAD_STRENGTH},
|
||||
{"ANA_ADC_CTRL", SGTL5000_CHIP_ANA_ADC_CTRL},
|
||||
{"ANA_HP_CTRL", SGTL5000_CHIP_ANA_HP_CTRL},
|
||||
{"ANA_CTRL", SGTL5000_CHIP_ANA_CTRL},
|
||||
{"LINREG_CTRL", SGTL5000_CHIP_LINREG_CTRL},
|
||||
{"REF_CTRL", SGTL5000_CHIP_REF_CTRL},
|
||||
{"MIC_CTRL", SGTL5000_CHIP_MIC_CTRL},
|
||||
{"LINE_OUT_CTRL", SGTL5000_CHIP_LINE_OUT_CTRL},
|
||||
{"LINE_OUT_VOL", SGTL5000_CHIP_LINE_OUT_VOL},
|
||||
{"ANA_POWER", SGTL5000_CHIP_ANA_POWER},
|
||||
{"PLL_CTRL", SGTL5000_CHIP_PLL_CTRL},
|
||||
{"CLK_TOP_CTRL", SGTL5000_CHIP_CLK_TOP_CTRL},
|
||||
{"ANA_STATUS", SGTL5000_CHIP_ANA_STATUS},
|
||||
{"SHORT_CTRL", SGTL5000_CHIP_SHORT_CTRL},
|
||||
{"ANA_TEST2", SGTL5000_CHIP_ANA_TEST2},
|
||||
{"DAP_CTRL", SGTL5000_DAP_CTRL},
|
||||
{"DAP_PEQ", SGTL5000_DAP_PEQ},
|
||||
{"DAP_BASS_ENHANCE", SGTL5000_DAP_BASS_ENHANCE},
|
||||
{"DAP_BASS_ENHANCE_CTRL", SGTL5000_DAP_BASS_ENHANCE_CTRL},
|
||||
{"DAP_AUDIO_EQ", SGTL5000_DAP_AUDIO_EQ},
|
||||
{"DAP_SURROUND", SGTL5000_DAP_SURROUND},
|
||||
{"DAP_FLT_COEF_ACCESS", SGTL5000_DAP_FLT_COEF_ACCESS},
|
||||
{"DAP_COEF_WR_B0_MSB", SGTL5000_DAP_COEF_WR_B0_MSB},
|
||||
{"DAP_COEF_WR_B0_LSB", SGTL5000_DAP_COEF_WR_B0_LSB},
|
||||
{"DAP_EQ_BASS_BAND0", SGTL5000_DAP_EQ_BASS_BAND0},
|
||||
{"DAP_EQ_BASS_BAND1", SGTL5000_DAP_EQ_BASS_BAND1},
|
||||
{"DAP_EQ_BASS_BAND2", SGTL5000_DAP_EQ_BASS_BAND2},
|
||||
{"DPA_EQ_BASS_BAND3", SGTL5000_DAP_EQ_BASS_BAND3},
|
||||
{"DAP_EQ_BASS_BAND4", SGTL5000_DAP_EQ_BASS_BAND4},
|
||||
{"DAP_MAIN_CHAIN", SGTL5000_DAP_MAIN_CHAN},
|
||||
{"DAP_MIX_CHAN", SGTL5000_DAP_MIX_CHAN},
|
||||
{"DAP_AVC_CTRL", SGTL5000_DAP_AVC_CTRL},
|
||||
{"DAP_AVC_THRESHOLD", SGTL5000_DAP_AVC_THRESHOLD},
|
||||
{"DAP_AVC_ATTACK", SGTL5000_DAP_AVC_ATTACK},
|
||||
{"DAP_AVC_DECAY", SGTL5000_DAP_AVC_DECAY},
|
||||
{"DAP_COEF_WR_B1_MSB", SGTL5000_DAP_COEF_WR_B1_MSB},
|
||||
{"DAP_COEF_WR_B1_LSB", SGTL5000_DAP_COEF_WR_B1_LSB},
|
||||
{"DAP_COEF_WR_B2_MSB", SGTL5000_DAP_COEF_WR_B2_MSB},
|
||||
{"DAP_COEF_WR_B2_LSB", SGTL5000_DAP_COEF_WR_B2_LSB},
|
||||
{"DAP_COEF_WR_A1_MSB", SGTL5000_DAP_COEF_WR_A1_MSB},
|
||||
{"DAP_COEF_WR_A1_LSB", SGTL5000_DAP_COEF_WR_A1_LSB},
|
||||
{"DAP_COEF_WR_A2_MSB", SGTL5000_DAP_COEF_WR_A2_MSB},
|
||||
{"DAP_COEF_WR_A2_LSB", SGTL5000_DAP_COEF_WR_A2_LSB},
|
||||
};
|
||||
|
||||
static unsigned int sgtl5000_hw_read(unsigned int reg)
|
||||
{
|
||||
struct i2c_adapter *adp;
|
||||
u8 buf0[2], buf1[2];
|
||||
u16 value;
|
||||
int ret;
|
||||
struct i2c_msg msg[2] = {
|
||||
{0x0a, 0, 2, buf0},
|
||||
{0x0a, I2C_M_RD, 2, buf1},
|
||||
};
|
||||
|
||||
adp = i2c_get_adapter(1);
|
||||
|
||||
buf0[0] = (reg & 0xff00) >> 8;
|
||||
buf0[1] = reg & 0xff;
|
||||
ret = i2c_transfer(adp, msg, 2);
|
||||
if (ret < 0) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
value = buf1[0] << 8 | buf1[1];
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
static unsigned int sgtl5000_hw_write(unsigned int reg, unsigned int value)
|
||||
{
|
||||
struct i2c_adapter *adp;
|
||||
u8 buf[4];
|
||||
int i2c_ret;
|
||||
struct i2c_msg msg = { 0x0a, 0, 4, buf };
|
||||
|
||||
buf[0] = (reg & 0xff00) >> 8;
|
||||
buf[1] = reg & 0xff;
|
||||
buf[2] = (value & 0xff00) >> 8;
|
||||
buf[3] = value & 0xff;
|
||||
|
||||
adp = i2c_get_adapter(1);
|
||||
i2c_ret = i2c_transfer(adp, &msg, 1);
|
||||
if (i2c_ret < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return i2c_ret;
|
||||
}
|
||||
|
||||
static ssize_t sgtl5000_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
u32 value;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sgtl_tbl); i++) {
|
||||
value = sgtl5000_hw_read(sgtl_tbl[i].reg_addr);
|
||||
if(value < 0)
|
||||
return -ENODEV;
|
||||
printk("%s:[0x%04x]=0x%04x\n", sgtl_tbl[i].name, sgtl_tbl[i].reg_addr, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t sgtl5000_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *end;
|
||||
char *token;
|
||||
char *running;
|
||||
const char delimiters[] = "=";
|
||||
u32 addr, value;
|
||||
|
||||
running = (char *)buf;
|
||||
|
||||
token = strsep(&running, delimiters);
|
||||
addr = simple_strtoul(token, &end, 16);
|
||||
if(addr > SGTL5000_DAP_COEF_WR_A2_LSB) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
token = strsep(&running, delimiters);
|
||||
if(token != NULL) {
|
||||
value = simple_strtoul(token, &end, 16);
|
||||
} else {
|
||||
value = sgtl5000_hw_read(addr);
|
||||
printk("[%d] = 0x%04x\n", addr, value);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sgtl5000_hw_write(addr, value);
|
||||
value = sgtl5000_hw_read(addr);
|
||||
|
||||
printk("[%d] = 0x%04x\n", addr, value);
|
||||
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
static struct kobj_attribute reg_read_attribute =
|
||||
__ATTR(reg_dump, 0666, reg_dump_show, reg_dump_store);
|
||||
static struct kobj_attribute reg_write_attribute =
|
||||
__ATTR(reg_write, 0666, reg_write_show, reg_write_store);
|
||||
static struct kobj_attribute pmic_attribute =
|
||||
__ATTR(pmic, 0666, pmic_show, pmic_store);
|
||||
static struct kobj_attribute edid_attribute =
|
||||
__ATTR(edid, 0666, edid_show, NULL);
|
||||
static struct kobj_attribute battery_attribute =
|
||||
__ATTR(battery, 0666, battery_show, NULL);
|
||||
static struct kobj_attribute mtl017_attribute =
|
||||
__ATTR(mtl017, 0666, mtl017_show, mtl017_store);
|
||||
static struct kobj_attribute sgtl5000_attribute =
|
||||
__ATTR(sgtl5000, 0666, sgtl5000_show, sgtl5000_store);
|
||||
|
||||
static struct attribute *debug_attrs[] = {
|
||||
®_read_attribute.attr,
|
||||
®_write_attribute.attr,
|
||||
&pmic_attribute.attr,
|
||||
&edid_attribute.attr,
|
||||
&battery_attribute.attr,
|
||||
&mtl017_attribute.attr,
|
||||
&sgtl5000_attribute.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group debug_attr_group = {
|
||||
.attrs = debug_attrs,
|
||||
};
|
||||
|
||||
|
||||
static struct platform_device mxc_debug_device = {
|
||||
.name = "mxc_debug",
|
||||
};
|
||||
|
||||
static struct kobject *debug_kobj;
|
||||
|
||||
static int __init mx51_debug_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
platform_device_register(&mxc_debug_device);
|
||||
|
||||
debug_kobj = kobject_create_and_add("debug", &mxc_debug_device.dev.kobj);
|
||||
if(!debug_kobj)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
retval = sysfs_create_group(debug_kobj, &debug_attr_group);
|
||||
if(retval) {
|
||||
kobject_put(debug_kobj);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void __exit mx51_debug_exit(void)
|
||||
{
|
||||
|
||||
sysfs_remove_group(debug_kobj, &debug_attr_group);
|
||||
kobject_put(debug_kobj);
|
||||
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Ron Lee <ron1_lee@pegatroncorp.com>, Pegatron Corp.");
|
||||
module_init(mx51_debug_init)
|
||||
module_exit(mx51_debug_exit)
|
||||
@@ -6,7 +6,7 @@ menu "Broadcom GPS ioctrl support"
|
||||
|
||||
config GPS_IOCTRL
|
||||
tristate "GPS ioctrl support"
|
||||
depends on MACH_MX31_3DS || MACH_MX35_3DS || MACH_MX37_3DS || MACH_MX51_3DS
|
||||
depends on MACH_MX31_3DS || MACH_MX35_3DS || MACH_MX37_3DS || MACH_MX51_3DS || MACH_MX51_EFIKASB
|
||||
---help---
|
||||
Say Y to enable Broadcom GPS ioctrl on MXC platform.
|
||||
|
||||
|
||||
@@ -124,4 +124,12 @@ config MXS_VBUS_CURRENT_DRAW
|
||||
Say Y to enable 100mA limitation when USB vbus power on system
|
||||
before enumeration to match USB2.0 requirement.
|
||||
|
||||
|
||||
config BATTERY_EFIKASB
|
||||
tristate "Efikasb battery driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here to enable support for Efikasb battery.
|
||||
|
||||
|
||||
endif # POWER_SUPPLY
|
||||
|
||||
@@ -30,3 +30,4 @@ obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
|
||||
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
|
||||
obj-$(CONFIG_BATTERY_STMP3XXX) += stmp37xx/
|
||||
obj-$(CONFIG_BATTERY_MXS) += mxs/
|
||||
obj-$(CONFIG_BATTERY_EFIKASB) += efikasb_battery.o
|
||||
855
drivers/power/efikasb_battery.c
Normal file
855
drivers/power/efikasb_battery.c
Normal file
@@ -0,0 +1,855 @@
|
||||
/*
|
||||
* Efikasb Smart Battery driver
|
||||
*
|
||||
* Copyright (C) 2009 Ron Lee <ron1_lee@pegatroncorp.com>
|
||||
*
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#define SBS_MFG_ACCESS 0x00
|
||||
#define SBS_REMAIN_CAPACITY_ALARM 0x01
|
||||
#define SBS_REMNAIN_TIME_ALARM 0x02
|
||||
#define SBS_BATTERY_MODE 0x03
|
||||
#define SBS_AT_RATE 0x04
|
||||
#define SBS_AT_RATE_TIME_TO_FULL 0x05
|
||||
#define SBS_AT_RATE_TIME_TO_EMPTY 0x06
|
||||
#define SBS_AT_RATE_OK 0x07
|
||||
#define SBS_TEMP 0x08
|
||||
#define SBS_VOLTAGE 0x09
|
||||
#define SBS_CURRENT 0x0A
|
||||
#define SBS_AVG_CURRENT 0x0B
|
||||
#define SBS_MAX_ERROR 0x0C
|
||||
#define SBS_REL_STATE_OF_CHARGE 0x0D
|
||||
#define SBS_ABS_STATE_OF_CHARGE 0x0E
|
||||
#define SBS_REMAIN_CAPABILITY 0x0F
|
||||
#define SBS_FULL_CHARGE_CAPACITY 0x10
|
||||
#define SBS_RUN_TIME_TO_EMPTY 0x11
|
||||
#define SBS_AVG_TIME_TO_EMPTY 0x12
|
||||
#define SBS_AVG_TIME_TO_FULL 0x13
|
||||
#define SBS_CHARGE_CURRENT 0x14
|
||||
#define SBS_CHARGE_VOLTAGE 0x15
|
||||
#define SBS_BATTERY_STATUS 0x16
|
||||
#define SBS_CYCLE_COUNT 0x17
|
||||
#define SBS_DESIGN_CAPACITY 0x18
|
||||
#define SBS_DESIGN_VOLTAGE 0x19
|
||||
#define SBS_SPEC_INFO 0x1A
|
||||
#define SBS_MFG_DATE 0x1B
|
||||
#define SBS_SERIAL_NO 0x1C
|
||||
#define SBS_MFG_NAME 0x20
|
||||
#define SBS_DEV_NAME 0x21
|
||||
#define SBS_DEV_CHEMISTRY 0x22
|
||||
#define SBS_MFG_DATA 0x23
|
||||
#define SBS_BATTERY_USAGE 0x30
|
||||
#define SBS_PERMANENT_FAILURE 0x31
|
||||
#define SBS_BATTERY_LOG1 0x32
|
||||
#define SBS_BATTERY_LOG2 0x33
|
||||
#define SBS_FET_TEMP 0x3B
|
||||
#define SBS_OPTION_MFG_FUNC5 0x2F
|
||||
#define SBS_OPTION_MFG_FUNC4 0x3C
|
||||
#define SBS_OPTION_MFG_FUNC3 0x3D
|
||||
#define SBS_OPTION_MFG_FUNC2 0x3E
|
||||
#define SBS_OPTION_MFG_FUNC1 0x3F
|
||||
|
||||
/* SBS_BATTERY_STATUS Register Bit Mapping */
|
||||
#define SBS_STATUS_OVER_CHARGE_ALARM 0x8000
|
||||
#define SBS_STATUS_TERM_CHARGE_ALARM 0x4000
|
||||
#define SBS_STATUS_OVER_TEMP_ALARM 0x1000
|
||||
#define SBS_STATUS_TERM_DISCHARGE_ALARM 0x0800
|
||||
#define SBS_STATUS_REMAIN_CAPACITY_ALARM 0x0200
|
||||
#define SBS_STATUS_REMAIN_TIME_ALARM 0x0100
|
||||
|
||||
#define SBS_STATUS_INITIALIZED 0x0080
|
||||
#define SBS_STATUS_DISCHARGING 0x0040
|
||||
#define SBS_STATUS_FULLY_CHARGED 0x0020
|
||||
#define SBS_STATUS_FULLY_DISCHARGED 0x0010
|
||||
|
||||
static void update_status_worker(struct work_struct *work);
|
||||
static DECLARE_DELAYED_WORK(update_status_work, update_status_worker);
|
||||
|
||||
static void batt_capacity_worker(struct work_struct *work);
|
||||
static DECLARE_WORK(batt_capacity_work, batt_capacity_worker);
|
||||
|
||||
static void power_off_worker(struct work_struct *work);
|
||||
static DECLARE_DELAYED_WORK(power_off_work, power_off_worker);
|
||||
|
||||
extern void kernel_power_off(void);
|
||||
|
||||
struct sbs_reg_tbl {
|
||||
char *name;
|
||||
unsigned char reg_offset;
|
||||
};
|
||||
|
||||
#ifdef EFIKASB_BATTERY_DEBUG
|
||||
static struct sbs_reg_tbl reg_tbl[] = {
|
||||
{"Manufacture Access", SBS_MFG_ACCESS},
|
||||
{"Remain Capacity Alarm", SBS_REMAIN_CAPACITY_ALARM },
|
||||
{"Remain Time Alarm", SBS_REMNAIN_TIME_ALARM},
|
||||
{"Battery Mode", SBS_BATTERY_MODE},
|
||||
{"AT Rate", SBS_AT_RATE},
|
||||
{"AT Rate Time To Full", SBS_AT_RATE_TIME_TO_FULL},
|
||||
{"AT Rate Time To Empty", SBS_AT_RATE_TIME_TO_EMPTY},
|
||||
{"AT Rate OK", SBS_AT_RATE_OK},
|
||||
{"Temperature", SBS_TEMP},
|
||||
{"Voltage", SBS_VOLTAGE},
|
||||
{"Current", SBS_CURRENT},
|
||||
{"Average Current", SBS_AVG_CURRENT},
|
||||
{"Maximum Error", SBS_MAX_ERROR},
|
||||
{"Relative State of Charge", SBS_REL_STATE_OF_CHARGE},
|
||||
{"Absolute State of Charge", SBS_ABS_STATE_OF_CHARGE},
|
||||
{"Remain Capacity", SBS_REMAIN_CAPABILITY},
|
||||
{"Full Charge Capacity", SBS_FULL_CHARGE_CAPACITY},
|
||||
{"Run Time To Empty", SBS_RUN_TIME_TO_EMPTY},
|
||||
{"Average Time To Empty", SBS_AVG_TIME_TO_EMPTY},
|
||||
{"Average Time To Full", SBS_AVG_TIME_TO_FULL},
|
||||
{"Charge Current", SBS_CHARGE_CURRENT},
|
||||
{"Charge Voltage", SBS_CHARGE_VOLTAGE},
|
||||
{"Battery Status", SBS_BATTERY_STATUS},
|
||||
{"Cycle Count", SBS_CYCLE_COUNT},
|
||||
{"Design Capacity", SBS_DESIGN_CAPACITY},
|
||||
{"Design Voltage", SBS_DESIGN_VOLTAGE},
|
||||
{"Spec Info", SBS_SPEC_INFO},
|
||||
{"Manufacture Date", SBS_MFG_DATE},
|
||||
{"Serial Number", SBS_SERIAL_NO},
|
||||
{"Manufacture Name", SBS_MFG_NAME},
|
||||
{"Device Name", SBS_DEV_NAME},
|
||||
{"Device Chemistry", SBS_DEV_CHEMISTRY},
|
||||
{"Manufacture Date", SBS_MFG_DATA},
|
||||
{"Battery Usage", SBS_BATTERY_USAGE},
|
||||
{"Permanent Failure", SBS_PERMANENT_FAILURE},
|
||||
{"Battery Log1", SBS_BATTERY_LOG1},
|
||||
{"Battery Log2", SBS_BATTERY_LOG2},
|
||||
{"FET Temperature", SBS_FET_TEMP},
|
||||
{"Optional Mfg Func5", SBS_OPTION_MFG_FUNC5},
|
||||
{"Optional Mfg Func4", SBS_OPTION_MFG_FUNC4},
|
||||
{"Optional Mfg Func3", SBS_OPTION_MFG_FUNC3},
|
||||
{"Optional Mfg Func2", SBS_OPTION_MFG_FUNC2},
|
||||
{"Optional Mfg Func1", SBS_OPTION_MFG_FUNC1},
|
||||
|
||||
};
|
||||
|
||||
void dump_sbs_reg(struct i2c_client *client)
|
||||
{
|
||||
int i;
|
||||
unsigned int value;
|
||||
|
||||
printk("Dump Smart Battery Register\n");
|
||||
for (i = 0; i < ARRAY_SIZE(reg_tbl); i ++) {
|
||||
value = i2c_smbus_read_word_data(client, reg_tbl[i].reg_offset);
|
||||
printk("%s: 0x%04x\n", reg_tbl[i].name, value);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void dump_sbs_reg(struct i2c_client *client) {}
|
||||
#endif
|
||||
|
||||
struct efikasb_batt_dev_info;
|
||||
|
||||
struct efikasb_batt_dev_info {
|
||||
struct device *dev;
|
||||
struct i2c_client *client;
|
||||
struct power_supply *bat;
|
||||
struct power_supply *ac_charger;
|
||||
char mfg_name[32];
|
||||
char model_name[32];
|
||||
char serial[32];
|
||||
char chemistry[32];
|
||||
|
||||
int batt_in_irq;
|
||||
int batt_low_irq;
|
||||
int ac_in_irq;
|
||||
|
||||
int batt_in;
|
||||
int ac_in;
|
||||
int batt_low;
|
||||
u32 capacity;
|
||||
|
||||
int (*get_batt_in_status) (void);
|
||||
int (*get_batt_low_status) (void);
|
||||
int (*get_ac_in_status) (void);
|
||||
void (*set_batt_low_led) (int);
|
||||
|
||||
struct timer_list batt_low_timer;
|
||||
};
|
||||
|
||||
static struct efikasb_batt_dev_info *batt = NULL;
|
||||
|
||||
static enum power_supply_property efikasb_batt_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
/* POWER_SUPPLY_PROP_HEALTH, */
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_AVG,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
|
||||
POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
|
||||
POWER_SUPPLY_PROP_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
POWER_SUPPLY_PROP_SERIAL_NUMBER,
|
||||
|
||||
};
|
||||
|
||||
static enum power_supply_property efikasb_ac_charger_props[] = {
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
};
|
||||
|
||||
static int efikasb_batt_read(struct i2c_client *client, u8 reg, u32 *value)
|
||||
{
|
||||
int ret;
|
||||
int retry = 5;
|
||||
|
||||
retry:
|
||||
ret = i2c_smbus_read_word_data(client, reg);
|
||||
if(ret < 0) { /* ron: retry i2c again to avoid conflict with PIC */
|
||||
if(retry -- > 0)
|
||||
goto retry;
|
||||
return ret;
|
||||
}
|
||||
|
||||
*value = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Smart Battery Helper Function */
|
||||
static int efikasb_batt_get_status(struct efikasb_batt_dev_info *di, u32 *value)
|
||||
{
|
||||
return efikasb_batt_read(di->client, SBS_BATTERY_STATUS, value);
|
||||
}
|
||||
|
||||
static int efikasb_batt_get_current(struct efikasb_batt_dev_info *di, u32 *value)
|
||||
{
|
||||
return efikasb_batt_read(di->client, SBS_CURRENT, value);
|
||||
}
|
||||
|
||||
static int efikasb_batt_get_voltage(struct efikasb_batt_dev_info *di, u32 *value)
|
||||
{
|
||||
return efikasb_batt_read(di->client, SBS_VOLTAGE, value);
|
||||
}
|
||||
|
||||
static int efikasb_batt_get_average_current(struct efikasb_batt_dev_info *di, u32 *value)
|
||||
{
|
||||
return efikasb_batt_read(di->client, SBS_AVG_CURRENT, value);
|
||||
}
|
||||
|
||||
static int efikasb_batt_get_capacity(struct efikasb_batt_dev_info *di, u32 *value)
|
||||
{
|
||||
return efikasb_batt_read(di->client, SBS_REL_STATE_OF_CHARGE, value);
|
||||
}
|
||||
|
||||
static int efikasb_batt_get_temperature(struct efikasb_batt_dev_info *di, u32 *value)
|
||||
{
|
||||
return efikasb_batt_read(di->client, SBS_TEMP, value);
|
||||
}
|
||||
|
||||
static int efikasb_batt_run_time_to_empty(struct efikasb_batt_dev_info *di, u32 *value)
|
||||
{
|
||||
return efikasb_batt_read(di->client, SBS_RUN_TIME_TO_EMPTY, value);
|
||||
}
|
||||
|
||||
static int efikasb_batt_avg_time_to_empty(struct efikasb_batt_dev_info *di, u32 *value)
|
||||
{
|
||||
return efikasb_batt_read(di->client, SBS_AVG_TIME_TO_EMPTY, value);
|
||||
}
|
||||
|
||||
static int efikasb_batt_avg_time_to_full(struct efikasb_batt_dev_info *di, u32 *value)
|
||||
{
|
||||
return efikasb_batt_read(di->client, SBS_AVG_TIME_TO_FULL, value);
|
||||
}
|
||||
|
||||
static int efikasb_batt_get_serial_no(struct efikasb_batt_dev_info *di)
|
||||
{
|
||||
int ret;
|
||||
u32 sn;
|
||||
|
||||
ret = efikasb_batt_read(di->client, SBS_SERIAL_NO, &sn);
|
||||
if(ret != 0)
|
||||
return ret;
|
||||
|
||||
sprintf(di->serial, "%d", sn);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int efikasb_batt_get_mfg_name(struct efikasb_batt_dev_info *di)
|
||||
{
|
||||
int ret;
|
||||
char mfg[33];
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(di->client, SBS_MFG_NAME, 32, mfg);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
||||
if(mfg[0] > sizeof(di->mfg_name))
|
||||
return -EINVAL;
|
||||
|
||||
strncpy(di->mfg_name, &mfg[1], mfg[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efikasb_batt_get_model_name(struct efikasb_batt_dev_info *di)
|
||||
{
|
||||
int ret;
|
||||
char model[33];
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(di->client, SBS_DEV_NAME, 32, model);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
||||
if(model[0] > sizeof(di->model_name))
|
||||
return -EINVAL;
|
||||
|
||||
strncpy(di->model_name, &model[1], model[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efikasb_batt_get_technology(struct efikasb_batt_dev_info *di)
|
||||
{
|
||||
int ret;
|
||||
char chem[33];
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(di->client, SBS_DEV_CHEMISTRY, 32, chem);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
||||
if(chem[0] > sizeof(di->chemistry))
|
||||
return -EINVAL;
|
||||
|
||||
strncpy(di->chemistry, &chem[1], chem[0]);
|
||||
/* printk("Technology: %s\n", di->chemistry); */
|
||||
|
||||
if (!strcasecmp("NiCd", di->chemistry))
|
||||
return POWER_SUPPLY_TECHNOLOGY_NiCd;
|
||||
if (!strcasecmp("NiMH", di->chemistry))
|
||||
return POWER_SUPPLY_TECHNOLOGY_NiMH;
|
||||
if (!strcasecmp("LION", di->chemistry))
|
||||
return POWER_SUPPLY_TECHNOLOGY_LION;
|
||||
if (!strncasecmp("LI-ION", di->chemistry, 6))
|
||||
return POWER_SUPPLY_TECHNOLOGY_LION;
|
||||
if (!strcasecmp("LiP", di->chemistry))
|
||||
return POWER_SUPPLY_TECHNOLOGY_LIPO;
|
||||
return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
|
||||
|
||||
}
|
||||
|
||||
#define to_efikasb_batt_device_info(x) container_of((x), \
|
||||
struct efikasb_batt_dev_info, bat);
|
||||
|
||||
static int efikasb_batt_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct efikasb_batt_dev_info *di = batt;
|
||||
u32 value;
|
||||
int ret;
|
||||
int batt_in, ac_in;
|
||||
|
||||
batt_in = di->get_batt_in_status();
|
||||
|
||||
if (!batt_in) {
|
||||
val->intval = 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ac_in = di->get_ac_in_status();
|
||||
|
||||
switch(psp) {
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
val->intval = di->get_batt_in_status();
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
if (ac_in) {
|
||||
ret = efikasb_batt_get_status(di, &value);
|
||||
if (ret != 0) {
|
||||
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (value & SBS_STATUS_FULLY_CHARGED)
|
||||
val->intval = POWER_SUPPLY_STATUS_FULL;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
} else {
|
||||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_TECHNOLOGY:
|
||||
val->intval = efikasb_batt_get_technology(di);
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW: /* mV */
|
||||
ret = efikasb_batt_get_voltage(di, &value);
|
||||
if(ret != 0) {
|
||||
val->intval = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
val->intval = value;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW: /* mA */
|
||||
ret = efikasb_batt_get_current(di, &value);
|
||||
if(ret != 0) {
|
||||
val->intval = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
val->intval = value;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_CURRENT_AVG: /* mA in 1 minute rolling avg */
|
||||
ret = efikasb_batt_get_average_current(di, &value);
|
||||
if(ret != 0)
|
||||
return ret;
|
||||
val->intval = value;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_CAPACITY: /* % percent */
|
||||
ret = efikasb_batt_get_capacity(di, &value);
|
||||
if(ret != 0)
|
||||
return ret;
|
||||
val->intval = value;
|
||||
di->capacity = value; /* ron: cache the battery capacity */
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_TEMP: /* K degree */
|
||||
ret = efikasb_batt_get_temperature(di, &value);
|
||||
if(ret != 0)
|
||||
return ret;
|
||||
val->intval = value;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: /* minutes */
|
||||
ret = efikasb_batt_run_time_to_empty(di, &value);
|
||||
if(ret != 0)
|
||||
return ret;
|
||||
val->intval = value;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: /* minutes */
|
||||
ret = efikasb_batt_avg_time_to_empty(di, &value);
|
||||
if(ret != 0)
|
||||
return ret;
|
||||
val->intval = value;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: /* minutes */
|
||||
ret = efikasb_batt_avg_time_to_full(di, &value);
|
||||
if(ret != 0)
|
||||
return ret;
|
||||
val->intval = value;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_MODEL_NAME:
|
||||
ret = efikasb_batt_get_model_name(di);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
val->strval = di->model_name;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_MANUFACTURER:
|
||||
ret = efikasb_batt_get_mfg_name(di);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
val->strval = di->mfg_name;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_SERIAL_NUMBER:
|
||||
ret = efikasb_batt_get_serial_no(di);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
val->strval = di->serial;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efikasb_ac_charger_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct efikasb_batt_dev_info *di = batt;
|
||||
|
||||
switch(psp) {
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval = di->get_ac_in_status();
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct power_supply efikasb_batt = {
|
||||
.name = "efikasb_battery",
|
||||
.type = POWER_SUPPLY_TYPE_BATTERY,
|
||||
.properties = efikasb_batt_props,
|
||||
.num_properties = ARRAY_SIZE(efikasb_batt_props),
|
||||
.get_property = efikasb_batt_get_property,
|
||||
.external_power_changed = NULL,
|
||||
|
||||
};
|
||||
|
||||
static struct power_supply efikasb_ac_charger = {
|
||||
.name = "efikasb_ac_charger",
|
||||
.type = POWER_SUPPLY_TYPE_MAINS,
|
||||
.properties = efikasb_ac_charger_props,
|
||||
.num_properties = ARRAY_SIZE(efikasb_ac_charger_props),
|
||||
.get_property = efikasb_ac_charger_get_property,
|
||||
.external_power_changed = NULL,
|
||||
};
|
||||
|
||||
static void update_status_worker(struct work_struct *work)
|
||||
{
|
||||
power_supply_changed(batt->ac_charger);
|
||||
power_supply_changed(batt->bat);
|
||||
}
|
||||
|
||||
|
||||
static irqreturn_t efikasb_ac_detect_handler(int irq, void *data)
|
||||
{
|
||||
struct efikasb_batt_dev_info *di = data;
|
||||
|
||||
di->ac_in = di->get_ac_in_status();
|
||||
printk("efikasb_ac_charger: AC %s\n",
|
||||
di->ac_in ? "Inserted" : "Removed");
|
||||
|
||||
schedule_delayed_work(&update_status_work, msecs_to_jiffies(1500));
|
||||
|
||||
if (di->ac_in) {
|
||||
if(di->set_batt_low_led)
|
||||
di->set_batt_low_led(0);
|
||||
set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
|
||||
mod_timer(&di->batt_low_timer, jiffies + 10);
|
||||
} else {
|
||||
mod_timer(&di->batt_low_timer, jiffies + 10);
|
||||
set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t efikasb_batt_detect_handler(int irq, void *data)
|
||||
{
|
||||
struct efikasb_batt_dev_info *di = data;
|
||||
|
||||
di->batt_in = di->get_batt_in_status();
|
||||
printk("efikasb_battery: Battery %s\n",
|
||||
di->batt_in ? "Inserted" : "Removed");
|
||||
|
||||
schedule_delayed_work(&update_status_work, msecs_to_jiffies(1500));
|
||||
|
||||
if (di->batt_in) {
|
||||
mod_timer(&di->batt_low_timer, jiffies + 10);
|
||||
set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
|
||||
} else {
|
||||
if(di->set_batt_low_led)
|
||||
di->set_batt_low_led(0);
|
||||
set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void power_off_worker(struct work_struct *work)
|
||||
{
|
||||
if(!batt->ac_in && batt->batt_low && batt->capacity == 0) {
|
||||
sys_sync();
|
||||
kernel_power_off();
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t efikasb_batt_low_handler(int irq, void *data)
|
||||
{
|
||||
struct efikasb_batt_dev_info *di = data;
|
||||
|
||||
di->batt_low = batt->get_batt_low_status();
|
||||
printk("efikasb_batter: Battery %s\n",
|
||||
di->batt_low ? "Low" : "Normal");
|
||||
|
||||
if (di->batt_low) {
|
||||
set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
|
||||
} else {
|
||||
set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void batt_capacity_worker(struct work_struct *work)
|
||||
{
|
||||
int ret;
|
||||
u32 capacity;
|
||||
|
||||
if(batt->batt_in) {
|
||||
ret = efikasb_batt_get_capacity(batt, &capacity);
|
||||
if(ret == 0)
|
||||
batt->capacity = capacity;
|
||||
|
||||
if(!batt->ac_in && batt->capacity == 0) {
|
||||
sys_sync();
|
||||
kernel_power_off();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void batt_low_fn(unsigned long data)
|
||||
{
|
||||
struct efikasb_batt_dev_info *di = (struct efikasb_batt_dev_info *)data;
|
||||
|
||||
if(!di->batt_in)
|
||||
return;
|
||||
|
||||
if(!di->ac_in && di->batt_in) { /* battery is discharging */
|
||||
schedule_work(&batt_capacity_work);
|
||||
if(di->set_batt_low_led) {
|
||||
if(di->capacity <= 10)
|
||||
di->set_batt_low_led(1);
|
||||
else
|
||||
di->set_batt_low_led(0);
|
||||
|
||||
if(di->capacity <= 11 && di->capacity > 9) {
|
||||
mod_timer(&di->batt_low_timer, jiffies + 4 * HZ);
|
||||
}
|
||||
|
||||
if(di->capacity <= 9 || di->capacity > 11) {
|
||||
mod_timer(&di->batt_low_timer, jiffies + 60 * HZ);
|
||||
}
|
||||
} else {
|
||||
mod_timer(&di->batt_low_timer, jiffies + 60 * HZ);
|
||||
}
|
||||
} else if(di->batt_in) { /* battery is charging */
|
||||
mod_timer(&di->batt_low_timer, jiffies + 60 * HZ);
|
||||
}
|
||||
|
||||
/* battery is not charging and capacity is critical low, power off immediately */
|
||||
if(!di->ac_in && di->batt_in && di->capacity == 0)
|
||||
schedule_delayed_work(&power_off_work, msecs_to_jiffies(1000));
|
||||
|
||||
}
|
||||
|
||||
static int efikasb_batt_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct efikasb_batt_dev_info *di;
|
||||
struct mxc_battery_platform_data *platform_data;
|
||||
int retval = 0;
|
||||
|
||||
platform_data = (struct mxc_battery_platform_data *)client->dev.platform_data;
|
||||
|
||||
di = kzalloc(sizeof(*di), GFP_KERNEL);
|
||||
if(!di) {
|
||||
dev_err(&client->dev, "failed to allocate device info\n");
|
||||
retval = -ENOMEM;
|
||||
return retval;
|
||||
}
|
||||
|
||||
batt = di;
|
||||
|
||||
i2c_set_clientdata(client, di);
|
||||
di->dev = &client->dev;
|
||||
di->client = client;
|
||||
di->bat = &efikasb_batt;
|
||||
di->ac_charger = &efikasb_ac_charger;
|
||||
|
||||
di->get_batt_in_status = platform_data->get_batt_in_status;
|
||||
di->get_batt_low_status = platform_data->get_batt_low_status;
|
||||
di->get_ac_in_status = platform_data->get_ac_in_status;
|
||||
di->set_batt_low_led = platform_data->set_batt_low_led;
|
||||
|
||||
if(di->get_batt_in_status)
|
||||
di->batt_in = di->get_batt_in_status();
|
||||
if(di->get_ac_in_status)
|
||||
di->ac_in = di->get_ac_in_status();
|
||||
if(di->get_batt_low_status)
|
||||
di->batt_low = di->get_batt_low_status();
|
||||
|
||||
di->batt_in_irq = platform_data->batt_in_irq;
|
||||
di->batt_low_irq = platform_data->batt_low_irq;
|
||||
di->ac_in_irq = platform_data->ac_in_irq;
|
||||
|
||||
#ifndef CONFIG_EFIKASB_EXPERIMENTAL_OS
|
||||
if(di->batt_in) {
|
||||
retval = request_irq(di->batt_in_irq,
|
||||
efikasb_batt_detect_handler, \
|
||||
IRQ_TYPE_EDGE_RISING,
|
||||
"efikasb_battery", di);
|
||||
} else {
|
||||
retval = request_irq(di->batt_in_irq,
|
||||
efikasb_batt_detect_handler,
|
||||
IRQ_TYPE_EDGE_FALLING,
|
||||
"efikasb_battery", di);
|
||||
}
|
||||
if(retval)
|
||||
goto batt_irq_failed;
|
||||
|
||||
if(di->ac_in) {
|
||||
retval = request_irq(di->ac_in_irq,
|
||||
efikasb_ac_detect_handler,
|
||||
IRQ_TYPE_EDGE_RISING,
|
||||
"efikasb_ac_charger", di);
|
||||
} else {
|
||||
retval = request_irq(di->ac_in_irq,
|
||||
efikasb_ac_detect_handler,
|
||||
IRQ_TYPE_EDGE_FALLING,
|
||||
"efikasb_ac_charger", di);
|
||||
}
|
||||
if(retval)
|
||||
goto ac_irq_failed;
|
||||
|
||||
if(di->batt_low) {
|
||||
retval = request_irq(di->batt_low_irq,
|
||||
efikasb_batt_low_handler,
|
||||
IRQ_TYPE_LEVEL_HIGH, "efikasb_batt_low", di);
|
||||
} else {
|
||||
retval = request_irq(di->batt_low_irq,
|
||||
efikasb_batt_low_handler,
|
||||
IRQ_TYPE_LEVEL_LOW, "efikasb_batt_low", di);
|
||||
}
|
||||
if(retval)
|
||||
goto batt_low_irq_failed;
|
||||
|
||||
/* ron: the battery low pin is triggered at 10% battery capacity,
|
||||
battery critical low won't generate wake up event,
|
||||
the battery power may be exhauseted */
|
||||
/* enable_irq_wake(di->batt_low_irq); */
|
||||
#endif
|
||||
|
||||
retval = power_supply_register(&client->dev, &efikasb_batt);
|
||||
if(retval) {
|
||||
dev_err(&client->dev, "failed to register battery\n");
|
||||
goto batt_failed;
|
||||
}
|
||||
|
||||
retval =power_supply_register(&client->dev, &efikasb_ac_charger);
|
||||
if(retval) {
|
||||
dev_err(&client->dev, "failed to register ac charger\n");
|
||||
goto ac_charger_failed;
|
||||
}
|
||||
if(di->batt_in) {
|
||||
efikasb_batt_get_mfg_name(di);
|
||||
efikasb_batt_get_model_name(di);
|
||||
efikasb_batt_get_capacity(di, &di->capacity);
|
||||
}
|
||||
|
||||
|
||||
printk("Probe Efikasb Battery: %s %s %s: %d%%, AC %s\n",
|
||||
di->mfg_name, di->model_name,
|
||||
di->batt_in ? "Inserted" : "Removed", di->capacity,
|
||||
di->ac_in ? "Inserted" : "Removed");
|
||||
|
||||
dump_sbs_reg(client);
|
||||
|
||||
init_timer(&di->batt_low_timer);
|
||||
di->batt_low_timer.data = (unsigned long)di;
|
||||
di->batt_low_timer.function = batt_low_fn;
|
||||
di->batt_low_timer.expires = jiffies + 10;
|
||||
if(!di->ac_in && di->batt_in)
|
||||
add_timer(&di->batt_low_timer);
|
||||
|
||||
/* ron: if battery critical low, shutdown immediately */
|
||||
if(!di->ac_in && di->batt_low && di->capacity == 0) {
|
||||
printk("Battery critical low, shutdown now....\n");
|
||||
schedule_delayed_work(&power_off_work, msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
ac_charger_failed:
|
||||
power_supply_unregister(&efikasb_batt);
|
||||
batt_failed:
|
||||
free_irq(di->batt_low_irq, NULL);
|
||||
batt_low_irq_failed:
|
||||
free_irq(di->ac_in_irq, NULL);
|
||||
ac_irq_failed:
|
||||
free_irq(di->batt_in_irq, NULL);
|
||||
batt_irq_failed:
|
||||
i2c_set_clientdata(client, NULL);
|
||||
kfree(di);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int efikasb_batt_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct efikasb_batt_dev_info *di = i2c_get_clientdata(client);
|
||||
|
||||
power_supply_unregister(&efikasb_batt);
|
||||
power_supply_unregister(&efikasb_ac_charger);
|
||||
free_irq(di->batt_in_irq, NULL);
|
||||
free_irq(di->ac_in_irq, NULL);
|
||||
kfree(di);
|
||||
batt = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id efikasb_batt_id[] = {
|
||||
{ "efikasb-battery", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, efikasb_batt_id);
|
||||
|
||||
static struct i2c_driver efikasb_batt_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "efikasb-battery",
|
||||
},
|
||||
.probe = efikasb_batt_i2c_probe,
|
||||
.remove = efikasb_batt_i2c_remove,
|
||||
.id_table = efikasb_batt_id,
|
||||
};
|
||||
|
||||
static int __init efikasb_batt_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_add_driver(&efikasb_batt_i2c_driver);
|
||||
if(ret)
|
||||
printk(KERN_ERR "Unable to register Efikasb Battery Driver\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(efikasb_batt_init);
|
||||
|
||||
static void __exit efikasb_batt_exit(void)
|
||||
{
|
||||
i2c_del_driver(&efikasb_batt_i2c_driver);
|
||||
|
||||
}
|
||||
module_exit(efikasb_batt_exit);
|
||||
|
||||
MODULE_AUTHOR("Ron Lee <ron1_lee@pegatroncorp.com>");
|
||||
MODULE_DESCRIPTION("Efikasb Smart Battery Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
@@ -258,6 +258,12 @@ config BACKLIGHT_MXC_MC13892
|
||||
depends on BACKLIGHT_MXC && MXC_MC13892_LIGHT
|
||||
default y
|
||||
|
||||
|
||||
config BACKLIGHT_MXC_EFIKASB
|
||||
tristate "MXC Efikasb LCD Backlight Driver"
|
||||
depends on BACKLIGHT_MXC
|
||||
default y
|
||||
|
||||
config BACKLIGHT_STMP37XX
|
||||
tristate "SigmaTel STMP37xx Backlight Driver"
|
||||
depends on BACKLIGHT_CLASS_DEVICE && (ARCH_STMP37XX || ARCH_STMP378X)
|
||||
|
||||
@@ -30,5 +30,6 @@ obj-$(CONFIG_BACKLIGHT_MXC_IPU) += mxc_ipu_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_MXC_PMIC) += mxc_pmic_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_WM8350) += wm8350_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_MXC_MC13892) += mxc_mc13892_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_MXC_EFIKASB) += mxc_efikasb_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_STMP37XX) += stmp37xx_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_MXS) += mxs_bl.o
|
||||
|
||||
332
drivers/video/backlight/mxc_efikasb_bl.c
Normal file
332
drivers/video/backlight/mxc_efikasb_bl.c
Normal file
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Copyright 2007 Pegatron Corp, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
/*!
|
||||
* @defgroup LCDC_BL MXC LCDC Backlight Driver
|
||||
*/
|
||||
/*!
|
||||
* @file mxc_efikasb_bl.c
|
||||
*
|
||||
* @brief Backlight Driver for LCDC PWM on Freescale MXC/i.MX Efikasb platforms.
|
||||
*
|
||||
* This file contains API defined in include/linux/clk.h for setting up and
|
||||
* retrieving clocks.
|
||||
*
|
||||
* Based on Sharp's Corgi Backlight Driver
|
||||
*
|
||||
* @ingroup LCDC_BL
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/clk.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#define MXC_MAX_BL_LEVEL 11
|
||||
#define MXC_MIN_BL_LEVEL 0
|
||||
#define MXC_DFL_BL_LEVEL 6
|
||||
|
||||
#define MXC_MAX_INTENSITY 255
|
||||
#define MXC_DEFAULT_INTENSITY 127
|
||||
#define MXC_INTENSITY_OFF 0
|
||||
#define MXC_PWM_PERIOD_NS 78770
|
||||
|
||||
#define MXC_PWMCR (0x00)
|
||||
#define MXC_PWMSR (0x04)
|
||||
#define MXC_PWMIR (0x08)
|
||||
#define MXC_PWMSAR (0x0C)
|
||||
#define MXC_PWMPR (0x10)
|
||||
#define MXC_PWMCNR (0x14)
|
||||
|
||||
#define MXC_PWMCR_EN (1)
|
||||
#define MXC_PWMCR_PRESCALER_MASK (0xFFFF000F)
|
||||
#define MXC_PWMCR_PRESCALER_OFFSET (4)
|
||||
#define MXC_PWMCR_CLKSRC_OFF (0)
|
||||
#define MXC_PWMCR_CLKSRC_IPG (1 << 16)
|
||||
#define MXC_PWMCR_CLKSRC_IPG_HIGH (2 << 16)
|
||||
#define MXC_PWMCR_CLKSRC_32K (3 << 16)
|
||||
#define MXC_PWMCR_STOPEN (1 << 25)
|
||||
#define MXC_PWMCR_DOZEEN (1 << 24)
|
||||
#define MXC_PWMCR_WAITEN (1 << 23)
|
||||
#define MXC_PWMCR_DBGEN (1 << 22)
|
||||
|
||||
#define MXC_PWMSAR_SAMPLE_MASK (0xFFFF0000)
|
||||
#define MXC_PWMPR_PERIOD_MASK (0xFFFF0000)
|
||||
|
||||
#define MXC_PWMCR_PRESCALER(x) (((x - 1) & 0xFFF) << 4)
|
||||
|
||||
int bl_level_to_pwm_map[MXC_MAX_BL_LEVEL] = {
|
||||
0, 4, 25, 63, 75, 101, 127, 153, 179, 205, 231, 255,
|
||||
};
|
||||
|
||||
static BLOCKING_NOTIFIER_HEAD(backlight_notifier_list);
|
||||
|
||||
int register_backlight_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_register(&backlight_notifier_list, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_backlight_notifier);
|
||||
|
||||
int unregister_backlight_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_unregister(&backlight_notifier_list, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_backlight_notifier);
|
||||
|
||||
struct mxcbl_dev_data {
|
||||
void *base;
|
||||
struct clk *clk;
|
||||
int clk_enabled;
|
||||
int intensity;
|
||||
int suspend;
|
||||
};
|
||||
|
||||
static int mxc_pwm_enable(struct mxcbl_dev_data *mxc_bl)
|
||||
{
|
||||
unsigned long reg;
|
||||
int rc = 0;
|
||||
|
||||
if (!mxc_bl->clk_enabled) {
|
||||
rc = clk_enable(mxc_bl->clk);
|
||||
if (!rc)
|
||||
mxc_bl->clk_enabled = 1;
|
||||
}
|
||||
|
||||
reg = __raw_readl(mxc_bl->base + MXC_PWMCR);
|
||||
reg |= MXC_PWMCR_EN;
|
||||
__raw_writel(reg, mxc_bl->base + MXC_PWMCR);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void mxc_pwm_disable(struct mxcbl_dev_data *mxc_bl)
|
||||
{
|
||||
unsigned long reg;
|
||||
|
||||
if (mxc_bl->clk_enabled) {
|
||||
clk_disable(mxc_bl->clk);
|
||||
mxc_bl->clk_enabled = 0;
|
||||
}
|
||||
|
||||
reg = __raw_readl(mxc_bl->base + MXC_PWMCR);
|
||||
reg &= ~MXC_PWMCR_EN;
|
||||
__raw_writel(reg, mxc_bl->base + MXC_PWMCR);
|
||||
|
||||
}
|
||||
|
||||
void mxc_set_brightness(struct mxcbl_dev_data *mxc_bl, uint8_t level)
|
||||
{
|
||||
unsigned long long c;
|
||||
unsigned long period_cycles, duty_cycles, prescale;
|
||||
int duty_ns, period_ns;
|
||||
|
||||
//printk("mxc_set_brightness: level=%x\n", level);
|
||||
|
||||
#if 0
|
||||
period_ns = MXC_PWM_PERIOD_NS;
|
||||
duty_ns = level * period_ns / MXC_MAX_INTENSITY;
|
||||
|
||||
c = clk_get_rate(mxc_bl->clk) * 665 / 80;
|
||||
c = c * period_ns;
|
||||
do_div(c, 1000000000);
|
||||
period_cycles = c;
|
||||
|
||||
prescale = period_cycles / 0x10000 + 1;
|
||||
|
||||
period_cycles /= prescale;
|
||||
c = (unsigned long long)period_cycles * duty_ns;
|
||||
do_div(c, period_ns);
|
||||
duty_cycles = c;
|
||||
#else
|
||||
/* ron: hard code the PWM configuration */
|
||||
prescale = 300;
|
||||
period_cycles = 0x03f1;
|
||||
duty_cycles = bl_level_to_pwm_map[level] * period_cycles / MXC_MAX_INTENSITY;
|
||||
#endif
|
||||
//printk("duty_cycles %d, period_cycles %d\n", duty_cycles, period_cycles);
|
||||
__raw_writel(duty_cycles, mxc_bl->base + MXC_PWMSAR);
|
||||
__raw_writel(period_cycles, mxc_bl->base + MXC_PWMPR);
|
||||
__raw_writel(MXC_PWMCR_PRESCALER(prescale) |
|
||||
MXC_PWMCR_CLKSRC_IPG |
|
||||
MXC_PWMCR_STOPEN | MXC_PWMCR_DOZEEN |
|
||||
MXC_PWMCR_WAITEN | MXC_PWMCR_DBGEN | MXC_PWMCR_EN,
|
||||
mxc_bl->base + MXC_PWMCR);
|
||||
}
|
||||
|
||||
#define BL_BRIGHTNESS 0x01
|
||||
|
||||
static int mxcbl_set_brightness(struct backlight_device *bd)
|
||||
{
|
||||
int level = bd->props.brightness;
|
||||
struct mxcbl_dev_data *devdata = dev_get_drvdata(&bd->dev);
|
||||
|
||||
if (level > MXC_MAX_BL_LEVEL)
|
||||
return 0;
|
||||
|
||||
if (bd->props.power != FB_BLANK_UNBLANK)
|
||||
level = 0;
|
||||
if (bd->props.fb_blank != FB_BLANK_UNBLANK)
|
||||
level = 0;
|
||||
|
||||
if (level && !devdata->clk_enabled)
|
||||
mxc_pwm_enable(devdata);
|
||||
|
||||
mxc_set_brightness(devdata, level);
|
||||
|
||||
if (level == 0 && devdata->clk_enabled)
|
||||
mxc_pwm_disable(devdata);
|
||||
|
||||
devdata->intensity = bl_level_to_pwm_map[level];
|
||||
blocking_notifier_call_chain(&backlight_notifier_list, BL_BRIGHTNESS, &level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxcbl_get_brightness(struct backlight_device *bd)
|
||||
{
|
||||
struct mxcbl_dev_data *devdata = dev_get_drvdata(&bd->dev);
|
||||
printk("intensity=%d\n", devdata->intensity);
|
||||
return bd->props.brightness;
|
||||
}
|
||||
|
||||
static int mxcbl_check_fb(struct fb_info *info)
|
||||
{
|
||||
|
||||
if (strcmp(info->fix.id, "DISP0 BG") == 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct backlight_ops mxcbl_ops = {
|
||||
.get_brightness = mxcbl_get_brightness,
|
||||
.update_status = mxcbl_set_brightness,
|
||||
.check_fb = mxcbl_check_fb,
|
||||
};
|
||||
|
||||
static int __init mxcbl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct backlight_device *bd;
|
||||
struct mxcbl_dev_data *devdata;
|
||||
int ret = 0;
|
||||
|
||||
devdata = kzalloc(sizeof(struct mxcbl_dev_data), GFP_KERNEL);
|
||||
if (!devdata)
|
||||
return -ENOMEM;
|
||||
;
|
||||
/* ron: TBD */
|
||||
devdata->base = IO_ADDRESS(PWM1_BASE_ADDR);
|
||||
devdata->clk = clk_get(&pdev->dev, "pwm");
|
||||
devdata->clk_enabled = 0;
|
||||
mxc_pwm_enable(devdata);
|
||||
|
||||
#if 0 //vv, 20100316 dev.bus_id is deprecated, change to use dev_name(&pdev->dev)
|
||||
bd = backlight_device_register(pdev->dev.bus_id, &pdev->dev, devdata,
|
||||
&mxcbl_ops);
|
||||
#else
|
||||
bd = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, devdata,
|
||||
&mxcbl_ops);
|
||||
#endif
|
||||
|
||||
if (IS_ERR(bd)) {
|
||||
ret = PTR_ERR(bd);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, bd);
|
||||
|
||||
bd->props.brightness = MXC_DFL_BL_LEVEL;
|
||||
bd->props.max_brightness = MXC_MAX_BL_LEVEL;
|
||||
bd->props.power = FB_BLANK_UNBLANK;
|
||||
bd->props.fb_blank = FB_BLANK_UNBLANK;
|
||||
mxc_set_brightness(devdata, MXC_DFL_BL_LEVEL);
|
||||
|
||||
/*printk("MXC Backlight Device %s Initialized.\n", pdev->dev.bus_id);*/
|
||||
printk("MXC Backlight Device %s Initialized.\n", dev_name(&pdev->dev));
|
||||
|
||||
return 0;
|
||||
|
||||
err0:
|
||||
|
||||
mxc_pwm_disable(devdata);
|
||||
kfree(devdata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxcbl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct backlight_device *bd = platform_get_drvdata(pdev);
|
||||
struct mxcbl_dev_data *devdata = dev_get_drvdata(&bd->dev);
|
||||
|
||||
bd->props.brightness = MXC_INTENSITY_OFF;
|
||||
backlight_update_status(bd);
|
||||
mxc_pwm_disable(devdata);
|
||||
backlight_device_unregister(bd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxcbl_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct backlight_device *bd = platform_get_drvdata(pdev);
|
||||
struct mxcbl_dev_data *devdata = dev_get_drvdata(&bd->dev);
|
||||
|
||||
devdata->suspend = 1;
|
||||
backlight_update_status(bd);
|
||||
mxc_pwm_disable(devdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxcbl_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct backlight_device *bd = platform_get_drvdata(pdev);
|
||||
struct mxcbl_dev_data *devdata = dev_get_drvdata(&bd->dev);
|
||||
|
||||
mxc_pwm_enable(devdata);
|
||||
devdata->suspend = 0;
|
||||
backlight_update_status(bd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mxcbl_driver = {
|
||||
.probe = mxcbl_probe,
|
||||
.remove = mxcbl_remove,
|
||||
.suspend = mxcbl_suspend,
|
||||
.resume = mxcbl_resume,
|
||||
.driver = {
|
||||
.name = "mxc_efikasb_bl",
|
||||
},
|
||||
};
|
||||
|
||||
static int __init mxcbl_init(void)
|
||||
{
|
||||
|
||||
return platform_driver_register(&mxcbl_driver);
|
||||
}
|
||||
|
||||
static void __exit mxcbl_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mxcbl_driver);
|
||||
}
|
||||
|
||||
module_init(mxcbl_init);
|
||||
module_exit(mxcbl_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Pegatron iMX51 Efikasb LCDC PWM Backlight Driver");
|
||||
MODULE_AUTHOR("Pegatron Corp.");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -42,6 +42,20 @@ config FB_MXC_SII9022
|
||||
depends on FB_MXC_SYNC_PANEL
|
||||
tristate "SII9022A HDMI Interface Chip"
|
||||
|
||||
config FB_MXC_CS8556
|
||||
depends on FB_MXC_SYNC_PANEL
|
||||
tristate "Myson CS8556 VGA Interface Chip"
|
||||
default y
|
||||
|
||||
|
||||
|
||||
|
||||
config FB_MXC_MTL017
|
||||
depends on FB_MXC_SYNC_PANEL
|
||||
tristate "Myson MTL017 LVDS Controller"
|
||||
default n
|
||||
|
||||
|
||||
config FB_MXC_CH7026
|
||||
depends on FB_MXC_SYNC_PANEL
|
||||
tristate "Chrontel CH7026 VGA Interface Chip"
|
||||
|
||||
@@ -21,5 +21,7 @@ obj-$(CONFIG_FB_MXC_LDB) += ldb.o
|
||||
obj-$(CONFIG_FB_MXC_CH7026) += mxcfb_ch7026.o
|
||||
#obj-$(CONFIG_FB_MODE_HELPERS) += mxc_edid.o
|
||||
obj-$(CONFIG_FB_MXC_SII9022) += mxcfb_sii9022.o
|
||||
obj-$(CONFIG_FB_MXC_CS8556) += mxcfb_cs8556.o
|
||||
obj-$(CONFIG_FB_MXC_MTL017) += mxcfb_mtl017.o
|
||||
obj-$(CONFIG_FB_MXC_EINK_PANEL) += mxc_epdc_fb.o
|
||||
obj-$(CONFIG_FB_MXC_ELCDIF_FB) += mxc_elcdif_fb.o
|
||||
|
||||
565
drivers/video/mxc/mxcfb_cs8556.c
Normal file
565
drivers/video/mxc/mxcfb_cs8556.c
Normal file
@@ -0,0 +1,565 @@
|
||||
/*
|
||||
* Copyright 2009 Pegatron Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @defgroup Framebuffer Framebuffer Driver for SDC and ADC.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file mxcfb_cs8556.c
|
||||
*
|
||||
* @brief MXC Frame buffer driver for SDC
|
||||
*
|
||||
* @ingroup Framebuffer
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Include files
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mxcfb.h>
|
||||
#include <linux/ipu.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
static struct i2c_client *cs8556_client;
|
||||
|
||||
static int lcd_init(void);
|
||||
static void lcd_poweron(struct fb_info *info);
|
||||
static void lcd_poweroff(void);
|
||||
|
||||
static void (*lcd_reset) (void);
|
||||
static struct regulator *io_reg;
|
||||
static struct regulator *core_reg;
|
||||
static struct regulator *analog_reg;
|
||||
|
||||
static struct fb_videomode mode = {
|
||||
"1024x768", 60, 1024, 768, 16081, 160, 56, 20, 3, 104, 4, 2, FB_VMODE_NONINTERLACED
|
||||
};
|
||||
|
||||
static void lcd_init_fb(struct fb_info *info)
|
||||
{
|
||||
struct fb_var_screeninfo var;
|
||||
|
||||
memset(&var, 0, sizeof(var));
|
||||
|
||||
fb_videomode_to_var(&var, &mode);
|
||||
|
||||
var.activate = FB_ACTIVATE_ALL;
|
||||
|
||||
acquire_console_sem();
|
||||
info->flags |= FBINFO_MISC_USEREVENT;
|
||||
fb_set_var(info, &var);
|
||||
fb_blank(info, FB_BLANK_UNBLANK);
|
||||
info->flags &= ~FBINFO_MISC_USEREVENT;
|
||||
release_console_sem();
|
||||
}
|
||||
|
||||
static int lcd_fb_event(struct notifier_block *nb, unsigned long val, void *v)
|
||||
{
|
||||
struct fb_event *event = v;
|
||||
|
||||
if (strcmp(event->info->fix.id, "DISP3 BG - DI1"))
|
||||
return 0;
|
||||
|
||||
switch (val) {
|
||||
case FB_EVENT_FB_REGISTERED:
|
||||
lcd_init_fb(event->info);
|
||||
lcd_poweron(event->info);
|
||||
break;
|
||||
case FB_EVENT_BLANK:
|
||||
if (*((int *)event->data) == FB_BLANK_UNBLANK)
|
||||
lcd_poweron(event->info);
|
||||
else
|
||||
lcd_poweroff();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block nb = {
|
||||
.notifier_call = lcd_fb_event,
|
||||
};
|
||||
|
||||
/*!
|
||||
* This function is called whenever the SPI slave device is detected.
|
||||
*
|
||||
* @param spi the SPI slave device
|
||||
*
|
||||
* @return Returns 0 on SUCCESS and error on FAILURE.
|
||||
*/
|
||||
static int __devinit lcd_probe(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
struct mxc_lcd_platform_data *plat = dev->platform_data;
|
||||
|
||||
if (plat) {
|
||||
lcd_reset = plat->reset;
|
||||
if (lcd_reset)
|
||||
lcd_reset();
|
||||
}
|
||||
|
||||
for (i = 0; i < num_registered_fb; i++) {
|
||||
if (strcmp(registered_fb[i]->fix.id, "DISP3 BG - DI1") == 0) {
|
||||
ret = lcd_init();
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
lcd_init_fb(registered_fb[i]);
|
||||
fb_show_logo(registered_fb[i], 0);
|
||||
lcd_poweron(registered_fb[i]);
|
||||
}
|
||||
}
|
||||
|
||||
fb_register_client(&nb);
|
||||
return 0;
|
||||
err:
|
||||
if (io_reg)
|
||||
regulator_disable(io_reg);
|
||||
if (core_reg)
|
||||
regulator_disable(core_reg);
|
||||
if (analog_reg)
|
||||
regulator_disable(analog_reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit cs8556_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int id_reg;
|
||||
cs8556_client = client;
|
||||
|
||||
return lcd_probe(&client->dev);
|
||||
}
|
||||
|
||||
static int __devexit cs8556_remove(struct i2c_client *client)
|
||||
{
|
||||
fb_unregister_client(&nb);
|
||||
lcd_poweroff();
|
||||
regulator_put(io_reg);
|
||||
regulator_put(core_reg);
|
||||
regulator_put(analog_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs8556_suspend(struct i2c_client *client, pm_message_t message)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs8556_resume(struct i2c_client *client)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Hungwen
|
||||
u8 __devinitdata xga2xga_tbl1[] = {
|
||||
// 0x00 - 0x0F
|
||||
0x00,
|
||||
0x0E, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x10 - 0x1F
|
||||
0x10,
|
||||
//0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //RGB24
|
||||
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //RGB565
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x20 - 0x2F
|
||||
0x20,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x30 - 0x3F
|
||||
0x30,
|
||||
0x3F, 0x05, 0x67, 0x00, 0x08, 0x01, 0x08, 0x05,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x40 - 0x4F
|
||||
0x40,
|
||||
0x1A, 0x03, 0x03, 0x00, 0x17, 0x00, 0x16, 0x03,
|
||||
0x00, 0x00, 0x9F, 0x00, 0x15, 0x00, 0x37, 0x00,
|
||||
// 0x50 - 0x5F
|
||||
0x50,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x60 - 0x6F
|
||||
0x60,
|
||||
0x1F, 0x05, 0x20, 0x00, 0xC0, 0x00, 0xC0, 0x04,
|
||||
0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x38, 0x03,
|
||||
// 0x70 - 0x7F
|
||||
0x70,
|
||||
0x3D, 0x03, 0x0C, 0x00, 0x16, 0x00, 0x04, 0x03,
|
||||
0xCC, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x80 - 0x8F
|
||||
0x80,
|
||||
0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x90 - 0x9F
|
||||
0x90,
|
||||
0x04, 0x01, 0x11, 0x0D, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xA0 - 0xAF
|
||||
0xA0,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
|
||||
// 0xB0 - 0xBF
|
||||
0xB0,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xC0 - 0xCF
|
||||
0xC0,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
|
||||
// 0xD0 - 0xDF
|
||||
0xD0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xE0 - 0xEF
|
||||
0xE0,
|
||||
//0x01, 0x06, 0x13, 0x00, 0x01, 0x02, 0x00, 0x00,
|
||||
0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xF0 - 0xFF
|
||||
0xF0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
u8 __devinitdata xga2xga_tbl2[] = {
|
||||
// 0x00 - 0x0F
|
||||
0x00,
|
||||
0x80, 0x10, 0x80, 0x00, 0x00, 0x00, 0x99, 0x11,
|
||||
0x2A, 0x00, 0x70, 0x30, 0x2A, 0x71, 0x9C, 0x00,
|
||||
// 0x10 - 0x1F
|
||||
0x10,
|
||||
0x10, 0x2A, 0x85, 0x82, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
// 0x20 - 0x2F
|
||||
0x20,
|
||||
0x41, 0x09, 0x98, 0x08, 0xCC, 0x00, 0x4C, 0x08,
|
||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00,
|
||||
// 0x30 - 0x3F
|
||||
0x30,
|
||||
0x00, 0x01, 0xEE, 0x02, 0x3A, 0x07, 0x65, 0x04,
|
||||
0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x40 - 0x4F
|
||||
0x40,
|
||||
0x06, 0x40, 0x07, 0x30, 0x15, 0x10, 0x31, 0x02,
|
||||
0x33, 0x12, 0x34, 0x52, 0x38, 0x42, 0x39, 0x62,
|
||||
// 0x50 - 0x5F
|
||||
0x50,
|
||||
0x48, 0x12, 0x64, 0x04, 0x66, 0x14, 0x00, 0x10,
|
||||
0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10,
|
||||
// 0x60 - 0x6F
|
||||
0x60,
|
||||
0x7E, 0x10, 0x00, 0xF4, 0x10, 0x76, 0x08, 0x00,
|
||||
0x8A, 0x00, 0x8F, 0x11, 0x8F, 0x8F, 0x81, 0x00,
|
||||
// 0x70 - 0x7F
|
||||
0x70,
|
||||
0x03, 0x00, 0x89, 0x45, 0x01, 0x45, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x80 - 0x8F
|
||||
0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x90 - 0x9F
|
||||
0x90,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xA0 - 0xAF
|
||||
0xA0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xB0 - 0xBF
|
||||
0xB0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xC0 - 0xCF
|
||||
0xC0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xD0 - 0xDF
|
||||
0xD0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xE0 - 0xEF
|
||||
0xE0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xF0 - 0xFF
|
||||
0xF0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
u8 __devinitdata wsvga2xga_tbl1[] = {
|
||||
// 0x00 - 0x0F
|
||||
0x00,
|
||||
0x0E, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01,
|
||||
// 0x10 - 0x0F
|
||||
0x10,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x20 - 0x0F
|
||||
0x20,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x30 - 0x0F
|
||||
0x30,
|
||||
0x7B, 0x04, 0x10, 0x00, 0x54, 0x00, 0x54, 0x04,
|
||||
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x40 - 0x0F
|
||||
0x40,
|
||||
0x97, 0x02, 0x03, 0x00, 0x12, 0x00, 0x6A, 0x02,
|
||||
0x00, 0x00, 0x50, 0x00, 0x14, 0x00, 0x17, 0x00,
|
||||
// 0x50 - 0x0F
|
||||
0x50,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x60 - 0x0F
|
||||
0x60,
|
||||
0x1F, 0x05, 0x20, 0x00, 0xC0, 0x00, 0xC0, 0x04,
|
||||
0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x38, 0x03,
|
||||
// 0x70 - 0x0F
|
||||
0x70,
|
||||
0x3D, 0x03, 0x0C, 0x00, 0x16, 0x00, 0x04, 0x03,
|
||||
0xCC, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x80 - 0x0F
|
||||
0x80,
|
||||
0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x90 - 0x0F
|
||||
0x90,
|
||||
0x04, 0x01, 0x11, 0x0D, 0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xA0 - 0x0F
|
||||
0xA0,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
|
||||
// 0xB0 - 0x0F
|
||||
0xB0,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xC0 - 0x0F
|
||||
0xC0,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
|
||||
// 0xD0 - 0x0F
|
||||
0xD0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xE0 - 0x0F
|
||||
0xE0,
|
||||
0x01, 0x06, 0x13, 0x00, 0x01, 0x02, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xF0 - 0x0F
|
||||
0xF0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
u8 __devinitdata wsvga2xga_tbl2[] = {
|
||||
// 0x00 - 0x0F
|
||||
0x00,
|
||||
0x80, 0x10, 0x80, 0x00, 0x00, 0x00, 0x99, 0x11,
|
||||
0x2A, 0x00, 0x70, 0x30, 0x2A, 0x71, 0x9C, 0x00,
|
||||
// 0x10 - 0x0F
|
||||
0x10,
|
||||
0x10, 0x2A, 0x85, 0x82, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
// 0x20 - 0x0F
|
||||
0x20,
|
||||
0x41, 0x01, 0x98, 0x08, 0xCC, 0x00, 0x4C, 0x08,
|
||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00,
|
||||
// 0x30 - 0x0F
|
||||
0x30,
|
||||
0x00, 0x01, 0xEE, 0x02, 0x3A, 0x07, 0x65, 0x04,
|
||||
0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x40 - 0x0F
|
||||
0x40,
|
||||
0x06, 0x40, 0x07, 0x30, 0x15, 0x10, 0x31, 0x02,
|
||||
0x33, 0x12, 0x34, 0x52, 0x38, 0x42, 0x39, 0x62,
|
||||
// 0x50 - 0x0F
|
||||
0x50,
|
||||
0x48, 0x12, 0x64, 0x04, 0x66, 0x14, 0x00, 0x10,
|
||||
0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10,
|
||||
// 0x60 - 0x0F
|
||||
0x60,
|
||||
0x7E, 0x10, 0x00, 0xF4, 0x10, 0x76, 0x08, 0x00,
|
||||
0x8A, 0x00, 0x8F, 0x11, 0x8F, 0x8F, 0x81, 0x00,
|
||||
// 0x70 - 0x0F
|
||||
0x70,
|
||||
0x03, 0x00, 0x89, 0x45, 0x01, 0x45, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x80 - 0x0F
|
||||
0x80,
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x90 - 0x0F
|
||||
0x90,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xA0 - 0x0F
|
||||
0xA0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xB0 - 0x0F
|
||||
0xB0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xC0 - 0x0F
|
||||
0xC0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xD0 - 0x0F
|
||||
0xD0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xE0 - 0x0F
|
||||
0xE0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0xF0 - 0x0F
|
||||
0xF0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
|
||||
#define REGMAP_LENGTH (sizeof(reg_init) / (2*sizeof(u8)))
|
||||
#define BLOCK_TX_SIZE (16+1) //Must small than 32
|
||||
|
||||
/*
|
||||
* Send init commands to L4F00242T03
|
||||
*
|
||||
*/
|
||||
static int lcd_init(void)
|
||||
{
|
||||
int i, j;
|
||||
int dat;
|
||||
u8 *tables[] = { xga2xga_tbl1, xga2xga_tbl2 };
|
||||
int tbl_len[] = {
|
||||
sizeof(xga2xga_tbl1) / sizeof(u8),
|
||||
sizeof(xga2xga_tbl2) / sizeof(u8)
|
||||
};
|
||||
|
||||
dev_dbg(&cs8556_client->dev, "initializing CS8556AG\n");
|
||||
|
||||
/* read device ID */
|
||||
msleep(100);
|
||||
dat = i2c_smbus_read_byte_data(cs8556_client, 0x00);
|
||||
dev_dbg(&cs8556_client->dev, "read id = 0x%02X\n", dat);
|
||||
//if (dat != 0x54)
|
||||
// return -ENODEV;
|
||||
|
||||
// Writing configuration table.
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (j = 0; j < tbl_len[i]; j += BLOCK_TX_SIZE) {
|
||||
if (i2c_smbus_write_i2c_block_data(cs8556_client, i,
|
||||
BLOCK_TX_SIZE, &(tables[i][j]) ) < 0) {
|
||||
printk("@_@ VGA controller init error!!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lcd_on;
|
||||
/*
|
||||
* Send Power On commands to L4F00242T03
|
||||
*
|
||||
*/
|
||||
static void lcd_poweron(struct fb_info *info)
|
||||
{
|
||||
u16 data[4];
|
||||
u32 refresh;
|
||||
|
||||
if (lcd_on)
|
||||
return;
|
||||
|
||||
dev_dbg(&cs8556_client->dev, "turning on LCD\n");
|
||||
|
||||
data[0] = PICOS2KHZ(info->var.pixclock) / 10;
|
||||
data[2] = info->var.hsync_len + info->var.left_margin +
|
||||
info->var.xres + info->var.right_margin;
|
||||
data[3] = info->var.vsync_len + info->var.upper_margin +
|
||||
info->var.yres + info->var.lower_margin;
|
||||
|
||||
refresh = data[2] * data[3];
|
||||
refresh = (PICOS2KHZ(info->var.pixclock) * 1000) / refresh;
|
||||
data[1] = refresh * 100;
|
||||
|
||||
lcd_on = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send Power Off commands to L4F00242T03
|
||||
*
|
||||
*/
|
||||
static void lcd_poweroff(void)
|
||||
{
|
||||
if (!lcd_on)
|
||||
return;
|
||||
|
||||
dev_dbg(&cs8556_client->dev, "turning off LCD\n");
|
||||
|
||||
lcd_on = 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id cs8556_id[] = {
|
||||
{"cs8556", 0},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, cs8556_id);
|
||||
|
||||
static struct i2c_driver cs8556_driver = {
|
||||
.driver = {
|
||||
.name = "cs8556",
|
||||
},
|
||||
.probe = cs8556_probe,
|
||||
.remove = cs8556_remove,
|
||||
.suspend = cs8556_suspend,
|
||||
.resume = cs8556_resume,
|
||||
.id_table = cs8556_id,
|
||||
};
|
||||
|
||||
static int __init cs8556_init(void)
|
||||
{
|
||||
return i2c_add_driver(&cs8556_driver);
|
||||
}
|
||||
|
||||
static void __exit cs8556_exit(void)
|
||||
{
|
||||
i2c_del_driver(&cs8556_driver);
|
||||
}
|
||||
|
||||
module_init(cs8556_init);
|
||||
module_exit(cs8556_exit);
|
||||
|
||||
MODULE_AUTHOR("Pegatron Corporation");
|
||||
MODULE_DESCRIPTION("cs8556 VGA driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
950
drivers/video/mxc/mxcfb_mtl017.c
Normal file
950
drivers/video/mxc/mxcfb_mtl017.c
Normal file
@@ -0,0 +1,950 @@
|
||||
/*
|
||||
* Copyright 2009 Pegatron, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @defgroup Framebuffer Framebuffer Driver for Efikasb Platform.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file mxcfb_mtl017.c
|
||||
*
|
||||
* @brief MXC Frame buffer driver for Efikasb Platform
|
||||
*
|
||||
* @ingroup Framebuffer
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Include files
|
||||
*/
|
||||
#define DEBUG
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mxcfb.h>
|
||||
#include <linux/ipu.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <mach/mxc_edid.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#define EDID_LENGTH 128
|
||||
|
||||
extern int register_backlight_notifier(struct notifier_block *nb);
|
||||
extern int unregister_backlight_notifier(struct notifier_block *nb);
|
||||
|
||||
#if 0 //vv
|
||||
struct mtl017_dev_data {
|
||||
struct i2c_client *client;
|
||||
u8 edid[EDID_LENGTH];
|
||||
struct fb_videomode *mode;
|
||||
u8 *regs;
|
||||
int suspending;
|
||||
int disp_on;
|
||||
|
||||
struct semaphore sem;
|
||||
|
||||
void (*reset)(void);
|
||||
void (*power_on_lcd) (int);
|
||||
void (*power_on_lvds) (int);
|
||||
void (*turn_on_backlight) (int);
|
||||
void (*lvds_enable) (int);
|
||||
};
|
||||
#else
|
||||
typedef struct mtl017_dev_data_tag {
|
||||
struct i2c_client *client;
|
||||
u8 edid[EDID_LENGTH];
|
||||
struct fb_videomode *mode;
|
||||
u8 *regs;
|
||||
int suspending;
|
||||
int disp_on;
|
||||
|
||||
struct semaphore sem;
|
||||
|
||||
void (*reset)(void);
|
||||
void (*power_on_lcd) (int);
|
||||
void (*power_on_lvds) (int);
|
||||
void (*turn_on_backlight) (int);
|
||||
void (*lvds_enable) (int);
|
||||
} mtl017_dev_data;
|
||||
#endif
|
||||
|
||||
//vv static struct mtl017_dev_data *mtl017 = NULL;
|
||||
static mtl017_dev_data * mtl017 = NULL; //vv
|
||||
static void mtl017_conf(u8 *reg_tbl);
|
||||
static void disp_power_on(void);
|
||||
static void disp_power_off(void);
|
||||
|
||||
static void disp_on_work_handler(struct work_struct *work);
|
||||
static void disp_off_work_handler(struct work_struct *work);
|
||||
|
||||
static void disp_on_work_handler(struct work_struct *work)
|
||||
{
|
||||
disp_power_on();
|
||||
}
|
||||
|
||||
static void disp_off_work_handler(struct work_struct *work)
|
||||
{
|
||||
disp_power_off();
|
||||
}
|
||||
|
||||
static DECLARE_WORK(disp_off_work, disp_off_work_handler);
|
||||
static DECLARE_WORK(disp_on_work, disp_on_work_handler);
|
||||
|
||||
#ifdef DEBUG_MTL017
|
||||
static void dump_edid(unsigned char *id)
|
||||
{
|
||||
int i;
|
||||
|
||||
printk("EDID Dump:\n");
|
||||
for (i=0; i < EDID_LENGTH; i++) {
|
||||
printk("[%x]=%x\n", i, id[i]);
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
static void dump_screeninfo(struct fb_var_screeninfo *einfo)
|
||||
{
|
||||
printk("resolution: r(%d, %d), v(%d, %d) o(%d, %d)\n",
|
||||
einfo->xres,
|
||||
einfo->yres,
|
||||
einfo->xres_virtual,
|
||||
einfo->yres_virtual,
|
||||
einfo->xoffset,
|
||||
einfo->yoffset);
|
||||
printk("bpp=%d, hw(%d, %d), pclk=%d\n",
|
||||
einfo->bits_per_pixel,
|
||||
einfo->height,
|
||||
einfo->width,
|
||||
einfo->pixclock);
|
||||
|
||||
printk("margin(%d, %d, %d, %d)\n",
|
||||
einfo->left_margin,
|
||||
einfo->right_margin,
|
||||
einfo->upper_margin,
|
||||
einfo->lower_margin);
|
||||
|
||||
printk("hv(%d, %d), sync=%x, vmode=%x\n",
|
||||
einfo->hsync_len,
|
||||
einfo->vsync_len,
|
||||
einfo->sync,
|
||||
einfo->vmode);
|
||||
|
||||
}
|
||||
#else
|
||||
static void dump_edid(unsigned char *edid) {}
|
||||
static void dump_screeninfo(struct fb_var_screeninfo *einfo) {}
|
||||
#endif
|
||||
|
||||
static u8 mtl017_auo_tbl[] = {
|
||||
/* ron: 66M to 66M */
|
||||
/* 0x00,0x20,0xAF,0x59,0x2B,0xDE,0x51,0x00, */
|
||||
/* 0x00,0x04,0x17,0x00,0x58,0x02,0x00,0x00, */
|
||||
/* 0x00,0x21,0x01,0x08,0x00,0x1E,0x01,0x05, */
|
||||
/* 0x00,0x01,0x7C,0x04,0x32,0x00,0x00,0x04, */
|
||||
/* 0x00,0x00,0x20,0xA8,0x02,0x12,0x00,0x58, */
|
||||
/* 0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00, */
|
||||
/* 0x00,0x02,0x10,0x01,0x68,0x03,0xC2,0x01, */
|
||||
/* 0x4A,0x03,0x46,0x00,0xF1,0x01,0x5C,0x04, */
|
||||
/* 0x08,0x00,0x10,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x3A, */
|
||||
/* 0x18,0x4B,0x29,0x5C,0xDE,0xF6,0xE0,0x1C, */
|
||||
/* 0x03,0xFC,0xE3,0x1F,0xF3,0x75,0x26,0x45, */
|
||||
/* 0x4A,0x91,0x8A,0xFF,0x3F,0x83,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x20,0x4E,0x48, */
|
||||
/* 0x00,0x00,0x06,0x01,0x02,0x00,0x10,0x04, */
|
||||
/* 0x02,0x1F,0x00,0x00,0x00,0x0A,0x00,0x00, */
|
||||
/* 0x32,0x00,0x00,0x04,0x12,0x00,0x00,0x03, */
|
||||
/* 0x02,0x7C,0x04,0x98,0x02,0x11,0x78,0x18, */
|
||||
/* 0x30,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
/* 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
/* 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
|
||||
/* ron: 44MHz to 54MHz */
|
||||
/* 0x00,0x20,0xAF,0x59,0x2B,0xDE,0x51,0x00, */
|
||||
/* 0x00,0x04,0x17,0x00,0x58,0x02,0x00,0x00, */
|
||||
/* 0x00,0x3B,0x01,0x08,0x00,0x1E,0x01,0x05, */
|
||||
/* 0x00,0x01,0x82,0x05,0x32,0x00,0x00,0x04, */
|
||||
/* 0x00,0x00,0x20,0xA8,0x02,0x12,0x00,0x58, */
|
||||
/* 0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00, */
|
||||
/* 0x00,0x02,0x10,0x01,0x68,0x03,0xC2,0x01, */
|
||||
/* 0x4A,0x03,0x46,0x00,0xF1,0x01,0x5C,0x04, */
|
||||
/* 0x08,0x00,0x10,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x3A, */
|
||||
/* 0x18,0x4B,0x29,0x5C,0xDE,0xF6,0xE0,0x1C, */
|
||||
/* 0x03,0xFC,0xE3,0x1F,0xF3,0x75,0x26,0x45, */
|
||||
/* 0x4A,0x91,0x8A,0xFF,0x3F,0x83,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x20,0x4E,0x48, */
|
||||
/* 0x00,0x04,0x2A,0x01,0x02,0x00,0x10,0x04, */
|
||||
/* 0x02,0x1F,0x00,0x00,0x00,0x0A,0x00,0x00, */
|
||||
/* 0x32,0x00,0x00,0x04,0x12,0x00,0x58,0x02, */
|
||||
/* 0x02,0x7C,0x04,0x7E,0x02,0x11,0x78,0x18, */
|
||||
/* 0x30,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
/* 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
/* 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
|
||||
|
||||
/* ron: 44MHz to 48MHz */
|
||||
/* 0x00,0x20,0xAF,0x59,0x2B,0xDE,0x51,0x00, */
|
||||
/* 0x00,0x04,0x16,0x00,0x59,0x02,0x00,0x00, */
|
||||
/* 0x00,0x21,0x00,0x09,0x00,0x1E,0x01,0x05, */
|
||||
/* 0x00,0x01,0xEA,0x04,0x32,0x00,0x00,0x04, */
|
||||
/* 0x00,0x00,0x20,0xA8,0x02,0x12,0x00,0x58, */
|
||||
/* 0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00, */
|
||||
/* 0x00,0x02,0x10,0x01,0x68,0x03,0xC2,0x01, */
|
||||
/* 0x4A,0x03,0x46,0x00,0xF1,0x01,0x5C,0x04, */
|
||||
/* 0x08,0x00,0x10,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x3A, */
|
||||
/* 0x18,0x4B,0x29,0x5C,0xDE,0xF6,0xE0,0x1C, */
|
||||
/* 0x03,0xFC,0xE3,0x1F,0xF3,0x75,0x26,0x45, */
|
||||
/* 0x4A,0x91,0x8A,0xFF,0x3F,0x83,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x20,0x4E,0x48, */
|
||||
/* 0x00,0x02,0x16,0x01,0x02,0x00,0x10,0x04, */
|
||||
/* 0x02,0x1F,0x00,0x00,0x00,0x0A,0x00,0x00, */
|
||||
/* 0x32,0x00,0x00,0x04,0x12,0x00,0x00,0x03, */
|
||||
/* 0x02,0x7C,0x04,0x7E,0x02,0x11,0x78,0x18, */
|
||||
/* 0x30,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
/* 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
/* 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
|
||||
/* ron: 44M to 53.8M */
|
||||
/* 0x00,0x20,0xAF,0x59,0x2B,0xDE,0x51,0x00, */
|
||||
/* 0x00,0x04,0x17,0x00,0x58,0x02,0x00,0x00, */
|
||||
/* 0x00,0x3B,0x01,0x08,0x00,0x1E,0x01,0x05, */
|
||||
/* 0x00,0x01,0x7E,0x05,0x32,0x00,0x00,0x04, */
|
||||
/* 0x00,0x00,0x20,0xA8,0x02,0x12,0x00,0x58, */
|
||||
/* 0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00, */
|
||||
/* 0x00,0x02,0x10,0x01,0x68,0x03,0xC2,0x01, */
|
||||
/* 0x4A,0x03,0x46,0x00,0xF1,0x01,0x5C,0x04, */
|
||||
/* 0x08,0x00,0x10,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x3A, */
|
||||
/* 0x18,0x4B,0x29,0x5C,0xDE,0xF6,0xE0,0x1C, */
|
||||
/* 0x03,0xFC,0xE3,0x1F,0xF3,0x75,0x26,0x45, */
|
||||
/* 0x4A,0x91,0x8A,0xFF,0x3F,0x83,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x20,0x4E,0x48, */
|
||||
/* 0x00,0x06,0x3B,0x01,0x02,0x00,0x10,0x04, */
|
||||
/* 0x02,0x1F,0x00,0x00,0x00,0x0A,0x00,0x00, */
|
||||
/* 0x32,0x00,0x00,0x04,0x12,0x00,0x58,0x02, */
|
||||
/* 0x02,0x7C,0x04,0x98,0x02,0x11,0x78,0x18, */
|
||||
/* 0x30,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
/* 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
/* 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
|
||||
/* ron: 44M to 53.9M */
|
||||
0x00,0x20,0xAF,0x59,0x2B,0xDE,0x51,0x00,
|
||||
0x00,0x04,0x17,0x00,0x58,0x02,0x00,0x00,
|
||||
0x00,0x3B,0x01,0x08,0x00,0x1E,0x01,0x05,
|
||||
0x00,0x01,0x72,0x05,0x32,0x00,0x00,0x04,
|
||||
0x00,0x00,0x20,0xA8,0x02,0x12,0x00,0x58,
|
||||
0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,
|
||||
0x00,0x02,0x10,0x01,0x68,0x03,0xC2,0x01,
|
||||
0x4A,0x03,0x46,0x00,0xF1,0x01,0x5C,0x04,
|
||||
0x08,0x00,0x10,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x3A,
|
||||
0x18,0x4B,0x29,0x5C,0xDE,0xF6,0xE0,0x1C,
|
||||
0x03,0xFC,0xE3,0x1F,0xF3,0x75,0x26,0x45,
|
||||
0x4A,0x91,0x8A,0xFF,0x3F,0x83,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x20,0x4E,0x48,
|
||||
0x00,0x01,0x10,0x01,0x00,0x00,0x10,0x04,
|
||||
0x02,0x1F,0x00,0x00,0x00,0x0A,0x00,0x00,
|
||||
0x32,0x00,0x00,0x04,0x12,0x00,0x58,0x02,
|
||||
0x02,0x7C,0x04,0x98,0x02,0x11,0x78,0x18,
|
||||
0x30,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
|
||||
};
|
||||
|
||||
static u8 mtl017_cpt_tbl[] = {
|
||||
/* 0x00,0x20,0xAF,0x59,0x2B,0xDE,0x51,0x00, */
|
||||
/* 0x00,0x04,0x17,0x00,0x58,0x02,0x00,0x00, */
|
||||
/* 0x00,0x21,0x01,0x08,0x00,0x1E,0x01,0x05, */
|
||||
/* 0x00,0x01,0x7C,0x04,0x32,0x00,0x00,0x04, */
|
||||
/* 0x00,0x00,0x20,0xA8,0x02,0x12,0x00,0x58, */
|
||||
/* 0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00, */
|
||||
/* 0x00,0x02,0x10,0x01,0x68,0x03,0xC2,0x01, */
|
||||
/* 0x4A,0x03,0x46,0x00,0xF1,0x01,0x5C,0x04, */
|
||||
/* 0x08,0x00,0x10,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x3A, */
|
||||
/* 0x18,0x4B,0x29,0x5C,0xDE,0xF6,0xE0,0x1C, */
|
||||
/* 0x03,0xFC,0xE3,0x1F,0xF3,0x75,0x26,0x45, */
|
||||
/* 0x4A,0x91,0x8A,0xFF,0x3F,0x83,0x00,0x00, */
|
||||
/* 0x00,0x00,0x00,0x00,0x00,0x20,0x4E,0x48, */
|
||||
/* 0x00,0x00,0x06,0x01,0x02,0x00,0x10,0x04, */
|
||||
/* 0x02,0x1F,0x00,0x00,0x00,0x0A,0x00,0x00, */
|
||||
/* 0x32,0x00,0x00,0x04,0x12,0x00,0x00,0x03, */
|
||||
/* 0x02,0x7C,0x04,0x98,0x02,0x11,0x78,0x18, */
|
||||
/* 0x30,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
/* 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
/* 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, */
|
||||
|
||||
/* ron: 44M to 53.9M */
|
||||
0x00,0x20,0xAF,0x59,0x2B,0xDE,0x51,0x00,
|
||||
0x00,0x04,0x17,0x00,0x58,0x02,0x00,0x00,
|
||||
0x00,0x3B,0x01,0x08,0x00,0x1E,0x01,0x05,
|
||||
0x00,0x01,0x72,0x05,0x32,0x00,0x00,0x04,
|
||||
0x00,0x00,0x20,0xA8,0x02,0x12,0x00,0x58,
|
||||
0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,
|
||||
0x00,0x02,0x10,0x01,0x68,0x03,0xC2,0x01,
|
||||
0x4A,0x03,0x46,0x00,0xF1,0x01,0x5C,0x04,
|
||||
0x08,0x00,0x10,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x3A,
|
||||
0x18,0x4B,0x29,0x5C,0xDE,0xF6,0xE0,0x1C,
|
||||
0x03,0xFC,0xE3,0x1F,0xF3,0x75,0x26,0x45,
|
||||
0x4A,0x91,0x8A,0xFF,0x3F,0x83,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x20,0x4E,0x48,
|
||||
0x00,0x01,0x10,0x01,0x00,0x00,0x10,0x04,
|
||||
0x02,0x1F,0x00,0x00,0x00,0x0A,0x00,0x00,
|
||||
0x32,0x00,0x00,0x04,0x12,0x00,0x58,0x02,
|
||||
0x02,0x7C,0x04,0x98,0x02,0x11,0x78,0x18,
|
||||
0x30,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
};
|
||||
|
||||
static u8 mtl017_auo_hires_tbl[] = {
|
||||
0x00,0x20,0xAF,0x59,0x2B,0xDE,0x3D,0x00,
|
||||
0x00,0x05,0x0C,0x00,0xD0,0x02,0x00,0x00,
|
||||
0x00,0x05,0x00,0x02,0x00,0x02,0x00,0x0A,
|
||||
0x00,0x01,0x70,0x05,0x3D,0x00,0x00,0x05,
|
||||
0x00,0x00,0x20,0xF0,0x02,0x0C,0x00,0xD0,
|
||||
0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,
|
||||
0x00,0x02,0x10,0x01,0x68,0x03,0xC2,0x01,
|
||||
0x4A,0x03,0x46,0x00,0xF1,0x01,0x5C,0x04,
|
||||
0x08,0x00,0x10,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x3A,
|
||||
0x18,0x4B,0x29,0x5C,0xDE,0xF6,0xE0,0x1C,
|
||||
0x03,0xFC,0xE3,0x1F,0xF3,0x75,0x26,0x45,
|
||||
0x4A,0x91,0x8A,0xFF,0x3F,0x83,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x20,0x4E,0x48,
|
||||
0x00,0x00,0x06,0x01,0x02,0x00,0x12,0x04,
|
||||
0x02,0x1F,0x00,0x00,0x00,0x0A,0x00,0x00,
|
||||
0x3D,0x00,0x00,0x05,0x0C,0x00,0xD0,0x02,
|
||||
0x02,0x70,0x05,0xE0,0x02,0x11,0x78,0x18,
|
||||
0x30,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
};
|
||||
|
||||
static u8 mtl017_cmo_tbl[] = {
|
||||
/* ron: 44M to 53.9M */
|
||||
0x00,0x20,0xAF,0x59,0x2B,0xDE,0x51,0x00,
|
||||
0x00,0x04,0x17,0x00,0x58,0x02,0x00,0x00,
|
||||
0x00,0x3B,0x01,0x08,0x00,0x1E,0x01,0x05,
|
||||
0x00,0x01,0x72,0x05,0x32,0x00,0x00,0x04,
|
||||
0x00,0x00,0x20,0xA8,0x02,0x12,0x00,0x58,
|
||||
0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,
|
||||
0x00,0x02,0x10,0x01,0x68,0x03,0xC2,0x01,
|
||||
0x4A,0x03,0x46,0x00,0xF1,0x01,0x5C,0x04,
|
||||
0x08,0x00,0x10,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x3A,
|
||||
0x18,0x4B,0x29,0x5C,0xDE,0xF6,0xE0,0x1C,
|
||||
0x03,0xFC,0xE3,0x1F,0xF3,0x75,0x26,0x45,
|
||||
0x4A,0x91,0x8A,0xFF,0x3F,0x83,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x20,0x4E,0x48,
|
||||
0x00,0x01,0x10,0x01,0x00,0x00,0x10,0x04,
|
||||
0x02,0x1F,0x00,0x00,0x00,0x0A,0x00,0x00,
|
||||
0x32,0x00,0x00,0x04,0x12,0x00,0x58,0x02,
|
||||
0x02,0x7C,0x04,0x98,0x02,0x11,0x78,0x18,
|
||||
0x30,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
};
|
||||
|
||||
#define REGMAP_LENGTH ( sizeof(mtl017_auo_tbl) / sizeof(u8) )
|
||||
#define BLOCK_TX_SIZE 32
|
||||
|
||||
static int mtl017_read_edid(struct i2c_adapter *adp, unsigned char *edid)
|
||||
{
|
||||
u8 buf0[2] = {0, 0};
|
||||
int dat = 0;
|
||||
u16 addr = 0x50;
|
||||
struct i2c_msg msg[2] = {
|
||||
{
|
||||
.addr = addr,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = buf0,
|
||||
}, {
|
||||
.addr = addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = EDID_LENGTH,
|
||||
.buf = edid,
|
||||
},
|
||||
};
|
||||
|
||||
if (adp == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
buf0[0] = 0x00;
|
||||
memset(edid, 0, EDID_LENGTH);
|
||||
dat = i2c_transfer(adp, msg, 2);
|
||||
if (dat <= 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (edid[1] == 0x00)
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ron: for AUO B101AW02 1024x600 LCD Panel */
|
||||
static struct fb_videomode auo_mode = {
|
||||
.name = "AUO B101AW02 1024x600",
|
||||
.refresh = 60,
|
||||
.xres = 1024,
|
||||
.yres = 600,
|
||||
/* .pixclock = 16666, */ /* ron: 66MHz display clock*/
|
||||
.pixclock = 22800, /* ron: 44MHz display clock*/
|
||||
.left_margin = 80,
|
||||
.right_margin = 40,
|
||||
.upper_margin = 20,
|
||||
.lower_margin = 21,
|
||||
.hsync_len = 4,
|
||||
.vsync_len = 4,
|
||||
.sync = FB_SYNC_OE_LOW_ACT,
|
||||
.vmode = FB_VMODE_NONINTERLACED,
|
||||
};
|
||||
|
||||
/* ron: for AUO B101EW01 1280x720 LCD Panel */
|
||||
static struct fb_videomode auo_hires_mode = {
|
||||
.name = "AUO B101EW01 1280x720",
|
||||
.refresh = 60,
|
||||
.xres = 1280,
|
||||
.yres = 720,
|
||||
.pixclock = 16260,
|
||||
.left_margin = 32,
|
||||
.right_margin = 48,
|
||||
.upper_margin = 7,
|
||||
.lower_margin = 3,
|
||||
.hsync_len = 32,
|
||||
.vsync_len = 6,
|
||||
.sync = FB_SYNC_OE_LOW_ACT,
|
||||
.vmode = FB_VMODE_NONINTERLACED,
|
||||
};
|
||||
|
||||
/* ron: for CPT CLAA101NB03A 1024x600 LCD Panel */
|
||||
static struct fb_videomode cpt_mode = {
|
||||
.name = "CPT CLAA101 1024x600",
|
||||
.refresh = 60,
|
||||
.xres = 1024,
|
||||
.yres = 600,
|
||||
.pixclock = 22800, /* ron: 44M display clock */
|
||||
.left_margin = 80,
|
||||
.right_margin = 40,
|
||||
.upper_margin = 20,
|
||||
.lower_margin = 21,
|
||||
.hsync_len = 4,
|
||||
.vsync_len = 4,
|
||||
.sync = FB_SYNC_OE_LOW_ACT,
|
||||
.vmode = FB_VMODE_NONINTERLACED,
|
||||
};
|
||||
|
||||
static struct fb_videomode cmo_mode = {
|
||||
.name = "CMO N101L6-L0D 1024x600",
|
||||
.refresh = 60,
|
||||
.xres = 1024,
|
||||
.yres = 600,
|
||||
.pixclock = 22800, /* ron: 44MHz display clock*/
|
||||
.left_margin = 80,
|
||||
.right_margin = 40,
|
||||
.upper_margin = 20,
|
||||
.lower_margin = 21,
|
||||
.hsync_len = 4,
|
||||
.vsync_len = 4,
|
||||
.sync = FB_SYNC_OE_LOW_ACT,
|
||||
.vmode = FB_VMODE_NONINTERLACED,
|
||||
};
|
||||
|
||||
struct lcd_panel_info {
|
||||
char manufacture[16];
|
||||
char product_name[16];
|
||||
struct fb_videomode *mode;
|
||||
u8 *regs;
|
||||
};
|
||||
|
||||
static struct lcd_panel_info pinfo[] = {
|
||||
{
|
||||
.manufacture = "AUO",
|
||||
.product_name = "B101AW02 V0",
|
||||
.mode = &auo_mode,
|
||||
.regs = mtl017_auo_tbl,
|
||||
},
|
||||
{
|
||||
.manufacture = "CPT",
|
||||
.product_name = "CLAA101NB03A",
|
||||
.mode = &cpt_mode,
|
||||
.regs = mtl017_cpt_tbl,
|
||||
},
|
||||
{
|
||||
.manufacture = "AUO",
|
||||
.product_name = "B101EW01",
|
||||
.mode = &auo_hires_mode,
|
||||
.regs = mtl017_auo_hires_tbl,
|
||||
},
|
||||
{
|
||||
.manufacture = "CMO",
|
||||
.product_name = "N101L6-L0D",
|
||||
.mode = &cmo_mode,
|
||||
.regs = mtl017_cmo_tbl,
|
||||
}
|
||||
};
|
||||
|
||||
//vv static void mtl017_find_videomode(struct mtl017_dev_data *mtl017)
|
||||
static void mtl017_find_videomode(mtl017_dev_data *mtl017)
|
||||
{
|
||||
int i;
|
||||
struct i2c_adapter *adp;
|
||||
struct fb_var_screeninfo var;
|
||||
int err;
|
||||
|
||||
adp = i2c_get_adapter(1);
|
||||
err = mtl017_read_edid(adp, mtl017->edid);
|
||||
|
||||
dump_edid(mtl017->edid);
|
||||
/* ron: use edid to parse screeninfo,
|
||||
but these parameters have some problem */
|
||||
memset(&var, 0, sizeof(var));
|
||||
fb_parse_edid(mtl017->edid, &var);
|
||||
dump_screeninfo(&var);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pinfo); i ++) {
|
||||
if(/* (memcmp(mtl017->edid + 0x5f, pinfo[i].manufacture, strlen(pinfo[i].manufacture)) == 0) && */
|
||||
(memcmp(mtl017->edid + 0x71, pinfo[i].product_name, strlen(pinfo[i].product_name)) == 0)) {
|
||||
printk("mtl017: Probe LCD Panel: %s %s\n",
|
||||
pinfo[i].manufacture,
|
||||
pinfo[i].product_name);
|
||||
mtl017->mode = pinfo[i].mode;
|
||||
mtl017->regs = pinfo[i].regs;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mtl017->regs = NULL;
|
||||
mtl017->mode = NULL;
|
||||
|
||||
}
|
||||
|
||||
static void lcd_init_fb(struct fb_info *info)
|
||||
{
|
||||
struct fb_var_screeninfo var;
|
||||
|
||||
memset(&var, 0, sizeof(var));
|
||||
|
||||
fb_videomode_to_var(&var, mtl017->mode);
|
||||
var.activate = FB_ACTIVATE_ALL;
|
||||
|
||||
acquire_console_sem();
|
||||
info->flags |= FBINFO_MISC_USEREVENT;
|
||||
fb_set_var(info, &var);
|
||||
fb_blank(info, FB_BLANK_UNBLANK);
|
||||
info->flags &= ~FBINFO_MISC_USEREVENT;
|
||||
release_console_sem();
|
||||
|
||||
|
||||
}
|
||||
|
||||
static int lcd_fb_event(struct notifier_block *nb, unsigned long val, void *v)
|
||||
{
|
||||
struct fb_event *event = v;
|
||||
|
||||
if (strcmp(event->info->fix.id, "DISP3 BG - DI1")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (val) {
|
||||
case FB_EVENT_FB_REGISTERED:
|
||||
lcd_init_fb(event->info);
|
||||
break;
|
||||
case FB_EVENT_BLANK:
|
||||
if (*((int *)event->data) == FB_BLANK_UNBLANK) {
|
||||
disp_power_on();
|
||||
} else {
|
||||
disp_power_off();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BL_BRIGHTNESS 0x01
|
||||
|
||||
static int lcd_bl_event(struct notifier_block *nb, unsigned long val, void *v)
|
||||
{
|
||||
int brightness = v;
|
||||
|
||||
switch (val) {
|
||||
case BL_BRIGHTNESS:
|
||||
if(brightness == 0) {
|
||||
disp_power_off();
|
||||
} else {
|
||||
disp_power_on();
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block fb_nb = {
|
||||
.notifier_call = lcd_fb_event,
|
||||
};
|
||||
|
||||
static struct notifier_block bl_nb = {
|
||||
.notifier_call = lcd_bl_event,
|
||||
};
|
||||
|
||||
/*!
|
||||
* This function is called whenever the SPI slave device is detected.
|
||||
*
|
||||
* @param spi the SPI slave device
|
||||
*
|
||||
* @return Returns 0 on SUCCESS and error on FAILURE.
|
||||
*/
|
||||
|
||||
static int __devinit mtl017_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct mxc_lcd_platform_data *plat = client->dev.platform_data;
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
//vv mtl017 = kzalloc(sizeof(*mtl017), GFP_KERNEL);
|
||||
mtl017 = (mtl017_dev_data*)kzalloc(sizeof(*mtl017), GFP_KERNEL);
|
||||
|
||||
if(!mtl017) {
|
||||
dev_err(&client->dev, "failed to allocate mtl017 device\n");
|
||||
retval = -ENOMEM;
|
||||
return retval;
|
||||
}
|
||||
|
||||
mtl017->suspending = 0;
|
||||
mtl017->client = client;
|
||||
if(plat) {
|
||||
mtl017->reset =
|
||||
plat->reset;
|
||||
mtl017->power_on_lcd =
|
||||
plat->power_on_lcd;
|
||||
mtl017->power_on_lvds =
|
||||
plat->power_on_lvds;
|
||||
mtl017->turn_on_backlight =
|
||||
plat->turn_on_backlight;
|
||||
mtl017->lvds_enable =
|
||||
plat->lvds_enable;
|
||||
}
|
||||
|
||||
/* mtl017->lock = SPIN_LOCK_UNLOCKED; */
|
||||
sema_init(&mtl017->sem, 1);
|
||||
|
||||
mtl017_find_videomode(mtl017);
|
||||
if(mtl017->mode == NULL)
|
||||
mtl017->mode = &auo_mode;
|
||||
if(mtl017->regs == NULL)
|
||||
mtl017->regs = mtl017_auo_tbl;
|
||||
|
||||
for (i = 0; i < num_registered_fb; i++) {
|
||||
if (strcmp(registered_fb[i]->fix.id, "DISP3 BG - DI1") == 0) {
|
||||
lcd_init_fb(registered_fb[i]);
|
||||
fb_show_logo(registered_fb[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
fb_register_client(&fb_nb);
|
||||
register_backlight_notifier(&bl_nb);
|
||||
|
||||
/* disp_power_on(); */
|
||||
schedule_work(&disp_on_work);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int __devexit mtl017_remove(struct i2c_client *client)
|
||||
{
|
||||
unregister_backlight_notifier(&bl_nb);
|
||||
fb_unregister_client(&fb_nb);
|
||||
disp_power_off();
|
||||
|
||||
kfree(mtl017);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtl017_suspend(struct i2c_client *client, pm_message_t message)
|
||||
{
|
||||
mtl017->suspending = 1;
|
||||
disp_power_off();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtl017_resume(struct i2c_client *client)
|
||||
{
|
||||
/* ron: because we turn off regulator, */
|
||||
/* so re-initialize MTL017 controller after suspending */
|
||||
mtl017->suspending = 0;
|
||||
disp_power_on();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mtl017_conf(u8 *reg_tbl)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
int retry = 5;
|
||||
|
||||
dev_dbg(&mtl017->client->dev, "Initializing MTL017 LVDS Controller\n");
|
||||
|
||||
// Writing configuration table.
|
||||
for (i = 0; i < REGMAP_LENGTH; i+=BLOCK_TX_SIZE) {
|
||||
retry:
|
||||
msleep(1);
|
||||
ret = i2c_smbus_write_i2c_block_data(mtl017->client, i, BLOCK_TX_SIZE, &(reg_tbl[i]));
|
||||
if (ret < 0) {
|
||||
printk(KERN_WARNING "MTL017 LVDS Controller Initialize Fail!\n");
|
||||
if(retry -- > 0)
|
||||
goto retry;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
static void disp_power_on(void)
|
||||
{
|
||||
if(mtl017->disp_on || mtl017->suspending)
|
||||
return;
|
||||
|
||||
down_interruptible(&mtl017->sem);
|
||||
|
||||
if(mtl017->mode == &auo_mode) {
|
||||
|
||||
|
||||
if(mtl017->power_on_lcd)
|
||||
mtl017->power_on_lcd(1);
|
||||
|
||||
msleep(10);
|
||||
|
||||
if(mtl017->lvds_enable)
|
||||
mtl017->lvds_enable(1);
|
||||
|
||||
msleep(5);
|
||||
|
||||
if(mtl017->power_on_lvds)
|
||||
mtl017->power_on_lvds(1);
|
||||
|
||||
msleep(5);
|
||||
|
||||
mtl017_conf(mtl017->regs);
|
||||
|
||||
msleep(200);
|
||||
|
||||
if(mtl017->turn_on_backlight)
|
||||
mtl017->turn_on_backlight(1);
|
||||
} else {
|
||||
if(mtl017->lvds_enable)
|
||||
mtl017->lvds_enable(-1);
|
||||
|
||||
if(mtl017->power_on_lcd)
|
||||
mtl017->power_on_lcd(1);
|
||||
|
||||
if(mtl017->power_on_lvds)
|
||||
mtl017->power_on_lvds(1);
|
||||
|
||||
mtl017_conf(mtl017->regs);
|
||||
|
||||
msleep(200);
|
||||
|
||||
if(mtl017->turn_on_backlight)
|
||||
mtl017->turn_on_backlight(1);
|
||||
}
|
||||
|
||||
mtl017->disp_on = 1;
|
||||
|
||||
up(&mtl017->sem);
|
||||
}
|
||||
|
||||
static void disp_power_off(void)
|
||||
{
|
||||
if(mtl017->disp_on == 0)
|
||||
return;
|
||||
|
||||
down_interruptible(&mtl017->sem);
|
||||
|
||||
if(mtl017->turn_on_backlight)
|
||||
mtl017->turn_on_backlight(0);
|
||||
|
||||
msleep(200);
|
||||
|
||||
if(mtl017->mode == &auo_mode) {
|
||||
if(mtl017->lvds_enable)
|
||||
mtl017->lvds_enable(0);
|
||||
}
|
||||
|
||||
if(mtl017->power_on_lvds)
|
||||
mtl017->power_on_lvds(0);
|
||||
|
||||
msleep(5);
|
||||
|
||||
if(mtl017->power_on_lcd)
|
||||
mtl017->power_on_lcd(0);
|
||||
|
||||
|
||||
mtl017->disp_on = 0;
|
||||
|
||||
up(&mtl017->sem);
|
||||
|
||||
}
|
||||
|
||||
static const struct i2c_device_id mtl017_id[] = {
|
||||
{ "mtl017", 0 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mtl017_id);
|
||||
|
||||
static struct i2c_driver mtl017_driver = {
|
||||
.driver = {
|
||||
.name = "mtl017",
|
||||
},
|
||||
.probe = mtl017_probe,
|
||||
.remove = mtl017_remove,
|
||||
.suspend = mtl017_suspend,
|
||||
.resume = mtl017_resume,
|
||||
.id_table = mtl017_id,
|
||||
};
|
||||
|
||||
static int __init mtl017_init(void)
|
||||
{
|
||||
return i2c_add_driver(&mtl017_driver);
|
||||
}
|
||||
|
||||
static void __exit mtl017_exit(void)
|
||||
{
|
||||
i2c_del_driver(&mtl017_driver);
|
||||
}
|
||||
|
||||
module_init(mtl017_init);
|
||||
module_exit(mtl017_exit);
|
||||
|
||||
MODULE_AUTHOR("Ron Lee <ron1_lee@pegatroncorp.com> Pegatron Corp.");
|
||||
MODULE_DESCRIPTION("MTL017 LVDS Controller driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
Reference in New Issue
Block a user