From 3a1ece5ea7ee9421f1e5bd4b892c8741dfc39306 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 3 Sep 2009 11:59:10 +0200 Subject: [PATCH] Add lcm driver. --- .../files-2.6.31/arch/mips/jz4740/platform.c | 65 ++++++- .../drivers/video/backlight/gpm940b0.c | 171 ++++++++++++++++++ .../linux/xburst/patches-2.6.31/103-lcm.patch | 26 +++ .../patches-2.6.31/400-spi-gpio-3wire.patch | 37 ++++ 4 files changed, 290 insertions(+), 9 deletions(-) create mode 100644 target/linux/xburst/files-2.6.31/drivers/video/backlight/gpm940b0.c create mode 100644 target/linux/xburst/patches-2.6.31/103-lcm.patch create mode 100644 target/linux/xburst/patches-2.6.31/400-spi-gpio-3wire.patch diff --git a/target/linux/xburst/files-2.6.31/arch/mips/jz4740/platform.c b/target/linux/xburst/files-2.6.31/arch/mips/jz4740/platform.c index 9718f81ec..62409edd0 100644 --- a/target/linux/xburst/files-2.6.31/arch/mips/jz4740/platform.c +++ b/target/linux/xburst/files-2.6.31/arch/mips/jz4740/platform.c @@ -16,8 +16,12 @@ #include #include #include +#include +#include +#include #include +#include /* OHCI (USB full speed host controller) */ static struct resource jz_usb_ohci_resources[] = { @@ -201,7 +205,7 @@ static struct jz_nand_platform_data jz_nand_platform_data = { .num_partitions = ARRAY_SIZE(qi_lb60_partitions), .partitions = qi_lb60_partitions, .ecc_layout = &qi_lb60_ecclayout, - .busy_gpio = 94, + .busy_gpio = 94, }; static struct platform_device jz_nand_device = { @@ -214,7 +218,7 @@ static struct platform_device jz_nand_device = { }; #define KEEP_UART_ALIVE -#define KEY_QI_QI KEY_F13 +#define KEY_QI_QI KEY_F13 #define KEY_QI_UPRED KEY_F14 #define KEY_QI_VOLUP KEY_F15 #define KEY_QI_VOLDOWN KEY_F16 @@ -285,8 +289,8 @@ static const uint32_t qi_lb60_keymap[] = { }; static const struct matrix_keymap_data qi_lb60_keymap_data = { - .keymap = qi_lb60_keymap, - .keymap_size = ARRAY_SIZE(qi_lb60_keymap), + .keymap = qi_lb60_keymap, + .keymap_size = ARRAY_SIZE(qi_lb60_keymap), }; static const unsigned int qi_lb60_keypad_cols[] = { @@ -296,12 +300,12 @@ static const unsigned int qi_lb60_keypad_cols[] = { static const unsigned int qi_lb60_keypad_rows[] = { 114, 115, 116, 117, 118, 119, 120, #ifndef KEEP_UART_ALIVE - 122, + 122, #endif }; static struct matrix_keypad_platform_data qi_lb60_pdata = { - .keymap_data = &qi_lb60_keymap_data, + .keymap_data = &qi_lb60_keymap_data, .col_gpios = qi_lb60_keypad_cols, .row_gpios = qi_lb60_keypad_rows, .num_col_gpios = ARRAY_SIZE(qi_lb60_keypad_cols), @@ -309,7 +313,7 @@ static struct matrix_keypad_platform_data qi_lb60_pdata = { .col_scan_delay_us = 10, .debounce_ms = 10, .wakeup = 1, - .active_low = 1, + .active_low = 1, }; static struct platform_device qi_lb60_keypad = { @@ -366,20 +370,63 @@ static struct platform_device qi_lb60_fb = { }, }; +struct spi_gpio_platform_data spigpio_platform_data = { + .sck = 32 * 2 + 23, + .mosi = 32 * 2 + 22, + .miso = 32 * 2 + 22, + .num_chipselect = 1, +}; + +static struct platform_device spigpio_device = { + .name = "spi_gpio", + .id = 1, + .dev = { + .platform_data = &spigpio_platform_data, + }, +}; + +static struct spi_board_info qi_lb60_spi_board_info[] = { + { + .modalias = "gpm940b0", + .controller_data = (void*)(32 * 2 + 21), + .chip_select = 0, + .bus_num = 1, + .max_speed_hz = 30 * 1000, + }, +}; + +static struct resource i2s_resources[] = { + [0] = { + .start = CPHYSADDR(AIC_BASE), + .end = CPHYSADDR(AIC_BASE) + 0x38 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device jz_i2s_device = { + .name = "jz4740-i2s", + .id = -1, + .num_resources = ARRAY_SIZE(i2s_resources), + .resource = i2s_resources, +}; + /* All */ static struct platform_device *jz_platform_devices[] __initdata = { &jz_usb_ohci_device, - &jz_lcd_device, &jz_usb_gdt_device, &jz_mmc_device, &jz_nand_device, &jz_i2c_device, - &qi_lb60_keypad, + &qi_lb60_keypad, &qi_lb60_fb, + &spigpio_device, + &jz_i2s_device, }; static int __init jz_platform_init(void) { + spi_register_board_info(qi_lb60_spi_board_info, + ARRAY_SIZE(qi_lb60_spi_board_info)); return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices)); } diff --git a/target/linux/xburst/files-2.6.31/drivers/video/backlight/gpm940b0.c b/target/linux/xburst/files-2.6.31/drivers/video/backlight/gpm940b0.c new file mode 100644 index 000000000..db250ab7f --- /dev/null +++ b/target/linux/xburst/files-2.6.31/drivers/video/backlight/gpm940b0.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * JZ4720/JZ4740 SoC LCD framebuffer driver + * + * 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 + +struct gpm940b0 { + struct spi_device *spi; + struct lcd_device *lcd; + struct backlight_device *bl; +}; + +static int gpm940b0_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 gpm940b0_set_power(struct lcd_device *lcd, int power) +{ + struct gpm940b0 *gpm940b0 = lcd_get_data(lcd); + + switch (power) { + case FB_BLANK_UNBLANK: + gpm940b0_write_reg(gpm940b0->spi, 0x05, 0x5f); + break; + default: + gpm940b0_write_reg(gpm940b0->spi, 0x05, 0x5e); + break; + } + return 0; +} + +static int gpm940b0_set_contrast(struct lcd_device *lcd, int contrast) +{ + struct gpm940b0 *gpm940b0 = lcd_get_data(lcd); + gpm940b0_write_reg(gpm940b0->spi, 0x0d, contrast); + return 0; +} + +static int gpm940b0_set_mode(struct lcd_device *lcd, struct fb_videomode *mode) +{ + if (mode->xres != 320 && mode->yres != 240) + return -EINVAL; + + return 0; +} + +int gpm940b0_bl_update_status(struct backlight_device *bl) +{ + struct gpm940b0 *gpm940b0 = bl_get_data(bl); + + /* The datasheet suggest that this is not possible on the giantplus module + gpm940b0_write_reg(gpm940b0->spi, 21, bl->props.brightness);*/ + + return 0; +} + +static struct lcd_ops gpm940b0_lcd_ops = { + .set_power = gpm940b0_set_power, + .set_contrast = gpm940b0_set_contrast, + .set_mode = gpm940b0_set_mode, +}; + +static struct backlight_ops gpm940b0_bl_ops = { +/* .get_brightness = gpm940b0_bl_get_brightness,*/ + .update_status = gpm940b0_bl_update_status, +}; + +static int __devinit gpm940b0_probe(struct spi_device *spi) +{ + int ret; + struct gpm940b0 *gpm940b0; + + gpm940b0 = kmalloc(sizeof(*gpm940b0), GFP_KERNEL); + + spi->bits_per_word = 8; + + ret = spi_setup(spi); + if (ret) { + dev_err(&spi->dev, "Failed to setup spi\n"); + goto err_free_gpm940b0; + } + + gpm940b0->spi = spi; + + gpm940b0->lcd = lcd_device_register("gpm940b0-lcd", &spi->dev, gpm940b0, + &gpm940b0_lcd_ops); + + if (IS_ERR(gpm940b0->lcd)) { + ret = PTR_ERR(gpm940b0->lcd); + dev_err(&spi->dev, "Failed to register lcd device: %d\n", ret); + goto err_free_gpm940b0; + } + + gpm940b0->lcd->props.max_contrast = 255; + + gpm940b0->bl = backlight_device_register("gpm940b0-bl", &spi->dev, gpm940b0, + &gpm940b0_bl_ops); + + if (IS_ERR(gpm940b0->bl)) { + ret = PTR_ERR(gpm940b0->bl); + dev_err(&spi->dev, "Failed to register backlight device: %d\n", ret); + gpm940b0->bl = NULL; + } else { + gpm940b0->bl->props.max_brightness = 15; + gpm940b0->bl->props.brightness = 0; + gpm940b0->bl->props.power = FB_BLANK_UNBLANK; + } + + return 0; +err_free_gpm940b0: + return ret; +} + +static int __devexit gpm940b0_remove(struct spi_device *spi) +{ + struct gpm940b0 *gpm940b0 = spi_get_drvdata(spi); + if (gpm940b0->bl) + backlight_device_unregister(gpm940b0->bl); + + lcd_device_unregister(gpm940b0->lcd); + + spi_set_drvdata(spi, NULL); + kfree(gpm940b0); + return 0; +} + +static struct spi_driver gpm940b0_driver = { + .driver = { + .name = "gpm940b0", + .owner = THIS_MODULE, + }, + .probe = gpm940b0_probe, + .remove = __devexit_p(gpm940b0_remove), +}; + +static int __init gpm940b0_init(void) +{ + return spi_register_driver(&gpm940b0_driver); +} +module_init(gpm940b0_init); + +static void __exit gpm940b0_exit(void) +{ + return spi_unregister_driver(&gpm940b0_driver); +} +module_exit(gpm940b0_exit) + +MODULE_AUTHOR("Lars-Peter Clausen"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("LCD and backlight controll for Giantplus GPM940B0"); +MODULE_ALIAS("i2c:gpm940b0"); diff --git a/target/linux/xburst/patches-2.6.31/103-lcm.patch b/target/linux/xburst/patches-2.6.31/103-lcm.patch new file mode 100644 index 000000000..33ca8675e --- /dev/null +++ b/target/linux/xburst/patches-2.6.31/103-lcm.patch @@ -0,0 +1,26 @@ +--- /opt/Projects/linux-2.6/drivers/video/backlight/Makefile 2009-09-02 16:48:24.000000000 +0200 ++++ ./Makefile 2009-08-24 13:51:57.000000000 +0200 +@@ -9,6 +9,7 @@ + obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o + obj-$(CONFIG_LCD_TDO24M) += tdo24m.o + obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o ++obj-$(CONFIG_LCD_GPM940B0) += gpm940b0.o + + obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o + obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o +--- /opt/Projects/linux-2.6/drivers/video/backlight/Kconfig 2009-09-02 16:48:24.000000000 +0200 ++++ ./Kconfig 2009-08-24 13:49:46.000000000 +0200 +@@ -93,6 +93,13 @@ + If you have an HP Jornada 700 series handheld (710/720/728) + say Y to enable LCD control driver. + ++config LCD_GPM940B0 ++ tristate "Giantplus GPM940B0 LCD and backlight driver" ++ depends on LCD_CLASS_DEVICE && BACKLIGHT_CLASS_DEVICE && SPI ++ default n ++ help ++ LCD and backlight driver for the Giantplus GPM940B0 LCD module. ++ + # + # Backlight + # diff --git a/target/linux/xburst/patches-2.6.31/400-spi-gpio-3wire.patch b/target/linux/xburst/patches-2.6.31/400-spi-gpio-3wire.patch new file mode 100644 index 000000000..84d6b2456 --- /dev/null +++ b/target/linux/xburst/patches-2.6.31/400-spi-gpio-3wire.patch @@ -0,0 +1,37 @@ +--- /opt/Projects/linux-2.6/drivers/spi/spi_gpio.c 2009-09-03 11:56:54.000000000 +0200 ++++ ./spi_gpio.c 2009-08-24 17:00:21.000000000 +0200 +@@ -254,9 +254,11 @@ + if (value) + goto done; + +- value = spi_gpio_alloc(SPI_MISO_GPIO, label, true); +- if (value) +- goto free_mosi; ++ if (SPI_MISO_GPIO != SPI_MOSI_GPIO) { ++ value = spi_gpio_alloc(SPI_MISO_GPIO, label, true); ++ if (value) ++ goto free_mosi; ++ } + + value = spi_gpio_alloc(SPI_SCK_GPIO, label, false); + if (value) +@@ -319,7 +321,8 @@ + if (status < 0) { + spi_master_put(spi_gpio->bitbang.master); + gpio_free: +- gpio_free(SPI_MISO_GPIO); ++ if (SPI_MISO_GPIO != SPI_MOSI_GPIO) ++ gpio_free(SPI_MISO_GPIO); + gpio_free(SPI_MOSI_GPIO); + gpio_free(SPI_SCK_GPIO); + spi_master_put(master); +@@ -343,7 +346,8 @@ + + platform_set_drvdata(pdev, NULL); + +- gpio_free(SPI_MISO_GPIO); ++ if (SPI_MISO_GPIO != SPI_MOSI_GPIO) ++ gpio_free(SPI_MISO_GPIO); + gpio_free(SPI_MOSI_GPIO); + gpio_free(SPI_SCK_GPIO); +