From b44a22a536ffe3756d71b8535ee49870c107fa0f Mon Sep 17 00:00:00 2001 From: Kristoffer Ericson Date: Mon, 25 Oct 2010 21:21:54 +0200 Subject: Apply ben nanonote patches for qi-kernel as suggested by blizzard. Signed-off-by: Kristoffer Ericson --- arch/mips/include/asm/r4kcache.h | 231 ++++++++++++++++++++++++++++++++++ arch/mips/jz4740/board-qi_lb60.c | 27 +++- drivers/power/Kconfig | 7 ++ drivers/power/Makefile | 1 + drivers/power/gpio-charger.c | 185 +++++++++++++++++++++++++++ drivers/video/backlight/Kconfig | 7 ++ drivers/video/backlight/Makefile | 1 + drivers/video/backlight/ili8960.c | 250 +++++++++++++++++++++++++++++++++++++ include/linux/power/gpio-charger.h | 28 +++++ 9 files changed, 735 insertions(+), 2 deletions(-) create mode 100644 drivers/power/gpio-charger.c create mode 100644 drivers/video/backlight/ili8960.c create mode 100644 include/linux/power/gpio-charger.h diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h index 387bf59f1e375d..b50005600ed45a 100644 --- a/arch/mips/include/asm/r4kcache.h +++ b/arch/mips/include/asm/r4kcache.h @@ -17,6 +17,58 @@ #include #include +#ifdef CONFIG_JZRISC + +#define K0_TO_K1() \ +do { \ + unsigned long __k0_addr; \ + \ + __asm__ __volatile__( \ + "la %0, 1f\n\t" \ + "or %0, %0, %1\n\t" \ + "jr %0\n\t" \ + "nop\n\t" \ + "1: nop\n" \ + : "=&r"(__k0_addr) \ + : "r" (0x20000000) ); \ +} while(0) + +#define K1_TO_K0() \ +do { \ + unsigned long __k0_addr; \ + __asm__ __volatile__( \ + "nop;nop;nop;nop;nop;nop;nop\n\t" \ + "la %0, 1f\n\t" \ + "jr %0\n\t" \ + "nop\n\t" \ + "1: nop\n" \ + : "=&r" (__k0_addr)); \ +} while (0) + +#define INVALIDATE_BTB() \ +do { \ + unsigned long tmp; \ + __asm__ __volatile__( \ + ".set mips32\n\t" \ + "mfc0 %0, $16, 7\n\t" \ + "nop\n\t" \ + "ori %0, 2\n\t" \ + "mtc0 %0, $16, 7\n\t" \ + "nop\n\t" \ + : "=&r" (tmp)); \ +} while (0) + +#define SYNC_WB() __asm__ __volatile__ ("sync") + +#else /* CONFIG_JZRISC */ + +#define K0_TO_K1() do { } while (0) +#define K1_TO_K0() do { } while (0) +#define INVALIDATE_BTB() do { } while (0) +#define SYNC_WB() do { } while (0) + +#endif /* CONFIG_JZRISC */ + /* * This macro return a properly sign-extended address suitable as base address * for indexed cache operations. Two issues here: @@ -144,6 +196,7 @@ static inline void flush_icache_line_indexed(unsigned long addr) { __iflush_prologue cache_op(Index_Invalidate_I, addr); + INVALIDATE_BTB(); __iflush_epilogue } @@ -151,6 +204,7 @@ static inline void flush_dcache_line_indexed(unsigned long addr) { __dflush_prologue cache_op(Index_Writeback_Inv_D, addr); + SYNC_WB(); __dflush_epilogue } @@ -163,6 +217,7 @@ static inline void flush_icache_line(unsigned long addr) { __iflush_prologue cache_op(Hit_Invalidate_I, addr); + INVALIDATE_BTB(); __iflush_epilogue } @@ -170,6 +225,7 @@ static inline void flush_dcache_line(unsigned long addr) { __dflush_prologue cache_op(Hit_Writeback_Inv_D, addr); + SYNC_WB(); __dflush_epilogue } @@ -177,6 +233,7 @@ static inline void invalidate_dcache_line(unsigned long addr) { __dflush_prologue cache_op(Hit_Invalidate_D, addr); + SYNC_WB(); __dflush_epilogue } @@ -209,6 +266,7 @@ static inline void flush_scache_line(unsigned long addr) static inline void protected_flush_icache_line(unsigned long addr) { protected_cache_op(Hit_Invalidate_I, addr); + INVALIDATE_BTB(); } /* @@ -220,6 +278,7 @@ static inline void protected_flush_icache_line(unsigned long addr) static inline void protected_writeback_dcache_line(unsigned long addr) { protected_cache_op(Hit_Writeback_Inv_D, addr); + SYNC_WB(); } static inline void protected_writeback_scache_line(unsigned long addr) @@ -396,8 +455,10 @@ static inline void blast_##pfx##cache##lsize##_page_indexed(unsigned long page) __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16) __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16) __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16) +#ifndef CONFIG_JZRISC __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32) __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32) +#endif __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32) __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 64) __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64) @@ -405,12 +466,122 @@ __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64) __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128) __BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16) +#ifndef CONFIG_JZRISC __BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32) +#endif __BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16) __BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32) __BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64) __BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128) +#ifdef CONFIG_JZRISC + +static inline void blast_dcache32(void) +{ + unsigned long start = INDEX_BASE; + unsigned long end = start + current_cpu_data.dcache.waysize; + unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit; + unsigned long ws_end = current_cpu_data.dcache.ways << + current_cpu_data.dcache.waybit; + unsigned long ws, addr; + + for (ws = 0; ws < ws_end; ws += ws_inc) + for (addr = start; addr < end; addr += 0x400) + cache32_unroll32(addr|ws,Index_Writeback_Inv_D); + + SYNC_WB(); +} + +static inline void blast_dcache32_page(unsigned long page) +{ + unsigned long start = page; + unsigned long end = page + PAGE_SIZE; + + do { + cache32_unroll32(start,Hit_Writeback_Inv_D); + start += 0x400; + } while (start < end); + + SYNC_WB(); +} + +static inline void blast_dcache32_page_indexed(unsigned long page) +{ + unsigned long indexmask = current_cpu_data.dcache.waysize - 1; + unsigned long start = INDEX_BASE + (page & indexmask); + unsigned long end = start + PAGE_SIZE; + unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit; + unsigned long ws_end = current_cpu_data.dcache.ways << + current_cpu_data.dcache.waybit; + unsigned long ws, addr; + + for (ws = 0; ws < ws_end; ws += ws_inc) + for (addr = start; addr < end; addr += 0x400) + cache32_unroll32(addr|ws,Index_Writeback_Inv_D); + + SYNC_WB(); +} + +static inline void blast_icache32(void) +{ + unsigned long start = INDEX_BASE; + unsigned long end = start + current_cpu_data.icache.waysize; + unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; + unsigned long ws_end = current_cpu_data.icache.ways << + current_cpu_data.icache.waybit; + unsigned long ws, addr; + + K0_TO_K1(); + + for (ws = 0; ws < ws_end; ws += ws_inc) + for (addr = start; addr < end; addr += 0x400) + cache32_unroll32(addr|ws,Index_Invalidate_I); + + INVALIDATE_BTB(); + + K1_TO_K0(); +} + +static inline void blast_icache32_page(unsigned long page) +{ + unsigned long start = page; + unsigned long end = page + PAGE_SIZE; + + K0_TO_K1(); + + do { + cache32_unroll32(start,Hit_Invalidate_I); + start += 0x400; + } while (start < end); + + INVALIDATE_BTB(); + + K1_TO_K0(); +} + +static inline void blast_icache32_page_indexed(unsigned long page) +{ + unsigned long indexmask = current_cpu_data.icache.waysize - 1; + unsigned long start = INDEX_BASE + (page & indexmask); + unsigned long end = start + PAGE_SIZE; + unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; + unsigned long ws_end = current_cpu_data.icache.ways << + current_cpu_data.icache.waybit; + unsigned long ws, addr; + + K0_TO_K1(); + + for (ws = 0; ws < ws_end; ws += ws_inc) + for (addr = start; addr < end; addr += 0x400) + cache32_unroll32(addr|ws,Index_Invalidate_I); + + INVALIDATE_BTB(); + + K1_TO_K0(); +} + +#endif /* CONFIG_JZRISC */ + /* build blast_xxx_range, protected_blast_xxx_range */ #define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \ static inline void prot##blast_##pfx##cache##_range(unsigned long start, \ @@ -432,13 +603,73 @@ static inline void prot##blast_##pfx##cache##_range(unsigned long start, \ __##pfx##flush_epilogue \ } +#ifndef CONFIG_JZRISC __BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_) +#endif __BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_) +#ifndef CONFIG_JZRISC __BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_) __BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, ) +#endif __BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, ) /* blast_inv_dcache_range */ __BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, ) __BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, ) +#ifdef CONFIG_JZRISC + +static inline void protected_blast_dcache_range(unsigned long start, + unsigned long end) +{ + unsigned long lsize = cpu_dcache_line_size(); + unsigned long addr = start & ~(lsize - 1); + unsigned long aend = (end - 1) & ~(lsize - 1); + + while (1) { + protected_cache_op(Hit_Writeback_Inv_D, addr); + if (addr == aend) + break; + addr += lsize; + } + SYNC_WB(); +} + +static inline void protected_blast_icache_range(unsigned long start, + unsigned long end) +{ + unsigned long lsize = cpu_icache_line_size(); + unsigned long addr = start & ~(lsize - 1); + unsigned long aend = (end - 1) & ~(lsize - 1); + + K0_TO_K1(); + + while (1) { + protected_cache_op(Hit_Invalidate_I, addr); + if (addr == aend) + break; + addr += lsize; + } + INVALIDATE_BTB(); + + K1_TO_K0(); +} + +static inline void blast_dcache_range(unsigned long start, + unsigned long end) +{ + unsigned long lsize = cpu_dcache_line_size(); + unsigned long addr = start & ~(lsize - 1); + unsigned long aend = (end - 1) & ~(lsize - 1); + + while (1) { + cache_op(Hit_Writeback_Inv_D, addr); + if (addr == aend) + break; + addr += lsize; + } + SYNC_WB(); +} + +#endif /* CONFIG_JZRISC */ + #endif /* _ASM_R4KCACHE_H */ diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index 5742bb4d78f4db..62cb03ce3b4a2a 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -235,7 +236,7 @@ static const unsigned int qi_lb60_keypad_rows[] = { QI_LB60_GPIO_KEYIN(3), QI_LB60_GPIO_KEYIN(4), QI_LB60_GPIO_KEYIN(5), - QI_LB60_GPIO_KEYIN(7), + QI_LB60_GPIO_KEYIN(6), QI_LB60_GPIO_KEYIN8, }; @@ -309,7 +310,6 @@ static struct spi_board_info qi_lb60_spi_board_info[] = { .chip_select = 0, .bus_num = 1, .max_speed_hz = 30 * 1000, - .mode = SPI_3WIRE, }, }; @@ -396,6 +396,28 @@ static struct platform_device qi_lb60_pwm_beeper = { }, }; +/* charger */ +static char *qi_lb60_batteries[] = { + "battery", +}; + +static struct gpio_charger_platform_data qi_lb60_charger_pdata = { + .name = "usb", + .type = POWER_SUPPLY_TYPE_USB, + .gpio = JZ_GPIO_PORTD(28), + .gpio_active_low = 1, + .batteries = qi_lb60_batteries, + .num_batteries = ARRAY_SIZE(qi_lb60_batteries), +}; + +static struct platform_device qi_lb60_charger_device = { + .name = "gpio-charger", + .dev = { + .platform_data = &qi_lb60_charger_pdata, + }, +}; + + static struct platform_device *jz_platform_devices[] __initdata = { &jz4740_udc_device, &jz4740_mmc_device, @@ -410,6 +432,7 @@ static struct platform_device *jz_platform_devices[] __initdata = { &jz4740_adc_device, &qi_lb60_gpio_keys, &qi_lb60_pwm_beeper, + &qi_lb60_charger_device, }; static void __init board_gpio_setup(void) diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 07343568a12ec8..8e4ffacfbb0b74 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -166,4 +166,11 @@ config BATTERY_INTEL_MID Say Y here to enable the battery driver on Intel MID platforms. +config CHARGER_GPIO + tristate "GPIO charger" + depends on GPIOLIB + help + Say Y to include support for chargers indicating their status through + a GPIO pin. + endif # POWER_SUPPLY diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 10143aaf4ee3b4..2ca71ac88711ce 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -37,3 +37,4 @@ obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o +obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c new file mode 100644 index 00000000000000..b877f74ea25294 --- /dev/null +++ b/drivers/power/gpio-charger.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * Driver for chargers indicating their status through a GPIO pin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct gpio_charger { + const struct gpio_charger_platform_data *pdata; + + int irq; + + struct power_supply charger; +}; + +static irqreturn_t gpio_charger_irq(int irq, void *devid) +{ + struct power_supply *charger = devid; + power_supply_changed(charger); + + return IRQ_HANDLED; +} + +static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy) +{ + return container_of(psy, struct gpio_charger, charger); +} + +static int gpio_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, union power_supply_propval *val) +{ + struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy); + const struct gpio_charger_platform_data *pdata = gpio_charger->pdata; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = gpio_get_value(pdata->gpio); + val->intval ^= pdata->gpio_active_low; + break; + default: + return -EINVAL; + } + + return 0; +} + +static enum power_supply_property gpio_charger_properties[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static int __devinit gpio_charger_probe(struct platform_device *pdev) +{ + const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data; + struct gpio_charger *gpio_charger; + struct power_supply *charger; + int ret; + + if (!pdata) { + dev_err(&pdev->dev, "No platform data"); + return -EINVAL; + } + + gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL); + + charger = &gpio_charger->charger; + + charger->name = pdata->name; + charger->type = pdata->type; + charger->properties = gpio_charger_properties; + charger->num_properties = ARRAY_SIZE(gpio_charger_properties); + charger->get_property = gpio_charger_get_property; + charger->supplied_to = pdata->batteries; + charger->num_supplicants = pdata->num_batteries; + + if (gpio_is_valid(pdata->gpio)) { + ret = gpio_request(pdata->gpio, dev_name(&pdev->dev)); + if (ret) { + dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret); + goto err; + } + ret = gpio_direction_input(pdata->gpio); + if (ret) { + dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret); + goto err_gpio_free; + } + + gpio_charger->irq = gpio_to_irq(pdata->gpio); + if (gpio_charger->irq >= 0) { + ret = request_irq(gpio_charger->irq, gpio_charger_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + dev_name(&pdev->dev), charger); + if (ret) { + dev_warn(&pdev->dev, "Failed to request online gpio irq: %d\n", ret); + gpio_charger->irq = -1; + } + } + } + + gpio_charger->pdata = pdata; + + ret = power_supply_register(&pdev->dev, charger); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register power supply: %d\n", ret); + goto err_gpio_free; + } + + platform_set_drvdata(pdev, gpio_charger); + + return 0; + +err_gpio_free: + if (gpio_is_valid(pdata->gpio)) { + if (gpio_charger->irq >= 0) + free_irq(gpio_charger->irq, charger); + gpio_free(pdata->gpio); + } +err: + return ret; +} + +static int __devexit gpio_charger_remove(struct platform_device *pdev) +{ + struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); + const struct gpio_charger_platform_data *pdata = gpio_charger->pdata; + + power_supply_unregister(&gpio_charger->charger); + + if (gpio_is_valid(pdata->gpio)) { + if (gpio_charger->irq >= 0) + free_irq(gpio_charger->irq, &gpio_charger->charger); + gpio_free(pdata->gpio); + } + + platform_set_drvdata(pdev, NULL); + kfree(gpio_charger); + + return 0; +} + +static struct platform_driver gpio_charger_driver = { + .probe = gpio_charger_probe, + .remove = __devexit_p(gpio_charger_remove), + .driver = { + .name = "gpio-charger", + .owner = THIS_MODULE, + }, +}; + +static int __init gpio_charger_init(void) +{ + return platform_driver_register(&gpio_charger_driver); +} +module_init(gpio_charger_init); + +static void __exit gpio_charger_exit(void) +{ + platform_driver_unregister(&gpio_charger_driver); +} +module_exit(gpio_charger_exit); + +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("Driver for chargers indicating their status through a gpio"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:gpio-charger"); diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index e54a337227ea96..867f61f1d6b6a3 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -59,6 +59,13 @@ config LCD_LTV350QV The LTV350QV panel is present on all ATSTK1000 boards. +config LCD_ILI8960 + tristate "Ilitek ili8960 LCD driver" + depends on LCD_CLASS_DEVICE && SPI + default n + help + Driver for the Ilitek ili8960 LCD controller chip. + config LCD_ILI9320 tristate help diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 44c0f81ad85d96..af91083a026805 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o +obj-$(CONFIG_LCD_ILI8960) += ili8960.o obj-$(CONFIG_LCD_ILI9320) += ili9320.o obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o diff --git a/drivers/video/backlight/ili8960.c b/drivers/video/backlight/ili8960.c new file mode 100644 index 00000000000000..d20a556bbe3a20 --- /dev/null +++ b/drivers/video/backlight/ili8960.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2009-2010, Lars-Peter Clausen + * Driver for Ilitek ili8960 LCD + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + +struct ili8960 { + struct spi_device *spi; + struct lcd_device *lcd; + struct backlight_device *bl; + bool enabled; + int brightness; +}; + +static int ili8960_write_reg(struct spi_device *spi, uint8_t reg, + uint8_t data) +{ + uint8_t buf[2]; + buf[0] = ((reg & 0x40) << 1) | (reg & 0x3f); + buf[1] = data; + + return spi_write(spi, buf, sizeof(buf)); +} + +static int ili8960_programm_power(struct spi_device *spi, bool enabled) +{ + int ret; + + if (enabled) + mdelay(20); + + ret = ili8960_write_reg(spi, 0x5, enabled ? 0xc7 : 0xc6); + + if (!enabled) + mdelay(20); + + return ret; +} + +static int ili8960_set_power(struct lcd_device *lcd, int power) +{ + struct ili8960 *ili8960 = lcd_get_data(lcd); + + switch (power) { + case FB_BLANK_UNBLANK: + ili8960->enabled = true; + break; + default: + ili8960->enabled = false; + break; + } + + return ili8960_programm_power(ili8960->spi, ili8960->enabled); +} + +static int ili8960_get_power(struct lcd_device *lcd) +{ + return ili8960->enabled ? FB_BLANK_UNBLANK : FB_BLANK_BLANK; +} + +static int ili8960_set_contrast(struct lcd_device *lcd, int contrast) +{ + struct ili8960 *ili8960 = lcd_get_data(lcd); + ili8960_write_reg(ili8960->spi, 0x0d, contrast); + + return 0; +} + +static int ili8960_set_mode(struct lcd_device *lcd, struct fb_videomode *mode) +{ + if (mode->xres != 320 && mode->yres != 240) + return -EINVAL; + + return 0; +} + +static int ili8960_set_brightness(struct ili8960 *ili8960, int brightness) +{ + int ret; + ret = ili8960_write_reg(ili8960->spi, 0x3, brightness); + + if (ret == 0) + ili8960->brightness = brightness; + + return ret; +} + +static ssize_t ili8960_show_brightness(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", ili8960->brightness); +} + +static ssize_t ili8960_store_brightness(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *endp; + struct lcd_device *ld = to_lcd_device(dev); + struct ili8960 *ili8960 = lcd_get_data(ld); + int brightness = simple_strtoul(buf, &endp, 0); + + if (brightness > 255 || brightness < 0) + return -EINVAL; + + ili8960_set_brightness(ili8960, brightness); + + return count; +} + + +static DEVICE_ATTR(brightness, 0644, ili8960_show_brightness, + ili8960_store_brightness); + +static struct lcd_ops ili8960_lcd_ops = { + .set_power = ili8960_set_power, + .get_power = ili8960_get_power, + .set_contrast = ili8960_set_contrast, + .set_mode = ili8960_set_mode, +}; + +static int __devinit ili8960_probe(struct spi_device *spi) +{ + int ret; + struct ili8960 *ili8960; + + ili8960 = kmalloc(sizeof(*ili8960), GFP_KERNEL); + + spi->bits_per_word = 8; + spi->mode = SPI_MODE_3 | SPI_3WIRE; + + ret = spi_setup(spi); + if (ret) { + dev_err(&spi->dev, "Failed to setup spi\n"); + goto err_free_ili8960; + } + + ili8960->spi = spi; + + ili8960->lcd = lcd_device_register("ili8960-lcd", &spi->dev, ili8960, + &ili8960_lcd_ops); + + if (IS_ERR(ili8960->lcd)) { + ret = PTR_ERR(ili8960->lcd); + dev_err(&spi->dev, "Failed to register lcd device: %d\n", ret); + goto err_free_ili8960; + } + + ili8960->lcd->props.max_contrast = 255; + + ret = device_create_file(&ili8960->lcd->dev, &dev_attr_brightness); + if (ret) + goto err_unregister_lcd; + + ili8960_programm_power(ili8960->spi, true); + ili8960->enabled = true; + dev_set_drvdata(&spi->dev, ili8960); + +/* + ili8960_write_reg(spi, 0x13, 0x01); + ili8960_write_reg(spi, 0x5, 0xc7); +*/ + return 0; +err_unregister_lcd: + lcd_device_unregister(ili8960->lcd); +err_free_ili8960: + kfree(ili8960); + return ret; +} + +static int __devexit ili8960_remove(struct spi_device *spi) +{ + struct ili8960 *ili8960 = spi_get_drvdata(spi); + + device_remove_file(&ili8960->lcd->dev, &dev_attr_brightness); + lcd_device_unregister(ili8960->lcd); + + spi_set_drvdata(spi, NULL); + kfree(ili8960); + return 0; +} + +#ifdef CONFIG_PM + +static int ili8960_suspend(struct spi_device *spi, pm_message_t state) +{ + struct ili8960 *ili8960 = spi_get_drvdata(spi); + + if (ili8960->enabled) + ili8960_programm_power(ili8960->spi, false); + + return 0; +} + +static int ili8960_resume(struct spi_device *spi) +{ + struct ili8960 *ili8960 = spi_get_drvdata(spi); + + if (ili8960->enabled) + ili8960_programm_power(ili8960->spi, true); + + return 0; +} + +#else +#define ili8960_suspend NULL +#define ili8960_resume NULL +#endif + +static struct spi_driver ili8960_driver = { + .driver = { + .name = "ili8960", + .owner = THIS_MODULE, + }, + .probe = ili8960_probe, + .remove = __devexit_p(ili8960_remove), + .suspend = ili8960_suspend, + .resume = ili8960_resume, +}; + +static int __init ili8960_init(void) +{ + return spi_register_driver(&ili8960_driver); +} +module_init(ili8960_init); + +static void __exit ili8960_exit(void) +{ + spi_unregister_driver(&ili8960_driver); +} +module_exit(ili8960_exit) + +MODULE_AUTHOR("Lars-Peter Clausen"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LCD driver for Ilitek ili8960"); +MODULE_ALIAS("spi:ili8960"); diff --git a/include/linux/power/gpio-charger.h b/include/linux/power/gpio-charger.h new file mode 100644 index 00000000000000..95cdfc352fc5a9 --- /dev/null +++ b/include/linux/power/gpio-charger.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_POWER_GPIO_CHARGER_H__ +#define __LINUX_POWER_GPIO_CHARGER_H__ + +struct gpio_charger_platform_data { + const char *name; + enum power_supply_type type; + int gpio; + int gpio_active_low; + + char **batteries; + size_t num_batteries; +}; + +#endif -- cgit 1.2.3-korg