From 71b7d633e566195b065e09e97164bec046ca7b6d Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@dominion.thruhere.net>
Date: Thu, 7 Oct 2010 09:25:45 +0200
-Subject: [PATCH 01/11] ARM: OMAP: Power on EHCI, serial, camera and DVI on beagleboard-xM
+Subject: [PATCH 01/29] ARM: OMAP: Power on EHCI, serial, camera and DVI on beagleboard-xM
Signed-off-by: Koen Kooi <koen@beagleboard.org>
---
From 60e119550f5a782c512c19d86a08313ae2ffa876 Mon Sep 17 00:00:00 2001
From: Robert Nelson <robertcnelson@gmail.com>
Date: Tue, 9 Nov 2010 08:34:55 -0600
-Subject: [PATCH 02/11] omap: Beagle: detect new xM revision B
+Subject: [PATCH 02/29] omap: Beagle: detect new xM revision B
The xM B uses a DM3730 ES1.1 over the ES1.0 on xM A's, no other board changes.
From 72657e1ec88da91b772c7158c4c987b29d274ece Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@dominion.thruhere.net>
Date: Wed, 6 Oct 2010 10:19:34 +0200
-Subject: [PATCH 03/11] ARM: OMAP: beagleboard: Add infrastructure to do fixups based on expansionboard name passed by u-boot
+Subject: [PATCH 03/29] ARM: OMAP: beagleboard: Add infrastructure to do fixups based on expansionboard name passed by u-boot
Add support for Tincantools Zippy and Zippy2 expansionboards as well
From 6f80e6f5205a429951244e690952f192b78d15a8 Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@dominion.thruhere.net>
Date: Sun, 5 Dec 2010 13:25:00 +0100
-Subject: [PATCH 04/11] ARM: OMAP: beagleboard: pre-export GPIOs to userspace when using a Tincantools trainerboard
+Subject: [PATCH 04/29] ARM: OMAP: beagleboard: pre-export GPIOs to userspace when using a Tincantools trainerboard
This really needs a for loop, patches welcome
From ea2b3d705162f8a1622e60da27b2b5b31ad3abe7 Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@dominion.thruhere.net>
Date: Mon, 8 Mar 2010 14:38:31 +0100
-Subject: [PATCH 05/11] modedb.c: add proper 720p60 mode
+Subject: [PATCH 05/29] modedb.c: add proper 720p60 mode
Signed-off-by: Koen Kooi <koen@beagleboard.org>
---
From 2036f80d16c1df22b00953f4d2e2457eef00a82d Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Mon, 4 Jan 2010 19:20:25 -0800
-Subject: [PATCH 06/11] mmc: don't display single block read console messages
+Subject: [PATCH 06/29] mmc: don't display single block read console messages
mmc: don't display single block read console messages
---
From 793eb265af99817165bc03ae96adaaf6e4860dca Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Mon, 26 Apr 2010 11:17:26 -0700
-Subject: [PATCH 07/11] MTD: silence ecc errors on mtdblock0
+Subject: [PATCH 07/29] MTD: silence ecc errors on mtdblock0
mtdblock0 is the x-load partition, which uses hw ecc
this confuses linux, which uses sw ecc
From 31949867bace7945acd3ec10c822e6988613aed7 Mon Sep 17 00:00:00 2001
From: Mike Galbraith <efault@gmx.de>
Date: Fri, 19 Nov 2010 12:52:42 +0100
-Subject: [PATCH 08/11] Miracle patch
+Subject: [PATCH 08/29] Miracle patch
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From 1beed5ee3301a9756c8cd2672d487c568c562e81 Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@dominion.thruhere.net>
Date: Tue, 23 Nov 2010 11:40:20 +0100
-Subject: [PATCH 09/11] ARM: OMAP: add omap_rev_* macros
+Subject: [PATCH 09/29] ARM: OMAP: add omap_rev_* macros
This is just to make the SGX modules build that depend on omap_rev_lt_3_0
From f051874f829ed2e2462c0e64c28e28bd6f942f2d Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Mon, 10 May 2010 20:44:09 -0700
-Subject: [PATCH 10/11] OMAP: DSS2: enable hsclk in dsi_pll_init for OMAP36XX
+Subject: [PATCH 10/29] OMAP: DSS2: enable hsclk in dsi_pll_init for OMAP36XX
Signed-off-by: Koen Kooi <koen@beagleboard.org>
---
From 18333339fe5e104c2ddfb2688989a15df0e0f94c Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@beagleboard.org>
Date: Mon, 20 Dec 2010 11:57:56 +0100
-Subject: [PATCH 11/11] omap3: beagleboard: add WIP support for beagleboardtoys WL12xx board
+Subject: [PATCH 11/29] omap3: beagleboard: add WIP support for beagleboardtoys WL12xx board
Based on a patch by Luciano Coelho <luciano.coelho@nokia.com>
--- /dev/null
+From 43b87f69e82217aff2a966559bdf28dcfedc2c8e Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <sakoman@gmail.com>
+Date: Tue, 15 Dec 2009 15:17:44 -0800
+Subject: [PATCH 12/29] drivers: net: smsc911x: return ENODEV if device is not found
+
+Signed-off-by: Steve Sakoman <sakoman@gmail.com>
+---
+ drivers/net/smsc911x.c | 4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
+index 64bfdae..ba2a00e 100644
+--- a/drivers/net/smsc911x.c
++++ b/drivers/net/smsc911x.c
+@@ -2019,8 +2019,10 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
+ }
+
+ retval = smsc911x_init(dev);
+- if (retval < 0)
++ if (retval < 0) {
++ retval = -ENODEV;
+ goto out_unmap_io_3;
++ }
+
+ /* configure irq polarity and type before connecting isr */
+ if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH)
+--
+1.6.6.1
+
--- /dev/null
+From 43b7984021e30a9aa9b97c2cf9a9ceb806372709 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <sakoman@gmail.com>
+Date: Tue, 15 Dec 2009 15:24:10 -0800
+Subject: [PATCH 13/29] drivers: input: touchscreen: ads7846: return ENODEV if device is not found
+
+Signed-off-by: Steve Sakoman <sakoman@gmail.com>
+---
+ drivers/input/touchscreen/ads7846.c | 13 ++++++++++---
+ 1 files changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
+index 14ea54b..c775e38 100644
+--- a/drivers/input/touchscreen/ads7846.c
++++ b/drivers/input/touchscreen/ads7846.c
+@@ -1325,11 +1325,18 @@ static int __devinit ads7846_probe(struct spi_device *spi)
+ * the touchscreen, in case it's not connected.
+ */
+ if (ts->model == 7845)
+- ads7845_read12_ser(&spi->dev, PWRDOWN);
++ err = ads7845_read12_ser(&spi->dev, PWRDOWN);
+ else
+- (void) ads7846_read12_ser(&spi->dev,
++ err = ads7846_read12_ser(&spi->dev,
+ READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+
++ /* if sample is all 0's or all 1's then there is no device on spi */
++ if ( (err == 0x000) || (err == 0xfff)) {
++ dev_info(&spi->dev, "no device detected, test read result was 0x%08X\n", err);
++ err = -ENODEV;
++ goto err_free_irq;
++ }
++
+ err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
+ if (err)
+ goto err_remove_hwmon;
+@@ -1353,7 +1360,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
+ err_put_regulator:
+ regulator_put(ts->reg);
+ err_free_gpio:
+- if (ts->gpio_pendown != -1)
++ if (!ts->get_pendown_state && ts->gpio_pendown != -1)
+ gpio_free(ts->gpio_pendown);
+ err_cleanup_filter:
+ if (ts->filter_cleanup)
+--
+1.6.6.1
+
--- /dev/null
+From ebb70888ec3601534601d7524212fbefa24d679e Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 17 Dec 2009 12:45:20 -0800
+Subject: [PATCH 14/29] ASoC: enable audio capture by default for twl4030
+
+---
+ sound/soc/codecs/twl4030.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
+index cbebec6..430cd10 100644
+--- a/sound/soc/codecs/twl4030.c
++++ b/sound/soc/codecs/twl4030.c
+@@ -56,8 +56,8 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
+ 0x00, /* REG_OPTION (0x2) */
+ 0x00, /* REG_UNKNOWN (0x3) */
+ 0x00, /* REG_MICBIAS_CTL (0x4) */
+- 0x00, /* REG_ANAMICL (0x5) */
+- 0x00, /* REG_ANAMICR (0x6) */
++ 0x34, /* REG_ANAMICL (0x5) */
++ 0x14, /* REG_ANAMICR (0x6) */
+ 0x00, /* REG_AVADC_CTL (0x7) */
+ 0x00, /* REG_ADCMICSEL (0x8) */
+ 0x00, /* REG_DIGMIXING (0x9) */
+--
+1.6.6.1
+
--- /dev/null
+From 0bedf8e81896a69ba77e9066ad9545412fd53cf8 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Sat, 23 Jan 2010 06:26:54 -0800
+Subject: [PATCH 15/29] MFD: enable madc clock
+
+---
+ drivers/mfd/twl-core.c | 8 ++++++++
+ include/linux/i2c/twl.h | 1 +
+ 2 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
+index 35275ba..5aa7358 100644
+--- a/drivers/mfd/twl-core.c
++++ b/drivers/mfd/twl-core.c
+@@ -208,6 +208,11 @@
+
+ /* Few power values */
+ #define R_CFG_BOOT 0x05
++#define R_GPBR1 0x0C
++
++/* MADC clock values for R_GPBR1 */
++#define MADC_HFCLK_EN 0x80
++#define DEFAULT_MADC_CLK_EN 0x10
+
+ /* some fields in R_CFG_BOOT */
+ #define HFCLK_FREQ_19p2_MHZ (1 << 0)
+@@ -929,6 +934,9 @@ static void clocks_init(struct device *dev,
+
+ e |= unprotect_pm_master();
+ /* effect->MADC+USB ck en */
++ if (twl_has_madc())
++ e |= twl_i2c_write_u8(TWL_MODULE_INTBR,
++ MADC_HFCLK_EN | DEFAULT_MADC_CLK_EN, R_GPBR1);
+ e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
+ e |= protect_pm_master();
+
+diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
+index c760991..cfdfdd3 100644
+--- a/include/linux/i2c/twl.h
++++ b/include/linux/i2c/twl.h
+@@ -74,6 +74,7 @@
+
+ #define TWL_MODULE_USB TWL4030_MODULE_USB
+ #define TWL_MODULE_AUDIO_VOICE TWL4030_MODULE_AUDIO_VOICE
++#define TWL_MODULE_INTBR TWL4030_MODULE_INTBR
+ #define TWL_MODULE_PIH TWL4030_MODULE_PIH
+ #define TWL_MODULE_MADC TWL4030_MODULE_MADC
+ #define TWL_MODULE_MAIN_CHARGE TWL4030_MODULE_MAIN_CHARGE
+--
+1.6.6.1
+
--- /dev/null
+From ea45cc880d407e9747dafa0efe5ab17ffb5e42d5 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 17 Dec 2009 14:19:34 -0800
+Subject: [PATCH 16/29] MFD: add twl4030 madc driver
+
+---
+ drivers/mfd/Kconfig | 21 ++
+ drivers/mfd/Makefile | 1 +
+ drivers/mfd/twl4030-madc.c | 537 ++++++++++++++++++++++++++++++++++++++
+ include/linux/i2c/twl4030-madc.h | 130 +++++++++
+ 4 files changed, 689 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mfd/twl4030-madc.c
+ create mode 100644 include/linux/i2c/twl4030-madc.h
+
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 3a1493b..26ca160 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -186,6 +186,27 @@ config TWL4030_CODEC
+ select MFD_CORE
+ default n
+
++config TWL4030_MADC
++ tristate "TWL4030 MADC Driver"
++ depends on TWL4030_CORE
++ help
++ The TWL4030 Monitoring ADC driver enables the host
++ processor to monitor analog signals using analog-to-digital
++ conversions on the input source. TWL4030 MADC provides the
++ following features:
++ - Single 10-bit ADC with successive approximation register (SAR) conversion;
++ - Analog multiplexer for 16 inputs;
++ - Seven (of the 16) inputs are freely available;
++ - Battery voltage monitoring;
++ - Concurrent conversion request management;
++ - Interrupt signal to Primary Interrupt Handler;
++ - Averaging feature;
++ - Selective enable/disable of the averaging feature.
++
++ Say 'y' here to statically link this module into the kernel or 'm'
++ to build it as a dinamically loadable module. The module will be
++ called twl4030-madc.ko
++
+ config TWL6030_PWM
+ tristate "TWL6030 PWM (Pulse Width Modulator) Support"
+ depends on TWL4030_CORE
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index f54b365..8c4ccb2 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -39,6 +39,7 @@ obj-$(CONFIG_MENELAUS) += menelaus.o
+ obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
+ obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
+ obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o
++obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
+ obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
+
+ obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
+diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
+new file mode 100644
+index 0000000..4adf880
+--- /dev/null
++++ b/drivers/mfd/twl4030-madc.c
+@@ -0,0 +1,537 @@
++/*
++ * TWL4030 MADC module driver
++ *
++ * Copyright (C) 2008 Nokia Corporation
++ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
++ *
++ * This program 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 program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * 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., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ *
++ */
++
++#include <linux/delay.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/i2c/twl.h>
++#include <linux/i2c/twl4030-madc.h>
++
++#include <asm/uaccess.h>
++
++#define TWL4030_MADC_PFX "twl4030-madc: "
++
++struct twl4030_madc_data {
++ struct device *dev;
++ struct mutex lock;
++ struct work_struct ws;
++ struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
++ int imr;
++ int isr;
++};
++
++static struct twl4030_madc_data *the_madc;
++
++static
++const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
++ [TWL4030_MADC_RT] = {
++ .sel = TWL4030_MADC_RTSELECT_LSB,
++ .avg = TWL4030_MADC_RTAVERAGE_LSB,
++ .rbase = TWL4030_MADC_RTCH0_LSB,
++ },
++ [TWL4030_MADC_SW1] = {
++ .sel = TWL4030_MADC_SW1SELECT_LSB,
++ .avg = TWL4030_MADC_SW1AVERAGE_LSB,
++ .rbase = TWL4030_MADC_GPCH0_LSB,
++ .ctrl = TWL4030_MADC_CTRL_SW1,
++ },
++ [TWL4030_MADC_SW2] = {
++ .sel = TWL4030_MADC_SW2SELECT_LSB,
++ .avg = TWL4030_MADC_SW2AVERAGE_LSB,
++ .rbase = TWL4030_MADC_GPCH0_LSB,
++ .ctrl = TWL4030_MADC_CTRL_SW2,
++ },
++};
++
++static int twl4030_madc_read(struct twl4030_madc_data *madc, u8 reg)
++{
++ int ret;
++ u8 val;
++
++ ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, reg);
++ if (ret) {
++ dev_dbg(madc->dev, "unable to read register 0x%X\n", reg);
++ return ret;
++ }
++
++ return val;
++}
++
++static void twl4030_madc_write(struct twl4030_madc_data *madc, u8 reg, u8 val)
++{
++ int ret;
++
++ ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, reg);
++ if (ret)
++ dev_err(madc->dev, "unable to write register 0x%X\n", reg);
++}
++
++static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
++{
++ u8 msb, lsb;
++
++ /* For each ADC channel, we have MSB and LSB register pair. MSB address
++ * is always LSB address+1. reg parameter is the addr of LSB register */
++ msb = twl4030_madc_read(madc, reg + 1);
++ lsb = twl4030_madc_read(madc, reg);
++
++ return (int)(((msb << 8) | lsb) >> 6);
++}
++
++static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
++ u8 reg_base, u16 channels, int *buf)
++{
++ int count = 0;
++ u8 reg, i;
++
++ if (unlikely(!buf))
++ return 0;
++
++ for (i = 0; i < TWL4030_MADC_MAX_CHANNELS; i++) {
++ if (channels & (1<<i)) {
++ reg = reg_base + 2*i;
++ buf[i] = twl4030_madc_channel_raw_read(madc, reg);
++ count++;
++ }
++ }
++ return count;
++}
++
++static void twl4030_madc_enable_irq(struct twl4030_madc_data *madc, int id)
++{
++ u8 val;
++
++ val = twl4030_madc_read(madc, madc->imr);
++ val &= ~(1 << id);
++ twl4030_madc_write(madc, madc->imr, val);
++}
++
++static void twl4030_madc_disable_irq(struct twl4030_madc_data *madc, int id)
++{
++ u8 val;
++
++ val = twl4030_madc_read(madc, madc->imr);
++ val |= (1 << id);
++ twl4030_madc_write(madc, madc->imr, val);
++}
++
++static irqreturn_t twl4030_madc_irq_handler(int irq, void *_madc)
++{
++ struct twl4030_madc_data *madc = _madc;
++ u8 isr_val, imr_val;
++ int i;
++
++#ifdef CONFIG_LOCKDEP
++ /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
++ * we don't want and can't tolerate. Although it might be
++ * friendlier not to borrow this thread context...
++ */
++ local_irq_enable();
++#endif
++
++ /* Use COR to ack interrupts since we have no shared IRQs in ISRx */
++ isr_val = twl4030_madc_read(madc, madc->isr);
++ imr_val = twl4030_madc_read(madc, madc->imr);
++
++ isr_val &= ~imr_val;
++
++ for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
++
++ if (!(isr_val & (1<<i)))
++ continue;
++
++ twl4030_madc_disable_irq(madc, i);
++ madc->requests[i].result_pending = 1;
++ }
++
++ schedule_work(&madc->ws);
++
++ return IRQ_HANDLED;
++}
++
++static void twl4030_madc_work(struct work_struct *ws)
++{
++ const struct twl4030_madc_conversion_method *method;
++ struct twl4030_madc_data *madc;
++ struct twl4030_madc_request *r;
++ int len, i;
++
++ madc = container_of(ws, struct twl4030_madc_data, ws);
++ mutex_lock(&madc->lock);
++
++ for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
++
++ r = &madc->requests[i];
++
++ /* No pending results for this method, move to next one */
++ if (!r->result_pending)
++ continue;
++
++ method = &twl4030_conversion_methods[r->method];
++
++ /* Read results */
++ len = twl4030_madc_read_channels(madc, method->rbase,
++ r->channels, r->rbuf);
++
++ /* Return results to caller */
++ if (r->func_cb != NULL) {
++ r->func_cb(len, r->channels, r->rbuf);
++ r->func_cb = NULL;
++ }
++
++ /* Free request */
++ r->result_pending = 0;
++ r->active = 0;
++ }
++
++ mutex_unlock(&madc->lock);
++}
++
++static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
++ struct twl4030_madc_request *req)
++{
++ struct twl4030_madc_request *p;
++
++ p = &madc->requests[req->method];
++
++ memcpy(p, req, sizeof *req);
++
++ twl4030_madc_enable_irq(madc, req->method);
++
++ return 0;
++}
++
++static inline void twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
++ int conv_method)
++{
++ const struct twl4030_madc_conversion_method *method;
++
++ method = &twl4030_conversion_methods[conv_method];
++
++ switch (conv_method) {
++ case TWL4030_MADC_SW1:
++ case TWL4030_MADC_SW2:
++ twl4030_madc_write(madc, method->ctrl, TWL4030_MADC_SW_START);
++ break;
++ case TWL4030_MADC_RT:
++ default:
++ break;
++ }
++}
++
++static int twl4030_madc_wait_conversion_ready(
++ struct twl4030_madc_data *madc,
++ unsigned int timeout_ms, u8 status_reg)
++{
++ unsigned long timeout;
++
++ timeout = jiffies + msecs_to_jiffies(timeout_ms);
++ do {
++ u8 reg;
++
++ reg = twl4030_madc_read(madc, status_reg);
++ if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
++ return 0;
++ } while (!time_after(jiffies, timeout));
++
++ return -EAGAIN;
++}
++
++int twl4030_madc_conversion(struct twl4030_madc_request *req)
++{
++ const struct twl4030_madc_conversion_method *method;
++ u8 ch_msb, ch_lsb;
++ int ret;
++
++ if (unlikely(!req))
++ return -EINVAL;
++
++ mutex_lock(&the_madc->lock);
++
++ /* Do we have a conversion request ongoing */
++ if (the_madc->requests[req->method].active) {
++ ret = -EBUSY;
++ goto out;
++ }
++
++ ch_msb = (req->channels >> 8) & 0xff;
++ ch_lsb = req->channels & 0xff;
++
++ method = &twl4030_conversion_methods[req->method];
++
++ /* Select channels to be converted */
++ twl4030_madc_write(the_madc, method->sel + 1, ch_msb);
++ twl4030_madc_write(the_madc, method->sel, ch_lsb);
++
++ /* Select averaging for all channels if do_avg is set */
++ if (req->do_avg) {
++ twl4030_madc_write(the_madc, method->avg + 1, ch_msb);
++ twl4030_madc_write(the_madc, method->avg, ch_lsb);
++ }
++
++ if ((req->type == TWL4030_MADC_IRQ_ONESHOT) && (req->func_cb != NULL)) {
++ twl4030_madc_set_irq(the_madc, req);
++ twl4030_madc_start_conversion(the_madc, req->method);
++ the_madc->requests[req->method].active = 1;
++ ret = 0;
++ goto out;
++ }
++
++ /* With RT method we should not be here anymore */
++ if (req->method == TWL4030_MADC_RT) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ twl4030_madc_start_conversion(the_madc, req->method);
++ the_madc->requests[req->method].active = 1;
++
++ /* Wait until conversion is ready (ctrl register returns EOC) */
++ ret = twl4030_madc_wait_conversion_ready(the_madc, 5, method->ctrl);
++ if (ret) {
++ dev_dbg(the_madc->dev, "conversion timeout!\n");
++ the_madc->requests[req->method].active = 0;
++ goto out;
++ }
++
++ ret = twl4030_madc_read_channels(the_madc, method->rbase, req->channels,
++ req->rbuf);
++
++ the_madc->requests[req->method].active = 0;
++
++out:
++ mutex_unlock(&the_madc->lock);
++
++ return ret;
++}
++EXPORT_SYMBOL(twl4030_madc_conversion);
++
++static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
++ int chan, int on)
++{
++ int ret;
++ u8 regval;
++
++ /* Current generator is only available for ADCIN0 and ADCIN1. NB:
++ * ADCIN1 current generator only works when AC or VBUS is present */
++ if (chan > 1)
++ return EINVAL;
++
++ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
++ ®val, TWL4030_BCI_BCICTL1);
++ if (on)
++ regval |= (chan) ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
++ else
++ regval &= (chan) ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
++ ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
++ regval, TWL4030_BCI_BCICTL1);
++
++ return ret;
++}
++
++static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
++{
++ u8 regval;
++
++ regval = twl4030_madc_read(madc, TWL4030_MADC_CTRL1);
++ if (on)
++ regval |= TWL4030_MADC_MADCON;
++ else
++ regval &= ~TWL4030_MADC_MADCON;
++ twl4030_madc_write(madc, TWL4030_MADC_CTRL1, regval);
++
++ return 0;
++}
++
++static long twl4030_madc_ioctl(struct file *filp, unsigned int cmd,
++ unsigned long arg)
++{
++ struct twl4030_madc_user_parms par;
++ int val, ret;
++
++ ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
++ if (ret) {
++ dev_dbg(the_madc->dev, "copy_from_user: %d\n", ret);
++ return -EACCES;
++ }
++
++ switch (cmd) {
++ case TWL4030_MADC_IOCX_ADC_RAW_READ: {
++ struct twl4030_madc_request req;
++ if (par.channel >= TWL4030_MADC_MAX_CHANNELS)
++ return -EINVAL;
++
++ req.channels = (1 << par.channel);
++ req.do_avg = par.average;
++ req.method = TWL4030_MADC_SW1;
++ req.func_cb = NULL;
++
++ val = twl4030_madc_conversion(&req);
++ if (val <= 0) {
++ par.status = -1;
++ } else {
++ par.status = 0;
++ par.result = (u16)req.rbuf[par.channel];
++ }
++ break;
++ }
++ default:
++ return -EINVAL;
++ }
++
++ ret = copy_to_user((void __user *) arg, &par, sizeof(par));
++ if (ret) {
++ dev_dbg(the_madc->dev, "copy_to_user: %d\n", ret);
++ return -EACCES;
++ }
++
++ return 0;
++}
++
++static struct file_operations twl4030_madc_fileops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = twl4030_madc_ioctl
++};
++
++static struct miscdevice twl4030_madc_device = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = "twl4030-madc",
++ .fops = &twl4030_madc_fileops
++};
++
++static int __init twl4030_madc_probe(struct platform_device *pdev)
++{
++ struct twl4030_madc_data *madc;
++ struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
++ int ret;
++ u8 regval;
++
++ madc = kzalloc(sizeof *madc, GFP_KERNEL);
++ if (!madc)
++ return -ENOMEM;
++
++ if (!pdata) {
++ dev_dbg(&pdev->dev, "platform_data not available\n");
++ ret = -EINVAL;
++ goto err_pdata;
++ }
++
++ madc->imr = (pdata->irq_line == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
++ madc->isr = (pdata->irq_line == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
++
++ ret = misc_register(&twl4030_madc_device);
++ if (ret) {
++ dev_dbg(&pdev->dev, "could not register misc_device\n");
++ goto err_misc;
++ }
++ twl4030_madc_set_power(madc, 1);
++ twl4030_madc_set_current_generator(madc, 0, 1);
++
++ /* Enable ADCIN3 through 6 */
++ ret = twl_i2c_read_u8(TWL4030_MODULE_USB,
++ ®val, TWL4030_USB_CARKIT_ANA_CTRL);
++
++ regval |= TWL4030_USB_SEL_MADC_MCPC;
++
++ ret = twl_i2c_write_u8(TWL4030_MODULE_USB,
++ regval, TWL4030_USB_CARKIT_ANA_CTRL);
++
++
++ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
++ ®val, TWL4030_BCI_BCICTL1);
++
++ regval |= TWL4030_BCI_MESBAT;
++
++ ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
++ regval, TWL4030_BCI_BCICTL1);
++
++ ret = request_irq(platform_get_irq(pdev, 0), twl4030_madc_irq_handler,
++ 0, "twl4030_madc", madc);
++ if (ret) {
++ dev_dbg(&pdev->dev, "could not request irq\n");
++ goto err_irq;
++ }
++
++ platform_set_drvdata(pdev, madc);
++ mutex_init(&madc->lock);
++ INIT_WORK(&madc->ws, twl4030_madc_work);
++
++ the_madc = madc;
++
++ return 0;
++
++err_irq:
++ misc_deregister(&twl4030_madc_device);
++
++err_misc:
++err_pdata:
++ kfree(madc);
++
++ return ret;
++}
++
++static int __exit twl4030_madc_remove(struct platform_device *pdev)
++{
++ struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
++
++ twl4030_madc_set_power(madc, 0);
++ twl4030_madc_set_current_generator(madc, 0, 0);
++ free_irq(platform_get_irq(pdev, 0), madc);
++ cancel_work_sync(&madc->ws);
++ misc_deregister(&twl4030_madc_device);
++
++ return 0;
++}
++
++static struct platform_driver twl4030_madc_driver = {
++ .probe = twl4030_madc_probe,
++ .remove = __exit_p(twl4030_madc_remove),
++ .driver = {
++ .name = "twl4030_madc",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init twl4030_madc_init(void)
++{
++ return platform_driver_register(&twl4030_madc_driver);
++}
++module_init(twl4030_madc_init);
++
++static void __exit twl4030_madc_exit(void)
++{
++ platform_driver_unregister(&twl4030_madc_driver);
++}
++module_exit(twl4030_madc_exit);
++
++MODULE_ALIAS("platform:twl4030-madc");
++MODULE_AUTHOR("Nokia Corporation");
++MODULE_DESCRIPTION("twl4030 ADC driver");
++MODULE_LICENSE("GPL");
++
+diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h
+new file mode 100644
+index 0000000..341a665
+--- /dev/null
++++ b/include/linux/i2c/twl4030-madc.h
+@@ -0,0 +1,130 @@
++/*
++ * include/linux/i2c/twl4030-madc.h
++ *
++ * TWL4030 MADC module driver header
++ *
++ * Copyright (C) 2008 Nokia Corporation
++ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
++ *
++ * This program 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 program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * 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., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ *
++ */
++
++#ifndef _TWL4030_MADC_H
++#define _TWL4030_MADC_H
++
++struct twl4030_madc_conversion_method {
++ u8 sel;
++ u8 avg;
++ u8 rbase;
++ u8 ctrl;
++};
++
++#define TWL4030_MADC_MAX_CHANNELS 16
++
++struct twl4030_madc_request {
++ u16 channels;
++ u16 do_avg;
++ u16 method;
++ u16 type;
++ int active;
++ int result_pending;
++ int rbuf[TWL4030_MADC_MAX_CHANNELS];
++ void (*func_cb)(int len, int channels, int *buf);
++};
++
++enum conversion_methods {
++ TWL4030_MADC_RT,
++ TWL4030_MADC_SW1,
++ TWL4030_MADC_SW2,
++ TWL4030_MADC_NUM_METHODS
++};
++
++enum sample_type {
++ TWL4030_MADC_WAIT,
++ TWL4030_MADC_IRQ_ONESHOT,
++ TWL4030_MADC_IRQ_REARM
++};
++
++#define TWL4030_MADC_CTRL1 0x00
++#define TWL4030_MADC_CTRL2 0x01
++
++#define TWL4030_MADC_RTSELECT_LSB 0x02
++#define TWL4030_MADC_SW1SELECT_LSB 0x06
++#define TWL4030_MADC_SW2SELECT_LSB 0x0A
++
++#define TWL4030_MADC_RTAVERAGE_LSB 0x04
++#define TWL4030_MADC_SW1AVERAGE_LSB 0x08
++#define TWL4030_MADC_SW2AVERAGE_LSB 0x0C
++
++#define TWL4030_MADC_CTRL_SW1 0x12
++#define TWL4030_MADC_CTRL_SW2 0x13
++
++#define TWL4030_MADC_RTCH0_LSB 0x17
++#define TWL4030_MADC_GPCH0_LSB 0x37
++
++#define TWL4030_MADC_MADCON (1<<0) /* MADC power on */
++#define TWL4030_MADC_BUSY (1<<0) /* MADC busy */
++#define TWL4030_MADC_EOC_SW (1<<1) /* MADC conversion completion */
++#define TWL4030_MADC_SW_START (1<<5) /* MADC SWx start conversion */
++
++#define TWL4030_MADC_ADCIN0 (1<<0)
++#define TWL4030_MADC_ADCIN1 (1<<1)
++#define TWL4030_MADC_ADCIN2 (1<<2)
++#define TWL4030_MADC_ADCIN3 (1<<3)
++#define TWL4030_MADC_ADCIN4 (1<<4)
++#define TWL4030_MADC_ADCIN5 (1<<5)
++#define TWL4030_MADC_ADCIN6 (1<<6)
++#define TWL4030_MADC_ADCIN7 (1<<7)
++#define TWL4030_MADC_ADCIN8 (1<<8)
++#define TWL4030_MADC_ADCIN9 (1<<9)
++#define TWL4030_MADC_ADCIN10 (1<<10)
++#define TWL4030_MADC_ADCIN11 (1<<11)
++#define TWL4030_MADC_ADCIN12 (1<<12)
++#define TWL4030_MADC_ADCIN13 (1<<13)
++#define TWL4030_MADC_ADCIN14 (1<<14)
++#define TWL4030_MADC_ADCIN15 (1<<15)
++
++/* Fixed channels */
++#define TWL4030_MADC_BTEMP TWL4030_MADC_ADCIN1
++#define TWL4030_MADC_VBUS TWL4030_MADC_ADCIN8
++#define TWL4030_MADC_VBKB TWL4030_MADC_ADCIN9
++#define TWL4030_MADC_ICHG TWL4030_MADC_ADCIN10
++#define TWL4030_MADC_VCHG TWL4030_MADC_ADCIN11
++#define TWL4030_MADC_VBAT TWL4030_MADC_ADCIN12
++
++/* BCI related - XXX To be moved elsewhere */
++#define TWL4030_BCI_BCICTL1 0x23
++#define TWL4030_BCI_MESBAT (1<<1)
++#define TWL4030_BCI_TYPEN (1<<4)
++#define TWL4030_BCI_ITHEN (1<<3)
++
++/* USB related - XXX To be moved elsewhere */
++#define TWL4030_USB_CARKIT_ANA_CTRL 0xBB
++#define TWL4030_USB_SEL_MADC_MCPC (1<<3)
++
++#define TWL4030_MADC_IOC_MAGIC '`'
++#define TWL4030_MADC_IOCX_ADC_RAW_READ _IO(TWL4030_MADC_IOC_MAGIC, 0)
++
++struct twl4030_madc_user_parms {
++ int channel;
++ int average;
++ int status;
++ u16 result;
++};
++
++int twl4030_madc_conversion(struct twl4030_madc_request *conv);
++
++#endif
+--
+1.6.6.1
+
--- /dev/null
+From 3bc70a68d2cfd1d41995bb7f33f2e4005542f62b Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 17 Dec 2009 14:27:15 -0800
+Subject: [PATCH 17/29] ARM: OMAP: Add twl4030 madc support to Overo
+
+---
+ arch/arm/mach-omap2/board-overo.c | 5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
+index cb26e5d..17f066a 100644
+--- a/arch/arm/mach-omap2/board-overo.c
++++ b/arch/arm/mach-omap2/board-overo.c
+@@ -369,10 +369,15 @@ static struct twl4030_codec_data overo_codec_data = {
+
+ /* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */
+
++static struct twl4030_madc_platform_data overo_madc_data = {
++ .irq_line = 1,
++};
++
+ static struct twl4030_platform_data overo_twldata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+ .gpio = &overo_gpio_data,
++ .madc = &overo_madc_data,
+ .usb = &overo_usb_data,
+ .codec = &overo_codec_data,
+ .vmmc1 = &overo_vmmc1,
+--
+1.6.6.1
+
--- /dev/null
+From afa4132d5e29ed90154fec8cd97f891c86ce748c Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 17 Dec 2009 14:32:36 -0800
+Subject: [PATCH 18/29] ARM: OMAP: Add twl4030 madc support to Beagle
+
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 073276b..781844c 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -578,6 +578,10 @@ static struct twl4030_codec_data beagle_codec_data = {
+ .audio = &beagle_audio_data,
+ };
+
++static struct twl4030_madc_platform_data beagle_madc_data = {
++ .irq_line = 1,
++};
++
+ static struct twl4030_platform_data beagle_twldata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+@@ -586,6 +590,7 @@ static struct twl4030_platform_data beagle_twldata = {
+ .usb = &beagle_usb_data,
+ .gpio = &beagle_gpio_data,
+ .codec = &beagle_codec_data,
++ .madc = &beagle_madc_data,
+ .vmmc1 = &beagle_vmmc1,
+ .vsim = &beagle_vsim,
+ .vdac = &beagle_vdac,
+--
+1.6.6.1
+
--- /dev/null
+From e6b15754a20c0306fb20d061358da67b5dd218cd Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Tue, 23 Feb 2010 14:40:27 -0800
+Subject: [PATCH 19/29] OMAP: DSS2: Add support for Samsung LTE430WQ-F0C panel
+
+---
+ .../omap2/displays/panel-samsung-lte430wq-f0c.c | 154 ++++++++++++++++++++
+ 1 files changed, 154 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/video/omap2/displays/panel-samsung-lte430wq-f0c.c
+
+diff --git a/drivers/video/omap2/displays/panel-samsung-lte430wq-f0c.c b/drivers/video/omap2/displays/panel-samsung-lte430wq-f0c.c
+new file mode 100644
+index 0000000..6a29f9c
+--- /dev/null
++++ b/drivers/video/omap2/displays/panel-samsung-lte430wq-f0c.c
+@@ -0,0 +1,154 @@
++/*
++ * LCD panel driver for Samsung LTE430WQ-F0C
++ *
++ * Author: Steve Sakoman <steve@sakoman.com>
++ *
++ * This program 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 program is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/module.h>
++#include <linux/delay.h>
++
++#include <plat/display.h>
++
++static struct omap_video_timings samsung_lte_timings = {
++ .x_res = 480,
++ .y_res = 272,
++
++ .pixel_clock = 9200,
++
++ .hsw = 41,
++ .hfp = 8,
++ .hbp = 45-41,
++
++ .vsw = 10,
++ .vfp = 4,
++ .vbp = 12-10,
++};
++
++static int samsung_lte_panel_power_on(struct omap_dss_device *dssdev)
++{
++ int r;
++
++ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
++ return 0;
++
++ r = omapdss_dpi_display_enable(dssdev);
++ if (r)
++ goto err0;
++
++ if (dssdev->platform_enable) {
++ r = dssdev->platform_enable(dssdev);
++ if (r)
++ goto err1;
++ }
++
++ return 0;
++err1:
++ omapdss_dpi_display_disable(dssdev);
++err0:
++ return r;
++}
++
++static void samsung_lte_panel_power_off(struct omap_dss_device *dssdev)
++{
++ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
++ return;
++
++ if (dssdev->platform_disable)
++ dssdev->platform_disable(dssdev);
++
++ omapdss_dpi_display_disable(dssdev);
++}
++
++static int samsung_lte_panel_probe(struct omap_dss_device *dssdev)
++{
++ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
++ OMAP_DSS_LCD_IHS;
++ dssdev->panel.timings = samsung_lte_timings;
++
++ return 0;
++}
++
++static void samsung_lte_panel_remove(struct omap_dss_device *dssdev)
++{
++}
++
++static int samsung_lte_panel_enable(struct omap_dss_device *dssdev)
++{
++ int r = 0;
++
++ r = samsung_lte_panel_power_on(dssdev);
++ if (r)
++ return r;
++
++ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
++
++ return 0;
++}
++
++static void samsung_lte_panel_disable(struct omap_dss_device *dssdev)
++{
++ samsung_lte_panel_power_off(dssdev);
++
++ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
++}
++
++static int samsung_lte_panel_suspend(struct omap_dss_device *dssdev)
++{
++ samsung_lte_panel_disable(dssdev);
++ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
++ return 0;
++}
++
++static int samsung_lte_panel_resume(struct omap_dss_device *dssdev)
++{
++ int r;
++
++ r = samsung_lte_panel_enable(dssdev);
++ if (r)
++ return r;
++
++ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
++
++ return 0;
++}
++
++static struct omap_dss_driver samsung_lte_driver = {
++ .probe = samsung_lte_panel_probe,
++ .remove = samsung_lte_panel_remove,
++
++ .enable = samsung_lte_panel_enable,
++ .disable = samsung_lte_panel_disable,
++ .suspend = samsung_lte_panel_suspend,
++ .resume = samsung_lte_panel_resume,
++
++ .driver = {
++ .name = "samsung_lte_panel",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init samsung_lte_panel_drv_init(void)
++{
++ return omap_dss_register_driver(&samsung_lte_driver);
++}
++
++static void __exit samsung_lte_panel_drv_exit(void)
++{
++ omap_dss_unregister_driver(&samsung_lte_driver);
++}
++
++module_init(samsung_lte_panel_drv_init);
++module_exit(samsung_lte_panel_drv_exit);
++MODULE_LICENSE("GPL");
+--
+1.6.6.1
+
--- /dev/null
+From 6861df53ce9212b348fba806f5a86404c1de8a95 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 17 Dec 2009 15:05:30 -0800
+Subject: [PATCH 20/29] OMAP: DSS2: Add support for LG Philips LB035Q02 panel
+
+---
+ drivers/video/omap2/displays/Kconfig | 12 +
+ drivers/video/omap2/displays/Makefile | 2 +
+ .../omap2/displays/panel-lgphilips-lb035q02.c | 244 ++++++++++++++++++++
+ 3 files changed, 258 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
+
+diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
+index 12327bb..48e872f 100644
+--- a/drivers/video/omap2/displays/Kconfig
++++ b/drivers/video/omap2/displays/Kconfig
+@@ -7,6 +7,18 @@ config PANEL_GENERIC
+ Generic panel driver.
+ Used for DVI output for Beagle and OMAP3 SDP.
+
++config PANEL_LGPHILIPS_LB035Q02
++ tristate "LG.Philips LB035Q02 LCD Panel"
++ depends on OMAP2_DSS
++ help
++ LCD Panel used on Overo Palo35
++
++config PANEL_SAMSUNG_LTE430WQ_F0C
++ tristate "Samsung LTE430WQ-F0C LCD Panel"
++ depends on OMAP2_DSS
++ help
++ LCD Panel used on Overo Palo43
++
+ config PANEL_SHARP_LS037V7DW01
+ tristate "Sharp LS037V7DW01 LCD Panel"
+ depends on OMAP2_DSS
+diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
+index aa38609..2fb1a57 100644
+--- a/drivers/video/omap2/displays/Makefile
++++ b/drivers/video/omap2/displays/Makefile
+@@ -1,4 +1,6 @@
+ obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
++obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
++obj-$(CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C) += panel-samsung-lte430wq-f0c.o
+ obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
+ obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o
+
+diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
+new file mode 100644
+index 0000000..4ad709d
+--- /dev/null
++++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
+@@ -0,0 +1,244 @@
++/*
++ * LCD panel driver for LG.Philips LB035Q02
++ *
++ * Author: Steve Sakoman <steve@sakoman.com>
++ *
++ * This program 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 program is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/spi/spi.h>
++
++#include <plat/display.h>
++
++static struct spi_device *spidev;
++
++static struct omap_video_timings lb035q02_timings = {
++ .x_res = 320,
++ .y_res = 240,
++
++ .pixel_clock = 6500,
++
++ .hsw = 2,
++ .hfp = 20,
++ .hbp = 68,
++
++ .vsw = 2,
++ .vfp = 4,
++ .vbp = 18,
++};
++
++static int lb035q02_write_reg(u8 reg, u16 val)
++{
++ struct spi_message msg;
++ struct spi_transfer index_xfer = {
++ .len = 3,
++ .cs_change = 1,
++ };
++ struct spi_transfer value_xfer = {
++ .len = 3,
++ };
++ u8 buffer[16];
++
++ spi_message_init(&msg);
++
++ /* register index */
++ buffer[0] = 0x70;
++ buffer[1] = 0x00;
++ buffer[2] = reg & 0x7f;
++ index_xfer.tx_buf = buffer;
++ spi_message_add_tail(&index_xfer, &msg);
++
++ /* register value */
++ buffer[4] = 0x72;
++ buffer[5] = val >> 8;
++ buffer[6] = val;
++ value_xfer.tx_buf = buffer + 4;
++ spi_message_add_tail(&value_xfer, &msg);
++
++ return spi_sync(spidev, &msg);
++}
++
++static int lb035q02_panel_power_on(struct omap_dss_device *dssdev)
++{
++ int r;
++
++ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
++ return 0;
++
++ r = omapdss_dpi_display_enable(dssdev);
++ if (r)
++ goto err0;
++
++ if (dssdev->platform_enable) {
++ r = dssdev->platform_enable(dssdev);
++ if (r)
++ goto err1;
++ }
++
++ /* Panel init sequence from page 28 of the spec */
++ lb035q02_write_reg(0x01, 0x6300);
++ lb035q02_write_reg(0x02, 0x0200);
++ lb035q02_write_reg(0x03, 0x0177);
++ lb035q02_write_reg(0x04, 0x04c7);
++ lb035q02_write_reg(0x05, 0xffc0);
++ lb035q02_write_reg(0x06, 0xe806);
++ lb035q02_write_reg(0x0a, 0x4008);
++ lb035q02_write_reg(0x0b, 0x0000);
++ lb035q02_write_reg(0x0d, 0x0030);
++ lb035q02_write_reg(0x0e, 0x2800);
++ lb035q02_write_reg(0x0f, 0x0000);
++ lb035q02_write_reg(0x16, 0x9f80);
++ lb035q02_write_reg(0x17, 0x0a0f);
++ lb035q02_write_reg(0x1e, 0x00c1);
++ lb035q02_write_reg(0x30, 0x0300);
++ lb035q02_write_reg(0x31, 0x0007);
++ lb035q02_write_reg(0x32, 0x0000);
++ lb035q02_write_reg(0x33, 0x0000);
++ lb035q02_write_reg(0x34, 0x0707);
++ lb035q02_write_reg(0x35, 0x0004);
++ lb035q02_write_reg(0x36, 0x0302);
++ lb035q02_write_reg(0x37, 0x0202);
++ lb035q02_write_reg(0x3a, 0x0a0d);
++ lb035q02_write_reg(0x3b, 0x0806);
++
++ return 0;
++err1:
++ omapdss_dpi_display_disable(dssdev);
++err0:
++ return r;
++}
++
++static void lb035q02_panel_power_off(struct omap_dss_device *dssdev)
++{
++ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
++ return;
++
++ if (dssdev->platform_disable)
++ dssdev->platform_disable(dssdev);
++
++ omapdss_dpi_display_disable(dssdev);
++}
++
++static int lb035q02_panel_probe(struct omap_dss_device *dssdev)
++{
++ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
++ OMAP_DSS_LCD_IHS;
++ dssdev->panel.timings = lb035q02_timings;
++
++ return 0;
++}
++
++static void lb035q02_panel_remove(struct omap_dss_device *dssdev)
++{
++}
++
++static int lb035q02_panel_enable(struct omap_dss_device *dssdev)
++{
++ int r = 0;
++
++ r = lb035q02_panel_power_on(dssdev);
++ if (r)
++ return r;
++
++ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
++
++ return 0;
++}
++
++static void lb035q02_panel_disable(struct omap_dss_device *dssdev)
++{
++ lb035q02_panel_power_off(dssdev);
++
++ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
++}
++
++static int lb035q02_panel_suspend(struct omap_dss_device *dssdev)
++{
++ lb035q02_panel_disable(dssdev);
++ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
++ return 0;
++}
++
++static int lb035q02_panel_resume(struct omap_dss_device *dssdev)
++{
++ int r;
++
++ r = lb035q02_panel_power_on(dssdev);
++ if (r)
++ return r;
++
++ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
++
++ return 0;
++}
++
++static struct omap_dss_driver lb035q02_driver = {
++ .probe = lb035q02_panel_probe,
++ .remove = lb035q02_panel_remove,
++
++ .enable = lb035q02_panel_enable,
++ .disable = lb035q02_panel_disable,
++ .suspend = lb035q02_panel_suspend,
++ .resume = lb035q02_panel_resume,
++
++ .driver = {
++ .name = "lgphilips_lb035q02_panel",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __devinit lb035q02_panel_spi_probe(struct spi_device *spi)
++{
++ spidev = spi;
++ return 0;
++}
++
++static int __devexit lb035q02_panel_spi_remove(struct spi_device *spi)
++{
++ return 0;
++}
++
++static struct spi_driver lb035q02_spi_driver = {
++ .driver = {
++ .name = "lgphilips_lb035q02_panel-spi",
++ .owner = THIS_MODULE,
++ },
++ .probe = lb035q02_panel_spi_probe,
++ .remove = __devexit_p (lb035q02_panel_spi_remove),
++};
++
++static int __init lb035q02_panel_drv_init(void)
++{
++ int r;
++ r = spi_register_driver(&lb035q02_spi_driver);
++ if (r != 0)
++ pr_err("lgphilips_lb035q02: Unable to register SPI driver: %d\n", r);
++
++ r = omap_dss_register_driver(&lb035q02_driver);
++ if (r != 0)
++ pr_err("lgphilips_lb035q02: Unable to register panel driver: %d\n", r);
++
++ return r;
++}
++
++static void __exit lb035q02_panel_drv_exit(void)
++{
++ spi_unregister_driver(&lb035q02_spi_driver);
++ omap_dss_unregister_driver(&lb035q02_driver);
++}
++
++module_init(lb035q02_panel_drv_init);
++module_exit(lb035q02_panel_drv_exit);
++MODULE_LICENSE("GPL");
+--
+1.6.6.1
+
--- /dev/null
+From 9e206307dbd65d557a57563c086af5089e52b2c8 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Tue, 19 Jan 2010 21:19:15 -0800
+Subject: [PATCH 21/29] OMAP: DSS2: add bootarg for selecting svideo or composite for tv output
+
+also add pal-16 and ntsc-16 omapfb.mode settings for 16bpp
+---
+ drivers/video/omap2/dss/venc.c | 22 ++++++++++++++++++++++
+ drivers/video/omap2/omapfb/omapfb-main.c | 10 +++++++++-
+ 2 files changed, 31 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
+index eff3505..e1f4aab 100644
+--- a/drivers/video/omap2/dss/venc.c
++++ b/drivers/video/omap2/dss/venc.c
+@@ -87,6 +87,11 @@
+ #define VENC_OUTPUT_TEST 0xC8
+ #define VENC_DAC_B__DAC_C 0xC8
+
++static char *tv_connection;
++
++module_param_named(tvcable, tv_connection, charp, 0);
++MODULE_PARM_DESC(tvcable, "TV connection type (svideo, composite)");
++
+ struct venc_config {
+ u32 f_control;
+ u32 vidout_ctrl;
+@@ -459,6 +464,23 @@ static int venc_panel_probe(struct omap_dss_device *dssdev)
+ {
+ dssdev->panel.timings = omap_dss_pal_timings;
+
++ /* Allow the TV output to be overriden */
++ if (tv_connection) {
++ if (strcmp(tv_connection, "svideo") == 0) {
++ printk(KERN_INFO
++ "omapdss: tv output is svideo.\n");
++ dssdev->phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO;
++ } else if (strcmp(tv_connection, "composite") == 0) {
++ printk(KERN_INFO
++ "omapdss: tv output is composite.\n");
++ dssdev->phy.venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE;
++ } else {
++ printk(KERN_INFO
++ "omapdss: unsupported output type'%s'.\n",
++ tv_connection);
++ }
++ }
++
+ return 0;
+ }
+
+diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
+index 6a704f1..7ee833f 100644
+--- a/drivers/video/omap2/omapfb/omapfb-main.c
++++ b/drivers/video/omap2/omapfb/omapfb-main.c
+@@ -2036,7 +2036,15 @@ static int omapfb_mode_to_timings(const char *mode_str,
+ int r;
+
+ #ifdef CONFIG_OMAP2_DSS_VENC
+- if (strcmp(mode_str, "pal") == 0) {
++ if (strcmp(mode_str, "pal-16") == 0) {
++ *timings = omap_dss_pal_timings;
++ *bpp = 16;
++ return 0;
++ } else if (strcmp(mode_str, "ntsc-16") == 0) {
++ *timings = omap_dss_ntsc_timings;
++ *bpp = 16;
++ return 0;
++ } else if (strcmp(mode_str, "pal") == 0) {
+ *timings = omap_dss_pal_timings;
+ *bpp = 24;
+ return 0;
+--
+1.6.6.1
+
--- /dev/null
+From 3924e990868742c19e5cd3e84191a01b55249079 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Sun, 24 Jan 2010 09:33:56 -0800
+Subject: [PATCH 22/29] ARM: OMAP2: mmc-twl4030: move clock input selection prior to vcc test
+
+otherwise it is not executed on systems that use non-twl regulators
+---
+ arch/arm/mach-omap2/hsmmc.c | 14 ++++++--------
+ 1 files changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
+index 34272e4..a74631d 100644
+--- a/arch/arm/mach-omap2/hsmmc.c
++++ b/arch/arm/mach-omap2/hsmmc.c
+@@ -186,15 +186,13 @@ static void hsmmc23_before_set_reg(struct device *dev, int slot,
+ if (mmc->slots[0].remux)
+ mmc->slots[0].remux(dev, slot, power_on);
+
+- if (power_on) {
+- /* Only MMC2 supports a CLKIN */
+- if (mmc->slots[0].internal_clock) {
+- u32 reg;
++ /* Only MMC2 supports a CLKIN */
++ if (mmc->slots[0].internal_clock) {
++ u32 reg;
+
+- reg = omap_ctrl_readl(control_devconf1_offset);
+- reg |= OMAP2_MMCSDIO2ADPCLKISEL;
+- omap_ctrl_writel(reg, control_devconf1_offset);
+- }
++ reg = omap_ctrl_readl(control_devconf1_offset);
++ reg |= OMAP2_MMCSDIO2ADPCLKISEL;
++ omap_ctrl_writel(reg, control_devconf1_offset);
+ }
+ }
+
+--
+1.6.6.1
+
--- /dev/null
+From ade216c2689a2dae645ca95fa443ee8eacfafb67 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 4 Feb 2010 12:26:22 -0800
+Subject: [PATCH 23/29] RTC: add support for backup battery recharge
+
+---
+ drivers/rtc/rtc-twl.c | 25 +++++++++++++++++++++++++
+ 1 files changed, 25 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
+index ed1b868..33a8598 100644
+--- a/drivers/rtc/rtc-twl.c
++++ b/drivers/rtc/rtc-twl.c
+@@ -30,6 +30,23 @@
+
+ #include <linux/i2c/twl.h>
+
++/*
++ * PM_RECEIVER block register offsets (use TWL4030_MODULE_PM_RECEIVER)
++ */
++#define REG_BB_CFG 0x12
++
++/* PM_RECEIVER BB_CFG bitfields */
++#define BIT_PM_RECEIVER_BB_CFG_BBCHEN 0x10
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL 0x0C
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL_2V5 0x00
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL_3V0 0x04
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL_3V1 0x08
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL_3v2 0x0c
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL 0x03
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL_25UA 0x00
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL_150UA 0x01
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL_500UA 0x02
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL_1MA 0x03
+
+ /*
+ * RTC block register offsets (use TWL_MODULE_RTC)
+@@ -508,6 +525,14 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)
+ if (ret < 0)
+ goto out2;
+
++ /* enable backup battery charging */
++ /* use a conservative 25uA @ 3.1V */
++ ret = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
++ BIT_PM_RECEIVER_BB_CFG_BBCHEN |
++ BIT_PM_RECEIVER_BB_CFG_BBSEL_3V1 |
++ BIT_PM_RECEIVER_BB_CFG_BBISEL_25UA,
++ REG_BB_CFG);
++
+ return ret;
+
+ out2:
+--
+1.6.6.1
+
--- /dev/null
+From 6a2f14bdd390695f5d88fb8ea18df8f80bddfc9d Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Wed, 24 Feb 2010 10:37:22 -0800
+Subject: [PATCH 24/29] ARM: OMAP: automatically set musb mode in platform data based on CONFIG options
+
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 6 ++++++
+ arch/arm/mach-omap2/board-overo.c | 6 ++++++
+ 2 files changed, 12 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 781844c..006dc26 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -759,7 +759,13 @@ static struct omap_board_mux board_mux[] __initdata = {
+
+ static struct omap_musb_board_data musb_board_data = {
+ .interface_type = MUSB_INTERFACE_ULPI,
++#if defined(CONFIG_USB_MUSB_OTG)
+ .mode = MUSB_OTG,
++#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
++ .mode = MUSB_PERIPHERAL,
++#else
++ .mode = MUSB_HOST,
++#endif
+ .power = 100,
+ };
+
+diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
+index 17f066a..b28a9d5 100644
+--- a/arch/arm/mach-omap2/board-overo.c
++++ b/arch/arm/mach-omap2/board-overo.c
+@@ -447,7 +447,13 @@ static struct omap_board_mux board_mux[] __initdata = {
+
+ static struct omap_musb_board_data musb_board_data = {
+ .interface_type = MUSB_INTERFACE_ULPI,
++#if defined(CONFIG_USB_MUSB_OTG)
+ .mode = MUSB_OTG,
++#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
++ .mode = MUSB_PERIPHERAL,
++#else
++ .mode = MUSB_HOST,
++#endif
+ .power = 100,
+ };
+
+--
+1.6.6.1
+
--- /dev/null
+From 6e383eb63993e011b6bdec84e3eb001e6b9e00a1 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Mon, 10 May 2010 13:59:14 -0700
+Subject: [PATCH 25/29] OMAP: DSS2: check for both cpu type and revision, rather than just revision
+
+---
+ drivers/video/omap2/dss/dispc.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
+index fa40fa5..133916a 100644
+--- a/drivers/video/omap2/dss/dispc.c
++++ b/drivers/video/omap2/dss/dispc.c
+@@ -2101,7 +2101,7 @@ void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
+ static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
+ int vsw, int vfp, int vbp)
+ {
+- if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
++ if (cpu_is_omap24xx() || (cpu_is_omap34xx() && omap_rev_lt_3_0())) {
+ if (hsw < 1 || hsw > 64 ||
+ hfp < 1 || hfp > 256 ||
+ hbp < 1 || hbp > 256 ||
+@@ -2134,7 +2134,7 @@ static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
+ {
+ u32 timing_h, timing_v;
+
+- if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
++ if (cpu_is_omap24xx() || (cpu_is_omap34xx() && omap_rev_lt_3_0())) {
+ timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
+ FLD_VAL(hbp-1, 27, 20);
+
+--
+1.6.6.1
+
--- /dev/null
+From 66db8210263893e9ffd4478c36a3a1a89bdaff37 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Fri, 18 Dec 2009 06:39:24 -0800
+Subject: [PATCH 26/29] OMAP: DSS2: Add DSS2 support for Overo
+
+---
+ arch/arm/mach-omap2/board-overo.c | 238 +++++++++++++++++++++++++++++++------
+ 1 files changed, 204 insertions(+), 34 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
+index b28a9d5..8a44c17 100644
+--- a/arch/arm/mach-omap2/board-overo.c
++++ b/arch/arm/mach-omap2/board-overo.c
+@@ -28,6 +28,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/i2c/twl.h>
+ #include <linux/regulator/machine.h>
++#include <linux/spi/spi.h>
+
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/nand.h>
+@@ -41,10 +42,13 @@
+
+ #include <plat/board.h>
+ #include <plat/common.h>
++#include <plat/display.h>
+ #include <mach/gpio.h>
+ #include <plat/gpmc.h>
+ #include <mach/hardware.h>
+ #include <plat/nand.h>
++#include <plat/mcspi.h>
++#include <plat/mux.h>
+ #include <plat/usb.h>
+
+ #include "mux.h"
+@@ -68,8 +72,6 @@
+ #if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
+ defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+
+-#include <plat/mcspi.h>
+-#include <linux/spi/spi.h>
+ #include <linux/spi/ads7846.h>
+
+ static struct omap2_mcspi_device_config ads7846_mcspi_config = {
+@@ -94,18 +96,6 @@ static struct ads7846_platform_data ads7846_config = {
+ .keep_vref_on = 1,
+ };
+
+-static struct spi_board_info overo_spi_board_info[] __initdata = {
+- {
+- .modalias = "ads7846",
+- .bus_num = 1,
+- .chip_select = 0,
+- .max_speed_hz = 1500000,
+- .controller_data = &ads7846_mcspi_config,
+- .irq = OMAP_GPIO_IRQ(OVERO_GPIO_PENDOWN),
+- .platform_data = &ads7846_config,
+- }
+-};
+-
+ static void __init overo_ads7846_init(void)
+ {
+ if ((gpio_request(OVERO_GPIO_PENDOWN, "ADS7846_PENDOWN") == 0) &&
+@@ -115,9 +105,6 @@ static void __init overo_ads7846_init(void)
+ printk(KERN_ERR "could not obtain gpio for ADS7846_PENDOWN\n");
+ return;
+ }
+-
+- spi_register_board_info(overo_spi_board_info,
+- ARRAY_SIZE(overo_spi_board_info));
+ }
+
+ #else
+@@ -233,6 +220,139 @@ static inline void __init overo_init_smsc911x(void)
+ static inline void __init overo_init_smsc911x(void) { return; }
+ #endif
+
++/* DSS */
++static int lcd_enabled;
++static int dvi_enabled;
++
++#define OVERO_GPIO_LCD_EN 144
++#define OVERO_GPIO_LCD_BL 145
++
++static void __init overo_display_init(void)
++{
++ if ((gpio_request(OVERO_GPIO_LCD_EN, "OVERO_GPIO_LCD_EN") == 0) &&
++ (gpio_direction_output(OVERO_GPIO_LCD_EN, 1) == 0))
++ gpio_export(OVERO_GPIO_LCD_EN, 0);
++ else
++ printk(KERN_ERR "could not obtain gpio for "
++ "OVERO_GPIO_LCD_EN\n");
++
++ if ((gpio_request(OVERO_GPIO_LCD_BL, "OVERO_GPIO_LCD_BL") == 0) &&
++ (gpio_direction_output(OVERO_GPIO_LCD_BL, 1) == 0))
++ gpio_export(OVERO_GPIO_LCD_BL, 0);
++ else
++ printk(KERN_ERR "could not obtain gpio for "
++ "OVERO_GPIO_LCD_BL\n");
++}
++
++static int overo_panel_enable_dvi(struct omap_dss_device *dssdev)
++{
++ if (lcd_enabled) {
++ printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
++ return -EINVAL;
++ }
++ dvi_enabled = 1;
++
++ return 0;
++}
++
++static void overo_panel_disable_dvi(struct omap_dss_device *dssdev)
++{
++ dvi_enabled = 0;
++}
++
++static struct omap_dss_device overo_dvi_device = {
++ .type = OMAP_DISPLAY_TYPE_DPI,
++ .name = "dvi",
++ .driver_name = "generic_panel",
++ .phy.dpi.data_lines = 24,
++ .platform_enable = overo_panel_enable_dvi,
++ .platform_disable = overo_panel_disable_dvi,
++};
++
++static struct omap_dss_device overo_tv_device = {
++ .name = "tv",
++ .driver_name = "venc",
++ .type = OMAP_DISPLAY_TYPE_VENC,
++ .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO,
++};
++
++static int overo_panel_enable_lcd(struct omap_dss_device *dssdev)
++{
++ if (dvi_enabled) {
++ printk(KERN_ERR "cannot enable LCD, DVI is enabled\n");
++ return -EINVAL;
++ }
++
++ gpio_set_value(OVERO_GPIO_LCD_EN, 1);
++ gpio_set_value(OVERO_GPIO_LCD_BL, 1);
++ lcd_enabled = 1;
++ return 0;
++}
++
++static void overo_panel_disable_lcd(struct omap_dss_device *dssdev)
++{
++ gpio_set_value(OVERO_GPIO_LCD_EN, 0);
++ gpio_set_value(OVERO_GPIO_LCD_BL, 0);
++ lcd_enabled = 0;
++}
++
++#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
++ defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
++static struct omap_dss_device overo_lcd35_device = {
++ .type = OMAP_DISPLAY_TYPE_DPI,
++ .name = "lcd35",
++ .driver_name = "lgphilips_lb035q02_panel",
++ .phy.dpi.data_lines = 24,
++ .platform_enable = overo_panel_enable_lcd,
++ .platform_disable = overo_panel_disable_lcd,
++};
++#endif
++
++#if defined(CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C) || \
++ defined(CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C_MODULE)
++static struct omap_dss_device overo_lcd43_device = {
++ .type = OMAP_DISPLAY_TYPE_DPI,
++ .name = "lcd43",
++ .driver_name = "samsung_lte_panel",
++ .phy.dpi.data_lines = 24,
++ .platform_enable = overo_panel_enable_lcd,
++ .platform_disable = overo_panel_disable_lcd,
++};
++#endif
++
++static struct omap_dss_device *overo_dss_devices[] = {
++ &overo_dvi_device,
++ &overo_tv_device,
++#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
++ defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
++ &overo_lcd35_device,
++#endif
++#if defined(CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C) || \
++ defined(CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C_MODULE)
++ &overo_lcd43_device,
++#endif
++};
++
++static struct omap_dss_board_info overo_dss_data = {
++ .num_devices = ARRAY_SIZE(overo_dss_devices),
++ .devices = overo_dss_devices,
++ .default_device = &overo_dvi_device,
++};
++
++static struct platform_device overo_dss_device = {
++ .name = "omapdss",
++ .id = -1,
++ .dev = {
++ .platform_data = &overo_dss_data,
++ },
++};
++
++static struct regulator_consumer_supply overo_vdda_dac_supply =
++ REGULATOR_SUPPLY("vdda_dac", "omapdss");
++
++static struct regulator_consumer_supply overo_vdds_dsi_supply =
++ REGULATOR_SUPPLY("vdds_dsi", "omapdss");
++
+ static struct mtd_partition overo_nand_partitions[] = {
+ {
+ .name = "xloader",
+@@ -358,6 +478,37 @@ static struct regulator_init_data overo_vmmc1 = {
+ .consumer_supplies = &overo_vmmc1_supply,
+ };
+
++/* VDAC for DSS driving S-Video (8 mA unloaded, max 65 mA) */
++static struct regulator_init_data overo_vdac = {
++ .constraints = {
++ .min_uV = 1800000,
++ .max_uV = 1800000,
++ .valid_modes_mask = REGULATOR_MODE_NORMAL
++ | REGULATOR_MODE_STANDBY,
++ .valid_ops_mask = REGULATOR_CHANGE_MODE
++ | REGULATOR_CHANGE_STATUS,
++ },
++ .num_consumer_supplies = 1,
++ .consumer_supplies = &overo_vdda_dac_supply,
++};
++
++/* VPLL2 for digital video outputs */
++static struct regulator_init_data overo_vpll2 = {
++ .constraints = {
++ .name = "VDVI",
++ .min_uV = 1800000,
++ .max_uV = 1800000,
++ .valid_modes_mask = REGULATOR_MODE_NORMAL
++ | REGULATOR_MODE_STANDBY,
++ .valid_ops_mask = REGULATOR_CHANGE_MODE
++ | REGULATOR_CHANGE_STATUS,
++ },
++ .num_consumer_supplies = 1,
++ .consumer_supplies = &overo_vdds_dsi_supply,
++};
++
++/* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */
++
+ static struct twl4030_codec_audio_data overo_audio_data = {
+ .audio_mclk = 26000000,
+ };
+@@ -367,8 +518,6 @@ static struct twl4030_codec_data overo_codec_data = {
+ .audio = &overo_audio_data,
+ };
+
+-/* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */
+-
+ static struct twl4030_madc_platform_data overo_madc_data = {
+ .irq_line = 1,
+ };
+@@ -381,6 +530,8 @@ static struct twl4030_platform_data overo_twldata = {
+ .usb = &overo_usb_data,
+ .codec = &overo_codec_data,
+ .vmmc1 = &overo_vmmc1,
++ .vdac = &overo_vdac,
++ .vpll2 = &overo_vpll2,
+ };
+
+ static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
+@@ -401,23 +552,41 @@ static int __init overo_i2c_init(void)
+ return 0;
+ }
+
+-static struct platform_device overo_lcd_device = {
+- .name = "overo_lcd",
+- .id = -1,
+-};
+-
+-static struct omap_lcd_config overo_lcd_config __initdata = {
+- .ctrl_name = "internal",
++static struct spi_board_info overo_spi_board_info[] __initdata = {
++#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
++ defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
++ {
++ .modalias = "ads7846",
++ .bus_num = 1,
++ .chip_select = 0,
++ .max_speed_hz = 1500000,
++ .controller_data = &ads7846_mcspi_config,
++ .irq = OMAP_GPIO_IRQ(OVERO_GPIO_PENDOWN),
++ .platform_data = &ads7846_config,
++ },
++#endif
++#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
++ defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
++ {
++ .modalias = "lgphilips_lb035q02_panel-spi",
++ .bus_num = 1,
++ .chip_select = 1,
++ .max_speed_hz = 500000,
++ .mode = SPI_MODE_3,
++ },
++#endif
+ };
+
+-static struct omap_board_config_kernel overo_config[] __initdata = {
+- { OMAP_TAG_LCD, &overo_lcd_config },
+-};
++static int __init overo_spi_init(void)
++{
++ overo_ads7846_init();
++ spi_register_board_info(overo_spi_board_info,
++ ARRAY_SIZE(overo_spi_board_info));
++ return 0;
++}
+
+ static void __init overo_init_irq(void)
+ {
+- omap_board_config = overo_config;
+- omap_board_config_size = ARRAY_SIZE(overo_config);
+ omap2_init_common_infrastructure();
+ omap2_init_common_devices(mt46h32m32lf6_sdrc_params,
+ mt46h32m32lf6_sdrc_params);
+@@ -425,7 +594,7 @@ static void __init overo_init_irq(void)
+ }
+
+ static struct platform_device *overo_devices[] __initdata = {
+- &overo_lcd_device,
++ &overo_dss_device,
+ };
+
+ static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+@@ -466,8 +635,9 @@ static void __init overo_init(void)
+ overo_flash_init();
+ usb_musb_init(&musb_board_data);
+ usb_ehci_init(&ehci_pdata);
+- overo_ads7846_init();
++ overo_spi_init();
+ overo_init_smsc911x();
++ overo_display_init();
+
+ /* Ensure SDRC pins are mux'd for self-refresh */
+ omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
+@@ -510,7 +680,7 @@ static void __init overo_init(void)
+ "OVERO_GPIO_USBH_CPEN\n");
+ }
+
+-MACHINE_START(OVERO, "Gumstix Overo")
++MACHINE_START(OVERO, "Gumstsix Overo")
+ .boot_params = 0x80000100,
+ .map_io = omap3_map_io,
+ .reserve = omap_reserve,
+--
+1.6.6.1
+
--- /dev/null
+From 98d0c3ce9209fe34699ec99aa90efab39fe05c36 Mon Sep 17 00:00:00 2001
+From: Philip Balister <balister@nomad.(none)>
+Date: Wed, 17 Feb 2010 14:51:39 -0800
+Subject: [PATCH 27/29] Add defines to set config options in GPMC per CS control registers.
+
+---
+ arch/arm/plat-omap/include/plat/gpmc.h | 36 ++++++++++++++++++++++++++++++++
+ 1 files changed, 36 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
+index 85ded59..1a6c748 100644
+--- a/arch/arm/plat-omap/include/plat/gpmc.h
++++ b/arch/arm/plat-omap/include/plat/gpmc.h
+@@ -46,6 +46,11 @@
+ #define GPMC_ECC_WRITE 1 /* Reset Hardware ECC for write */
+ #define GPMC_ECC_READSYN 2 /* Reset before syndrom is read back */
+
++#define GPMC_CONFIG 0x50
++#define GPMC_STATUS 0x54
++#define GPMC_CS0_BASE 0x60
++#define GPMC_CS_SIZE 0x30
++
+ #define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31)
+ #define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30)
+ #define GPMC_CONFIG1_READTYPE_ASYNC (0 << 29)
+@@ -63,6 +68,7 @@
+ #define GPMC_CONFIG1_DEVICESIZE_16 GPMC_CONFIG1_DEVICESIZE(1)
+ #define GPMC_CONFIG1_DEVICETYPE(val) ((val & 3) << 10)
+ #define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0)
++#define GPMC_CONFIG1_DEVICETYPE_NAND GPMC_CONFIG1_DEVICETYPE(2)
+ #define GPMC_CONFIG1_MUXADDDATA (1 << 9)
+ #define GPMC_CONFIG1_TIME_PARA_GRAN (1 << 4)
+ #define GPMC_CONFIG1_FCLK_DIV(val) (val & 3)
+@@ -79,6 +85,35 @@
+ #define GPMC_PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F)
+ #define GPMC_PREFETCH_STATUS_COUNT(val) (val & 0x00003fff)
+
++#define GPMC_CONFIG2_CSWROFFTIME(val) ((val & 31) << 16)
++#define GPMC_CONFIG2_CSRDOFFTIME(val) ((val & 31) << 8)
++#define GPMC_CONFIG2_CSEXTRADELAY (1 << 7)
++#define GPMC_CONFIG2_CSONTIME(val) (val & 15)
++
++#define GPMC_CONFIG3_ADVWROFFTIME(val) ((val & 31) << 16)
++#define GPMC_CONFIG3_ADVRDOFFTIME(val) ((val & 31) << 8)
++#define GPMC_CONFIG3_ADVEXTRADELAY (1 << 7)
++#define GPMC_CONFIG3_ADVONTIME(val) (val & 15)
++
++#define GPMC_CONFIG4_WEOFFTIME(val) ((val & 31) << 24)
++#define GPMC_CONFIG4_WEEXTRADELAY (1 << 23)
++#define GPMC_CONFIG4_WEONTIME(val) ((val & 15) << 16)
++#define GPMC_CONFIG4_OEOFFTIME(val) ((val & 31) << 8)
++#define GPMC_CONFIG4_OEEXTRADELAY (1 << 7)
++#define GPMC_CONFIG4_OEONTIME(val) (val & 15)
++
++#define GPMC_CONFIG5_PAGEBURSTACCESSTIME(val) ((val & 15) << 24)
++#define GPMC_CONFIG5_RDACCESSTIME(val) ((val & 31) << 16)
++#define GPMC_CONFIG5_WRCYCLETIME(val) ((val & 31) << 8)
++#define GPMC_CONFIG5_RDCYCLETIME(val) (val & 31)
++
++#define GPMC_CONFIG6_WRACCESSTIME(val) ((val & 31) << 24)
++#define GPMC_CONFIG6_WRDATAONADMUXBUS(val) ((val & 15) << 16)
++#define GPMC_CONFIG6_CYCLE2CYCLEDELAY(val) ((val & 15) << 8)
++#define GPMC_CONFIG6_CYCLE2CYCLESAMECSEN (1 << 7)
++#define GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN (1 << 6)
++#define GPMC_CONFIG6_BUSTURNAROUND(val) (val & 15)
++
+ /*
+ * Note that all values in this struct are in nanoseconds except sync_clk
+ * (which is in picoseconds), while the register values are in gpmc_fck cycles.
+@@ -133,6 +168,7 @@ extern int gpmc_cs_reserved(int cs);
+ extern int gpmc_prefetch_enable(int cs, int dma_mode,
+ unsigned int u32_count, int is_write);
+ extern int gpmc_prefetch_reset(int cs);
++extern int gpmc_prefetch_status(void);
+ extern void omap3_gpmc_save_context(void);
+ extern void omap3_gpmc_restore_context(void);
+ extern void gpmc_init(void);
+--
+1.6.6.1
+
--- /dev/null
+From 5469329878e4bdb38fe39fc95676d9b752b1528f Mon Sep 17 00:00:00 2001
+From: Philip Balister <philip@opensdr.com>
+Date: Thu, 22 Apr 2010 19:41:58 -0700
+Subject: [PATCH 28/29] Add functions to dma.c to set address and length for src and dest.
+
+---
+ arch/arm/plat-omap/dma.c | 30 ++++++++++++++++++++++++++++++
+ arch/arm/plat-omap/include/plat/dma.h | 4 ++++
+ 2 files changed, 34 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
+index c4b2b47..f28f756 100644
+--- a/arch/arm/plat-omap/dma.c
++++ b/arch/arm/plat-omap/dma.c
+@@ -471,6 +471,21 @@ void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
+ }
+ EXPORT_SYMBOL(omap_set_dma_src_burst_mode);
+
++void omap_set_dma_src_addr_size(int lch, unsigned int addr, int elem_count)
++{
++
++ if (cpu_class_is_omap1()) {
++ p->dma_write(addr >> 16, CSSA, lch);
++ //p->dma_write((u16)addr, CSSA_L, lch);
++ }
++
++ if (cpu_class_is_omap2())
++ p->dma_write(addr, CSSA, lch);
++
++ p->dma_write(elem_count, CEN, lch);
++}
++EXPORT_SYMBOL_GPL(omap_set_dma_src_addr_size);
++
+ /* Note that dest_port is only for OMAP1 */
+ void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
+ unsigned long dest_start,
+@@ -561,6 +576,21 @@ void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
+ }
+ EXPORT_SYMBOL(omap_set_dma_dest_burst_mode);
+
++void omap_set_dma_dest_addr_size(int lch, unsigned int addr, int elem_count)
++{
++
++ if (cpu_class_is_omap1()) {
++ p->dma_write(addr >> 16, CDSA, lch);
++ //p->dma_write((u16)addr, CDSA_L, lch);
++ }
++
++ if (cpu_class_is_omap2())
++ p->dma_write(addr, CDSA, lch);
++
++ p->dma_write(elem_count, CEN, lch);
++}
++EXPORT_SYMBOL_GPL(omap_set_dma_dest_addr_size);
++
+ static inline void omap_enable_channel_irq(int lch)
+ {
+ u32 status;
+diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h
+index d1c916f..1e7243e 100644
+--- a/arch/arm/plat-omap/include/plat/dma.h
++++ b/arch/arm/plat-omap/include/plat/dma.h
+@@ -462,6 +462,8 @@ extern void omap_set_dma_src_index(int lch, int eidx, int fidx);
+ extern void omap_set_dma_src_data_pack(int lch, int enable);
+ extern void omap_set_dma_src_burst_mode(int lch,
+ enum omap_dma_burst_mode burst_mode);
++extern void omap_set_dma_src_addr_size(int lch, unsigned int addr,
++ int elem_count);
+
+ extern void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
+ unsigned long dest_start,
+@@ -470,6 +472,8 @@ extern void omap_set_dma_dest_index(int lch, int eidx, int fidx);
+ extern void omap_set_dma_dest_data_pack(int lch, int enable);
+ extern void omap_set_dma_dest_burst_mode(int lch,
+ enum omap_dma_burst_mode burst_mode);
++extern void omap_set_dma_dest_addr_size(int lch, unsigned int addr,
++ int elem_count);
+
+ extern void omap_set_dma_params(int lch,
+ struct omap_dma_channel_params *params);
+--
+1.6.6.1
+
--- /dev/null
+From 511a2c7822e68d081de3cefa8a2a82815da6ce78 Mon Sep 17 00:00:00 2001
+From: Philip Balister <balister@moose.(none)>
+Date: Wed, 13 Jan 2010 14:35:39 -0500
+Subject: [PATCH 29/29] usrp-embedded : Add driver for USRP Embedded FPGA interface.
+
+---
+ arch/arm/mach-omap2/board-overo.c | 176 +++++-
+ drivers/misc/Kconfig | 9 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/usrp_e.c | 1481 +++++++++++++++++++++++++++++++++++++
+ include/linux/usrp_e.h | 87 +++
+ 5 files changed, 1750 insertions(+), 4 deletions(-)
+ create mode 100644 drivers/misc/usrp_e.c
+ create mode 100644 include/linux/usrp_e.h
+
+diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
+index 8a44c17..8686015 100644
+--- a/arch/arm/mach-omap2/board-overo.c
++++ b/arch/arm/mach-omap2/board-overo.c
+@@ -35,6 +35,8 @@
+ #include <linux/mtd/partitions.h>
+ #include <linux/mmc/host.h>
+
++#include <linux/spi/spi.h>
++
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+ #include <asm/mach/flash.h>
+@@ -63,6 +65,8 @@
+ #define OVERO_GPIO_USBH_NRESET 183
+
+ #define NAND_BLOCK_SIZE SZ_128K
++#define GPMC_CS0_BASE 0x60
++#define GPMC_CS_SIZE 0x30
+
+ #define OVERO_SMSC911X_CS 5
+ #define OVERO_SMSC911X_GPIO 176
+@@ -164,7 +168,9 @@ static struct platform_device overo_smsc911x2_device = {
+
+ static struct platform_device *smsc911x_devices[] = {
+ &overo_smsc911x_device,
++#if 0
+ &overo_smsc911x2_device,
++#endif
+ };
+
+ static inline void __init overo_init_smsc911x(void)
+@@ -194,6 +200,7 @@ static inline void __init overo_init_smsc911x(void)
+
+ /* set up second smsc911x chip */
+
++#if 0
+ if (gpmc_cs_request(OVERO_SMSC911X2_CS, SZ_16M, &cs_mem_base2) < 0) {
+ printk(KERN_ERR "Failed request for GPMC mem for smsc911x2\n");
+ return;
+@@ -213,6 +220,7 @@ static inline void __init overo_init_smsc911x(void)
+ overo_smsc911x2_resources[1].start = OMAP_GPIO_IRQ(OVERO_SMSC911X2_GPIO);
+ overo_smsc911x2_resources[1].end = 0;
+
++#endif
+ platform_add_devices(smsc911x_devices, ARRAY_SIZE(smsc911x_devices));
+ }
+
+@@ -353,6 +361,16 @@ static struct regulator_consumer_supply overo_vdda_dac_supply =
+ static struct regulator_consumer_supply overo_vdds_dsi_supply =
+ REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+
++static struct spi_board_info overo_mcspi_board_info[] = {
++ {
++ .modalias = "spidev",
++ .max_speed_hz = 12000000, // 12 MHz
++ .bus_num = 1,
++ .chip_select = 0,
++ .mode = SPI_MODE_1,
++ },
++};
++
+ static struct mtd_partition overo_nand_partitions[] = {
+ {
+ .name = "xloader",
+@@ -432,8 +450,8 @@ static struct omap2_hsmmc_info mmc[] = {
+ .mmc = 2,
+ .caps = MMC_CAP_4_BIT_DATA,
+ .gpio_cd = -EINVAL,
+- .gpio_wp = -EINVAL,
+- .transceiver = true,
++ .transceiver = true,
++ .gpio_wp = 150,
+ .ocr_mask = 0x00100000, /* 3.3V */
+ },
+ {} /* Terminator */
+@@ -612,6 +630,8 @@ static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+ static struct omap_board_mux board_mux[] __initdata = {
+ { .reg_offset = OMAP_MUX_TERMINATOR },
+ };
++#else
++#define board_mux NULL
+ #endif
+
+ static struct omap_musb_board_data musb_board_data = {
+@@ -626,6 +646,148 @@ static struct omap_musb_board_data musb_board_data = {
+ .power = 100,
+ };
+
++static void __init usrp1_e_init(void)
++{
++ unsigned int tmp;
++
++ printk("Setup up gpmc timing.\n");
++
++// Set up CS4, data read/write
++
++#if 1
++ // Signal control parameters per chip select
++ tmp = gpmc_cs_read_reg(4, GPMC_CS_CONFIG1);
++// tmp |= (GPMC_CONFIG1_MUXADDDATA);
++// tmp |= (GPMC_CONFIG1_WRITETYPE_SYNC);
++// tmp |= (GPMC_CONFIG1_READTYPE_SYNC);
++ tmp |= (GPMC_CONFIG1_FCLK_DIV(0));
++ gpmc_cs_write_reg(4, GPMC_CS_CONFIG1, tmp);
++ printk("GPMC_CONFIG1 reg: %x\n", tmp);
++#endif
++
++#if 1
++ // CS signal timing parameter configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG2_CSONTIME(1); /* 1 */
++ tmp |= GPMC_CONFIG2_CSWROFFTIME(16); /* 16 */
++ tmp |= GPMC_CONFIG2_CSRDOFFTIME(16); /* 16 */
++ printk("GPMC_CONFIG2 reg: %x\n", tmp);
++ gpmc_cs_write_reg(4, GPMC_CS_CONFIG2, tmp);
++#endif
++
++#if 0
++ // nADV signal timing parameter configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG3_ADVONTIME(1);
++ tmp |= GPMC_CONFIG3_ADVRDOFFTIME(2);
++ tmp |= GPMC_CONFIG3_ADVWROFFTIME(2);
++ printk("GPMC_CONFIG3 reg: %x\n", tmp);
++ gpmc_cs_write_reg(4, GPMC_CS_CONFIG3, tmp);
++#endif
++
++#if 1
++ // nWE and nOE signals timing parameter configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG4_WEONTIME(3); /* 3 */
++ tmp |= GPMC_CONFIG4_WEOFFTIME(16); /* 16 */
++ tmp |= GPMC_CONFIG4_OEONTIME(3); /* 3 */
++ tmp |= GPMC_CONFIG4_OEOFFTIME(16); /* 16 */
++ printk("GPMC_CONFIG4 reg: %x\n", tmp);
++ gpmc_cs_write_reg(4, GPMC_CS_CONFIG4, tmp);
++#endif
++
++#if 1
++ // RdAccess time and Cycle time timing parameters configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG5_PAGEBURSTACCESSTIME(1);
++ tmp |= GPMC_CONFIG5_RDACCESSTIME(15); /* 15 */
++ tmp |= GPMC_CONFIG5_WRCYCLETIME(17); /* 17 */
++ tmp |= GPMC_CONFIG5_RDCYCLETIME(17); /* 17 */
++ printk("GPMC_CONFIG5 reg: %x\n", tmp);
++
++ gpmc_cs_write_reg(4, GPMC_CS_CONFIG5, tmp);
++#endif
++
++#if 1
++ // WrAccessTime WrDataOnADmuxBus, Cycle2Cycle, and BusTurnAround params
++ tmp = (1<<31);
++ tmp |= GPMC_CONFIG6_WRACCESSTIME(15); /* 15 */
++ tmp |= GPMC_CONFIG6_WRDATAONADMUXBUS(3);
++ tmp |= GPMC_CONFIG6_CYCLE2CYCLEDELAY(0);
++ tmp |= GPMC_CONFIG6_BUSTURNAROUND(0);
++ printk("GPMC_CONFIG6 reg: %x\n", tmp);
++ gpmc_cs_write_reg(4, GPMC_CS_CONFIG6, tmp);
++#endif
++
++// Configure timing for CS6, wishbone access
++
++#if 1
++ // Signal control parameters per chip select
++ tmp = gpmc_cs_read_reg(6, GPMC_CS_CONFIG1);
++// tmp |= (GPMC_CONFIG1_MUXADDDATA);
++ tmp |= (GPMC_CONFIG1_WRITETYPE_SYNC);
++ tmp |= (GPMC_CONFIG1_READTYPE_SYNC);
++ tmp |= (GPMC_CONFIG1_FCLK_DIV(0));
++ gpmc_cs_write_reg(6, GPMC_CS_CONFIG1, tmp);
++ printk("GPMC_CONFIG1 reg: %x\n", tmp);
++#endif
++
++#if 1
++ // CS signal timing parameter configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG2_CSONTIME(1);
++ tmp |= GPMC_CONFIG2_CSWROFFTIME(17);
++ tmp |= GPMC_CONFIG2_CSRDOFFTIME(17);
++ printk("GPMC_CONFIG2 reg: %x\n", tmp);
++ gpmc_cs_write_reg(6, GPMC_CS_CONFIG2, tmp);
++#endif
++
++#if 0
++ // nADV signal timing parameter configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG3_ADVONTIME(1);
++ tmp |= GPMC_CONFIG3_ADVRDOFFTIME(2);
++ tmp |= GPMC_CONFIG3_ADVWROFFTIME(2);
++ printk("GPMC_CONFIG3 reg: %x\n", tmp);
++ gpmc_cs_write_reg(6, GPMC_CS_CONFIG3, tmp);
++#endif
++
++#if 0
++ // nWE and nOE signals timing parameter configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG4_WEONTIME(3);
++ tmp |= GPMC_CONFIG4_WEOFFTIME(4);
++ tmp |= GPMC_CONFIG4_OEONTIME(3);
++ tmp |= GPMC_CONFIG4_OEOFFTIME(4);
++ printk("GPMC_CONFIG4 reg: %x\n", tmp);
++ gpmc_cs_write_reg(6, GPMC_CS_CONFIG4, tmp);
++#endif
++
++#if 0
++ // RdAccess time and Cycle time timing paraters configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG5_PAGEBURSTACCESSTIME(1);
++ tmp |= GPMC_CONFIG5_RDACCESSTIME(4);
++ tmp |= GPMC_CONFIG5_WRCYCLETIME(5);
++ tmp |= GPMC_CONFIG5_RDCYCLETIME(5);
++ printk("GPMC_CONFIG5 reg: %x\n", tmp);
++ gpmc_cs_write_reg(6, GPMC_CS_CONFIG5, tmp);
++#endif
++
++#if 1
++ // WrAccessTime WrDataOnADmuxBus, Cycle2Cycle, and BusTurnAround params
++ tmp = 0;
++ tmp |= GPMC_CONFIG6_WRACCESSTIME(15);
++ tmp |= GPMC_CONFIG6_WRDATAONADMUXBUS(3);
++ tmp |= GPMC_CONFIG6_CYCLE2CYCLEDELAY(3);
++ tmp |= GPMC_CONFIG6_CYCLE2CYCLESAMECSEN;
++ tmp |= GPMC_CONFIG6_BUSTURNAROUND(0);
++ printk("GPMC_CONFIG6 reg: %x\n", tmp);
++ gpmc_cs_write_reg(6, GPMC_CS_CONFIG6, tmp);
++#endif
++
++}
++
+ static void __init overo_init(void)
+ {
+ omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+@@ -637,8 +799,14 @@ static void __init overo_init(void)
+ usb_ehci_init(&ehci_pdata);
+ overo_spi_init();
+ overo_init_smsc911x();
++#if 0
+ overo_display_init();
+-
++#endif
++ usrp1_e_init();
++#if 1
++ spi_register_board_info(overo_mcspi_board_info,
++ ARRAY_SIZE(overo_mcspi_board_info));
++#endif
+ /* Ensure SDRC pins are mux'd for self-refresh */
+ omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
+ omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
+@@ -680,7 +848,7 @@ static void __init overo_init(void)
+ "OVERO_GPIO_USBH_CPEN\n");
+ }
+
+-MACHINE_START(OVERO, "Gumstsix Overo")
++MACHINE_START(OVERO, "Gumstix Overo")
+ .boot_params = 0x80000100,
+ .map_io = omap3_map_io,
+ .reserve = omap_reserve,
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 4d073f1..8bd6dfb 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -452,6 +452,15 @@ config PCH_PHUB
+ To compile this driver as a module, choose M here: the module will
+ be called pch_phub.
+
++config USRP_E
++ tristate "USRP-E FPGA interface driver"
++ default n
++ help
++ This driver is for the Ettus Research USRP Embedded Software
++ Defined Radio platform.
++
++ If you do not plan to run this kernel on that hardware choose N.
++
+ source "drivers/misc/c2port/Kconfig"
+ source "drivers/misc/eeprom/Kconfig"
+ source "drivers/misc/cb710/Kconfig"
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index 98009cc..f43483e 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -35,6 +35,7 @@ obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o
+ obj-$(CONFIG_C2PORT) += c2port/
+ obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/
+ obj-$(CONFIG_HMC6352) += hmc6352.o
++obj-$(CONFIG_USRP_E) += usrp_e.o
+ obj-y += eeprom/
+ obj-y += cb710/
+ obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o
+diff --git a/drivers/misc/usrp_e.c b/drivers/misc/usrp_e.c
+new file mode 100644
+index 0000000..2923b14
+--- /dev/null
++++ b/drivers/misc/usrp_e.c
+@@ -0,0 +1,1481 @@
++/*
++ * -*- linux-c -*-
++ * Interface for USRP Embedded from Ettus Research, LLC.
++ * This driver uses the GPMC interface on the OMAP3 to pass data
++ * to/from a Spartan 3 FPGA.
++ *
++ * Copyright (C) Ettus Research, LLC
++ *
++ * Written by Philip Balister <philip@opensdr.com>
++ *
++ * This program 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.
++ */
++
++#include "linux/fs.h"
++#include "linux/module.h"
++#include "linux/cdev.h"
++#include "linux/device.h"
++#include "linux/spinlock.h"
++#include "linux/errno.h"
++#include "linux/irq.h"
++#include "linux/interrupt.h"
++#include "linux/wait.h"
++#include "linux/sched.h"
++#include "linux/dma-mapping.h"
++#include "linux/semaphore.h"
++#include "linux/kthread.h"
++#include "linux/poll.h"
++#include "linux/slab.h"
++
++#include "plat/gpmc.h"
++#include "plat/gpio.h"
++#include "plat/dma.h"
++
++#include "asm/uaccess.h"
++#include "asm/io.h"
++#include "asm/atomic.h"
++
++#include "linux/usrp_e.h"
++
++#define TX_SPACE_AVAILABLE_GPIO 144
++#define RX_DATA_READY_GPIO 146
++
++static atomic_t use_count = ATOMIC_INIT(0);
++static atomic_t mapped = ATOMIC_INIT(0);
++static int shutting_down;
++
++struct spi_regs_wb;
++struct i2c_regs_wb;
++
++struct usrp_e_dev {
++ struct cdev cdev;
++ unsigned long mem_base;
++ unsigned long control_mem_base;
++ u32 *ioaddr;
++ u8 *ctl_addr;
++ struct spi_regs_wb *ctl_spi;
++ struct i2c_regs_wb *ctl_i2c;
++ spinlock_t fpga_lock;
++
++ atomic_t n_overruns;
++ atomic_t n_underruns;
++
++} *usrp_e_devp;
++
++struct dma_data {
++ int ch;
++ struct omap_dma_channel_params params;
++
++ unsigned long virt_from;
++ unsigned long virt_to;
++ unsigned long phys_from;
++ unsigned long phys_to;
++};
++
++#define MISC_REGS_BASE 0x0
++
++#define UE_REG_MISC_LED (MISC_REGS_BASE + 0)
++
++#define UE_REG_MISC_RX_LEN (MISC_REGS_BASE + 10)
++#define UE_REG_MISC_TX_LEN (MISC_REGS_BASE + 12)
++
++#define UE_REG_SLAVE(n) ((n)<<7)
++#define UE_REG_SR_ADDR(n) ((UE_REG_SLAVE(5)) + (4*(n)))
++
++#define UE_REG_CTRL_TX_CLEAR_UNDERRUN UE_REG_SR_ADDR(25)
++#define UE_SR_CLEAR_FIFO UE_REG_SR_ADDR(6)
++
++#define CTL_SPI_BASE 0x100
++
++struct spi_regs_wb {
++ u32 txrx0;
++ u32 txrx1;
++ u32 txrx2;
++ u32 txrx3;
++ u32 ctrl;
++ u32 div;
++ u32 ss;
++};
++
++/* Defines for spi ctrl register */
++#define UE_SPI_CTRL_ASS (BIT(13))
++#define UE_SPI_CTRL_IE (BIT(12))
++#define UE_SPI_CTRL_LSB (BIT(11))
++/* defines for TXNEG and RXNEG in usrp_e.h so user can pass them to driver. */
++#define UE_SPI_CTRL_GO_BSY (BIT(8))
++#define UE_SPI_CTRL_CHAR_LEN_MASK 0x7f
++
++
++#define CTL_I2C_BASE 0x180
++#if 1
++struct i2c_regs_wb {
++ u8 prescalar_lo;
++ u8 dummy;
++ u8 dummy1;
++ u8 dummy2;
++ u8 prescalar_hi;
++ u8 dummy3;
++ u8 dummy4;
++ u8 dummy5;
++ u8 ctrl;
++ u8 dummy6;
++ u8 dummy7;
++ u8 dummy8;
++ u8 data;
++ u8 dummy9;
++ u8 dummy10;
++ u8 dummy11;
++ u8 cmd_status;
++};
++#else
++struct i2c_regs_wb {
++ u16 prescalar_lo;
++ u16 dummy2;
++ u16 prescalar_hi;
++ u16 dummy3;
++ u16 ctrl;
++ u16 dummy6;
++ u16 data;
++ u16 dummy9;
++ u16 cmd_status;
++};
++#endif
++
++#define I2C_CTRL_EN (BIT(7)) /* core enable */
++#define I2C_CTRL_IE (BIT(6)) /* interrupt enable */
++
++/* STA, STO, RD, WR, and IACK bits are cleared automatically */
++
++#define I2C_CMD_START (BIT(7))
++#define I2C_CMD_STOP (BIT(6))
++#define I2C_CMD_RD (BIT(5))
++#define I2C_CMD_WR (BIT(4))
++#define I2C_CMD_NACK (BIT(3))
++#define I2C_CMD_RSVD_2 (BIT(2))
++#define I2C_CMD_RSVD_1 (BIT(1))
++#define I2C_CMD_IACK (BIT(0))
++
++#define I2C_ST_RXACK (BIT(7))
++#define I2C_ST_BUSY (BIT(6))
++#define I2C_ST_AL (BIT(5))
++#define I2C_RSVD_4 (BIT(4))
++#define I2C_RSVD_3 (BIT(3))
++#define I2C_RSVD_2 (BIT(2))
++#define I2C_ST_TIP (BIT(1))
++#define I2C_ST_IP (BIT(0))
++
++#define MAX_WB_DIV 4
++#define MASTER_CLK_RATE 64000000
++#define PRESCALAR(wb_div) (((MASTER_CLK_RATE/(wb_div)) / (5 * 100000)) - 1)
++
++static __u16 prescalar_values[MAX_WB_DIV+1] = {
++ 0xffff,
++ PRESCALAR(1),
++ PRESCALAR(2),
++ PRESCALAR(3),
++ PRESCALAR(4),
++};
++
++static struct dma_data *rx_dma;
++static struct dma_data *tx_dma;
++
++struct ring_buffer_entry {
++ unsigned long dma_addr;
++ __u8 *frame_addr;
++};
++
++struct ring_buffer {
++ struct ring_buffer_info (*rbi)[];
++ struct ring_buffer_entry (*rbe)[];
++ int num_pages;
++ unsigned long (*pages)[];
++};
++
++static struct ring_buffer tx_rb;
++static struct ring_buffer rx_rb;
++
++static struct usrp_e_ring_buffer_size_t rb_size;
++
++#define NUM_PAGES_RX_FLAGS 1
++#define NUM_RX_FRAMES 100
++#define NUM_PAGES_TX_FLAGS 1
++#define NUM_TX_FRAMES 100
++
++static int tx_rb_write;
++static int tx_rb_read;
++static int rx_rb_write;
++static int rx_rb_read;
++
++static int alloc_ring_buffer(struct ring_buffer *rb,
++ unsigned int num_bufs, enum dma_data_direction direction);
++static void delete_ring_buffer(struct ring_buffer *rb,
++ unsigned int num_bufs, enum dma_data_direction direction);
++static int alloc_ring_buffers(void);
++static void init_ring_buffer(struct ring_buffer *rb, int num_bufs,
++ int init_flags, enum dma_data_direction direction);
++
++static dev_t usrp_e_dev_number;
++static struct class *usrp_e_class;
++
++#define DEVICE_NAME "usrp_e"
++
++static const struct file_operations usrp_e_fops;
++
++static irqreturn_t space_available_irqhandler(int irq, void *dev_id);
++static irqreturn_t data_ready_irqhandler(int irq, void *dev_id);
++static void usrp_rx_dma_irq(int ch, u16 stat, void *data);
++static void usrp_tx_dma_irq(int ch, u16 stat, void *data);
++
++static DECLARE_WAIT_QUEUE_HEAD(data_received_queue);
++static DECLARE_WAIT_QUEUE_HEAD(space_available_queue);
++static DECLARE_WAIT_QUEUE_HEAD(received_data_from_user);
++static DECLARE_WAIT_QUEUE_HEAD(tx_rb_space_available);
++
++static int tx_dma_waiting_for_data;
++static int waiting_for_space_in_tx_rb;
++
++#define DEBUG_RX 1
++
++static DEFINE_SEMAPHORE(dma_lock);
++
++static void usrp_e_spi_init(void);
++static void usrp_e_i2c_init(void);
++
++static int init_dma_controller(void);
++static void release_dma_controller(void);
++static int get_frame_from_fpga_start(void);
++static int get_frame_from_fpga_finish(void);
++static int send_frame_to_fpga_start(void);
++static int send_frame_to_fpga_finish(void);
++
++static int rx_dma_active;
++static int tx_dma_active;
++
++static int __init
++usrp_e_init(void)
++{
++ int ret;
++ struct usrp_e_dev *p;
++
++ printk(KERN_DEBUG "usrp_e entering driver initialization\n");
++
++ if (alloc_chrdev_region(&usrp_e_dev_number, 0, 1, DEVICE_NAME) < 0) {
++ printk(KERN_DEBUG "Can't register device\n");
++ return -1;
++ }
++
++ usrp_e_class = class_create(THIS_MODULE, DEVICE_NAME);
++
++ usrp_e_devp = kzalloc(sizeof(struct usrp_e_dev), GFP_KERNEL);
++ if (!usrp_e_devp) {
++ printk(KERN_ERR "Bad kmalloc\n");
++ return -ENOMEM;
++ }
++
++ p = usrp_e_devp; /* Shorten var name so I stay sane. */
++
++ printk(KERN_DEBUG "usrp_e data struct malloc'd.\n");
++
++ atomic_set(&p->n_underruns, 0);
++ atomic_set(&p->n_overruns, 0);
++
++ printk(KERN_DEBUG "usrp_e Data initialized..\n");
++
++ cdev_init(&p->cdev, &usrp_e_fops);
++ p->cdev.owner = THIS_MODULE;
++
++ ret = cdev_add(&p->cdev, MKDEV(MAJOR(usrp_e_dev_number), 0), 1);
++ if (ret) {
++ printk(KERN_ERR "Bad cdev\n");
++ return ret;
++ }
++
++ printk(KERN_DEBUG "usrp_e major number : %d\n",
++ MAJOR(usrp_e_dev_number));
++ device_create(usrp_e_class, NULL, MKDEV(MAJOR(usrp_e_dev_number), 0),
++ NULL, "usrp_e%d", 0);
++
++ printk(KERN_DEBUG "Getting Chip Select\n");
++
++ if (gpmc_cs_request(4, SZ_2K, &p->mem_base) < 0) {
++ printk(KERN_ERR "Failed request for GPMC mem for usrp_e\n");
++ return -1;
++ }
++ printk(KERN_DEBUG "Got CS4, address = %lx\n", p->mem_base);
++
++ if (!request_mem_region(p->mem_base, SZ_2K, "usrp_e")) {
++ printk(KERN_ERR "Request_mem_region failed.\n");
++ gpmc_cs_free(4);
++ return -1;
++ }
++
++ p->ioaddr = ioremap(p->mem_base, SZ_2K);
++ spin_lock_init(&p->fpga_lock);
++
++ if (gpmc_cs_request(6, SZ_2K, &p->control_mem_base) < 0) {
++ printk(KERN_ERR "Failed request for GPMC control mem for usrp_e\n");
++ return -1;
++ }
++ printk(KERN_DEBUG "Got CS6, address = %lx\n", p->control_mem_base);
++
++ if (!request_mem_region(p->control_mem_base, SZ_2K, "usrp_e_c")) {
++ printk(KERN_ERR "Request_mem_region failed.\n");
++ gpmc_cs_free(6);
++ return -1;
++ }
++
++ p->ctl_addr = ioremap_nocache(p->control_mem_base, SZ_2K);
++
++ /* Initialize wishbone SPI and I2C interfaces */
++
++ usrp_e_spi_init();
++ usrp_e_i2c_init();
++
++ /* Configure GPIO's */
++
++ if (!(((gpio_request(TX_SPACE_AVAILABLE_GPIO,
++ "TX_SPACE_AVAILABLE_GPIO") == 0) &&
++ (gpio_direction_input(TX_SPACE_AVAILABLE_GPIO) == 0)))) {
++ printk(KERN_ERR "Could not claim GPIO for TX_SPACE_AVAILABLE_GPIO\n");
++ return -1;
++ }
++
++ if (!(((gpio_request(RX_DATA_READY_GPIO, "RX_DATA_READY_GPIO") == 0) &&
++ (gpio_direction_input(RX_DATA_READY_GPIO) == 0)))) {
++ printk(KERN_ERR "Could not claim GPIO for RX_DATA_READY_GPIO\n");
++ return -1;
++ }
++
++ /* Debug gpios */
++ if (!(((gpio_request(14, "Debug0") == 0) &&
++ (gpio_direction_output(14, 0) == 0)))) {
++ printk(KERN_ERR "Could not claim GPIO for Debug0\n");
++ return -1;
++ }
++
++ if (!(((gpio_request(21, "Debug1") == 0) &&
++ (gpio_direction_output(21, 0) == 0)))) {
++ printk(KERN_ERR "Could not claim GPIO for Debug1\n");
++ return -1;
++ }
++
++ if (!(((gpio_request(22, "Debug2") == 0) &&
++ (gpio_direction_output(22, 0) == 0)))) {
++ printk(KERN_ERR "Could not claim GPIO for Debug2\n");
++ return -1;
++ }
++
++ if (!(((gpio_request(23, "Debug3") == 0) &&
++ (gpio_direction_output(23, 0) == 0)))) {
++ printk(KERN_ERR "Could not claim GPIO for Debug3\n");
++ return -1;
++ }
++
++
++ rb_size.num_pages_rx_flags = NUM_PAGES_RX_FLAGS;
++ rb_size.num_rx_frames = NUM_RX_FRAMES;
++ rb_size.num_pages_tx_flags = NUM_PAGES_TX_FLAGS;
++ rb_size.num_tx_frames = NUM_TX_FRAMES;
++
++ ret = alloc_ring_buffers();
++ if (ret < 0)
++ return ret;
++
++ /* Initialize various DMA related flags */
++ rx_dma_active = 0;
++ tx_dma_active = 0;
++ shutting_down = 0;
++
++ printk(KERN_DEBUG "usrp_e Driver Initialized.\n");
++
++ return 0;
++}
++
++static void __exit
++usrp_e_cleanup(void)
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++
++ unregister_chrdev_region(usrp_e_dev_number, 1);
++
++ release_mem_region(p->mem_base, SZ_2K);
++ release_mem_region(p->control_mem_base, SZ_2K);
++
++ device_destroy(usrp_e_class, MKDEV(MAJOR(usrp_e_dev_number), 0));
++ cdev_del(&p->cdev);
++
++ class_destroy(usrp_e_class);
++
++ iounmap(p->ioaddr);
++ iounmap(p->ctl_addr);
++
++ gpmc_cs_free(4);
++ gpmc_cs_free(6);
++
++ printk(KERN_DEBUG "Freeing gpios\n");
++
++ gpio_free(TX_SPACE_AVAILABLE_GPIO);
++ gpio_free(RX_DATA_READY_GPIO);
++
++ /* debug */
++ gpio_free(14);
++ gpio_free(21);
++ gpio_free(22);
++ gpio_free(23);
++
++ delete_ring_buffer(&tx_rb, rb_size.num_tx_frames, DMA_TO_DEVICE);
++ delete_ring_buffer(&rx_rb, rb_size.num_rx_frames, DMA_FROM_DEVICE);
++
++ kfree(p);
++
++ printk(KERN_DEBUG "Leaving cleanup\n");
++}
++
++static int
++usrp_e_open(struct inode *inode, struct file *file)
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++ int ret;
++
++ printk(KERN_DEBUG "usrp_e open called, use_count = %d\n",
++ atomic_read(&use_count));
++ if (atomic_add_return(1, &use_count) != 1) {
++ printk(KERN_ERR "use_count = %d\n", atomic_read(&use_count));
++ atomic_dec(&use_count);
++ return -EBUSY;
++ }
++
++ /* Clear rx and tx fifos in the fpga */
++ writel(1, p->ctl_addr + UE_SR_CLEAR_FIFO);
++ writel(2, p->ctl_addr + UE_SR_CLEAR_FIFO);
++
++#if 0
++ usrp_e_devp = container_of(inode->i_cdev, struct usrp_e_dev, cdev);
++
++ file->private_data = usrp_e_devp;
++#endif
++
++ ret = init_dma_controller();
++ if (ret < 0)
++ return ret;
++
++ tx_rb_write = 0;
++ tx_rb_read = 0;
++
++ rx_rb_write = 0;
++ rx_rb_read = 0;
++
++ tx_dma_active = 0;
++ rx_dma_active = 0;
++ shutting_down = 0;
++
++ init_ring_buffer(&rx_rb, rb_size.num_rx_frames, RB_KERNEL, DMA_FROM_DEVICE);
++ init_ring_buffer(&tx_rb, rb_size.num_tx_frames, RB_KERNEL, DMA_TO_DEVICE);
++
++ /* Configure interrupts for GPIO pins */
++
++ ret = request_irq(gpio_to_irq(TX_SPACE_AVAILABLE_GPIO),
++ space_available_irqhandler,
++ IRQF_TRIGGER_RISING, "usrp_e_space_available", NULL);
++
++ ret = request_irq(gpio_to_irq(RX_DATA_READY_GPIO),
++ data_ready_irqhandler,
++ IRQF_TRIGGER_RISING, "usrp_e_data_ready", NULL);
++
++ printk(KERN_DEBUG "usrp: leaving open\n");
++ return 0;
++}
++
++static int
++usrp_e_release(struct inode *inode, struct file *file)
++{
++ struct usrp_e_dev *usrp_e_devp = file->private_data;
++
++ printk(KERN_DEBUG "usrp_e release called\n");
++
++ if (atomic_read(&use_count) != 1) {
++ printk(KERN_ERR "Attempt to close usrp_e driver that is not open");
++ return -ENOENT;
++ }
++
++ printk(KERN_DEBUG "Waiting for DMA to become inactive\n");
++ shutting_down = 0;
++ while (tx_dma_active || rx_dma_active)
++ cpu_relax();
++
++ /* Freeing gpio irq's */
++ printk(KERN_DEBUG "Freeing gpio irq's\n");
++
++ free_irq(gpio_to_irq(TX_SPACE_AVAILABLE_GPIO), NULL);
++ free_irq(gpio_to_irq(RX_DATA_READY_GPIO), NULL);
++
++ printk(KERN_DEBUG "Freeing DMA channels\n");
++
++ release_dma_controller();
++
++ usrp_e_devp = 0;
++
++ atomic_dec(&use_count);
++
++ return 0;
++}
++
++static ssize_t
++usrp_e_read(struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++ size_t ret;
++ int rx_pkt_len;
++
++ if (count > SZ_2K)
++ return -EMSGSIZE;
++
++ if (!((*rx_rb.rbi)[rx_rb_read].flags & RB_USER)) {
++ if (wait_event_interruptible(data_received_queue,
++ (((*rx_rb.rbi)[rx_rb_read].flags & RB_USER))))
++ return -EINTR;
++ }
++
++ rx_pkt_len = (*rx_rb.rbi)[rx_rb_read].len;
++ ret = copy_to_user(buf, (*rx_rb.rbe)[rx_rb_read].frame_addr, rx_pkt_len);
++
++ (*rx_rb.rbi)[rx_rb_read].flags = RB_KERNEL;
++
++ rx_rb_read++;
++ if (rx_rb_read == rb_size.num_rx_frames)
++ rx_rb_read = 0;
++
++ get_frame_from_fpga_start();
++
++ return ((ret == 0) ? rx_pkt_len : -ret);
++}
++
++static ssize_t
++usrp_e_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
++{
++ size_t ret;
++
++#if 0
++// printk("In write.\n");
++
++ /* Trigger a DMA transfer. Used to start transmit after writing */
++ /* data into the transmit ring buffer from user space */
++ if (count < 0) {
++ send_frame_to_fpga_start();
++ return 0;
++ }
++
++ if (count > SZ_2K)
++ return -EMSGSIZE;
++
++// printk("Write flags: %d\n", (*tx_rb.rbe)[tx_rb_write].flags);
++ if (!((*tx_rb.rbi)[tx_rb_write].flags & RB_KERNEL)) {
++ waiting_for_space_in_tx_rb = 1;
++// printk("Sleeping\n");
++ if (wait_event_interruptible(tx_rb_space_available,
++ ((*tx_rb.rbi)[tx_rb_write].flags & RB_KERNEL)))
++ return -EINTR;
++// printk("Waking\n");
++ }
++
++ ret = copy_from_user((*tx_rb.rbe)[tx_rb_write].frame_addr, buf, count);
++ if (ret)
++ return -ret;
++
++ (*tx_rb.rbi)[tx_rb_write].len = count;
++ (*tx_rb.rbi)[tx_rb_write].flags = RB_USER;
++
++ tx_rb_write++;
++ if (tx_rb_write == rb_size.num_tx_frames)
++ tx_rb_write = 0;
++
++// printk("Calling send_to_fpga_start from write\n");
++#endif
++ send_frame_to_fpga_start();
++
++ return count;
++}
++
++static loff_t
++usrp_e_llseek(struct file *file, loff_t offest, int orig)
++{
++ printk(KERN_DEBUG "usrp_e llseek called\n");
++
++ return 0;
++}
++
++static int usrp_e_ctl16(unsigned long arg, int direction)
++{
++ struct usrp_e_ctl16 __user *argp = (struct usrp_e_ctl16 __user *) arg;
++ int i;
++ struct usrp_e_ctl16 ctl;
++
++ if (copy_from_user(&ctl, argp, sizeof(struct usrp_e_ctl16)))
++ return -EFAULT;
++
++ if (ctl.count > 10)
++ return -EINVAL;
++
++ if (direction == 0) {
++ for (i = 0; i < ctl.count; i++)
++ writew(ctl.buf[i], &usrp_e_devp->ctl_addr \
++ [i + ctl.offset]);
++ } else if (direction == 1) {
++ for (i = 0; i < ctl.count; i++)
++ ctl.buf[i] = readw(&usrp_e_devp->ctl_addr \
++ [i + ctl.offset]);
++
++ if (copy_to_user(argp, &ctl, sizeof(struct usrp_e_ctl16)))
++ return -EFAULT;
++ } else
++ return -EFAULT;
++
++ return 0;
++}
++
++static int usrp_e_ctl32(unsigned long arg, int direction)
++{
++ struct usrp_e_ctl32 __user *argp = (struct usrp_e_ctl32 __user *) arg;
++ int i;
++ struct usrp_e_ctl32 ctl;
++
++ if (copy_from_user(&ctl, argp, sizeof(struct usrp_e_ctl32)))
++ return -EFAULT;
++
++ if (ctl.count > 20)
++ return -EINVAL;
++
++ if (direction == 0) {
++ for (i = 0; i < ctl.count; i++)
++ writel(ctl.buf[i], &usrp_e_devp->ctl_addr \
++ [i + ctl.offset]);
++ } else if (direction == 1) {
++ for (i = 0; i < ctl.count; i++)
++ ctl.buf[i] = readl(&usrp_e_devp->ctl_addr \
++ [i + ctl.offset]);
++
++ if (copy_to_user(argp, &ctl, sizeof(struct usrp_e_ctl16)))
++ return -EFAULT;
++
++ } else
++ return -EFAULT;
++
++ return 0;
++}
++
++static int usrp_e_get_rb_info(unsigned long arg)
++{
++ struct usrp_e_ring_buffer_size_t __user *argp = (struct usrp_e_ring_buffer_size_t __user *) arg;
++ int i;
++
++ if (copy_to_user(argp, &rb_size, sizeof(rb_size)))
++ return -EFAULT;
++
++ return 0;
++}
++
++static void usrp_e_spi_init()
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++
++ p->ctl_spi = (struct spi_regs_wb *)(p->ctl_addr + CTL_SPI_BASE);
++ p->ctl_spi->div = 64; /* 1 = Div by 4 (12.5 MHz) */
++}
++
++static int usrp_e_spi_wait(void)
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++
++ while (p->ctl_spi->ctrl & UE_SPI_CTRL_GO_BSY) {
++ if (signal_pending(current)) {
++ printk(KERN_DEBUG "Signal received.\n");
++ set_current_state(TASK_RUNNING);
++ return -EINTR;
++ }
++ schedule();
++ }
++
++ return 0;
++}
++
++static int usrp_e_spi(unsigned long __user arg)
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++ struct usrp_e_spi __user *argp = (struct usrp_e_spi __user *) arg;
++ struct usrp_e_spi spi_cmd;
++ int ctrl, ret;
++
++ if (copy_from_user(&spi_cmd, argp, sizeof(struct usrp_e_spi)))
++ return -EFAULT;
++
++ spi_cmd.flags &= (UE_SPI_CTRL_TXNEG | UE_SPI_CTRL_RXNEG);
++ ctrl = UE_SPI_CTRL_ASS | (UE_SPI_CTRL_CHAR_LEN_MASK & spi_cmd.length) \
++ | spi_cmd.flags;
++
++ ret = usrp_e_spi_wait();
++ if (ret < 0)
++ return ret;
++
++ p->ctl_spi->ss = spi_cmd.slave & 0xff;
++
++ p->ctl_spi->txrx0 = spi_cmd.data;
++
++ p->ctl_spi->ctrl = ctrl;
++ p->ctl_spi->ctrl = ctrl | UE_SPI_CTRL_GO_BSY;
++
++ if (spi_cmd.readback) {
++ usrp_e_spi_wait();
++ if (copy_to_user(&argp->data, &p->ctl_spi->txrx0,
++ sizeof(__u32)))
++ return -EFAULT;
++ else
++ return 0;
++ } else
++ return 0;
++
++}
++
++static void usrp_e_i2c_init()
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++ int wb_div;
++
++ p->ctl_i2c = (struct i2c_regs_wb *)(p->ctl_addr + CTL_I2C_BASE);
++
++ writeb(0, &p->ctl_i2c->ctrl); /* disable core */
++
++ /* Assume wb_div is 4, deal with this later */
++ wb_div = 4;
++ if (wb_div > MAX_WB_DIV)
++ wb_div = MAX_WB_DIV;
++
++ writeb((prescalar_values[wb_div] & 0xff), &p->ctl_i2c->prescalar_lo);
++ writeb(((prescalar_values[wb_div] >> 8) & 0xff),
++ &p->ctl_i2c->prescalar_hi);
++ writeb(I2C_CTRL_EN, &p->ctl_i2c->ctrl); /* enable core */
++}
++
++static int usrp_e_i2c_wait(__u32 mask, int chk_ack)
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++
++ while (readb(&p->ctl_i2c->cmd_status) & mask) {
++ if (signal_pending(current)) {
++ printk(KERN_DEBUG "Signal received.\n");
++ set_current_state(TASK_RUNNING);
++ return -EINTR;
++ }
++ schedule();
++ }
++
++ if (chk_ack) {
++ if ((readb(&p->ctl_i2c->cmd_status) & I2C_ST_RXACK) == 0)
++ return 1;
++ else
++ return 0;
++ }
++
++ return 0;
++}
++
++static int usrp_e_i2c(unsigned long arg, int direction)
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++ struct usrp_e_i2c __user *argp = (struct usrp_e_i2c __user *) arg;
++ struct usrp_e_i2c tmp;
++ struct usrp_e_i2c *i2c_msg;
++ int ret, len, i;
++
++ if (copy_from_user(&tmp, argp, sizeof(struct usrp_e_i2c)))
++ return -EFAULT;
++
++ i2c_msg = kmalloc(sizeof(struct usrp_e_i2c) + tmp.len, GFP_KERNEL);
++ if (!i2c_msg)
++ return -ENOMEM;
++
++ if (copy_from_user(i2c_msg, argp,
++ (sizeof(struct usrp_e_i2c) + tmp.len)))
++ return -EFAULT;
++
++ if (direction) {
++ /* read */
++ if (i2c_msg->len == 0)
++ return 1;
++
++ usrp_e_i2c_wait(I2C_ST_BUSY, 0);
++
++ writeb(((i2c_msg->addr << 1) | 1), &p->ctl_i2c->data);
++ writeb((I2C_CMD_WR | I2C_CMD_START), &p->ctl_i2c->cmd_status);
++ ret = usrp_e_i2c_wait(I2C_ST_TIP, 1);
++ if (ret < 0) {
++ return ret;
++ } else if (ret == 0) {
++ writeb(I2C_CMD_STOP, &p->ctl_i2c->cmd_status);
++ return 2;
++ }
++
++ for (len = i2c_msg->len, i = 0; len > 0; i++, len--) {
++ writeb((I2C_CMD_RD | ((len == 1) ?
++ (I2C_CMD_NACK | I2C_CMD_STOP) : 0)),
++ &p->ctl_i2c->cmd_status);
++ usrp_e_i2c_wait(I2C_ST_TIP, 0);
++ i2c_msg->data[i] = readb(&p->ctl_i2c->data);
++ }
++ if (copy_to_user(argp, i2c_msg, (sizeof(struct usrp_e_i2c) +
++ tmp.len)))
++ return -EFAULT;
++ } else {
++ /* write */
++ usrp_e_i2c_wait(I2C_ST_BUSY, 0);
++ writeb(((i2c_msg->addr << 1) | 0), &p->ctl_i2c->data);
++ writeb((I2C_CMD_WR | I2C_CMD_START |
++ (i2c_msg->len == 0 ? I2C_CMD_STOP : 0)),
++ &p->ctl_i2c->cmd_status);
++ ret = usrp_e_i2c_wait(I2C_ST_TIP, 1);
++ if (ret < 0) {
++ return ret;
++ } else if (ret == 0) {
++ writeb(I2C_CMD_STOP, &p->ctl_i2c->cmd_status);
++ return 2;
++ }
++ for (len = i2c_msg->len, i = 0; len > 0; i++, len--) {
++ writeb(i2c_msg->data[i], &p->ctl_i2c->data);
++ writeb((I2C_CMD_WR | (len == 1 ? I2C_CMD_STOP : 0)),
++ &p->ctl_i2c->cmd_status);
++ ret = usrp_e_i2c_wait(I2C_ST_TIP, 1);
++ if (ret < 0) {
++ return ret;
++ } else if (ret == 0) {
++ writeb(I2C_CMD_STOP, &p->ctl_i2c->cmd_status);
++ return 2;
++ }
++ }
++
++ }
++
++
++ return 1;
++}
++
++static int usrp_e_ioctl(struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++
++ switch (cmd) {
++ case USRP_E_WRITE_CTL16:
++ return usrp_e_ctl16(arg, 0);
++
++ case USRP_E_READ_CTL16:
++ return usrp_e_ctl16(arg, 1);
++
++ case USRP_E_WRITE_CTL32:
++ return usrp_e_ctl32(arg, 0);
++
++ case USRP_E_READ_CTL32:
++ return usrp_e_ctl32(arg, 1);
++
++ case USRP_E_SPI:
++ return usrp_e_spi(arg);
++
++ case USRP_E_I2C_WRITE:
++ return usrp_e_i2c(arg, 0);
++
++ case USRP_E_I2C_READ:
++ return usrp_e_i2c(arg, 1);
++
++ case USRP_E_GET_RB_INFO:
++ return usrp_e_get_rb_info(arg);
++
++ default:
++ return -ENOTTY;
++ }
++
++ return 0;
++}
++
++static unsigned int usrp_e_poll(struct file *filp, poll_table *wait)
++{
++ unsigned int mask = 0;
++
++ poll_wait(filp, &data_received_queue, wait);
++ poll_wait(filp, &tx_rb_space_available, wait);
++
++ // Make sure write is active before sleeping
++ send_frame_to_fpga_start();
++
++ /* Make sure to read in case the rx ring buffer is full */
++ get_frame_from_fpga_start();
++
++ // This likely needs some locking. The pointer is incremented
++ // before the flag state is updated.
++
++ if (rx_rb_write == 0) {
++ if ((*rx_rb.rbi)[rb_size.num_rx_frames - 1].flags & RB_USER)
++ mask |= POLLIN | POLLRDNORM;
++ } else {
++ if ((*rx_rb.rbi)[rx_rb_write - 1].flags & RB_USER)
++ mask |= POLLIN | POLLRDNORM;
++ }
++
++ if (tx_rb_read == 0) {
++ if ((*tx_rb.rbi)[rb_size.num_tx_frames - 1].flags & RB_KERNEL)
++ mask |= POLLOUT | POLLWRNORM;
++ } else {
++ if ((*tx_rb.rbi)[tx_rb_read - 1].flags & RB_KERNEL)
++ mask |= POLLOUT | POLLWRNORM;
++ }
++
++ return mask;
++
++}
++
++/* The mmap code is based on code in af_packet.c */
++
++static void usrp_e_mm_open(struct vm_area_struct *vma)
++{
++
++ atomic_inc(&mapped);
++}
++
++static void usrp_e_mm_close(struct vm_area_struct *vma)
++{
++
++ atomic_dec(&mapped);
++}
++
++static const struct vm_operations_struct usrp_e_mmap_ops = {
++ .open = usrp_e_mm_open,
++ .close = usrp_e_mm_close,
++};
++
++static int usrp_e_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ unsigned long size, expected_size;
++ unsigned int i;
++ unsigned long start;
++ int err;
++ struct page *page;
++
++ printk("In mmap\n");
++
++ if (vma->vm_pgoff)
++ return -EINVAL;
++
++ /* Verify the user will map the entire tx and rx ring buffer space */
++ expected_size = (rb_size.num_rx_frames + rb_size.num_tx_frames) * (PAGE_SIZE >> 1)
++ + (rb_size.num_pages_rx_flags + rb_size.num_pages_tx_flags) * PAGE_SIZE;
++
++ size = vma->vm_end - vma->vm_start;
++ printk(KERN_DEBUG "Size = %d, expected sixe = %d\n", size, expected_size);
++
++ if (size != expected_size)
++ return -EINVAL;
++
++ start = vma->vm_start;
++
++ page = virt_to_page(rx_rb.rbi);
++ err = vm_insert_page(vma, start, page);
++ if (err)
++ return -EINVAL;
++
++ start += PAGE_SIZE;
++
++ for (i = 0; i < rx_rb.num_pages; ++i) {
++ struct page *page = virt_to_page((*rx_rb.pages)[i]);
++ err = vm_insert_page(vma, start, page);
++ if (err)
++ return -EINVAL;
++
++ start += PAGE_SIZE;
++ }
++
++ page = virt_to_page(tx_rb.rbi);
++ err = vm_insert_page(vma, start, page);
++ if (err)
++ return -EINVAL;
++
++ start += PAGE_SIZE;
++
++ for (i = 0; i < tx_rb.num_pages; ++i) {
++ struct page *page = virt_to_page((*tx_rb.pages)[i]);
++
++ err = vm_insert_page(vma, start, page);
++ if (err)
++ return err;
++
++ start += PAGE_SIZE;
++ }
++
++ vma->vm_ops = &usrp_e_mmap_ops;
++
++ return 0;
++}
++
++static const struct file_operations usrp_e_fops = {
++ .owner = THIS_MODULE,
++ .open = usrp_e_open,
++ .release = usrp_e_release,
++ .read = usrp_e_read,
++ .write = usrp_e_write,
++ .llseek = usrp_e_llseek,
++ .unlocked_ioctl = usrp_e_ioctl,
++ .poll = usrp_e_poll,
++ .mmap = usrp_e_mmap,
++};
++
++MODULE_VERSION("0.1");
++MODULE_ALIAS(DEVICE_NAME);
++MODULE_DESCRIPTION(DEVICE_NAME);
++MODULE_AUTHOR("Philip Balister <philip@opensdr.com>");
++MODULE_LICENSE("GPL v2");
++
++module_init(usrp_e_init);
++module_exit(usrp_e_cleanup);
++
++static irqreturn_t space_available_irqhandler(int irq, void *dev_id)
++{
++ int serviced = IRQ_NONE;
++
++#ifdef DEBUG_TX
++ gpio_set_value(22, 1);
++#endif
++
++// printk("Calling send_to_fpga_start from space_available irq\n");
++ send_frame_to_fpga_start();
++
++ serviced = IRQ_HANDLED;
++
++#ifdef DEBUG_TX
++ gpio_set_value(22, 0);
++#endif
++
++ return serviced;
++}
++
++static void usrp_rx_dma_irq(int ch, u16 stat, void *data)
++{
++
++#ifdef DEBUG_RX
++ gpio_set_value(23, 1);
++#endif
++
++ rx_dma_active = 0;
++
++ get_frame_from_fpga_finish();
++
++#ifdef DEBUG_RX
++ gpio_set_value(23, 0);
++#endif
++}
++
++static void usrp_tx_dma_irq(int ch, u16 stat, void *data)
++{
++
++#ifdef DEBUG_TX
++ gpio_set_value(23, 1);
++#endif
++ tx_dma_active = 0;
++
++ send_frame_to_fpga_finish();
++
++#ifdef DEBUG_TX
++ gpio_set_value(23, 0);
++#endif
++
++/* Save
++ gpio_set_value(21, 1);
++ gpio_set_value(21, 0);
++*/
++
++}
++
++static irqreturn_t data_ready_irqhandler(int irq, void *dev_id)
++{
++ int serviced = IRQ_NONE;
++
++#ifdef DEBUG_RX
++ gpio_set_value(22, 1);
++#endif
++
++ get_frame_from_fpga_start();
++
++ serviced = IRQ_HANDLED;
++
++#ifdef DEBUG_RX
++ gpio_set_value(22, 0);
++#endif
++ return serviced;
++}
++
++static int init_dma_controller()
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++
++ rx_dma = kzalloc(sizeof(struct dma_data), GFP_KERNEL);
++ if (!rx_dma) {
++ printk(KERN_ERR "Failed to allocate memory for rx_dma struct.");
++ return -ENOMEM;
++ }
++
++ if (omap_request_dma(OMAP_DMA_NO_DEVICE, "usrp-e-rx",
++ usrp_rx_dma_irq, (void *) rx_dma, &rx_dma->ch)) {
++ printk(KERN_ERR "Could not get rx DMA channel for usrp_e\n");
++ return -ENOMEM;
++ }
++ printk(KERN_DEBUG "rx_dma->ch %d\n", rx_dma->ch);
++
++ rx_dma->phys_from = p->mem_base;
++
++ memset(&rx_dma->params, 0, sizeof(rx_dma->params));
++ rx_dma->params.data_type = OMAP_DMA_DATA_TYPE_S16;
++
++ rx_dma->params.src_amode = OMAP_DMA_AMODE_CONSTANT;
++ rx_dma->params.dst_amode = OMAP_DMA_AMODE_POST_INC;
++
++ rx_dma->params.src_start = p->mem_base;
++ rx_dma->params.dst_start = rx_dma->phys_to;
++
++ rx_dma->params.src_ei = 1;
++ rx_dma->params.src_fi = 1;
++ rx_dma->params.dst_ei = 1;
++ rx_dma->params.dst_fi = 1;
++
++ rx_dma->params.elem_count = 1024;
++ rx_dma->params.frame_count = 1;
++
++ rx_dma->params.read_prio = DMA_CH_PRIO_HIGH;
++ rx_dma->params.write_prio = DMA_CH_PRIO_LOW;
++
++ omap_set_dma_params(rx_dma->ch, &rx_dma->params);
++
++// Play with these with a real application
++//G omap_set_dma_src_burst_mode(rx_dma->ch, OMAP_DMA_DATA_BURST_16);
++// omap_set_dma_dest_burst_mode(rx_dma->ch, OMAP_DMA_DATA_BURST_16);
++
++#if 0 // Need to find implentations of the endian calls
++ omap_set_dma_src_endian_type(rx_dma->ch, OMAP_DMA_BIG_ENDIAN);
++ omap_set_dma_dst_endian_type(rx_dma->ch, OMAP_DMA_LITTLE_ENDIAN);
++#endif
++
++ tx_dma = kzalloc(sizeof(struct dma_data), GFP_KERNEL);
++ if (!tx_dma) {
++ printk(KERN_ERR "Failed to allocate memory for tx_dma struct.");
++ return -ENOMEM;
++ }
++
++ if (omap_request_dma(OMAP_DMA_NO_DEVICE, "usrp-e-tx",
++ usrp_tx_dma_irq, (void *) tx_dma, &tx_dma->ch)) {
++ printk(KERN_ERR "Could not get tx DMA channel for usrp_e\n");
++ return -ENOMEM;
++ }
++
++ printk(KERN_DEBUG "tx_dma->ch %d\n", tx_dma->ch);
++
++ tx_dma->phys_from = p->mem_base;
++
++ memset(&tx_dma->params, 0, sizeof(tx_dma->params));
++ tx_dma->params.data_type = OMAP_DMA_DATA_TYPE_S16;
++
++ tx_dma->params.src_amode = OMAP_DMA_AMODE_POST_INC;
++ tx_dma->params.dst_amode = OMAP_DMA_AMODE_CONSTANT;
++
++ tx_dma->params.src_start = tx_dma->phys_from;
++ tx_dma->params.dst_start = p->mem_base;
++
++ tx_dma->params.src_ei = 1;
++ tx_dma->params.src_fi = 1;
++ tx_dma->params.dst_ei = 1;
++ tx_dma->params.dst_fi = 1;
++
++ tx_dma->params.elem_count = 1024;
++ tx_dma->params.frame_count = 1;
++
++ tx_dma->params.read_prio = DMA_CH_PRIO_LOW;
++ tx_dma->params.write_prio = DMA_CH_PRIO_HIGH;
++
++ omap_set_dma_params(tx_dma->ch, &tx_dma->params);
++
++// Play with these with a real application
++//G omap_set_dma_src_burst_mode(tx_dma->ch, OMAP_DMA_DATA_BURST_16);
++// omap_set_dma_dest_burst_mode(tx_dma->ch, OMAP_DMA_DATA_BURST_16);
++
++ return 0;
++}
++
++static void release_dma_controller()
++{
++
++ omap_free_dma(rx_dma->ch);
++ omap_free_dma(tx_dma->ch);
++
++ kfree(rx_dma);
++ kfree(tx_dma);
++}
++
++static int get_frame_from_fpga_start()
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++ struct ring_buffer_info *rbi = &(*rx_rb.rbi)[rx_rb_write];
++ struct ring_buffer_entry *rbe = &(*rx_rb.rbe)[rx_rb_write];
++ u16 elements_to_read;
++
++ /* Check for space available in the ring buffer */
++ /* If no space, drop data. A read call will restart dma transfers. */
++ if (((*rx_rb.rbi)[rx_rb_write].flags & RB_KERNEL) && (gpio_get_value(RX_DATA_READY_GPIO)) && !rx_dma_active && !shutting_down) {
++
++ rx_dma_active = 1;
++#ifdef DEBUG_RX
++ gpio_set_value(14, 1);
++#endif
++
++ elements_to_read = readw(p->ctl_addr + UE_REG_MISC_RX_LEN);
++
++ rbi->flags = RB_DMA_ACTIVE;
++
++ rbi->len = elements_to_read << 1;
++
++ omap_set_dma_dest_addr_size(rx_dma->ch, rbe->dma_addr,
++ elements_to_read);
++
++ dma_sync_single_for_device(NULL, rbe->dma_addr, SZ_2K, DMA_FROM_DEVICE);
++
++ omap_start_dma(rx_dma->ch);
++ }
++
++ return 0;
++}
++
++
++static int get_frame_from_fpga_finish()
++{
++ dma_sync_single_for_cpu(NULL, (*rx_rb.rbe)[rx_rb_write].dma_addr, SZ_2K, DMA_FROM_DEVICE);
++
++ (*rx_rb.rbi)[rx_rb_write].flags = RB_USER;
++ rx_rb_write++;
++ if (rx_rb_write == rb_size.num_rx_frames)
++ rx_rb_write = 0;
++
++ wake_up_interruptible(&data_received_queue);
++
++ rx_dma_active = 0;
++
++ get_frame_from_fpga_start();
++
++#ifdef DEBUG_RX
++ gpio_set_value(14, 0);
++#endif
++
++ return 0;
++}
++
++static int send_frame_to_fpga_start()
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++ struct ring_buffer_info *rbi = &(*tx_rb.rbi)[tx_rb_read];
++ struct ring_buffer_entry *rbe = &(*tx_rb.rbe)[tx_rb_read];
++ u16 elements_to_write;
++
++// printk("In send_frame_to_fpga_start.\n");
++
++ /* Check if there is data to write to the FPGA, if so send it */
++ /* Otherwise, do nothing. Process is restarted by calls to write */
++ if (((*tx_rb.rbi)[tx_rb_read].flags & RB_USER) && !tx_dma_active && (gpio_get_value(TX_SPACE_AVAILABLE_GPIO)) && !shutting_down) {
++// printk("In send_frame_to_fpga_start, past if.\n");
++ tx_dma_active = 1;
++#ifdef DEBUG_TX
++ gpio_set_value(14, 1);
++#endif
++
++ elements_to_write = ((rbi->len) >> 1);
++
++ writew(elements_to_write, p->ctl_addr + UE_REG_MISC_TX_LEN);
++
++ rbi->flags = RB_DMA_ACTIVE;
++
++ omap_set_dma_src_addr_size(tx_dma->ch, rbe->dma_addr,
++ elements_to_write);
++
++ dma_sync_single_for_device(NULL, rbe->dma_addr, SZ_2K, DMA_TO_DEVICE);
++
++ omap_start_dma(tx_dma->ch);
++ }
++
++ return 0;
++}
++
++static int send_frame_to_fpga_finish()
++{
++
++ dma_sync_single_for_cpu(NULL, (*tx_rb.rbe)[tx_rb_read].dma_addr, SZ_2K, DMA_TO_DEVICE);
++
++ (*tx_rb.rbi)[tx_rb_read].flags = RB_KERNEL;
++
++ tx_rb_read++;
++ if (tx_rb_read == rb_size.num_tx_frames)
++ tx_rb_read = 0;
++
++ wake_up_interruptible(&tx_rb_space_available);
++
++ tx_dma_active = 0;
++
++ send_frame_to_fpga_start();
++
++#ifdef DEBUG_TX
++ gpio_set_value(14, 0);
++#endif
++
++ return 0;
++}
++
++static int alloc_ring_buffer(struct ring_buffer *rb,
++ unsigned int num_bufs, enum dma_data_direction direction)
++{
++ int i;
++
++ rb->rbi = __get_free_page(GFP_KERNEL | __GFP_COMP | __GFP_ZERO | __GFP_NOWARN);
++
++ rb->rbe = kzalloc(sizeof(struct ring_buffer_entry) * num_bufs, GFP_KERNEL);
++ if (!rb) {
++ printk(KERN_ERR "Failed to allocate memory for rb entries\n");
++ return -ENOMEM;
++ }
++
++ rb->num_pages = (num_bufs & 1) ? ((num_bufs + 1) / 2) : (num_bufs / 2);
++
++ rb->pages = kzalloc(sizeof(unsigned long) * rb->num_pages, GFP_KERNEL);
++ if (!(rb->pages)) {
++ printk(KERN_ERR "Failed to allocate memory for rb page entries\n");
++ return -ENOMEM;
++ }
++
++ for (i = 0; i < rb->num_pages; i++) {
++ (*rb->pages)[i] = __get_free_page(GFP_KERNEL | __GFP_DMA | __GFP_COMP | __GFP_ZERO | __GFP_NOWARN);
++
++ (*(rb->rbe))[i*2].frame_addr =
++ (*(rb->pages))[i];
++ (*(rb->rbe))[i*2 + 1].frame_addr =
++ ((*(rb->pages))[i] + SZ_2K);
++ if (!(*(rb->rbe))[i*2].frame_addr || !(*(rb->rbe))[i*2 + 1].frame_addr) {
++ printk(KERN_ERR "Failed to allocate memory dma buf\n");
++ return -ENOMEM;
++ }
++
++ (*(rb->rbe))[i*2].dma_addr = dma_map_single(NULL, (*(rb->rbe))[i*2].frame_addr, SZ_2K, direction);
++ (*(rb->rbe))[i*2 + 1].dma_addr = dma_map_single(NULL, (*(rb->rbe))[i*2 + 1].frame_addr, SZ_2K, direction);
++ if (!(*(rb->rbe))[i*2].dma_addr || !(*(rb->rbe))[i*2 + 1].dma_addr) {
++ printk(KERN_ERR "Failed to get physical address for dma buf\n");
++ return -ENOMEM;
++ }
++ }
++
++ return 0;
++}
++
++static void delete_ring_buffer(struct ring_buffer *rb,
++ unsigned int num_bufs, enum dma_data_direction direction)
++{
++ unsigned int i;
++ unsigned int num_pages;
++
++ printk(KERN_DEBUG "Entering delete_ring_buffer\n");
++
++ num_pages = (num_bufs & 1) ? ((num_bufs + 1) / 2) : (num_bufs / 2);
++
++ for (i = 0; i < num_pages; i++) {
++ dma_unmap_single(NULL, (*rb->rbe)[i*2].dma_addr, SZ_2K, direction);
++ dma_unmap_single(NULL, (*rb->rbe)[i*2 + 1].dma_addr, SZ_2K, direction);
++ free_page((*rb->pages)[i]);
++ }
++
++ free_page(rb->rbi);
++
++ kfree(rb->pages);
++ kfree(rb->rbe);
++
++ printk(KERN_DEBUG "Leaving delete_ring_buffer\n");
++}
++
++static int alloc_ring_buffers()
++{
++
++ if (alloc_ring_buffer(&tx_rb, rb_size.num_rx_frames, DMA_TO_DEVICE) < 0)
++ return -ENOMEM;
++ if (alloc_ring_buffer(&rx_rb, rb_size.num_tx_frames, DMA_FROM_DEVICE) < 0)
++ return -ENOMEM;
++
++ return 0;
++}
++
++static void init_ring_buffer(struct ring_buffer *rb, int num_bufs,
++ int initial_flags, enum dma_data_direction direction)
++{
++ int i;
++
++ for (i = 0; i < num_bufs; i++) {
++ dma_sync_single_for_device(NULL, (*rb->rbe)[i].dma_addr,
++ SZ_2K, direction);
++ dma_sync_single_for_cpu(NULL, (*rb->rbe)[i].dma_addr,
++ SZ_2K, direction);
++ (*rb->rbi)[i].flags = initial_flags;
++ }
++
++}
++
++#if 0
++static int tx_dma_func(void *data)
++{
++ int ret;
++ struct sched_param s = { .sched_priority = 1};
++
++ printk(KERN_DEBUG "In tx_dma_func\n");
++
++ allow_signal(SIGSTOP);
++
++ sched_setscheduler(current, SCHED_FIFO, &s);
++
++ while (!kthread_should_stop() && !closing_driver) {
++
++ if (!((*tx_rb.rbe)[tx_rb_read].flags & RB_USER)) {
++ tx_dma_waiting_for_data = 1;
++ ret = wait_event_interruptible(received_data_from_user,
++ (*tx_rb.rbe)[tx_rb_read].flags & RB_USER);
++ if (ret) {
++ printk(KERN_DEBUG
++ "tx_dma_func received signal %d\n",
++ ret);
++ if (closing_driver)
++ break;
++
++ }
++ tx_dma_waiting_for_data = 0;
++ }
++
++ if (wait_event_interruptible(space_available_queue,
++ gpio_get_value(TX_SPACE_AVAILABLE_GPIO))) {
++ printk(KERN_DEBUG "tx_dma received signal waiting for space.\n");
++ if (closing_driver)
++ break;
++ }
++
++ if (send_frame_to_fpga(&(*tx_rb.rbe)[tx_rb_read]) != 0) {
++ printk(KERN_DEBUG "send_frame received signal.\n");
++ if (closing_driver)
++ break;
++ }
++
++ (*tx_rb.rbe)[tx_rb_read].flags = RB_KERNEL;
++
++ tx_rb_read++;
++ if (tx_rb_read == RB_SIZE)
++ tx_rb_read = 0;
++
++#if 0
++ if (waiting_for_space_in_tx_rb)
++#endif
++ wake_up_interruptible(&tx_rb_space_queue);
++
++ }
++ return 0;
++}
++#endif
+diff --git a/include/linux/usrp_e.h b/include/linux/usrp_e.h
+new file mode 100644
+index 0000000..e52f709
+--- /dev/null
++++ b/include/linux/usrp_e.h
+@@ -0,0 +1,87 @@
++
++/*
++ * Copyright (C) 2010 Ettus Research, LLC
++ *
++ * Written by Philip Balister <philip@opensdr.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#ifndef __USRP_E_H
++#define __USRP_E_H
++
++#include <linux/types.h>
++#include <linux/ioctl.h>
++
++struct usrp_e_ctl16 {
++ __u32 offset;
++ __u32 count;
++ __u16 buf[20];
++};
++
++struct usrp_e_ctl32 {
++ __u32 offset;
++ __u32 count;
++ __u32 buf[10];
++};
++
++/* SPI interface */
++
++#define UE_SPI_TXONLY 0
++#define UE_SPI_TXRX 1
++
++/* Defines for spi ctrl register */
++#define UE_SPI_CTRL_TXNEG (BIT(10))
++#define UE_SPI_CTRL_RXNEG (BIT(9))
++
++#define UE_SPI_PUSH_RISE 0
++#define UE_SPI_PUSH_FALL UE_SPI_CTRL_TXNEG
++#define UE_SPI_LATCH_RISE 0
++#define UE_SPI_LATCH_FALL UE_SPI_CTRL_RXNEG
++
++struct usrp_e_spi {
++ __u8 readback;
++ __u32 slave;
++ __u32 data;
++ __u32 length;
++ __u32 flags;
++};
++
++struct usrp_e_i2c {
++ __u8 addr;
++ __u32 len;
++ __u8 data[];
++};
++
++#define USRP_E_IOC_MAGIC 'u'
++#define USRP_E_WRITE_CTL16 _IOW(USRP_E_IOC_MAGIC, 0x20, struct usrp_e_ctl16)
++#define USRP_E_READ_CTL16 _IOWR(USRP_E_IOC_MAGIC, 0x21, struct usrp_e_ctl16)
++#define USRP_E_WRITE_CTL32 _IOW(USRP_E_IOC_MAGIC, 0x22, struct usrp_e_ctl32)
++#define USRP_E_READ_CTL32 _IOWR(USRP_E_IOC_MAGIC, 0x23, struct usrp_e_ctl32)
++#define USRP_E_SPI _IOWR(USRP_E_IOC_MAGIC, 0x24, struct usrp_e_spi)
++#define USRP_E_I2C_READ _IOWR(USRP_E_IOC_MAGIC, 0x25, struct usrp_e_i2c)
++#define USRP_E_I2C_WRITE _IOW(USRP_E_IOC_MAGIC, 0x26, struct usrp_e_i2c)
++#define USRP_E_GET_RB_INFO _IOR(USRP_E_IOC_MAGIC, 0x27, struct usrp_e_ring_buffer_size_t)
++
++/* Flag defines */
++#define RB_USER (BIT(0))
++#define RB_KERNEL (BIT(1))
++#define RB_OVERRUN (BIT(2))
++#define RB_DMA_ACTIVE (BIT(3))
++
++struct ring_buffer_info {
++ int flags;
++ int len;
++};
++
++struct usrp_e_ring_buffer_size_t {
++ int num_pages_rx_flags;
++ int num_rx_frames;
++ int num_pages_tx_flags;
++ int num_tx_frames;
++};
++
++#endif
+--
+1.6.6.1
+
--- /dev/null
+../beagleboard/defconfig
\ No newline at end of file
DESCRIPTION = "Linux kernel for OMAP processors"
KERNEL_IMAGETYPE = "uImage"
-COMPATIBLE_MACHINE = "beagleboard"
+COMPATIBLE_MACHINE = "(beagleboard|overo|omap3evm|omap3-touchbook|usrp-e1xx)"
# The main PR is now using MACHINE_KERNEL_PR, for omap3 see conf/machine/include/omap3.inc
PV = "2.6.36+2.6.37-rc7"
-MACHINE_KERNEL_PR_append = "b+gitr${SRCREV}"
+MACHINE_KERNEL_PR_append = "c+gitr${SRCREV}"
SRCREV = "7b6b2e84ada1eca268eac17a90f93fc6145f6146"
FILESPATHPKG_prepend = "linux-omap-2.6.37rc:"
file://0009-ARM-OMAP-add-omap_rev_-macros.patch \
file://0010-OMAP-DSS2-enable-hsclk-in-dsi_pll_init-for-OMAP36XX.patch \
file://0011-omap3-beagleboard-add-WIP-support-for-beagleboardtoy.patch \
+ file://0012-drivers-net-smsc911x-return-ENODEV-if-device-is-not-.patch \
+ file://0013-drivers-input-touchscreen-ads7846-return-ENODEV-if-d.patch \
+ file://0014-ASoC-enable-audio-capture-by-default-for-twl4030.patch \
+ file://0015-MFD-enable-madc-clock.patch \
+ file://0016-MFD-add-twl4030-madc-driver.patch \
+ file://0017-ARM-OMAP-Add-twl4030-madc-support-to-Overo.patch \
+ file://0018-ARM-OMAP-Add-twl4030-madc-support-to-Beagle.patch \
+ file://0019-OMAP-DSS2-Add-support-for-Samsung-LTE430WQ-F0C-panel.patch \
+ file://0020-OMAP-DSS2-Add-support-for-LG-Philips-LB035Q02-panel.patch \
+ file://0021-OMAP-DSS2-add-bootarg-for-selecting-svideo-or-compos.patch \
+ file://0022-ARM-OMAP2-mmc-twl4030-move-clock-input-selection-pri.patch \
+ file://0023-RTC-add-support-for-backup-battery-recharge.patch \
+ file://0024-ARM-OMAP-automatically-set-musb-mode-in-platform-dat.patch \
+ file://0025-OMAP-DSS2-check-for-both-cpu-type-and-revision-rathe.patch \
+ file://0026-OMAP-DSS2-Add-DSS2-support-for-Overo.patch \
+"
+
+SRC_URI_append_usrp-e1xx = "\
+ file://0027-Add-defines-to-set-config-options-in-GPMC-per-CS-con.patch \
+ file://0028-Add-functions-to-dma.c-to-set-address-and-length-for.patch \
+ file://0029-usrp-embedded-Add-driver-for-USRP-Embedded-FPGA-inte.patch \
"
SRC_URI_append_beagleboard = " file://logo_linux_clut224.ppm \