summaryrefslogtreecommitdiff
path: root/target/linux/xburst/patches-3.18
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/xburst/patches-3.18')
-rw-r--r--target/linux/xburst/patches-3.18/001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch25
-rw-r--r--target/linux/xburst/patches-3.18/002-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch48
-rw-r--r--target/linux/xburst/patches-3.18/003-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch109
-rw-r--r--target/linux/xburst/patches-3.18/004-ASoC-JZ4740-delay-activation-of-the-DAC-to-work-arou.patch38
-rw-r--r--target/linux/xburst/patches-3.18/005-RTC-JZ4740-Init-the-regulator-register-on-startup.patch60
-rw-r--r--target/linux/xburst/patches-3.18/006-Add-ili8960-lcd-driver.patch319
-rw-r--r--target/linux/xburst/patches-3.18/007-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch26
7 files changed, 625 insertions, 0 deletions
diff --git a/target/linux/xburst/patches-3.18/001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch b/target/linux/xburst/patches-3.18/001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch
new file mode 100644
index 0000000..180fa1d
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch
@@ -0,0 +1,25 @@
+From b0eb5175e0de3e5134a36a7da382d8811562af12 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 15 Mar 2011 12:49:15 +0100
+Subject: [PATCH 1/7] ubi: Read only the vid header instead of the whole page
+
+---
+ drivers/mtd/ubi/io.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
+index d361349..596b568 100644
+--- a/drivers/mtd/ubi/io.c
++++ b/drivers/mtd/ubi/io.c
+@@ -1009,7 +1009,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
+
+ p = (char *)vid_hdr - ubi->vid_hdr_shift;
+ read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
+- ubi->vid_hdr_alsize);
++ UBI_VID_HDR_SIZE + ubi->vid_hdr_shift);
+ if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err))
+ return read_err;
+
+--
+1.7.10.4
+
diff --git a/target/linux/xburst/patches-3.18/002-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch b/target/linux/xburst/patches-3.18/002-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch
new file mode 100644
index 0000000..bba9f0b
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/002-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch
@@ -0,0 +1,48 @@
+From 98d33db1c87e2447b9b203399d2f995e05ecdb52 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Sat, 26 Feb 2011 15:30:07 +0100
+Subject: [PATCH 2/7] NAND: Optimize NAND_ECC_HW_OOB_FIRST read
+
+Avoid sending unnecessary READ commands to the chip.
+---
+ drivers/mtd/nand/nand_base.c | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
+index 5b5c627..4c8d646 100644
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -1360,9 +1360,16 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
+ unsigned int max_bitflips = 0;
+
+ /* Read the OOB area first */
+- chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++ /* Read the OOB area first */
++ if (mtd->writesize > 512) {
++ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
++ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
++ } else {
++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
++ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++ }
+
+ for (i = 0; i < chip->ecc.total; i++)
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
+@@ -1575,7 +1582,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
+ __func__, buf);
+
+ read_retry:
+- chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
++ if (chip->ecc.mode != NAND_ECC_HW_OOB_FIRST) {
++ chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
++ }
+
+ /*
+ * Now read the page into the buffer. Absent an error,
+--
+1.7.10.4
+
diff --git a/target/linux/xburst/patches-3.18/003-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch b/target/linux/xburst/patches-3.18/003-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch
new file mode 100644
index 0000000..f3f6ca9
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/003-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch
@@ -0,0 +1,109 @@
+From 6031a240816d1c9a10f596d0648e586f6b878809 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 15 Mar 2011 12:33:41 +0100
+Subject: [PATCH 3/7] NAND: Add support for subpage reads for
+ NAND_ECC_HW_OOB_FIRST
+
+---
+ drivers/mtd/nand/nand_base.c | 77 +++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 76 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
+index 4c8d646..9809059 100644
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -1393,6 +1393,75 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
+ }
+
+ /**
++ * nand_read_subpage_hwecc_oob_first - [REPLACABLE] hw ecc based sub-page read function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @data_offs: offset of requested data within the page
++ * @readlen: data length
++ * @bufpoi: buffer to store read data
++ * @page: page number to read
++ *
++ * Hardware ECC for large page chips, require OOB to be read first.
++ * For this ECC mode, the write_page method is re-used from ECC_HW.
++ * These methods read/write ECC from the OOB area, unlike the
++ * ECC_HW_SYNDROME support with multiple ECC steps, follows the
++ * "infix ECC" scheme and reads/writes ECC from the data area, by
++ * overwriting the NAND manufacturer bad block markings.
++ */
++static int nand_read_subpage_hwecc_oob_first(struct mtd_info *mtd, struct nand_chip *chip,
++ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page)
++{
++ int start_step, end_step, num_steps;
++ uint32_t *eccpos = chip->ecc.layout->eccpos;
++ uint8_t *p;
++ int data_col_addr;
++ int eccsize = chip->ecc.size;
++ int eccbytes = chip->ecc.bytes;
++ uint8_t *ecc_code = chip->buffers->ecccode;
++ uint8_t *ecc_calc = chip->buffers->ecccalc;
++ int i;
++
++ /* Column address wihin the page aligned to ECC size */
++ start_step = data_offs / chip->ecc.size;
++ end_step = (data_offs + readlen - 1) / chip->ecc.size;
++ num_steps = end_step - start_step + 1;
++
++ data_col_addr = start_step * chip->ecc.size;
++
++ /* Read the OOB area first */
++ if (mtd->writesize > 512) {
++ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
++ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
++ } else {
++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
++ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++ chip->cmdfunc(mtd, NAND_CMD_READ0, data_col_addr, page);
++ }
++
++ for (i = 0; i < chip->ecc.total; i++)
++ ecc_code[i] = chip->oob_poi[eccpos[i]];
++
++ p = bufpoi + data_col_addr;
++
++ for (i = eccbytes * start_step; num_steps; num_steps--, i += eccbytes, p += eccsize) {
++ int stat;
++
++ chip->ecc.hwctl(mtd, NAND_ECC_READ);
++ chip->read_buf(mtd, p, eccsize);
++ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
++
++ stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
++ if (stat < 0)
++ mtd->ecc_stats.failed++;
++ else
++ mtd->ecc_stats.corrected += stat;
++ }
++
++ return 0;
++}
++
++/**
+ * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+@@ -3950,8 +4019,14 @@ int nand_scan_tail(struct mtd_info *mtd)
+ pr_warn("No ECC functions supplied; hardware ECC not possible\n");
+ BUG();
+ }
+- if (!ecc->read_page)
++
++ if (!ecc->read_page) {
+ ecc->read_page = nand_read_page_hwecc_oob_first;
++ if (!ecc->read_subpage) {
++ ecc->read_subpage = nand_read_subpage_hwecc_oob_first;
++ chip->options |= NAND_SUBPAGE_READ;
++ }
++ }
+
+ case NAND_ECC_HW:
+ /* Use standard hwecc read page function? */
+--
+1.7.10.4
+
diff --git a/target/linux/xburst/patches-3.18/004-ASoC-JZ4740-delay-activation-of-the-DAC-to-work-arou.patch b/target/linux/xburst/patches-3.18/004-ASoC-JZ4740-delay-activation-of-the-DAC-to-work-arou.patch
new file mode 100644
index 0000000..3de6ee0
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/004-ASoC-JZ4740-delay-activation-of-the-DAC-to-work-arou.patch
@@ -0,0 +1,38 @@
+From 1a1095927d224403af8ad57c354cc64521bf3081 Mon Sep 17 00:00:00 2001
+From: Paul Cercueil <paul@crapouillou.net>
+Date: Sat, 16 Jun 2012 19:36:31 +0200
+Subject: [PATCH 4/7] ASoC: JZ4740: delay activation of the DAC to work around
+ a sound bug.
+
+A proper fix of that bug would require a big rewrite of the driver,
+which (I hope) will be done eventually.
+---
+ sound/soc/codecs/jz4740.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
+index df7c01c..6939444 100644
+--- a/sound/soc/codecs/jz4740.c
++++ b/sound/soc/codecs/jz4740.c
+@@ -249,12 +249,15 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+- mask = JZ4740_CODEC_1_VREF_DISABLE |
+- JZ4740_CODEC_1_VREF_AMP_DISABLE |
+- JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
++ mask = JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
+ value = 0;
+
+ regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
++
++ msleep(500);
++ mask = JZ4740_CODEC_1_VREF_DISABLE |
++ JZ4740_CODEC_1_VREF_AMP_DISABLE;
++ regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, 0);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ /* The only way to clear the suspend flag is to reset the codec */
+--
+1.7.10.4
+
diff --git a/target/linux/xburst/patches-3.18/005-RTC-JZ4740-Init-the-regulator-register-on-startup.patch b/target/linux/xburst/patches-3.18/005-RTC-JZ4740-Init-the-regulator-register-on-startup.patch
new file mode 100644
index 0000000..2dd8858
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/005-RTC-JZ4740-Init-the-regulator-register-on-startup.patch
@@ -0,0 +1,60 @@
+From f05b1ecd7e4fde7e69320a4b7be461636e982991 Mon Sep 17 00:00:00 2001
+From: Paul Cercueil <paul@crapouillou.net>
+Date: Thu, 13 Sep 2012 00:09:20 +0200
+Subject: [PATCH 5/7] RTC: JZ4740: Init the "regulator" register on startup.
+
+This register controls the accuracy of the RTC. uC/OS-II use
+the RTC as a 100Hz clock, and writes a completely wrong value
+on that register, that we have to overwrite if we want a working
+real-time clock.
+
+Signed-off-by: Paul Cercueil <paul@crapouillou.net>
+---
+ drivers/rtc/rtc-jz4740.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c
+index 08f5160..5f027dc 100644
+--- a/drivers/rtc/rtc-jz4740.c
++++ b/drivers/rtc/rtc-jz4740.c
+@@ -15,6 +15,7 @@
+ */
+
+ #include <linux/io.h>
++#include <linux/clk.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+@@ -216,6 +217,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
+ struct jz4740_rtc *rtc;
+ uint32_t scratchpad;
+ struct resource *mem;
++ struct clk *rtc_clk;
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+@@ -263,6 +265,21 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
+ }
+ }
+
++ rtc_clk = clk_get(&pdev->dev, "rtc");
++ if (IS_ERR(rtc_clk)) {
++ dev_err(&pdev->dev, "Failed to get RTC clock\n");
++ return PTR_ERR(rtc_clk);
++ }
++
++ /* TODO: initialize the ADJC bits (25:16) to fine-tune
++ * the accuracy of the RTC */
++ ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_REGULATOR,
++ (clk_get_rate(rtc_clk) - 1) & 0xffff);
++ clk_put(rtc_clk);
++
++ if (ret)
++ dev_warn(&pdev->dev, "Could not update RTC regulator register\n");
++
+ return 0;
+ }
+
+--
+1.7.10.4
+
diff --git a/target/linux/xburst/patches-3.18/006-Add-ili8960-lcd-driver.patch b/target/linux/xburst/patches-3.18/006-Add-ili8960-lcd-driver.patch
new file mode 100644
index 0000000..906b996
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/006-Add-ili8960-lcd-driver.patch
@@ -0,0 +1,319 @@
+From 8741ead92bc93e66740237e51b88b8690ebcbba3 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Sun, 1 Aug 2010 21:19:40 +0200
+Subject: [PATCH 6/7] Add ili8960 lcd driver
+
+Includes the following changes from the jz-3.5 branch:
+- Use module_spi_driver
+- Use devm_kzalloc
+- Use kstrtoul
+
+Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
+---
+ drivers/video/backlight/Kconfig | 7 +
+ drivers/video/backlight/Makefile | 1 +
+ drivers/video/backlight/ili8960.c | 262 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 270 insertions(+)
+ create mode 100644 drivers/video/backlight/ili8960.c
+
+diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
+index 8d03924..14adcc6 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_ILI922X
+ tristate "ILI Technology ILI9221/ILI9222 support"
+ depends on SPI
+diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
+index fcd50b73..1f89974 100644
+--- a/drivers/video/backlight/Makefile
++++ b/drivers/video/backlight/Makefile
+@@ -5,6 +5,7 @@ obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o
+ obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o
+ obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o
+ obj-$(CONFIG_LCD_HX8357) += hx8357.o
++obj-$(CONFIG_LCD_ILI8960) += ili8960.o
+ obj-$(CONFIG_LCD_ILI922X) += ili922x.o
+ obj-$(CONFIG_LCD_ILI9320) += ili9320.o
+ obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o
+diff --git a/drivers/video/backlight/ili8960.c b/drivers/video/backlight/ili8960.c
+new file mode 100644
+index 0000000..61eb815
+--- /dev/null
++++ b/drivers/video/backlight/ili8960.c
+@@ -0,0 +1,262 @@
++/*
++ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
++ * 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 <linux/module.h>
++#include <linux/spi/spi.h>
++#include <linux/lcd.h>
++#include <linux/delay.h>
++
++struct ili8960 {
++ struct spi_device *spi;
++ struct lcd_device *lcd;
++ bool enabled;
++ unsigned int brightness;
++};
++
++#define ILI8960_REG_BRIGHTNESS 0x03
++#define ILI8960_REG_POWER 0x05
++#define ILI8960_REG_CONTRAST 0x0d
++
++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, ILI8960_REG_POWER, 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:
++ return 0;
++ }
++
++ return ili8960_programm_power(ili8960->spi, ili8960->enabled);
++}
++
++static int ili8960_early_set_power(struct lcd_device *lcd, int power)
++{
++ struct ili8960 *ili8960 = lcd_get_data(lcd);
++
++ switch (power) {
++ case FB_BLANK_UNBLANK:
++ return 0;
++ default:
++ ili8960->enabled = false;
++ break;
++ }
++
++ return ili8960_programm_power(ili8960->spi, ili8960->enabled);
++}
++
++static int ili8960_get_power(struct lcd_device *lcd)
++{
++ struct ili8960 *ili8960 = lcd_get_data(lcd);
++ return ili8960->enabled ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
++}
++
++static int ili8960_set_contrast(struct lcd_device *lcd, int contrast)
++{
++ struct ili8960 *ili8960 = lcd_get_data(lcd);
++
++ return ili8960_write_reg(ili8960->spi, ILI8960_REG_CONTRAST, contrast);
++}
++
++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, ILI8960_REG_BRIGHTNESS, brightness);
++
++ if (ret == 0)
++ ili8960->brightness = brightness;
++
++ return ret;
++}
++
++static ssize_t ili8960_show_brightness(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct lcd_device *ld = to_lcd_device(dev);
++ struct ili8960 *ili8960 = lcd_get_data(ld);
++
++ return sprintf(buf, "%u\n", ili8960->brightness);
++}
++
++static ssize_t ili8960_store_brightness(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct lcd_device *ld = to_lcd_device(dev);
++ struct ili8960 *ili8960 = lcd_get_data(ld);
++ unsigned long brightness;
++ int ret;
++
++ ret = kstrtoul(buf, 0, &brightness);
++ if (ret)
++ return ret;
++
++ if (brightness > 255)
++ 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,
++ .early_set_power = ili8960_early_set_power,
++ .get_power = ili8960_get_power,
++ .set_contrast = ili8960_set_contrast,
++ .set_mode = ili8960_set_mode,
++};
++
++static int ili8960_probe(struct spi_device *spi)
++{
++ int ret;
++ struct ili8960 *ili8960;
++
++ ili8960 = devm_kzalloc(&spi->dev, sizeof(*ili8960), GFP_KERNEL);
++ if (!ili8960)
++ return -ENOMEM;
++
++ spi->bits_per_word = 8;
++ spi->mode = SPI_MODE_3;
++
++ ret = spi_setup(spi);
++ if (ret) {
++ dev_err(&spi->dev, "Failed to setup spi\n");
++ return ret;
++ }
++
++ 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);
++ return ret;
++ }
++
++ 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;
++
++ spi_set_drvdata(spi, ili8960);
++
++ ili8960_write_reg(spi, 0x13, 0x01);
++
++ return 0;
++err_unregister_lcd:
++ lcd_device_unregister(ili8960->lcd);
++ return ret;
++}
++
++static int 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);
++ 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 = ili8960_remove,
++ .suspend = ili8960_suspend,
++ .resume = ili8960_resume,
++};
++module_spi_driver(ili8960_driver);
++
++MODULE_AUTHOR("Lars-Peter Clausen");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("LCD driver for Ilitek ili8960");
++MODULE_ALIAS("spi:ili8960");
+--
+1.7.10.4
+
diff --git a/target/linux/xburst/patches-3.18/007-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch b/target/linux/xburst/patches-3.18/007-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch
new file mode 100644
index 0000000..aa8a476
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/007-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch
@@ -0,0 +1,26 @@
+From 4371d60ae342c76708c4317e06fb7dcf0159c2f1 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Wed, 13 Oct 2010 01:17:24 +0200
+Subject: [PATCH 7/7] qi_lb60: Don't use 3-wire spi mode for the display for
+ now
+
+The spi_gpio driver does not support 3-wire mode.
+---
+ arch/mips/jz4740/board-qi_lb60.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
+index c454525..04cf890 100644
+--- a/arch/mips/jz4740/board-qi_lb60.c
++++ b/arch/mips/jz4740/board-qi_lb60.c
+@@ -312,7 +312,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,
+ },
+ };
+
+--
+1.7.10.4
+