linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v8 00/11]  tnetv107x ssp drivers
@ 2011-01-18 19:21 Cyril Chemparathy
  2011-01-18 19:21 ` [PATCH v8 01/11] mfd: add driver for sequencer serial port Cyril Chemparathy
                   ` (5 more replies)
  0 siblings, 6 replies; 20+ messages in thread
From: Cyril Chemparathy @ 2011-01-18 19:21 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

TI's sequencer serial port (TI-SSP) is a jack-of-all-trades type of serial port
device.  It has a built-in programmable execution engine that can be programmed
to operate as almost any serial bus (I2C, SPI, EasyScale, and others).

This patch series implements a driver stack that looks like the following:

                             +--------+
                             | eeprom | . . .
                             +--------+
   +-----------+             +--------------+ +---------+
   | regulator | . . .       |   i2c-gpio   | | 1-wire  | . . .
   +-----------+             +--------------+ +---------+
   +----------------------+  +--------------------------------+
   |       ssp-spi        |  |           ssp-gpio             |
   +----------------------+  +--------------------------------+
   +----------------------------------------------------------+
   |                            ssp                           |
   +----------------------------------------------------------+

Changes between v8 and v7 of this series:
  - Reorder commits, removed regulator driver patch (already upstreamed)
  - Renamed static function definitions to keep namespace clean (mfd, gpio)
  - Removed instance pdata in mfd driver

Changes between v7 and v6 of this series:
  - Workaround for iosel2 register not reading back set bits.
  - Update backlight status once probe succeeds.

Changes between v6 and v5 of this series:
  - Changed initcalls to module_init() across all drivers.  This series now
    uses a late_initcall() in the board to delay initialization of gpio and
    regulator dependent devices.

Changes between v5 and v4 of this series:
  - Moved drivers from misc/gpio/spi to mfd
  - Removed implicit init-time iosel setup
  - Minor cleanups in backlight driver

Changes between v3 and v4 of this series:
  - Replaced polled wait for sequence termination with interrupt
  - Improved locking within SSP driver
  - Other minor cleanups

Changes between v2 and v3 of this series:
  - Minor cleanups in Kconfig and Makefile ordering

Changes between v1 and v2 of this series:
  - Replaced open()/close() semantics with dynamic platform_device
    registration on SSP probe.
  - Removed user-land interface to regulator registers
  - More sensible regulator constraints
  - Other minor cleanups


Cyril Chemparathy (11):
  mfd: add driver for sequencer serial port
  spi: add ti-ssp spi master driver
  gpio: add ti-ssp gpio driver
  backlight: add support for tps6116x controller
  davinci: add tnetv107x ssp platform device
  davinci: add ssp config for tnetv107x evm board
  davinci: add spi devices on tnetv107x evm
  davinci: add tnetv107x evm regulators
  davinci: add tnetv107x evm ti-ssp gpio device
  davinci: add tnetv107x evm backlight device
  davinci: add tnetv107x evm i2c eeprom device

 arch/arm/mach-davinci/board-tnetv107x-evm.c    |  197 ++++++++++
 arch/arm/mach-davinci/devices-tnetv107x.c      |   25 ++
 arch/arm/mach-davinci/include/mach/tnetv107x.h |    2 +
 arch/arm/mach-davinci/tnetv107x.c              |    2 +-
 drivers/gpio/Kconfig                           |   10 +
 drivers/gpio/Makefile                          |    1 +
 drivers/gpio/ti-ssp-gpio.c                     |  207 ++++++++++
 drivers/mfd/Kconfig                            |   11 +
 drivers/mfd/Makefile                           |    1 +
 drivers/mfd/ti-ssp.c                           |  476 ++++++++++++++++++++++++
 drivers/spi/Kconfig                            |   10 +
 drivers/spi/Makefile                           |    1 +
 drivers/spi/ti-ssp-spi.c                       |  402 ++++++++++++++++++++
 drivers/video/backlight/Kconfig                |    7 +
 drivers/video/backlight/Makefile               |    2 +-
 drivers/video/backlight/tps6116x.c             |  299 +++++++++++++++
 include/linux/mfd/ti_ssp.h                     |   97 +++++
 17 files changed, 1748 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpio/ti-ssp-gpio.c
 create mode 100644 drivers/mfd/ti-ssp.c
 create mode 100644 drivers/spi/ti-ssp-spi.c
 create mode 100644 drivers/video/backlight/tps6116x.c
 create mode 100644 include/linux/mfd/ti_ssp.h

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v8 01/11] mfd: add driver for sequencer serial port
  2011-01-18 19:21 [PATCH v8 00/11] tnetv107x ssp drivers Cyril Chemparathy
@ 2011-01-18 19:21 ` Cyril Chemparathy
  2011-01-19 17:43   ` Kevin Hilman
  2011-01-18 19:21 ` [PATCH v8 02/11] spi: add ti-ssp spi master driver Cyril Chemparathy
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 20+ messages in thread
From: Cyril Chemparathy @ 2011-01-18 19:21 UTC (permalink / raw)
  To: davinci-linux-open-source, spi-devel-general, sameo, rpurdie, dbrownell
  Cc: c-park, linux-arm-kernel, linux-kernel, Cyril Chemparathy

TI's sequencer serial port (TI-SSP) is a jack-of-all-trades type of serial port
device.  It has a built-in programmable execution engine that can be programmed
to operate as almost any serial bus (I2C, SPI, EasyScale, and others).

This patch adds a driver for this controller device.  The driver does not
expose a user-land interface.  Protocol drivers built on top of this layer are
expected to remain in-kernel.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 drivers/mfd/Kconfig        |   11 +
 drivers/mfd/Makefile       |    1 +
 drivers/mfd/ti-ssp.c       |  476 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/ti_ssp.h |   87 ++++++++
 4 files changed, 575 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mfd/ti-ssp.c
 create mode 100644 include/linux/mfd/ti_ssp.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3a1493b..a4b4b70 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -81,6 +81,17 @@ config MFD_DM355EVM_MSP
 	  boards.  MSP430 firmware manages resets and power sequencing,
 	  inputs from buttons and the IR remote, LEDs, an RTC, and more.
 
+config MFD_TI_SSP
+	tristate "TI Sequencer Serial Port support"
+	depends on ARCH_DAVINCI_TNETV107X
+	select MFD_CORE
+	---help---
+	  Say Y here if you want support for the Sequencer Serial Port
+	  in a Texas Instruments TNETV107X SoC.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ti-ssp.
+
 config HTC_EGPIO
 	bool "HTC EGPIO support"
 	depends on GENERIC_HARDIRQS && GPIOLIB && ARM
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f54b365..f64cf13 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_HTC_I2CPLD)	+= htc-i2cpld.o
 
 obj-$(CONFIG_MFD_DAVINCI_VOICECODEC)	+= davinci_voicecodec.o
 obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
+obj-$(CONFIG_MFD_TI_SSP)	+= ti-ssp.o
 
 obj-$(CONFIG_MFD_STMPE)		+= stmpe.o
 obj-$(CONFIG_MFD_TC35892)	+= tc35892.o
diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c
new file mode 100644
index 0000000..af9ab0e
--- /dev/null
+++ b/drivers/mfd/ti-ssp.c
@@ -0,0 +1,476 @@
+/*
+ * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
+ *
+ * Copyright (C) 2010 Texas Instruments Inc
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ti_ssp.h>
+
+/* Register Offsets */
+#define REG_REV		0x00
+#define REG_IOSEL_1	0x04
+#define REG_IOSEL_2	0x08
+#define REG_PREDIV	0x0c
+#define REG_INTR_ST	0x10
+#define REG_INTR_EN	0x14
+#define REG_TEST_CTRL	0x18
+
+/* Per port registers */
+#define PORT_CFG_2	0x00
+#define PORT_ADDR	0x04
+#define PORT_DATA	0x08
+#define PORT_CFG_1	0x0c
+#define PORT_STATE	0x10
+
+#define SSP_PORT_CONFIG_MASK	(SSP_EARLY_DIN | SSP_DELAY_DOUT)
+#define SSP_PORT_CLKRATE_MASK	0x0f
+
+#define SSP_SEQRAM_WR_EN	BIT(4)
+#define SSP_SEQRAM_RD_EN	BIT(5)
+#define SSP_START		BIT(15)
+#define SSP_BUSY		BIT(10)
+#define SSP_PORT_ASL		BIT(7)
+#define SSP_PORT_CFO1		BIT(6)
+
+#define SSP_PORT_SEQRAM_SIZE	32
+
+static const int ssp_port_base[]   = {0x040, 0x080};
+static const int ssp_port_seqram[] = {0x100, 0x180};
+
+struct ti_ssp {
+	struct resource		*res;
+	struct device		*dev;
+	void __iomem		*regs;
+	spinlock_t		lock;
+	struct clk		*clk;
+	int			irq;
+	wait_queue_head_t	wqh;
+
+	/*
+	 * Some of the iosel2 register bits always read-back as 0, we need to
+	 * remember these values so that we don't clobber previously set
+	 * values.
+	 */
+	u32			iosel2;
+};
+
+static inline struct ti_ssp *dev_to_ssp(struct device *dev)
+{
+	return dev_get_drvdata(dev->parent);
+}
+
+static inline int dev_to_port(struct device *dev)
+{
+	return to_platform_device(dev)->id;
+}
+
+/* Register Access Helpers, rmw() functions need to run locked */
+static inline u32 ssp_read(struct ti_ssp *ssp, int reg)
+{
+	return __raw_readl(ssp->regs + reg);
+}
+
+static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val)
+{
+	__raw_writel(val, ssp->regs + reg);
+}
+
+static inline void ssp_rmw(struct ti_ssp *ssp, int reg, u32 mask, u32 bits)
+{
+	ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~mask) | bits);
+}
+
+static inline u32 ssp_port_read(struct ti_ssp *ssp, int port, int reg)
+{
+	return ssp_read(ssp, ssp_port_base[port] + reg);
+}
+
+static inline void ssp_port_write(struct ti_ssp *ssp, int port, int reg,
+				  u32 val)
+{
+	ssp_write(ssp, ssp_port_base[port] + reg, val);
+}
+
+static inline void ssp_port_rmw(struct ti_ssp *ssp, int port, int reg,
+				u32 mask, u32 bits)
+{
+	ssp_rmw(ssp, ssp_port_base[port] + reg, mask, bits);
+}
+
+static inline void ssp_port_clr_bits(struct ti_ssp *ssp, int port, int reg,
+				     u32 bits)
+{
+	ssp_port_rmw(ssp, port, reg, bits, 0);
+}
+
+static inline void ssp_port_set_bits(struct ti_ssp *ssp, int port, int reg,
+				     u32 bits)
+{
+	ssp_port_rmw(ssp, port, reg, 0, bits);
+}
+
+/* Called to setup port clock mode, caller must hold ssp->lock */
+static int __set_mode(struct ti_ssp *ssp, int port, int mode)
+{
+	mode &= SSP_PORT_CONFIG_MASK;
+	ssp_port_rmw(ssp, port, PORT_CFG_1, SSP_PORT_CONFIG_MASK, mode);
+
+	return 0;
+}
+
+int ti_ssp_set_mode(struct device *dev, int mode)
+{
+	struct ti_ssp *ssp = dev_to_ssp(dev);
+	int port = dev_to_port(dev);
+	int ret;
+
+	spin_lock(&ssp->lock);
+	ret = __set_mode(ssp, port, mode);
+	spin_unlock(&ssp->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(ti_ssp_set_mode);
+
+/* Called to setup iosel2, caller must hold ssp->lock */
+static void __set_iosel2(struct ti_ssp *ssp, u32 mask, u32 val)
+{
+	ssp->iosel2 = (ssp->iosel2 & ~mask) | val;
+	ssp_write(ssp, REG_IOSEL_2, ssp->iosel2);
+}
+
+/* Called to setup port iosel, caller must hold ssp->lock */
+static void __set_iosel(struct ti_ssp *ssp, int port, u32 iosel)
+{
+	unsigned val, shift = port ? 16 : 0;
+
+	/* IOSEL1 gets the least significant 16 bits */
+	val = ssp_read(ssp, REG_IOSEL_1);
+	val &= 0xffff << (port ? 0 : 16);
+	val |= (iosel & 0xffff) << (port ? 16 : 0);
+	ssp_write(ssp, REG_IOSEL_1, val);
+
+	/* IOSEL2 gets the most significant 16 bits */
+	val = (iosel >> 16) & 0x7;
+	__set_iosel2(ssp, 0x7 << shift, val << shift);
+}
+
+int ti_ssp_set_iosel(struct device *dev, u32 iosel)
+{
+	struct ti_ssp *ssp = dev_to_ssp(dev);
+	int port = dev_to_port(dev);
+
+	spin_lock(&ssp->lock);
+	__set_iosel(ssp, port, iosel);
+	spin_unlock(&ssp->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ti_ssp_set_iosel);
+
+int ti_ssp_load(struct device *dev, int offs, u32* prog, int len)
+{
+	struct ti_ssp *ssp = dev_to_ssp(dev);
+	int port = dev_to_port(dev);
+	int i;
+
+	if (len > SSP_PORT_SEQRAM_SIZE)
+		return -ENOSPC;
+
+	spin_lock(&ssp->lock);
+
+	/* Enable SeqRAM access */
+	ssp_port_set_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
+
+	/* Copy code */
+	for (i = 0; i < len; i++) {
+		__raw_writel(prog[i], ssp->regs + offs + 4*i +
+			     ssp_port_seqram[port]);
+	}
+
+	/* Disable SeqRAM access */
+	ssp_port_clr_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
+
+	spin_unlock(&ssp->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ti_ssp_load);
+
+int ti_ssp_raw_read(struct device *dev)
+{
+	struct ti_ssp *ssp = dev_to_ssp(dev);
+	int port = dev_to_port(dev);
+	int shift = port ? 27 : 11;
+
+	return (ssp_read(ssp, REG_IOSEL_2) >> shift) & 0xf;
+}
+EXPORT_SYMBOL(ti_ssp_raw_read);
+
+int ti_ssp_raw_write(struct device *dev, u32 val)
+{
+	struct ti_ssp *ssp = dev_to_ssp(dev);
+	int port = dev_to_port(dev), shift;
+
+	spin_lock(&ssp->lock);
+
+	shift = port ? 22 : 6;
+	val &= 0xf;
+	__set_iosel2(ssp, 0xf << shift, val << shift);
+
+	spin_unlock(&ssp->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ti_ssp_raw_write);
+
+static inline int __xfer_done(struct ti_ssp *ssp, int port)
+{
+	return !(ssp_port_read(ssp, port, PORT_CFG_1) & SSP_BUSY);
+}
+
+int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output)
+{
+	struct ti_ssp *ssp = dev_to_ssp(dev);
+	int port = dev_to_port(dev);
+	int ret;
+
+	if (pc & ~(0x3f))
+		return -EINVAL;
+
+	/* Grab ssp->lock to serialize rmw on ssp registers */
+	spin_lock(&ssp->lock);
+
+	ssp_port_write(ssp, port, PORT_ADDR, input >> 16);
+	ssp_port_write(ssp, port, PORT_DATA, input & 0xffff);
+	ssp_port_rmw(ssp, port, PORT_CFG_1, 0x3f, pc);
+
+	/* grab wait queue head lock to avoid race with the isr */
+	spin_lock_irq(&ssp->wqh.lock);
+
+	/* kick off sequence execution in hardware */
+	ssp_port_set_bits(ssp, port, PORT_CFG_1, SSP_START);
+
+	/* drop ssp lock; no register writes beyond this */
+	spin_unlock(&ssp->lock);
+
+	ret = wait_event_interruptible_locked_irq(ssp->wqh,
+						  __xfer_done(ssp, port));
+	spin_unlock_irq(&ssp->wqh.lock);
+
+	if (ret < 0)
+		return ret;
+
+	if (output) {
+		*output = (ssp_port_read(ssp, port, PORT_ADDR) << 16) |
+			  (ssp_port_read(ssp, port, PORT_DATA) &  0xffff);
+	}
+
+	ret = ssp_port_read(ssp, port, PORT_STATE) & 0x3f; /* stop address */
+
+	return ret;
+}
+EXPORT_SYMBOL(ti_ssp_run);
+
+static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data)
+{
+	struct ti_ssp *ssp = dev_data;
+
+	spin_lock(&ssp->wqh.lock);
+
+	ssp_write(ssp, REG_INTR_ST, 0x3);
+	wake_up_locked(&ssp->wqh);
+
+	spin_unlock(&ssp->wqh.lock);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit ti_ssp_probe(struct platform_device *pdev)
+{
+	static struct ti_ssp *ssp;
+	const struct ti_ssp_data *pdata = pdev->dev.platform_data;
+	int error = 0, prediv = 0xff, id;
+	unsigned long sysclk;
+	struct device *dev = &pdev->dev;
+	struct mfd_cell cells[2];
+
+	ssp = kzalloc(sizeof(*ssp), GFP_KERNEL);
+	if (!ssp) {
+		dev_err(dev, "cannot allocate device info\n");
+		return -ENOMEM;
+	}
+
+	ssp->dev = dev;
+	dev_set_drvdata(dev, ssp);
+
+	ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!ssp->res) {
+		error = -ENODEV;
+		dev_err(dev, "cannot determine register area\n");
+		goto error_res;
+	}
+
+	if (!request_mem_region(ssp->res->start, resource_size(ssp->res),
+				pdev->name)) {
+		error = -ENOMEM;
+		dev_err(dev, "cannot claim register memory\n");
+		goto error_res;
+	}
+
+	ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res));
+	if (!ssp->regs) {
+		error = -ENOMEM;
+		dev_err(dev, "cannot map register memory\n");
+		goto error_map;
+	}
+
+	ssp->clk = clk_get(dev, NULL);
+	if (IS_ERR(ssp->clk)) {
+		error = PTR_ERR(ssp->clk);
+		dev_err(dev, "cannot claim device clock\n");
+		goto error_clk;
+	}
+
+	ssp->irq = platform_get_irq(pdev, 0);
+	if (ssp->irq < 0) {
+		error = -ENODEV;
+		dev_err(dev, "unknown irq\n");
+		goto error_irq;
+	}
+
+	error = request_threaded_irq(ssp->irq, NULL, ti_ssp_interrupt, 0,
+				     dev_name(dev), ssp);
+	if (error < 0) {
+		dev_err(dev, "cannot acquire irq\n");
+		goto error_irq;
+	}
+
+	spin_lock_init(&ssp->lock);
+	init_waitqueue_head(&ssp->wqh);
+
+	/* Power on and initialize SSP */
+	error = clk_enable(ssp->clk);
+	if (error) {
+		dev_err(dev, "cannot enable device clock\n");
+		goto error_enable;
+	}
+
+	/* Reset registers to a sensible known state */
+	ssp_write(ssp, REG_IOSEL_1, 0);
+	ssp_write(ssp, REG_IOSEL_2, 0);
+	ssp_write(ssp, REG_INTR_EN, 0x3);
+	ssp_write(ssp, REG_INTR_ST, 0x3);
+	ssp_write(ssp, REG_TEST_CTRL, 0);
+	ssp_port_write(ssp, 0, PORT_CFG_1, SSP_PORT_ASL);
+	ssp_port_write(ssp, 1, PORT_CFG_1, SSP_PORT_ASL);
+	ssp_port_write(ssp, 0, PORT_CFG_2, SSP_PORT_CFO1);
+	ssp_port_write(ssp, 1, PORT_CFG_2, SSP_PORT_CFO1);
+
+	sysclk = clk_get_rate(ssp->clk);
+	if (pdata && pdata->out_clock)
+		prediv = (sysclk / pdata->out_clock) - 1;
+	prediv = clamp(prediv, 0, 0xff);
+	ssp_rmw(ssp, REG_PREDIV, 0xff, prediv);
+
+	memset(cells, 0, sizeof(cells));
+	for (id = 0; id < 2; id++) {
+		const struct ti_ssp_dev_data *data = &pdata->dev_data[id];
+
+		cells[id].id		= id;
+		cells[id].name		= data->dev_name;
+		cells[id].platform_data	= data->pdata;
+		cells[id].data_size	= data->pdata_size;
+	}
+
+	error = mfd_add_devices(dev, 0, cells, 2, NULL, 0);
+	if (error < 0) {
+		dev_err(dev, "cannot add mfd cells\n");
+		goto error_enable;
+	}
+
+	return 0;
+
+error_enable:
+	free_irq(ssp->irq, ssp);
+error_irq:
+	clk_put(ssp->clk);
+error_clk:
+	iounmap(ssp->regs);
+error_map:
+	release_mem_region(ssp->res->start, resource_size(ssp->res));
+error_res:
+	kfree(ssp);
+	return error;
+}
+
+static int __devexit ti_ssp_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ti_ssp *ssp = dev_get_drvdata(dev);
+
+	mfd_remove_devices(dev);
+	clk_disable(ssp->clk);
+	free_irq(ssp->irq, ssp);
+	clk_put(ssp->clk);
+	iounmap(ssp->regs);
+	release_mem_region(ssp->res->start, resource_size(ssp->res));
+	kfree(ssp);
+	dev_set_drvdata(dev, NULL);
+	return 0;
+}
+
+static struct platform_driver ti_ssp_driver = {
+	.probe		= ti_ssp_probe,
+	.remove		= __devexit_p(ti_ssp_remove),
+	.driver		= {
+		.name	= "ti-ssp",
+		.owner	= THIS_MODULE,
+	}
+};
+
+static int __init ti_ssp_init(void)
+{
+	return platform_driver_register(&ti_ssp_driver);
+}
+module_init(ti_ssp_init);
+
+static void __exit ti_ssp_exit(void)
+{
+	platform_driver_unregister(&ti_ssp_driver);
+}
+module_exit(ti_ssp_exit);
+
+MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ti-ssp");
diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h
new file mode 100644
index 0000000..021fe09
--- /dev/null
+++ b/include/linux/mfd/ti_ssp.h
@@ -0,0 +1,87 @@
+/*
+ * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
+ *
+ * Copyright (C) 2010 Texas Instruments Inc
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __TI_SSP_H__
+#define __TI_SSP_H__
+
+struct ti_ssp_dev_data {
+	const char	*dev_name;
+	void		*pdata;
+	size_t		pdata_size;
+};
+
+struct ti_ssp_data {
+	unsigned long		out_clock;
+	struct ti_ssp_dev_data	dev_data[2];
+};
+
+/*
+ * Sequencer port IO pin configuration bits.  These do not correlate 1-1 with
+ * the hardware.  The iosel field in the port data combines iosel1 and iosel2,
+ * and is therefore not a direct map to register space.  It is best to use the
+ * macros below to construct iosel values.
+ *
+ * least significant 16 bits --> iosel1
+ * most significant 16 bits  --> iosel2
+ */
+
+#define SSP_IN			0x0000
+#define SSP_DATA		0x0001
+#define SSP_CLOCK		0x0002
+#define SSP_CHIPSEL		0x0003
+#define SSP_OUT			0x0004
+#define SSP_PIN_SEL(pin, v)	((v) << ((pin) * 3))
+#define SSP_PIN_MASK(pin)	SSP_PIN_SEL(pin, 0x7)
+#define SSP_INPUT_SEL(pin)	((pin) << 16)
+
+/* Sequencer port config bits */
+#define SSP_EARLY_DIN		BIT(8)
+#define SSP_DELAY_DOUT		BIT(9)
+
+/* Sequence map definitions */
+#define SSP_CLK_HIGH		BIT(0)
+#define SSP_CLK_LOW		0
+#define SSP_DATA_HIGH		BIT(1)
+#define SSP_DATA_LOW		0
+#define SSP_CS_HIGH		BIT(2)
+#define SSP_CS_LOW		0
+#define SSP_OUT_MODE		BIT(3)
+#define SSP_IN_MODE		0
+#define SSP_DATA_REG		BIT(4)
+#define SSP_ADDR_REG		0
+
+#define SSP_OPCODE_DIRECT	((0x0) << 5)
+#define SSP_OPCODE_TOGGLE	((0x1) << 5)
+#define SSP_OPCODE_SHIFT	((0x2) << 5)
+#define SSP_OPCODE_BRANCH0	((0x4) << 5)
+#define SSP_OPCODE_BRANCH1	((0x5) << 5)
+#define SSP_OPCODE_BRANCH	((0x6) << 5)
+#define SSP_OPCODE_STOP		((0x7) << 5)
+#define SSP_BRANCH(addr)	((addr) << 8)
+#define SSP_COUNT(cycles)	((cycles) << 8)
+
+int ti_ssp_raw_read(struct device *dev);
+int ti_ssp_raw_write(struct device *dev, u32 val);
+int ti_ssp_load(struct device *dev, int offs, u32* prog, int len);
+int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output);
+int ti_ssp_set_mode(struct device *dev, int mode);
+int ti_ssp_set_iosel(struct device *dev, u32 iosel);
+
+#endif /* __TI_SSP_H__ */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v8 02/11] spi: add ti-ssp spi master driver
  2011-01-18 19:21 [PATCH v8 00/11] tnetv107x ssp drivers Cyril Chemparathy
  2011-01-18 19:21 ` [PATCH v8 01/11] mfd: add driver for sequencer serial port Cyril Chemparathy
@ 2011-01-18 19:21 ` Cyril Chemparathy
  2011-01-18 19:21 ` [PATCH v8 05/11] davinci: add tnetv107x ssp platform device Cyril Chemparathy
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 20+ messages in thread
From: Cyril Chemparathy @ 2011-01-18 19:21 UTC (permalink / raw)
  To: davinci-linux-open-source, spi-devel-general, sameo, rpurdie, dbrownell
  Cc: c-park, linux-arm-kernel, linux-kernel, Cyril Chemparathy

This patch adds an SPI master implementation that operates on top of an
underlying TI-SSP port.

Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 drivers/spi/Kconfig        |   10 +
 drivers/spi/Makefile       |    1 +
 drivers/spi/ti-ssp-spi.c   |  402 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/ti_ssp.h |    6 +
 4 files changed, 419 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/ti-ssp-spi.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 78f9fd0..7f0ed2a 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -336,6 +336,16 @@ config SPI_TEGRA
 	help
 	  SPI driver for NVidia Tegra SoCs
 
+config SPI_TI_SSP
+	tristate "TI Sequencer Serial Port - SPI Support"
+	depends on MFD_TI_SSP
+	help
+	  This selects an SPI master implementation using a TI sequencer
+	  serial port.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ti-ssp-spi.
+
 config SPI_TOPCLIFF_PCH
 	tristate "Topcliff PCH SPI Controller"
 	depends on PCI
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 8bc1a5a..595e5b8 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx_hw.o
 obj-$(CONFIG_SPI_S3C64XX)		+= spi_s3c64xx.o
 obj-$(CONFIG_SPI_TEGRA)			+= spi_tegra.o
+obj-$(CONFIG_SPI_TI_SSP)		+= ti-ssp-spi.o
 obj-$(CONFIG_SPI_TOPCLIFF_PCH)		+= spi_topcliff_pch.o
 obj-$(CONFIG_SPI_TXX9)			+= spi_txx9.o
 obj-$(CONFIG_SPI_XILINX)		+= xilinx_spi.o
diff --git a/drivers/spi/ti-ssp-spi.c b/drivers/spi/ti-ssp-spi.c
new file mode 100644
index 0000000..ee22795
--- /dev/null
+++ b/drivers/spi/ti-ssp-spi.c
@@ -0,0 +1,402 @@
+/*
+ * Sequencer Serial Port (SSP) based SPI master driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/ti_ssp.h>
+
+#define MODE_BITS	(SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
+
+struct ti_ssp_spi {
+	struct spi_master		*master;
+	struct device			*dev;
+	spinlock_t			lock;
+	struct list_head		msg_queue;
+	struct completion		complete;
+	bool				shutdown;
+	struct workqueue_struct		*workqueue;
+	struct work_struct		work;
+	u8				mode, bpw;
+	int				cs_active;
+	u32				pc_en, pc_dis, pc_wr, pc_rd;
+	void				(*select)(int cs);
+};
+
+static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw)
+{
+	u32 ret;
+
+	ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret);
+	return ret;
+}
+
+static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data)
+{
+	ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL);
+}
+
+static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg,
+		       struct spi_transfer *t)
+{
+	int count;
+
+	if (hw->bpw <= 8) {
+		u8		*rx = t->rx_buf;
+		const u8	*tx = t->tx_buf;
+
+		for (count = 0; count < t->len; count += 1) {
+			if (t->tx_buf)
+				ti_ssp_spi_tx(hw, *tx++);
+			if (t->rx_buf)
+				*rx++ = ti_ssp_spi_rx(hw);
+		}
+	} else if (hw->bpw <= 16) {
+		u16		*rx = t->rx_buf;
+		const u16	*tx = t->tx_buf;
+
+		for (count = 0; count < t->len; count += 2) {
+			if (t->tx_buf)
+				ti_ssp_spi_tx(hw, *tx++);
+			if (t->rx_buf)
+				*rx++ = ti_ssp_spi_rx(hw);
+		}
+	} else {
+		u32		*rx = t->rx_buf;
+		const u32	*tx = t->tx_buf;
+
+		for (count = 0; count < t->len; count += 4) {
+			if (t->tx_buf)
+				ti_ssp_spi_tx(hw, *tx++);
+			if (t->rx_buf)
+				*rx++ = ti_ssp_spi_rx(hw);
+		}
+	}
+
+	msg->actual_length += count; /* bytes transferred */
+
+	dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n",
+		t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len,
+		hw->bpw, count, (count < t->len) ? " (under)" : "");
+
+	return (count < t->len) ? -EIO : 0; /* left over data */
+}
+
+static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active)
+{
+	cs_active = !!cs_active;
+	if (cs_active == hw->cs_active)
+		return;
+	ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL);
+	hw->cs_active = cs_active;
+}
+
+#define __SHIFT_OUT(bits)	(SSP_OPCODE_SHIFT | SSP_OUT_MODE | \
+				 cs_en | clk | SSP_COUNT((bits) * 2 - 1))
+#define __SHIFT_IN(bits)	(SSP_OPCODE_SHIFT | SSP_IN_MODE  | \
+				 cs_en | clk | SSP_COUNT((bits) * 2 - 1))
+
+static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode)
+{
+	int error, idx = 0;
+	u32 seqram[16];
+	u32 cs_en, cs_dis, clk;
+	u32 topbits, botbits;
+
+	mode &= MODE_BITS;
+	if (mode == hw->mode && bpw == hw->bpw)
+		return 0;
+
+	cs_en  = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW;
+	cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW  : SSP_CS_HIGH;
+	clk    = (mode & SPI_CPOL)    ? SSP_CLK_HIGH : SSP_CLK_LOW;
+
+	/* Construct instructions */
+
+	/* Disable Chip Select */
+	hw->pc_dis = idx;
+	seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk;
+	seqram[idx++] = SSP_OPCODE_STOP   | SSP_OUT_MODE | cs_dis | clk;
+
+	/* Enable Chip Select */
+	hw->pc_en = idx;
+	seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk;
+	seqram[idx++] = SSP_OPCODE_STOP   | SSP_OUT_MODE | cs_en | clk;
+
+	/* Reads and writes need to be split for bpw > 16 */
+	topbits = (bpw > 16) ? 16 : bpw;
+	botbits = bpw - topbits;
+
+	/* Write */
+	hw->pc_wr = idx;
+	seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG;
+	if (botbits)
+		seqram[idx++] = __SHIFT_OUT(botbits)  | SSP_DATA_REG;
+	seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
+
+	/* Read */
+	hw->pc_rd = idx;
+	if (botbits)
+		seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG;
+	seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG;
+	seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
+
+	error = ti_ssp_load(hw->dev, 0, seqram, idx);
+	if (error < 0)
+		return error;
+
+	error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ?
+					  0 : SSP_EARLY_DIN));
+	if (error < 0)
+		return error;
+
+	hw->bpw = bpw;
+	hw->mode = mode;
+
+	return error;
+}
+
+static void ti_ssp_spi_work(struct work_struct *work)
+{
+	struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work);
+
+	spin_lock(&hw->lock);
+
+	 while (!list_empty(&hw->msg_queue)) {
+		struct spi_message	*m;
+		struct spi_device	*spi;
+		struct spi_transfer	*t = NULL;
+		int			status = 0;
+
+		m = container_of(hw->msg_queue.next, struct spi_message,
+				 queue);
+
+		list_del_init(&m->queue);
+
+		spin_unlock(&hw->lock);
+
+		spi = m->spi;
+
+		if (hw->select)
+			hw->select(spi->chip_select);
+
+		list_for_each_entry(t, &m->transfers, transfer_list) {
+			int bpw = spi->bits_per_word;
+			int xfer_status;
+
+			if (t->bits_per_word)
+				bpw = t->bits_per_word;
+
+			if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0)
+				break;
+
+			ti_ssp_spi_chip_select(hw, 1);
+
+			xfer_status = ti_ssp_spi_txrx(hw, m, t);
+			if (xfer_status < 0)
+				status = xfer_status;
+
+			if (t->delay_usecs)
+				udelay(t->delay_usecs);
+
+			if (t->cs_change)
+				ti_ssp_spi_chip_select(hw, 0);
+		}
+
+		ti_ssp_spi_chip_select(hw, 0);
+		m->status = status;
+		m->complete(m->context);
+
+		spin_lock(&hw->lock);
+	}
+
+	if (hw->shutdown)
+		complete(&hw->complete);
+
+	spin_unlock(&hw->lock);
+}
+
+static int ti_ssp_spi_setup(struct spi_device *spi)
+{
+	if (spi->bits_per_word > 32)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
+{
+	struct ti_ssp_spi	*hw;
+	struct spi_transfer	*t;
+	int			error = 0;
+
+	m->actual_length = 0;
+	m->status = -EINPROGRESS;
+
+	hw = spi_master_get_devdata(spi->master);
+
+	if (list_empty(&m->transfers) || !m->complete)
+		return -EINVAL;
+
+	list_for_each_entry(t, &m->transfers, transfer_list) {
+		if (t->len && !(t->rx_buf || t->tx_buf)) {
+			dev_err(&spi->dev, "invalid xfer, no buffer\n");
+			return -EINVAL;
+		}
+
+		if (t->len && t->rx_buf && t->tx_buf) {
+			dev_err(&spi->dev, "invalid xfer, full duplex\n");
+			return -EINVAL;
+		}
+
+		if (t->bits_per_word > 32) {
+			dev_err(&spi->dev, "invalid xfer width %d\n",
+				t->bits_per_word);
+			return -EINVAL;
+		}
+	}
+
+	spin_lock(&hw->lock);
+	if (hw->shutdown) {
+		error = -ESHUTDOWN;
+		goto error_unlock;
+	}
+	list_add_tail(&m->queue, &hw->msg_queue);
+	queue_work(hw->workqueue, &hw->work);
+error_unlock:
+	spin_unlock(&hw->lock);
+	return error;
+}
+
+static int __devinit ti_ssp_spi_probe(struct platform_device *pdev)
+{
+	const struct ti_ssp_spi_data *pdata;
+	struct ti_ssp_spi *hw;
+	struct spi_master *master;
+	struct device *dev = &pdev->dev;
+	int error = 0;
+
+	pdata = dev->platform_data;
+	if (!pdata) {
+		dev_err(dev, "platform data not found\n");
+		return -EINVAL;
+	}
+
+	master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi));
+	if (!master) {
+		dev_err(dev, "cannot allocate SPI master\n");
+		return -ENOMEM;
+	}
+
+	hw = spi_master_get_devdata(master);
+	platform_set_drvdata(pdev, hw);
+
+	hw->master = master;
+	hw->dev = dev;
+	hw->select = pdata->select;
+
+	spin_lock_init(&hw->lock);
+	init_completion(&hw->complete);
+	INIT_LIST_HEAD(&hw->msg_queue);
+	INIT_WORK(&hw->work, ti_ssp_spi_work);
+
+	hw->workqueue = create_singlethread_workqueue(dev_name(dev));
+	if (!hw->workqueue) {
+		error = -ENOMEM;
+		dev_err(dev, "work queue creation failed\n");
+		goto error_wq;
+	}
+
+	error = ti_ssp_set_iosel(hw->dev, pdata->iosel);
+	if (error < 0) {
+		dev_err(dev, "io setup failed\n");
+		goto error_iosel;
+	}
+
+	master->bus_num		= pdev->id;
+	master->num_chipselect	= pdata->num_cs;
+	master->mode_bits	= MODE_BITS;
+	master->flags		= SPI_MASTER_HALF_DUPLEX;
+	master->setup		= ti_ssp_spi_setup;
+	master->transfer	= ti_ssp_spi_transfer;
+
+	error = spi_register_master(master);
+	if (error) {
+		dev_err(dev, "master registration failed\n");
+		goto error_reg;
+	}
+
+	return 0;
+
+error_reg:
+error_iosel:
+	destroy_workqueue(hw->workqueue);
+error_wq:
+	spi_master_put(master);
+	return error;
+}
+
+static int __devexit ti_ssp_spi_remove(struct platform_device *pdev)
+{
+	struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
+	int error;
+
+	hw->shutdown = 1;
+	while (!list_empty(&hw->msg_queue)) {
+		error = wait_for_completion_interruptible(&hw->complete);
+		if (error < 0) {
+			hw->shutdown = 0;
+			return error;
+		}
+	}
+	destroy_workqueue(hw->workqueue);
+	spi_unregister_master(hw->master);
+
+	return 0;
+}
+
+static struct platform_driver ti_ssp_spi_driver = {
+	.probe		= ti_ssp_spi_probe,
+	.remove		= __devexit_p(ti_ssp_spi_remove),
+	.driver		= {
+		.name	= "ti-ssp-spi",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ti_ssp_spi_init(void)
+{
+	return platform_driver_register(&ti_ssp_spi_driver);
+}
+module_init(ti_ssp_spi_init);
+
+static void __exit ti_ssp_spi_exit(void)
+{
+	platform_driver_unregister(&ti_ssp_spi_driver);
+}
+module_exit(ti_ssp_spi_exit);
+
+MODULE_DESCRIPTION("SSP SPI Master");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ti-ssp-spi");
diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h
index 021fe09..dbb4b43 100644
--- a/include/linux/mfd/ti_ssp.h
+++ b/include/linux/mfd/ti_ssp.h
@@ -32,6 +32,12 @@ struct ti_ssp_data {
 	struct ti_ssp_dev_data	dev_data[2];
 };
 
+struct ti_ssp_spi_data {
+	unsigned long	iosel;
+	int		num_cs;
+	void		(*select)(int cs);
+};
+
 /*
  * Sequencer port IO pin configuration bits.  These do not correlate 1-1 with
  * the hardware.  The iosel field in the port data combines iosel1 and iosel2,
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v8 03/11] gpio: add ti-ssp gpio driver
       [not found] ` <1295378505-15221-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
@ 2011-01-18 19:21   ` Cyril Chemparathy
       [not found]     ` <1295378505-15221-4-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2011-01-18 19:21   ` [PATCH v8 04/11] backlight: add support for tps6116x controller Cyril Chemparathy
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 20+ messages in thread
From: Cyril Chemparathy @ 2011-01-18 19:21 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: c-park-l0cyMroinI0, Cyril Chemparathy,
	linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

TI's SSP controller pins can be directly read and written to behave like a
GPIO.  This patch adds a GPIO driver that exposes such functionality.

Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
---
 drivers/gpio/Kconfig       |   10 ++
 drivers/gpio/Makefile      |    1 +
 drivers/gpio/ti-ssp-gpio.c |  207 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/ti_ssp.h |    4 +
 4 files changed, 222 insertions(+), 0 deletions(-)
 create mode 100644 drivers/gpio/ti-ssp-gpio.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 3143ac7..05bbe4c 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -128,6 +128,16 @@ config GPIO_VX855
 	  additional drivers must be enabled in order to use the
 	  functionality of the device.
 
+config GPIO_TI_SSP
+	tristate "TI Sequencer Serial Port - GPIO Support"
+	depends on MFD_TI_SSP
+	help
+	  Say yes here to support a GPIO interface on TI SSP port pins.
+	  Each SSP port translates into 4 GPIOs.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called ti-ssp-gpio.
+
 comment "I2C GPIO expanders:"
 
 config GPIO_MAX7300
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index bdf3dde..0e2a844 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_GPIO_PL061)	+= pl061.o
 obj-$(CONFIG_GPIO_STMPE)	+= stmpe-gpio.o
 obj-$(CONFIG_GPIO_TC35892)	+= tc35892-gpio.o
 obj-$(CONFIG_GPIO_TIMBERDALE)	+= timbgpio.o
+obj-$(CONFIG_GPIO_TI_SSP)	+= ti-ssp-gpio.o
 obj-$(CONFIG_GPIO_TWL4030)	+= twl4030-gpio.o
 obj-$(CONFIG_GPIO_UCB1400)	+= ucb1400_gpio.o
 obj-$(CONFIG_GPIO_XILINX)	+= xilinx_gpio.o
diff --git a/drivers/gpio/ti-ssp-gpio.c b/drivers/gpio/ti-ssp-gpio.c
new file mode 100644
index 0000000..edc3142
--- /dev/null
+++ b/drivers/gpio/ti-ssp-gpio.c
@@ -0,0 +1,207 @@
+/*
+ * Sequencer Serial Port (SSP) based virtual GPIO driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/ti_ssp.h>
+
+struct ti_ssp_gpio_chip {
+	struct gpio_chip		chip;
+	struct device			*dev;
+	spinlock_t			lock;
+	u8				out;
+	u32				iosel;
+};
+
+#define to_ssp_gpio_chip(c) container_of(c, struct ti_ssp_gpio_chip, chip)
+
+static int ti_ssp_gpio_dir_in(struct gpio_chip *chip, unsigned gpio_num)
+{
+	struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip);
+	int error = 0;
+
+	spin_lock(&gpio->lock);
+
+	gpio->iosel &= ~SSP_PIN_MASK(gpio_num);
+	gpio->iosel |=  SSP_PIN_SEL(gpio_num, SSP_IN);
+
+	error = ti_ssp_set_iosel(gpio->dev, gpio->iosel);
+
+	spin_unlock(&gpio->lock);
+
+	return error;
+}
+
+static int ti_ssp_gpio_dir_out(struct gpio_chip *chip, unsigned gpio_num,
+			       int val)
+{
+	struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip);
+	int error;
+
+	spin_lock(&gpio->lock);
+
+	gpio->iosel &= ~SSP_PIN_MASK(gpio_num);
+	gpio->iosel |=  SSP_PIN_SEL(gpio_num, SSP_OUT);
+
+	error = ti_ssp_set_iosel(gpio->dev, gpio->iosel);
+
+	if (error < 0)
+		goto error;
+
+	if (val)
+		gpio->out |= BIT(gpio_num);
+	else
+		gpio->out &= ~BIT(gpio_num);
+
+	error = ti_ssp_raw_write(gpio->dev, gpio->out);
+
+error:
+	spin_unlock(&gpio->lock);
+	return error;
+}
+
+static int ti_ssp_gpio_get(struct gpio_chip *chip, unsigned gpio_num)
+{
+	struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip);
+	int ret;
+
+	spin_lock(&gpio->lock);
+
+	ret = ti_ssp_raw_read(gpio->dev);
+	if (ret >= 0)
+		ret = !!(ret & BIT(gpio_num));
+
+	spin_unlock(&gpio->lock);
+	return ret;
+}
+
+static void ti_ssp_gpio_set(struct gpio_chip *chip, unsigned gpio_num, int val)
+{
+	struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip);
+
+	spin_lock(&gpio->lock);
+
+	if (val)
+		gpio->out |= BIT(gpio_num);
+	else
+		gpio->out &= ~BIT(gpio_num);
+
+	ti_ssp_raw_write(gpio->dev, gpio->out);
+
+	spin_unlock(&gpio->lock);
+}
+
+static int __devinit ti_ssp_gpio_probe(struct platform_device *pdev)
+{
+	const struct ti_ssp_gpio_data *pdata = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct ti_ssp_gpio_chip *gpio;
+	int error;
+
+	if (!pdata) {
+		dev_err(dev, "platform data not found\n");
+		return -EINVAL;
+	}
+
+	gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
+	if (!gpio) {
+		dev_err(dev, "cannot allocate driver data\n");
+		return -ENOMEM;
+	}
+
+	gpio->dev = dev;
+	gpio->iosel = SSP_PIN_SEL(0, SSP_IN) | SSP_PIN_SEL(1, SSP_IN) |
+		      SSP_PIN_SEL(2, SSP_IN) | SSP_PIN_SEL(3, SSP_IN);
+	error = ti_ssp_set_iosel(gpio->dev, gpio->iosel);
+	if (error < 0) {
+		dev_err(dev, "gpio io setup failed (%d)\n", error);
+		goto error;
+	}
+
+	spin_lock_init(&gpio->lock);
+	platform_set_drvdata(pdev, gpio);
+
+	gpio->chip.base  = pdata->start;
+	gpio->chip.ngpio = 4;
+	gpio->chip.dev   = &pdev->dev;
+	gpio->chip.label = "ti_ssp_gpio";
+	gpio->chip.owner = THIS_MODULE;
+	gpio->chip.get   = ti_ssp_gpio_get;
+	gpio->chip.set   = ti_ssp_gpio_set;
+	gpio->chip.direction_input  = ti_ssp_gpio_dir_in;
+	gpio->chip.direction_output = ti_ssp_gpio_dir_out;
+
+	error = gpiochip_add(&gpio->chip);
+	if (error < 0) {
+		dev_err(dev, "gpio chip registration failed (%d)\n", error);
+		goto error;
+	}
+
+	dev_info(dev, "ssp gpio interface registered\n");
+	return 0;
+
+error:
+	kfree(gpio);
+	return error;
+}
+
+static int __devexit ti_ssp_gpio_remove(struct platform_device *pdev)
+{
+	struct ti_ssp_gpio_chip *gpio = platform_get_drvdata(pdev);
+	int error;
+
+	error = gpiochip_remove(&gpio->chip);
+	if (error < 0)
+		return error;
+	kfree(gpio);
+	return 0;
+}
+
+static struct platform_driver ti_ssp_gpio_driver = {
+	.probe		= ti_ssp_gpio_probe,
+	.remove		= __devexit_p(ti_ssp_gpio_remove),
+	.driver		= {
+		.name	= "ti-ssp-gpio",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ti_ssp_gpio_init(void)
+{
+	return platform_driver_register(&ti_ssp_gpio_driver);
+}
+module_init(ti_ssp_gpio_init);
+
+static void __exit ti_ssp_gpio_exit(void)
+{
+	platform_driver_unregister(&ti_ssp_gpio_driver);
+}
+module_exit(ti_ssp_gpio_exit);
+
+MODULE_DESCRIPTION("GPIO interface for TI-SSP");
+MODULE_AUTHOR("Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ti-ssp-gpio");
diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h
index dbb4b43..10c65bb 100644
--- a/include/linux/mfd/ti_ssp.h
+++ b/include/linux/mfd/ti_ssp.h
@@ -38,6 +38,10 @@ struct ti_ssp_spi_data {
 	void		(*select)(int cs);
 };
 
+struct ti_ssp_gpio_data {
+	int		start;
+};
+
 /*
  * Sequencer port IO pin configuration bits.  These do not correlate 1-1 with
  * the hardware.  The iosel field in the port data combines iosel1 and iosel2,
-- 
1.7.1


------------------------------------------------------------------------------
Protect Your Site and Customers from Malware Attacks
Learn about various malware tactics and how to avoid them. Understand 
malware threats, the impact they can have on your business, and how you 
can protect your company and customers by using code signing.
http://p.sf.net/sfu/oracle-sfdevnl

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v8 04/11] backlight: add support for tps6116x controller
       [not found] ` <1295378505-15221-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2011-01-18 19:21   ` [PATCH v8 03/11] gpio: add ti-ssp gpio driver Cyril Chemparathy
@ 2011-01-18 19:21   ` Cyril Chemparathy
  2011-01-19 17:42     ` Kevin Hilman
  2011-01-18 19:21   ` [PATCH v8 06/11] davinci: add ssp config for tnetv107x evm board Cyril Chemparathy
                     ` (3 subsequent siblings)
  5 siblings, 1 reply; 20+ messages in thread
From: Cyril Chemparathy @ 2011-01-18 19:21 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: c-park-l0cyMroinI0, Cyril Chemparathy,
	linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

TPS6116x is an EasyScale backlight controller device.  This driver supports
TPS6116x devices connected on a single GPIO.

Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
---
 drivers/video/backlight/Kconfig    |    7 +
 drivers/video/backlight/Makefile   |    2 +-
 drivers/video/backlight/tps6116x.c |  299 ++++++++++++++++++++++++++++++++++++
 3 files changed, 307 insertions(+), 1 deletions(-)
 create mode 100644 drivers/video/backlight/tps6116x.c

diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index e54a337..06e868e 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -307,6 +307,13 @@ config BACKLIGHT_PCF50633
 	  If you have a backlight driven by a NXP PCF50633 MFD, say Y here to
 	  enable its driver.
 
+config BACKLIGHT_TPS6116X
+	tristate "TPS6116X LCD Backlight"
+	depends on GENERIC_GPIO
+	help
+	  This driver controls the LCD backlight level for EasyScale capable
+	  SSP connected backlight controllers.
+
 endif # BACKLIGHT_CLASS_DEVICE
 
 endif # BACKLIGHT_LCD_SUPPORT
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 44c0f81..5d407c8 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -35,4 +35,4 @@ obj-$(CONFIG_BACKLIGHT_ADP5520)	+= adp5520_bl.o
 obj-$(CONFIG_BACKLIGHT_ADP8860)	+= adp8860_bl.o
 obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
 obj-$(CONFIG_BACKLIGHT_PCF50633)	+= pcf50633-backlight.o
-
+obj-$(CONFIG_BACKLIGHT_TPS6116X)+= tps6116x.o
diff --git a/drivers/video/backlight/tps6116x.c b/drivers/video/backlight/tps6116x.c
new file mode 100644
index 0000000..7f846ab
--- /dev/null
+++ b/drivers/video/backlight/tps6116x.c
@@ -0,0 +1,299 @@
+/*
+ * TPS6116X LCD Backlight Controller Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/fb.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#define TPS6116X_MAX_INTENSITY		31
+#define TPS6116X_DEFAULT_INTENSITY	10
+
+/* Easyscale timing w/ margin (usecs) */
+#define T_POWER_SETTLE			2000
+#define T_ES_DELAY			120
+#define T_ES_DETECT			280
+#define T_ES_WINDOW			(1000 - T_ES_DELAY - T_ES_DETECT)
+#define T_START				3
+#define T_EOS				3
+#define T_INACTIVE			3
+#define T_ACTIVE			(3 * T_INACTIVE)
+
+#define CMD_SET				0x72
+
+struct tps6116x {
+	struct ti_ssp_device		*handle;
+	struct device			*dev;
+	int				gpio;
+	struct mutex			lock;
+	int				intensity;
+	struct backlight_properties	props;
+	struct backlight_device		*bl;
+	struct regulator		*regulator;
+	bool				power;
+	bool				suspended;
+};
+
+static int __set_power(struct tps6116x *hw, bool power)
+{
+	unsigned long flags;
+	int error;
+
+	if (power == hw->power)
+		return 0; /* nothing to do */
+
+	/* disabling is simple... choke power */
+	if (!power) {
+		error = regulator_disable(hw->regulator);
+		goto done;
+	}
+
+	/* set ctrl pin init state for easyscale detection */
+	gpio_set_value(hw->gpio, 0);
+
+	error = regulator_enable(hw->regulator);
+	if (error < 0)
+		goto done;
+
+	udelay(T_POWER_SETTLE);
+
+	/*
+	 * Now that the controller is powered up, we need to put it into 1-wire
+	 * mode.  This is a timing sensitive operation, hence the irq disable.
+	 * Ideally, this should happen rarely, and mostly at init, so disabling
+	 * interrupts for the duration should not be a problem.
+	 */
+	local_irq_save(flags);
+
+	gpio_set_value(hw->gpio, 1);
+	udelay(T_ES_DELAY);
+	gpio_set_value(hw->gpio, 0);
+	udelay(T_ES_DETECT);
+	gpio_set_value(hw->gpio, 1);
+
+	local_irq_restore(flags);
+
+done:
+	if (error >= 0)
+		hw->power = power;
+
+	return error;
+}
+
+static void __write_byte(struct tps6116x *hw, u8 data)
+{
+	int bit;
+
+	gpio_set_value(hw->gpio, 1);
+	udelay(T_START);
+
+	for (bit = 0; bit < 8; bit++, data <<= 1) {
+		int val = data & 0x80;
+		int t_lo = val ? T_INACTIVE : T_ACTIVE;
+		int t_hi = val ? T_ACTIVE : T_INACTIVE;
+
+		gpio_set_value(hw->gpio, 0);
+		udelay(t_lo);
+		gpio_set_value(hw->gpio, 1);
+		udelay(t_hi);
+	}
+
+	gpio_set_value(hw->gpio, 0);
+	udelay(T_EOS);
+	gpio_set_value(hw->gpio, 1);
+}
+
+static void __set_intensity(struct tps6116x *hw, int intensity)
+{
+	unsigned long flags;
+
+	intensity = clamp(intensity, 0, TPS6116X_MAX_INTENSITY);
+
+	local_irq_save(flags);
+	__write_byte(hw, CMD_SET);
+	__write_byte(hw, intensity);
+	local_irq_restore(flags);
+}
+
+static int set_intensity(struct tps6116x *hw, int intensity)
+{
+	int error = 0;
+
+	if (intensity == hw->intensity)
+		return 0;
+
+	mutex_lock(&hw->lock);
+
+	error = __set_power(hw, intensity ? true : false);
+	if (error < 0)
+		goto error;
+
+	if (intensity > 0)
+		__set_intensity(hw, intensity);
+
+	hw->intensity = intensity;
+error:
+	mutex_unlock(&hw->lock);
+
+	return error;
+}
+
+static int get_brightness(struct backlight_device *bl)
+{
+	struct tps6116x *hw = bl_get_data(bl);
+
+	return hw->intensity;
+}
+
+static int update_status(struct backlight_device *bl)
+{
+	struct tps6116x *hw = bl_get_data(bl);
+	int intensity = bl->props.brightness;
+
+	if (hw->suspended || hw->props.state & BL_CORE_SUSPENDED)
+		intensity = 0;
+	if (bl->props.power != FB_BLANK_UNBLANK)
+		intensity = 0;
+	if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+		intensity = 0;
+
+	return set_intensity(hw, intensity);
+}
+
+static const struct backlight_ops tps6116x_backlight_ops = {
+	.options	= BL_CORE_SUSPENDRESUME,
+	.get_brightness	= get_brightness,
+	.update_status	= update_status,
+};
+
+static int __devinit tps6116x_probe(struct platform_device *pdev)
+{
+	struct tps6116x *hw;
+	struct device *dev = &pdev->dev;
+	struct backlight_properties props;
+	int error;
+
+	hw = kzalloc(sizeof(struct tps6116x), GFP_KERNEL);
+	if (!hw) {
+		dev_err(dev, "cannot allocate driver data\n");
+		return -ENOMEM;
+	}
+	platform_set_drvdata(pdev, hw);
+
+	hw->gpio = (int)dev->platform_data;
+	hw->dev = dev;
+
+	mutex_init(&hw->lock);
+
+	hw->regulator = regulator_get(dev, "vlcd");
+	if (IS_ERR(hw->regulator)) {
+		error = PTR_ERR(hw->regulator);
+		dev_err(dev, "cannot claim regulator\n");
+		goto error_regulator;
+	}
+
+	error = gpio_request_one(hw->gpio, GPIOF_DIR_OUT, dev_name(dev));
+	if (error < 0) {
+		dev_err(dev, "cannot claim gpio\n");
+		goto error_gpio;
+	}
+
+	memset(&props, 0, sizeof(props));
+	props.max_brightness = TPS6116X_MAX_INTENSITY;
+	props.brightness     = TPS6116X_DEFAULT_INTENSITY;
+	props.power          = FB_BLANK_UNBLANK;
+
+	hw->bl = backlight_device_register("tps6116x", hw->dev, hw,
+					   &tps6116x_backlight_ops, &props);
+	if (IS_ERR(hw->bl)) {
+		error = PTR_ERR(hw->bl);
+		dev_err(dev, "backlight registration failed\n");
+		goto error_register;
+	}
+
+	update_status(hw->bl);
+	dev_info(dev, "registered backlight controller\n");
+	return 0;
+
+error_register:
+	gpio_free(hw->gpio);
+error_gpio:
+	regulator_put(hw->regulator);
+error_regulator:
+	kfree(hw);
+	platform_set_drvdata(pdev, NULL);
+	return error;
+}
+
+static int __devexit tps6116x_remove(struct platform_device *pdev)
+{
+	struct tps6116x *hw = platform_get_drvdata(pdev);
+
+	backlight_device_unregister(hw->bl);
+	regulator_disable(hw->regulator);
+	regulator_put(hw->regulator);
+	gpio_free(hw->gpio);
+	kfree(hw);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static int tps6116x_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct tps6116x *hw = platform_get_drvdata(pdev);
+	hw->suspended = true;
+	update_status(hw->bl);
+	return 0;
+}
+
+static int tps6116x_resume(struct platform_device *pdev)
+{
+	struct tps6116x *hw = platform_get_drvdata(pdev);
+	hw->suspended = false;
+	update_status(hw->bl);
+	return 0;
+}
+
+static struct platform_driver tps6116x_driver = {
+	.probe		= tps6116x_probe,
+	.remove		= __devexit_p(tps6116x_remove),
+	.suspend	= tps6116x_suspend,
+	.resume		= tps6116x_resume,
+	.driver		= {
+		.name	= "tps6116x",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init tps6116x_init(void)
+{
+	return platform_driver_register(&tps6116x_driver);
+}
+module_init(tps6116x_init);
+
+static void __exit tps6116x_exit(void)
+{
+	platform_driver_unregister(&tps6116x_driver);
+}
+module_exit(tps6116x_exit);
+
+MODULE_DESCRIPTION("SSP TPS6116X Driver");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tps6116x");
-- 
1.7.1


------------------------------------------------------------------------------
Protect Your Site and Customers from Malware Attacks
Learn about various malware tactics and how to avoid them. Understand 
malware threats, the impact they can have on your business, and how you 
can protect your company and customers by using code signing.
http://p.sf.net/sfu/oracle-sfdevnl

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v8 05/11] davinci: add tnetv107x ssp platform device
  2011-01-18 19:21 [PATCH v8 00/11] tnetv107x ssp drivers Cyril Chemparathy
  2011-01-18 19:21 ` [PATCH v8 01/11] mfd: add driver for sequencer serial port Cyril Chemparathy
  2011-01-18 19:21 ` [PATCH v8 02/11] spi: add ti-ssp spi master driver Cyril Chemparathy
@ 2011-01-18 19:21 ` Cyril Chemparathy
       [not found] ` <1295378505-15221-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 20+ messages in thread
From: Cyril Chemparathy @ 2011-01-18 19:21 UTC (permalink / raw)
  To: davinci-linux-open-source, spi-devel-general, sameo, rpurdie, dbrownell
  Cc: c-park, linux-arm-kernel, linux-kernel, Cyril Chemparathy

This patch adds an SSP platform device definition for the tnetv107x soc family.
The clock lookup entry has also been updated to match.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 arch/arm/mach-davinci/devices-tnetv107x.c      |   25 ++++++++++++++++++++++++
 arch/arm/mach-davinci/include/mach/tnetv107x.h |    2 +
 arch/arm/mach-davinci/tnetv107x.c              |    2 +-
 3 files changed, 28 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-davinci/devices-tnetv107x.c b/arch/arm/mach-davinci/devices-tnetv107x.c
index 85503de..6162cae 100644
--- a/arch/arm/mach-davinci/devices-tnetv107x.c
+++ b/arch/arm/mach-davinci/devices-tnetv107x.c
@@ -35,6 +35,7 @@
 #define TNETV107X_SDIO0_BASE			0x08088700
 #define TNETV107X_SDIO1_BASE			0x08088800
 #define TNETV107X_KEYPAD_BASE			0x08088a00
+#define TNETV107X_SSP_BASE			0x08088c00
 #define TNETV107X_ASYNC_EMIF_CNTRL_BASE		0x08200000
 #define TNETV107X_ASYNC_EMIF_DATA_CE0_BASE	0x30000000
 #define TNETV107X_ASYNC_EMIF_DATA_CE1_BASE	0x40000000
@@ -342,6 +343,25 @@ static struct platform_device tsc_device = {
 	.resource	= tsc_resources,
 };
 
+static struct resource ssp_resources[] = {
+	{
+		.start	= TNETV107X_SSP_BASE,
+		.end	= TNETV107X_SSP_BASE + 0x1ff,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_TNETV107X_SSP,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ssp_device = {
+	.name		= "ti-ssp",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ssp_resources),
+	.resource	= ssp_resources,
+};
+
 void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
 {
 	int i, error;
@@ -380,4 +400,9 @@ void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
 		keypad_device.dev.platform_data = info->keypad_config;
 		platform_device_register(&keypad_device);
 	}
+
+	if (info->ssp_config) {
+		ssp_device.dev.platform_data = info->ssp_config;
+		platform_device_register(&ssp_device);
+	}
 }
diff --git a/arch/arm/mach-davinci/include/mach/tnetv107x.h b/arch/arm/mach-davinci/include/mach/tnetv107x.h
index 5a681d8..89c1fdc 100644
--- a/arch/arm/mach-davinci/include/mach/tnetv107x.h
+++ b/arch/arm/mach-davinci/include/mach/tnetv107x.h
@@ -34,6 +34,7 @@
 
 #include <linux/serial_8250.h>
 #include <linux/input/matrix_keypad.h>
+#include <linux/mfd/ti_ssp.h>
 
 #include <mach/mmc.h>
 #include <mach/nand.h>
@@ -44,6 +45,7 @@ struct tnetv107x_device_info {
 	struct davinci_mmc_config	*mmc_config[2];  /* 2 controllers */
 	struct davinci_nand_pdata	*nand_config[4]; /* 4 chipsels */
 	struct matrix_keypad_platform_data *keypad_config;
+	struct ti_ssp_data		*ssp_config;
 };
 
 extern struct platform_device tnetv107x_wdt_device;
diff --git a/arch/arm/mach-davinci/tnetv107x.c b/arch/arm/mach-davinci/tnetv107x.c
index 6fcdece..1b28fdd 100644
--- a/arch/arm/mach-davinci/tnetv107x.c
+++ b/arch/arm/mach-davinci/tnetv107x.c
@@ -278,7 +278,7 @@ static struct clk_lookup clks[] = {
 	CLK(NULL,		"timer1",		&clk_timer1),
 	CLK("tnetv107x_wdt.0",	NULL,			&clk_wdt_arm),
 	CLK(NULL,		"clk_wdt_dsp",		&clk_wdt_dsp),
-	CLK("ti-ssp.0",		NULL,			&clk_ssp),
+	CLK("ti-ssp",		NULL,			&clk_ssp),
 	CLK(NULL,		"clk_tdm0",		&clk_tdm0),
 	CLK(NULL,		"clk_vlynq",		&clk_vlynq),
 	CLK(NULL,		"clk_mcdma",		&clk_mcdma),
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v8 06/11] davinci: add ssp config for tnetv107x evm board
       [not found] ` <1295378505-15221-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2011-01-18 19:21   ` [PATCH v8 03/11] gpio: add ti-ssp gpio driver Cyril Chemparathy
  2011-01-18 19:21   ` [PATCH v8 04/11] backlight: add support for tps6116x controller Cyril Chemparathy
@ 2011-01-18 19:21   ` Cyril Chemparathy
  2011-01-18 19:21   ` [PATCH v8 08/11] davinci: add tnetv107x evm regulators Cyril Chemparathy
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 20+ messages in thread
From: Cyril Chemparathy @ 2011-01-18 19:21 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: c-park-l0cyMroinI0, Cyril Chemparathy,
	linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

This patch adds SSP configuration and pin muxing info for tnetv107x
evm boards.

Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
---
 arch/arm/mach-davinci/board-tnetv107x-evm.c |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index a6db854..ef526b1 100644
--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -99,6 +99,12 @@ static const short uart1_pins[] __initdata = {
 	-1
 };
 
+static const short ssp_pins[] __initdata = {
+	TNETV107X_SSP0_0, TNETV107X_SSP0_1, TNETV107X_SSP0_2,
+	TNETV107X_SSP1_0, TNETV107X_SSP1_1, TNETV107X_SSP1_2,
+	TNETV107X_SSP1_3, -1
+};
+
 static struct mtd_partition nand_partitions[] = {
 	/* bootloader (U-Boot, etc) in first 12 sectors */
 	{
@@ -196,17 +202,25 @@ static struct matrix_keypad_platform_data keypad_config = {
 	.no_autorepeat	= 0,
 };
 
+static struct ti_ssp_data ssp_config = {
+	.out_clock	= 250 * 1000,
+	.dev_data	= {
+	},
+};
+
 static struct tnetv107x_device_info evm_device_info __initconst = {
 	.serial_config		= &serial_config,
 	.mmc_config[1]		= &mmc_config,	/* controller 1 */
 	.nand_config[0]		= &nand_config,	/* chip select 0 */
 	.keypad_config		= &keypad_config,
+	.ssp_config		= &ssp_config,
 };
 
 static __init void tnetv107x_evm_board_init(void)
 {
 	davinci_cfg_reg_list(sdio1_pins);
 	davinci_cfg_reg_list(uart1_pins);
+	davinci_cfg_reg_list(ssp_pins);
 
 	tnetv107x_devices_init(&evm_device_info);
 }
-- 
1.7.1


------------------------------------------------------------------------------
Protect Your Site and Customers from Malware Attacks
Learn about various malware tactics and how to avoid them. Understand 
malware threats, the impact they can have on your business, and how you 
can protect your company and customers by using code signing.
http://p.sf.net/sfu/oracle-sfdevnl

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v8 07/11] davinci: add spi devices on tnetv107x evm
  2011-01-18 19:21 [PATCH v8 00/11] tnetv107x ssp drivers Cyril Chemparathy
                   ` (3 preceding siblings ...)
       [not found] ` <1295378505-15221-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
@ 2011-01-18 19:21 ` Cyril Chemparathy
  2011-01-18 19:21 ` [PATCH v8 09/11] davinci: add tnetv107x evm ti-ssp gpio device Cyril Chemparathy
  5 siblings, 0 replies; 20+ messages in thread
From: Cyril Chemparathy @ 2011-01-18 19:21 UTC (permalink / raw)
  To: davinci-linux-open-source, spi-devel-general, sameo, rpurdie, dbrownell
  Cc: c-park, linux-arm-kernel, linux-kernel, Cyril Chemparathy

This patch adds definitions for spi devices on the tnetv107x evm platform.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 arch/arm/mach-davinci/board-tnetv107x-evm.c |   43 +++++++++++++++++++++++++++
 1 files changed, 43 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index ef526b1..1a656e8 100644
--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -25,6 +25,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
+#include <linux/spi/spi.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
@@ -37,6 +38,7 @@
 
 #define EVM_MMC_WP_GPIO		21
 #define EVM_MMC_CD_GPIO		24
+#define EVM_SPI_CS_GPIO		54
 
 static int initialize_gpio(int gpio, char *desc)
 {
@@ -202,9 +204,45 @@ static struct matrix_keypad_platform_data keypad_config = {
 	.no_autorepeat	= 0,
 };
 
+static void spi_select_device(int cs)
+{
+	static int gpio;
+
+	if (!gpio) {
+		int ret;
+		ret = gpio_request(EVM_SPI_CS_GPIO, "spi chipsel");
+		if (ret < 0) {
+			pr_err("cannot open spi chipsel gpio\n");
+			gpio = -ENOSYS;
+			return;
+		} else {
+			gpio = EVM_SPI_CS_GPIO;
+			gpio_direction_output(gpio, 0);
+		}
+	}
+
+	if (gpio < 0)
+		return;
+
+	return gpio_set_value(gpio, cs ? 1 : 0);
+}
+
+static struct ti_ssp_spi_data spi_master_data = {
+	.num_cs	= 2,
+	.select	= spi_select_device,
+	.iosel	= SSP_PIN_SEL(0, SSP_CLOCK)	| SSP_PIN_SEL(1, SSP_DATA) |
+		  SSP_PIN_SEL(2, SSP_CHIPSEL)	| SSP_PIN_SEL(3, SSP_IN)   |
+		  SSP_INPUT_SEL(3),
+};
+
 static struct ti_ssp_data ssp_config = {
 	.out_clock	= 250 * 1000,
 	.dev_data	= {
+		[1] = {
+			.dev_name = "ti-ssp-spi",
+			.pdata = &spi_master_data,
+			.pdata_size = sizeof(spi_master_data),
+		},
 	},
 };
 
@@ -216,6 +254,9 @@ static struct tnetv107x_device_info evm_device_info __initconst = {
 	.ssp_config		= &ssp_config,
 };
 
+static struct spi_board_info spi_info[] __initconst = {
+};
+
 static __init void tnetv107x_evm_board_init(void)
 {
 	davinci_cfg_reg_list(sdio1_pins);
@@ -223,6 +264,8 @@ static __init void tnetv107x_evm_board_init(void)
 	davinci_cfg_reg_list(ssp_pins);
 
 	tnetv107x_devices_init(&evm_device_info);
+
+	spi_register_board_info(spi_info, ARRAY_SIZE(spi_info));
 }
 
 #ifdef CONFIG_SERIAL_8250_CONSOLE
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v8 08/11] davinci: add tnetv107x evm regulators
       [not found] ` <1295378505-15221-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (2 preceding siblings ...)
  2011-01-18 19:21   ` [PATCH v8 06/11] davinci: add ssp config for tnetv107x evm board Cyril Chemparathy
@ 2011-01-18 19:21   ` Cyril Chemparathy
  2011-01-18 19:21   ` [PATCH v8 10/11] davinci: add tnetv107x evm backlight device Cyril Chemparathy
  2011-01-18 19:21   ` [PATCH v8 11/11] davinci: add tnetv107x evm i2c eeprom device Cyril Chemparathy
  5 siblings, 0 replies; 20+ messages in thread
From: Cyril Chemparathy @ 2011-01-18 19:21 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: c-park-l0cyMroinI0, Cyril Chemparathy,
	linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

This patch adds regulator and spi board info definitions for the tps6524x
power management IC found on tnetv107x evm boards.

Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
---
 arch/arm/mach-davinci/board-tnetv107x-evm.c |   85 +++++++++++++++++++++++++++
 1 files changed, 85 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index 1a656e8..ca23516 100644
--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -26,6 +26,9 @@
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
@@ -254,7 +257,89 @@ static struct tnetv107x_device_info evm_device_info __initconst = {
 	.ssp_config		= &ssp_config,
 };
 
+static struct regulator_consumer_supply usb_consumers[] = {
+	REGULATOR_SUPPLY("vbus", "musb_hdrc.1"),
+};
+
+static struct regulator_consumer_supply lcd_consumers[] = {
+	REGULATOR_SUPPLY("vlcd", "tps6116x"),
+};
+
+static struct regulator_init_data regulators[] = {
+	{
+		.constraints		= {
+			.name		= "DCDC1",
+			.min_uV		= 1000000,
+			.max_uV		= 1000000,
+			.always_on	= 1,
+			.boot_on	= 1,
+		},
+	},
+	{
+		.constraints		= {
+			.name		= "DCDC2",
+			.min_uV		= 1800000,
+			.max_uV		= 1800000,
+			.always_on	= 1,
+			.boot_on	= 1,
+		},
+	},
+	{
+		.constraints		= {
+			.name		= "DCDC3",
+			.min_uV		= 3300000,
+			.max_uV		= 3300000,
+			.always_on	= 1,
+			.boot_on	= 1,
+		},
+	},
+	{
+		.constraints		= {
+			.name		= "LDO1",
+			.min_uV		= 4800000,
+			.max_uV		= 4800000,
+			.always_on	= 1,
+			.boot_on	= 1,
+		},
+	},
+	{
+		.constraints		= {
+			.name		= "LDO1",
+			.min_uV		= 3300000,
+			.max_uV		= 3300000,
+			.always_on	= 1,
+			.boot_on	= 1,
+		},
+	},
+	{
+		.num_consumer_supplies	= ARRAY_SIZE(usb_consumers),
+		.consumer_supplies	= usb_consumers,
+		.constraints		= {
+			.name		= "USB",
+			.min_uA		= 200000,
+			.max_uA		= 1000000,
+			.valid_ops_mask	= REGULATOR_CHANGE_CURRENT |
+					  REGULATOR_CHANGE_STATUS,
+		},
+	},
+	{
+		.num_consumer_supplies	= ARRAY_SIZE(lcd_consumers),
+		.consumer_supplies	= lcd_consumers,
+		.constraints		= {
+			.name		= "LCD",
+			.valid_ops_mask	= REGULATOR_CHANGE_STATUS,
+		},
+	},
+};
+
 static struct spi_board_info spi_info[] __initconst = {
+	{
+		.modalias	= "tps6524x",
+		.bus_num	= 1,
+		.chip_select	= 0,
+		.mode		= SPI_MODE_0,
+		.platform_data	= regulators,
+	},
 };
 
 static __init void tnetv107x_evm_board_init(void)
-- 
1.7.1


------------------------------------------------------------------------------
Protect Your Site and Customers from Malware Attacks
Learn about various malware tactics and how to avoid them. Understand 
malware threats, the impact they can have on your business, and how you 
can protect your company and customers by using code signing.
http://p.sf.net/sfu/oracle-sfdevnl

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v8 09/11] davinci: add tnetv107x evm ti-ssp gpio device
  2011-01-18 19:21 [PATCH v8 00/11] tnetv107x ssp drivers Cyril Chemparathy
                   ` (4 preceding siblings ...)
  2011-01-18 19:21 ` [PATCH v8 07/11] davinci: add spi devices on tnetv107x evm Cyril Chemparathy
@ 2011-01-18 19:21 ` Cyril Chemparathy
  5 siblings, 0 replies; 20+ messages in thread
From: Cyril Chemparathy @ 2011-01-18 19:21 UTC (permalink / raw)
  To: davinci-linux-open-source, spi-devel-general, sameo, rpurdie, dbrownell
  Cc: c-park, linux-arm-kernel, linux-kernel, Cyril Chemparathy

This patch adds definitions to hook up one of the ti-ssp ports to the SSP GPIO
driver.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 arch/arm/mach-davinci/board-tnetv107x-evm.c |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index ca23516..e3863dd 100644
--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -39,6 +39,8 @@
 #include <mach/cp_intc.h>
 #include <mach/tnetv107x.h>
 
+#define SSP_GPIO_START		128
+
 #define EVM_MMC_WP_GPIO		21
 #define EVM_MMC_CD_GPIO		24
 #define EVM_SPI_CS_GPIO		54
@@ -238,9 +240,18 @@ static struct ti_ssp_spi_data spi_master_data = {
 		  SSP_INPUT_SEL(3),
 };
 
+static struct ti_ssp_gpio_data ssp_gpio_data = {
+	.start		= SSP_GPIO_START,
+};
+
 static struct ti_ssp_data ssp_config = {
 	.out_clock	= 250 * 1000,
 	.dev_data	= {
+		[0] = {
+			.dev_name = "ti-ssp-gpio",
+			.pdata = &ssp_gpio_data,
+			.pdata_size = sizeof(ssp_gpio_data),
+		},
 		[1] = {
 			.dev_name = "ti-ssp-spi",
 			.pdata = &spi_master_data,
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v8 10/11] davinci: add tnetv107x evm backlight device
       [not found] ` <1295378505-15221-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (3 preceding siblings ...)
  2011-01-18 19:21   ` [PATCH v8 08/11] davinci: add tnetv107x evm regulators Cyril Chemparathy
@ 2011-01-18 19:21   ` Cyril Chemparathy
  2011-01-18 19:21   ` [PATCH v8 11/11] davinci: add tnetv107x evm i2c eeprom device Cyril Chemparathy
  5 siblings, 0 replies; 20+ messages in thread
From: Cyril Chemparathy @ 2011-01-18 19:21 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: c-park-l0cyMroinI0, Cyril Chemparathy,
	linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

The tnetv107x evm board has a backlight device that is connected on one of the
SSP ports.  This patch adds the board definitions necessary to plug the
backlight driver to the GPIO corresponding to this SSP pin.

Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
---
 arch/arm/mach-davinci/board-tnetv107x-evm.c |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index e3863dd..ac62de2 100644
--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -44,6 +44,7 @@
 #define EVM_MMC_WP_GPIO		21
 #define EVM_MMC_CD_GPIO		24
 #define EVM_SPI_CS_GPIO		54
+#define EVM_BACKLIGHT_GPIO	(SSP_GPIO_START + 2)
 
 static int initialize_gpio(int gpio, char *desc)
 {
@@ -353,6 +354,12 @@ static struct spi_board_info spi_info[] __initconst = {
 	},
 };
 
+static struct platform_device backlight_device = {
+	.name		= "tps6116x",
+	.id		= -1,
+	.dev.platform_data = (void *)EVM_BACKLIGHT_GPIO,
+};
+
 static __init void tnetv107x_evm_board_init(void)
 {
 	davinci_cfg_reg_list(sdio1_pins);
@@ -364,6 +371,13 @@ static __init void tnetv107x_evm_board_init(void)
 	spi_register_board_info(spi_info, ARRAY_SIZE(spi_info));
 }
 
+static int __init tnetv107x_evm_late_init(void)
+{
+	platform_device_register(&backlight_device);
+	return 0;
+}
+late_initcall(tnetv107x_evm_late_init);
+
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 static int __init tnetv107x_evm_console_init(void)
 {
-- 
1.7.1


------------------------------------------------------------------------------
Protect Your Site and Customers from Malware Attacks
Learn about various malware tactics and how to avoid them. Understand 
malware threats, the impact they can have on your business, and how you 
can protect your company and customers by using code signing.
http://p.sf.net/sfu/oracle-sfdevnl

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v8 11/11] davinci: add tnetv107x evm i2c eeprom device
       [not found] ` <1295378505-15221-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (4 preceding siblings ...)
  2011-01-18 19:21   ` [PATCH v8 10/11] davinci: add tnetv107x evm backlight device Cyril Chemparathy
@ 2011-01-18 19:21   ` Cyril Chemparathy
  5 siblings, 0 replies; 20+ messages in thread
From: Cyril Chemparathy @ 2011-01-18 19:21 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: c-park-l0cyMroinI0, Cyril Chemparathy,
	linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

The tnetv107x evm board has an I2C device connected on one of the SSP ports.
This patch adds board definitions for a GPIO based I2C master, as well as
definitions for the eeprom device on these boards.

Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
---
 arch/arm/mach-davinci/board-tnetv107x-evm.c |   30 +++++++++++++++++++++++++++
 1 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index ac62de2..869af15 100644
--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -29,6 +29,9 @@
 #include <linux/regulator/machine.h>
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/driver.h>
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+#include <linux/i2c-gpio.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
@@ -44,6 +47,8 @@
 #define EVM_MMC_WP_GPIO		21
 #define EVM_MMC_CD_GPIO		24
 #define EVM_SPI_CS_GPIO		54
+#define EVM_I2C_SDA_GPIO	(SSP_GPIO_START + 0)
+#define EVM_I2C_SCL_GPIO	(SSP_GPIO_START + 1)
 #define EVM_BACKLIGHT_GPIO	(SSP_GPIO_START + 2)
 
 static int initialize_gpio(int gpio, char *desc)
@@ -360,6 +365,29 @@ static struct platform_device backlight_device = {
 	.dev.platform_data = (void *)EVM_BACKLIGHT_GPIO,
 };
 
+struct i2c_gpio_platform_data i2c_data = {
+	.sda_pin	= EVM_I2C_SDA_GPIO,
+	.scl_pin	= EVM_I2C_SCL_GPIO,
+};
+
+static struct platform_device i2c_device = {
+	.name		= "i2c-gpio",
+	.id		= 0,
+	.dev.platform_data = &i2c_data,
+};
+
+static struct at24_platform_data at24_config = {
+	.byte_len	= SZ_16K / 8,
+	.page_size	= 16,
+};
+
+static struct i2c_board_info i2c_info[] __initconst =  {
+	{
+		I2C_BOARD_INFO("24c16", 0x50),
+		.platform_data	= &at24_config,
+	},
+};
+
 static __init void tnetv107x_evm_board_init(void)
 {
 	davinci_cfg_reg_list(sdio1_pins);
@@ -369,11 +397,13 @@ static __init void tnetv107x_evm_board_init(void)
 	tnetv107x_devices_init(&evm_device_info);
 
 	spi_register_board_info(spi_info, ARRAY_SIZE(spi_info));
+	i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info));
 }
 
 static int __init tnetv107x_evm_late_init(void)
 {
 	platform_device_register(&backlight_device);
+	platform_device_register(&i2c_device);
 	return 0;
 }
 late_initcall(tnetv107x_evm_late_init);
-- 
1.7.1


------------------------------------------------------------------------------
Protect Your Site and Customers from Malware Attacks
Learn about various malware tactics and how to avoid them. Understand 
malware threats, the impact they can have on your business, and how you 
can protect your company and customers by using code signing.
http://p.sf.net/sfu/oracle-sfdevnl

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH v8 04/11] backlight: add support for tps6116x controller
  2011-01-18 19:21   ` [PATCH v8 04/11] backlight: add support for tps6116x controller Cyril Chemparathy
@ 2011-01-19 17:42     ` Kevin Hilman
  0 siblings, 0 replies; 20+ messages in thread
From: Kevin Hilman @ 2011-01-19 17:42 UTC (permalink / raw)
  To: rpurdie, Andrew Morton
  Cc: davinci-linux-open-source, spi-devel-general, sameo, dbrownell,
	linux-arm-kernel, linux-kernel, Cyril Chemparathy

Richard,

Cyril Chemparathy <cyril@ti.com> writes:

> TPS6116x is an EasyScale backlight controller device.  This driver supports
> TPS6116x devices connected on a single GPIO.
>
> Signed-off-by: Cyril Chemparathy <cyril@ti.com>

Any comments on this driver?

With your Ack, I'll be happy to merge it via the davinci tree with the
rest of the series.

Thanks,

Kevin

> ---
>  drivers/video/backlight/Kconfig    |    7 +
>  drivers/video/backlight/Makefile   |    2 +-
>  drivers/video/backlight/tps6116x.c |  299 ++++++++++++++++++++++++++++++++++++
>  3 files changed, 307 insertions(+), 1 deletions(-)
>  create mode 100644 drivers/video/backlight/tps6116x.c
>
> diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> index e54a337..06e868e 100644
> --- a/drivers/video/backlight/Kconfig
> +++ b/drivers/video/backlight/Kconfig
> @@ -307,6 +307,13 @@ config BACKLIGHT_PCF50633
>  	  If you have a backlight driven by a NXP PCF50633 MFD, say Y here to
>  	  enable its driver.
>  
> +config BACKLIGHT_TPS6116X
> +	tristate "TPS6116X LCD Backlight"
> +	depends on GENERIC_GPIO
> +	help
> +	  This driver controls the LCD backlight level for EasyScale capable
> +	  SSP connected backlight controllers.
> +
>  endif # BACKLIGHT_CLASS_DEVICE
>  
>  endif # BACKLIGHT_LCD_SUPPORT
> diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
> index 44c0f81..5d407c8 100644
> --- a/drivers/video/backlight/Makefile
> +++ b/drivers/video/backlight/Makefile
> @@ -35,4 +35,4 @@ obj-$(CONFIG_BACKLIGHT_ADP5520)	+= adp5520_bl.o
>  obj-$(CONFIG_BACKLIGHT_ADP8860)	+= adp8860_bl.o
>  obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
>  obj-$(CONFIG_BACKLIGHT_PCF50633)	+= pcf50633-backlight.o
> -
> +obj-$(CONFIG_BACKLIGHT_TPS6116X)+= tps6116x.o
> diff --git a/drivers/video/backlight/tps6116x.c b/drivers/video/backlight/tps6116x.c
> new file mode 100644
> index 0000000..7f846ab
> --- /dev/null
> +++ b/drivers/video/backlight/tps6116x.c
> @@ -0,0 +1,299 @@
> +/*
> + * TPS6116X LCD Backlight Controller Driver
> + *
> + * Copyright (C) 2010 Texas Instruments
> + *
> + * 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 version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
> + * whether express or implied; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/fb.h>
> +#include <linux/err.h>
> +#include <linux/delay.h>
> +#include <linux/gpio.h>
> +#include <linux/backlight.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
> +
> +#define TPS6116X_MAX_INTENSITY		31
> +#define TPS6116X_DEFAULT_INTENSITY	10
> +
> +/* Easyscale timing w/ margin (usecs) */
> +#define T_POWER_SETTLE			2000
> +#define T_ES_DELAY			120
> +#define T_ES_DETECT			280
> +#define T_ES_WINDOW			(1000 - T_ES_DELAY - T_ES_DETECT)
> +#define T_START				3
> +#define T_EOS				3
> +#define T_INACTIVE			3
> +#define T_ACTIVE			(3 * T_INACTIVE)
> +
> +#define CMD_SET				0x72
> +
> +struct tps6116x {
> +	struct ti_ssp_device		*handle;
> +	struct device			*dev;
> +	int				gpio;
> +	struct mutex			lock;
> +	int				intensity;
> +	struct backlight_properties	props;
> +	struct backlight_device		*bl;
> +	struct regulator		*regulator;
> +	bool				power;
> +	bool				suspended;
> +};
> +
> +static int __set_power(struct tps6116x *hw, bool power)
> +{
> +	unsigned long flags;
> +	int error;
> +
> +	if (power == hw->power)
> +		return 0; /* nothing to do */
> +
> +	/* disabling is simple... choke power */
> +	if (!power) {
> +		error = regulator_disable(hw->regulator);
> +		goto done;
> +	}
> +
> +	/* set ctrl pin init state for easyscale detection */
> +	gpio_set_value(hw->gpio, 0);
> +
> +	error = regulator_enable(hw->regulator);
> +	if (error < 0)
> +		goto done;
> +
> +	udelay(T_POWER_SETTLE);
> +
> +	/*
> +	 * Now that the controller is powered up, we need to put it into 1-wire
> +	 * mode.  This is a timing sensitive operation, hence the irq disable.
> +	 * Ideally, this should happen rarely, and mostly at init, so disabling
> +	 * interrupts for the duration should not be a problem.
> +	 */
> +	local_irq_save(flags);
> +
> +	gpio_set_value(hw->gpio, 1);
> +	udelay(T_ES_DELAY);
> +	gpio_set_value(hw->gpio, 0);
> +	udelay(T_ES_DETECT);
> +	gpio_set_value(hw->gpio, 1);
> +
> +	local_irq_restore(flags);
> +
> +done:
> +	if (error >= 0)
> +		hw->power = power;
> +
> +	return error;
> +}
> +
> +static void __write_byte(struct tps6116x *hw, u8 data)
> +{
> +	int bit;
> +
> +	gpio_set_value(hw->gpio, 1);
> +	udelay(T_START);
> +
> +	for (bit = 0; bit < 8; bit++, data <<= 1) {
> +		int val = data & 0x80;
> +		int t_lo = val ? T_INACTIVE : T_ACTIVE;
> +		int t_hi = val ? T_ACTIVE : T_INACTIVE;
> +
> +		gpio_set_value(hw->gpio, 0);
> +		udelay(t_lo);
> +		gpio_set_value(hw->gpio, 1);
> +		udelay(t_hi);
> +	}
> +
> +	gpio_set_value(hw->gpio, 0);
> +	udelay(T_EOS);
> +	gpio_set_value(hw->gpio, 1);
> +}
> +
> +static void __set_intensity(struct tps6116x *hw, int intensity)
> +{
> +	unsigned long flags;
> +
> +	intensity = clamp(intensity, 0, TPS6116X_MAX_INTENSITY);
> +
> +	local_irq_save(flags);
> +	__write_byte(hw, CMD_SET);
> +	__write_byte(hw, intensity);
> +	local_irq_restore(flags);
> +}
> +
> +static int set_intensity(struct tps6116x *hw, int intensity)
> +{
> +	int error = 0;
> +
> +	if (intensity == hw->intensity)
> +		return 0;
> +
> +	mutex_lock(&hw->lock);
> +
> +	error = __set_power(hw, intensity ? true : false);
> +	if (error < 0)
> +		goto error;
> +
> +	if (intensity > 0)
> +		__set_intensity(hw, intensity);
> +
> +	hw->intensity = intensity;
> +error:
> +	mutex_unlock(&hw->lock);
> +
> +	return error;
> +}
> +
> +static int get_brightness(struct backlight_device *bl)
> +{
> +	struct tps6116x *hw = bl_get_data(bl);
> +
> +	return hw->intensity;
> +}
> +
> +static int update_status(struct backlight_device *bl)
> +{
> +	struct tps6116x *hw = bl_get_data(bl);
> +	int intensity = bl->props.brightness;
> +
> +	if (hw->suspended || hw->props.state & BL_CORE_SUSPENDED)
> +		intensity = 0;
> +	if (bl->props.power != FB_BLANK_UNBLANK)
> +		intensity = 0;
> +	if (bl->props.fb_blank != FB_BLANK_UNBLANK)
> +		intensity = 0;
> +
> +	return set_intensity(hw, intensity);
> +}
> +
> +static const struct backlight_ops tps6116x_backlight_ops = {
> +	.options	= BL_CORE_SUSPENDRESUME,
> +	.get_brightness	= get_brightness,
> +	.update_status	= update_status,
> +};
> +
> +static int __devinit tps6116x_probe(struct platform_device *pdev)
> +{
> +	struct tps6116x *hw;
> +	struct device *dev = &pdev->dev;
> +	struct backlight_properties props;
> +	int error;
> +
> +	hw = kzalloc(sizeof(struct tps6116x), GFP_KERNEL);
> +	if (!hw) {
> +		dev_err(dev, "cannot allocate driver data\n");
> +		return -ENOMEM;
> +	}
> +	platform_set_drvdata(pdev, hw);
> +
> +	hw->gpio = (int)dev->platform_data;
> +	hw->dev = dev;
> +
> +	mutex_init(&hw->lock);
> +
> +	hw->regulator = regulator_get(dev, "vlcd");
> +	if (IS_ERR(hw->regulator)) {
> +		error = PTR_ERR(hw->regulator);
> +		dev_err(dev, "cannot claim regulator\n");
> +		goto error_regulator;
> +	}
> +
> +	error = gpio_request_one(hw->gpio, GPIOF_DIR_OUT, dev_name(dev));
> +	if (error < 0) {
> +		dev_err(dev, "cannot claim gpio\n");
> +		goto error_gpio;
> +	}
> +
> +	memset(&props, 0, sizeof(props));
> +	props.max_brightness = TPS6116X_MAX_INTENSITY;
> +	props.brightness     = TPS6116X_DEFAULT_INTENSITY;
> +	props.power          = FB_BLANK_UNBLANK;
> +
> +	hw->bl = backlight_device_register("tps6116x", hw->dev, hw,
> +					   &tps6116x_backlight_ops, &props);
> +	if (IS_ERR(hw->bl)) {
> +		error = PTR_ERR(hw->bl);
> +		dev_err(dev, "backlight registration failed\n");
> +		goto error_register;
> +	}
> +
> +	update_status(hw->bl);
> +	dev_info(dev, "registered backlight controller\n");
> +	return 0;
> +
> +error_register:
> +	gpio_free(hw->gpio);
> +error_gpio:
> +	regulator_put(hw->regulator);
> +error_regulator:
> +	kfree(hw);
> +	platform_set_drvdata(pdev, NULL);
> +	return error;
> +}
> +
> +static int __devexit tps6116x_remove(struct platform_device *pdev)
> +{
> +	struct tps6116x *hw = platform_get_drvdata(pdev);
> +
> +	backlight_device_unregister(hw->bl);
> +	regulator_disable(hw->regulator);
> +	regulator_put(hw->regulator);
> +	gpio_free(hw->gpio);
> +	kfree(hw);
> +	platform_set_drvdata(pdev, NULL);
> +	return 0;
> +}
> +
> +static int tps6116x_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct tps6116x *hw = platform_get_drvdata(pdev);
> +	hw->suspended = true;
> +	update_status(hw->bl);
> +	return 0;
> +}
> +
> +static int tps6116x_resume(struct platform_device *pdev)
> +{
> +	struct tps6116x *hw = platform_get_drvdata(pdev);
> +	hw->suspended = false;
> +	update_status(hw->bl);
> +	return 0;
> +}
> +
> +static struct platform_driver tps6116x_driver = {
> +	.probe		= tps6116x_probe,
> +	.remove		= __devexit_p(tps6116x_remove),
> +	.suspend	= tps6116x_suspend,
> +	.resume		= tps6116x_resume,
> +	.driver		= {
> +		.name	= "tps6116x",
> +		.owner	= THIS_MODULE,
> +	},
> +};
> +
> +static int __init tps6116x_init(void)
> +{
> +	return platform_driver_register(&tps6116x_driver);
> +}
> +module_init(tps6116x_init);
> +
> +static void __exit tps6116x_exit(void)
> +{
> +	platform_driver_unregister(&tps6116x_driver);
> +}
> +module_exit(tps6116x_exit);
> +
> +MODULE_DESCRIPTION("SSP TPS6116X Driver");
> +MODULE_AUTHOR("Cyril Chemparathy");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:tps6116x");

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v8 01/11] mfd: add driver for sequencer serial port
  2011-01-18 19:21 ` [PATCH v8 01/11] mfd: add driver for sequencer serial port Cyril Chemparathy
@ 2011-01-19 17:43   ` Kevin Hilman
  2011-01-31  0:40     ` Samuel Ortiz
  0 siblings, 1 reply; 20+ messages in thread
From: Kevin Hilman @ 2011-01-19 17:43 UTC (permalink / raw)
  To: sameo, Andrew Morton
  Cc: davinci-linux-open-source, spi-devel-general, rpurdie, dbrownell,
	linux-arm-kernel, linux-kernel, Cyril Chemparathy

Samuel,

Cyril Chemparathy <cyril@ti.com> writes:

> TI's sequencer serial port (TI-SSP) is a jack-of-all-trades type of serial port
> device.  It has a built-in programmable execution engine that can be programmed
> to operate as almost any serial bus (I2C, SPI, EasyScale, and others).
>
> This patch adds a driver for this controller device.  The driver does not
> expose a user-land interface.  Protocol drivers built on top of this layer are
> expected to remain in-kernel.
>
> Signed-off-by: Cyril Chemparathy <cyril@ti.com>

Any comments on this driver?

With your ack, I'll be happy to merge this via the davinci tree with the
rest of the series.

Thanks,

Kevin

> ---
>  drivers/mfd/Kconfig        |   11 +
>  drivers/mfd/Makefile       |    1 +
>  drivers/mfd/ti-ssp.c       |  476 ++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/ti_ssp.h |   87 ++++++++
>  4 files changed, 575 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/mfd/ti-ssp.c
>  create mode 100644 include/linux/mfd/ti_ssp.h
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 3a1493b..a4b4b70 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -81,6 +81,17 @@ config MFD_DM355EVM_MSP
>  	  boards.  MSP430 firmware manages resets and power sequencing,
>  	  inputs from buttons and the IR remote, LEDs, an RTC, and more.
>  
> +config MFD_TI_SSP
> +	tristate "TI Sequencer Serial Port support"
> +	depends on ARCH_DAVINCI_TNETV107X
> +	select MFD_CORE
> +	---help---
> +	  Say Y here if you want support for the Sequencer Serial Port
> +	  in a Texas Instruments TNETV107X SoC.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called ti-ssp.
> +
>  config HTC_EGPIO
>  	bool "HTC EGPIO support"
>  	depends on GENERIC_HARDIRQS && GPIOLIB && ARM
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index f54b365..f64cf13 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_HTC_I2CPLD)	+= htc-i2cpld.o
>  
>  obj-$(CONFIG_MFD_DAVINCI_VOICECODEC)	+= davinci_voicecodec.o
>  obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
> +obj-$(CONFIG_MFD_TI_SSP)	+= ti-ssp.o
>  
>  obj-$(CONFIG_MFD_STMPE)		+= stmpe.o
>  obj-$(CONFIG_MFD_TC35892)	+= tc35892.o
> diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c
> new file mode 100644
> index 0000000..af9ab0e
> --- /dev/null
> +++ b/drivers/mfd/ti-ssp.c
> @@ -0,0 +1,476 @@
> +/*
> + * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
> + *
> + * Copyright (C) 2010 Texas Instruments Inc
> + *
> + * 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.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/wait.h>
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/device.h>
> +#include <linux/spinlock.h>
> +#include <linux/platform_device.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/ti_ssp.h>
> +
> +/* Register Offsets */
> +#define REG_REV		0x00
> +#define REG_IOSEL_1	0x04
> +#define REG_IOSEL_2	0x08
> +#define REG_PREDIV	0x0c
> +#define REG_INTR_ST	0x10
> +#define REG_INTR_EN	0x14
> +#define REG_TEST_CTRL	0x18
> +
> +/* Per port registers */
> +#define PORT_CFG_2	0x00
> +#define PORT_ADDR	0x04
> +#define PORT_DATA	0x08
> +#define PORT_CFG_1	0x0c
> +#define PORT_STATE	0x10
> +
> +#define SSP_PORT_CONFIG_MASK	(SSP_EARLY_DIN | SSP_DELAY_DOUT)
> +#define SSP_PORT_CLKRATE_MASK	0x0f
> +
> +#define SSP_SEQRAM_WR_EN	BIT(4)
> +#define SSP_SEQRAM_RD_EN	BIT(5)
> +#define SSP_START		BIT(15)
> +#define SSP_BUSY		BIT(10)
> +#define SSP_PORT_ASL		BIT(7)
> +#define SSP_PORT_CFO1		BIT(6)
> +
> +#define SSP_PORT_SEQRAM_SIZE	32
> +
> +static const int ssp_port_base[]   = {0x040, 0x080};
> +static const int ssp_port_seqram[] = {0x100, 0x180};
> +
> +struct ti_ssp {
> +	struct resource		*res;
> +	struct device		*dev;
> +	void __iomem		*regs;
> +	spinlock_t		lock;
> +	struct clk		*clk;
> +	int			irq;
> +	wait_queue_head_t	wqh;
> +
> +	/*
> +	 * Some of the iosel2 register bits always read-back as 0, we need to
> +	 * remember these values so that we don't clobber previously set
> +	 * values.
> +	 */
> +	u32			iosel2;
> +};
> +
> +static inline struct ti_ssp *dev_to_ssp(struct device *dev)
> +{
> +	return dev_get_drvdata(dev->parent);
> +}
> +
> +static inline int dev_to_port(struct device *dev)
> +{
> +	return to_platform_device(dev)->id;
> +}
> +
> +/* Register Access Helpers, rmw() functions need to run locked */
> +static inline u32 ssp_read(struct ti_ssp *ssp, int reg)
> +{
> +	return __raw_readl(ssp->regs + reg);
> +}
> +
> +static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val)
> +{
> +	__raw_writel(val, ssp->regs + reg);
> +}
> +
> +static inline void ssp_rmw(struct ti_ssp *ssp, int reg, u32 mask, u32 bits)
> +{
> +	ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~mask) | bits);
> +}
> +
> +static inline u32 ssp_port_read(struct ti_ssp *ssp, int port, int reg)
> +{
> +	return ssp_read(ssp, ssp_port_base[port] + reg);
> +}
> +
> +static inline void ssp_port_write(struct ti_ssp *ssp, int port, int reg,
> +				  u32 val)
> +{
> +	ssp_write(ssp, ssp_port_base[port] + reg, val);
> +}
> +
> +static inline void ssp_port_rmw(struct ti_ssp *ssp, int port, int reg,
> +				u32 mask, u32 bits)
> +{
> +	ssp_rmw(ssp, ssp_port_base[port] + reg, mask, bits);
> +}
> +
> +static inline void ssp_port_clr_bits(struct ti_ssp *ssp, int port, int reg,
> +				     u32 bits)
> +{
> +	ssp_port_rmw(ssp, port, reg, bits, 0);
> +}
> +
> +static inline void ssp_port_set_bits(struct ti_ssp *ssp, int port, int reg,
> +				     u32 bits)
> +{
> +	ssp_port_rmw(ssp, port, reg, 0, bits);
> +}
> +
> +/* Called to setup port clock mode, caller must hold ssp->lock */
> +static int __set_mode(struct ti_ssp *ssp, int port, int mode)
> +{
> +	mode &= SSP_PORT_CONFIG_MASK;
> +	ssp_port_rmw(ssp, port, PORT_CFG_1, SSP_PORT_CONFIG_MASK, mode);
> +
> +	return 0;
> +}
> +
> +int ti_ssp_set_mode(struct device *dev, int mode)
> +{
> +	struct ti_ssp *ssp = dev_to_ssp(dev);
> +	int port = dev_to_port(dev);
> +	int ret;
> +
> +	spin_lock(&ssp->lock);
> +	ret = __set_mode(ssp, port, mode);
> +	spin_unlock(&ssp->lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(ti_ssp_set_mode);
> +
> +/* Called to setup iosel2, caller must hold ssp->lock */
> +static void __set_iosel2(struct ti_ssp *ssp, u32 mask, u32 val)
> +{
> +	ssp->iosel2 = (ssp->iosel2 & ~mask) | val;
> +	ssp_write(ssp, REG_IOSEL_2, ssp->iosel2);
> +}
> +
> +/* Called to setup port iosel, caller must hold ssp->lock */
> +static void __set_iosel(struct ti_ssp *ssp, int port, u32 iosel)
> +{
> +	unsigned val, shift = port ? 16 : 0;
> +
> +	/* IOSEL1 gets the least significant 16 bits */
> +	val = ssp_read(ssp, REG_IOSEL_1);
> +	val &= 0xffff << (port ? 0 : 16);
> +	val |= (iosel & 0xffff) << (port ? 16 : 0);
> +	ssp_write(ssp, REG_IOSEL_1, val);
> +
> +	/* IOSEL2 gets the most significant 16 bits */
> +	val = (iosel >> 16) & 0x7;
> +	__set_iosel2(ssp, 0x7 << shift, val << shift);
> +}
> +
> +int ti_ssp_set_iosel(struct device *dev, u32 iosel)
> +{
> +	struct ti_ssp *ssp = dev_to_ssp(dev);
> +	int port = dev_to_port(dev);
> +
> +	spin_lock(&ssp->lock);
> +	__set_iosel(ssp, port, iosel);
> +	spin_unlock(&ssp->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ti_ssp_set_iosel);
> +
> +int ti_ssp_load(struct device *dev, int offs, u32* prog, int len)
> +{
> +	struct ti_ssp *ssp = dev_to_ssp(dev);
> +	int port = dev_to_port(dev);
> +	int i;
> +
> +	if (len > SSP_PORT_SEQRAM_SIZE)
> +		return -ENOSPC;
> +
> +	spin_lock(&ssp->lock);
> +
> +	/* Enable SeqRAM access */
> +	ssp_port_set_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
> +
> +	/* Copy code */
> +	for (i = 0; i < len; i++) {
> +		__raw_writel(prog[i], ssp->regs + offs + 4*i +
> +			     ssp_port_seqram[port]);
> +	}
> +
> +	/* Disable SeqRAM access */
> +	ssp_port_clr_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
> +
> +	spin_unlock(&ssp->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ti_ssp_load);
> +
> +int ti_ssp_raw_read(struct device *dev)
> +{
> +	struct ti_ssp *ssp = dev_to_ssp(dev);
> +	int port = dev_to_port(dev);
> +	int shift = port ? 27 : 11;
> +
> +	return (ssp_read(ssp, REG_IOSEL_2) >> shift) & 0xf;
> +}
> +EXPORT_SYMBOL(ti_ssp_raw_read);
> +
> +int ti_ssp_raw_write(struct device *dev, u32 val)
> +{
> +	struct ti_ssp *ssp = dev_to_ssp(dev);
> +	int port = dev_to_port(dev), shift;
> +
> +	spin_lock(&ssp->lock);
> +
> +	shift = port ? 22 : 6;
> +	val &= 0xf;
> +	__set_iosel2(ssp, 0xf << shift, val << shift);
> +
> +	spin_unlock(&ssp->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ti_ssp_raw_write);
> +
> +static inline int __xfer_done(struct ti_ssp *ssp, int port)
> +{
> +	return !(ssp_port_read(ssp, port, PORT_CFG_1) & SSP_BUSY);
> +}
> +
> +int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output)
> +{
> +	struct ti_ssp *ssp = dev_to_ssp(dev);
> +	int port = dev_to_port(dev);
> +	int ret;
> +
> +	if (pc & ~(0x3f))
> +		return -EINVAL;
> +
> +	/* Grab ssp->lock to serialize rmw on ssp registers */
> +	spin_lock(&ssp->lock);
> +
> +	ssp_port_write(ssp, port, PORT_ADDR, input >> 16);
> +	ssp_port_write(ssp, port, PORT_DATA, input & 0xffff);
> +	ssp_port_rmw(ssp, port, PORT_CFG_1, 0x3f, pc);
> +
> +	/* grab wait queue head lock to avoid race with the isr */
> +	spin_lock_irq(&ssp->wqh.lock);
> +
> +	/* kick off sequence execution in hardware */
> +	ssp_port_set_bits(ssp, port, PORT_CFG_1, SSP_START);
> +
> +	/* drop ssp lock; no register writes beyond this */
> +	spin_unlock(&ssp->lock);
> +
> +	ret = wait_event_interruptible_locked_irq(ssp->wqh,
> +						  __xfer_done(ssp, port));
> +	spin_unlock_irq(&ssp->wqh.lock);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	if (output) {
> +		*output = (ssp_port_read(ssp, port, PORT_ADDR) << 16) |
> +			  (ssp_port_read(ssp, port, PORT_DATA) &  0xffff);
> +	}
> +
> +	ret = ssp_port_read(ssp, port, PORT_STATE) & 0x3f; /* stop address */
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(ti_ssp_run);
> +
> +static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data)
> +{
> +	struct ti_ssp *ssp = dev_data;
> +
> +	spin_lock(&ssp->wqh.lock);
> +
> +	ssp_write(ssp, REG_INTR_ST, 0x3);
> +	wake_up_locked(&ssp->wqh);
> +
> +	spin_unlock(&ssp->wqh.lock);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int __devinit ti_ssp_probe(struct platform_device *pdev)
> +{
> +	static struct ti_ssp *ssp;
> +	const struct ti_ssp_data *pdata = pdev->dev.platform_data;
> +	int error = 0, prediv = 0xff, id;
> +	unsigned long sysclk;
> +	struct device *dev = &pdev->dev;
> +	struct mfd_cell cells[2];
> +
> +	ssp = kzalloc(sizeof(*ssp), GFP_KERNEL);
> +	if (!ssp) {
> +		dev_err(dev, "cannot allocate device info\n");
> +		return -ENOMEM;
> +	}
> +
> +	ssp->dev = dev;
> +	dev_set_drvdata(dev, ssp);
> +
> +	ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!ssp->res) {
> +		error = -ENODEV;
> +		dev_err(dev, "cannot determine register area\n");
> +		goto error_res;
> +	}
> +
> +	if (!request_mem_region(ssp->res->start, resource_size(ssp->res),
> +				pdev->name)) {
> +		error = -ENOMEM;
> +		dev_err(dev, "cannot claim register memory\n");
> +		goto error_res;
> +	}
> +
> +	ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res));
> +	if (!ssp->regs) {
> +		error = -ENOMEM;
> +		dev_err(dev, "cannot map register memory\n");
> +		goto error_map;
> +	}
> +
> +	ssp->clk = clk_get(dev, NULL);
> +	if (IS_ERR(ssp->clk)) {
> +		error = PTR_ERR(ssp->clk);
> +		dev_err(dev, "cannot claim device clock\n");
> +		goto error_clk;
> +	}
> +
> +	ssp->irq = platform_get_irq(pdev, 0);
> +	if (ssp->irq < 0) {
> +		error = -ENODEV;
> +		dev_err(dev, "unknown irq\n");
> +		goto error_irq;
> +	}
> +
> +	error = request_threaded_irq(ssp->irq, NULL, ti_ssp_interrupt, 0,
> +				     dev_name(dev), ssp);
> +	if (error < 0) {
> +		dev_err(dev, "cannot acquire irq\n");
> +		goto error_irq;
> +	}
> +
> +	spin_lock_init(&ssp->lock);
> +	init_waitqueue_head(&ssp->wqh);
> +
> +	/* Power on and initialize SSP */
> +	error = clk_enable(ssp->clk);
> +	if (error) {
> +		dev_err(dev, "cannot enable device clock\n");
> +		goto error_enable;
> +	}
> +
> +	/* Reset registers to a sensible known state */
> +	ssp_write(ssp, REG_IOSEL_1, 0);
> +	ssp_write(ssp, REG_IOSEL_2, 0);
> +	ssp_write(ssp, REG_INTR_EN, 0x3);
> +	ssp_write(ssp, REG_INTR_ST, 0x3);
> +	ssp_write(ssp, REG_TEST_CTRL, 0);
> +	ssp_port_write(ssp, 0, PORT_CFG_1, SSP_PORT_ASL);
> +	ssp_port_write(ssp, 1, PORT_CFG_1, SSP_PORT_ASL);
> +	ssp_port_write(ssp, 0, PORT_CFG_2, SSP_PORT_CFO1);
> +	ssp_port_write(ssp, 1, PORT_CFG_2, SSP_PORT_CFO1);
> +
> +	sysclk = clk_get_rate(ssp->clk);
> +	if (pdata && pdata->out_clock)
> +		prediv = (sysclk / pdata->out_clock) - 1;
> +	prediv = clamp(prediv, 0, 0xff);
> +	ssp_rmw(ssp, REG_PREDIV, 0xff, prediv);
> +
> +	memset(cells, 0, sizeof(cells));
> +	for (id = 0; id < 2; id++) {
> +		const struct ti_ssp_dev_data *data = &pdata->dev_data[id];
> +
> +		cells[id].id		= id;
> +		cells[id].name		= data->dev_name;
> +		cells[id].platform_data	= data->pdata;
> +		cells[id].data_size	= data->pdata_size;
> +	}
> +
> +	error = mfd_add_devices(dev, 0, cells, 2, NULL, 0);
> +	if (error < 0) {
> +		dev_err(dev, "cannot add mfd cells\n");
> +		goto error_enable;
> +	}
> +
> +	return 0;
> +
> +error_enable:
> +	free_irq(ssp->irq, ssp);
> +error_irq:
> +	clk_put(ssp->clk);
> +error_clk:
> +	iounmap(ssp->regs);
> +error_map:
> +	release_mem_region(ssp->res->start, resource_size(ssp->res));
> +error_res:
> +	kfree(ssp);
> +	return error;
> +}
> +
> +static int __devexit ti_ssp_remove(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct ti_ssp *ssp = dev_get_drvdata(dev);
> +
> +	mfd_remove_devices(dev);
> +	clk_disable(ssp->clk);
> +	free_irq(ssp->irq, ssp);
> +	clk_put(ssp->clk);
> +	iounmap(ssp->regs);
> +	release_mem_region(ssp->res->start, resource_size(ssp->res));
> +	kfree(ssp);
> +	dev_set_drvdata(dev, NULL);
> +	return 0;
> +}
> +
> +static struct platform_driver ti_ssp_driver = {
> +	.probe		= ti_ssp_probe,
> +	.remove		= __devexit_p(ti_ssp_remove),
> +	.driver		= {
> +		.name	= "ti-ssp",
> +		.owner	= THIS_MODULE,
> +	}
> +};
> +
> +static int __init ti_ssp_init(void)
> +{
> +	return platform_driver_register(&ti_ssp_driver);
> +}
> +module_init(ti_ssp_init);
> +
> +static void __exit ti_ssp_exit(void)
> +{
> +	platform_driver_unregister(&ti_ssp_driver);
> +}
> +module_exit(ti_ssp_exit);
> +
> +MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
> +MODULE_AUTHOR("Cyril Chemparathy");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:ti-ssp");
> diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h
> new file mode 100644
> index 0000000..021fe09
> --- /dev/null
> +++ b/include/linux/mfd/ti_ssp.h
> @@ -0,0 +1,87 @@
> +/*
> + * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
> + *
> + * Copyright (C) 2010 Texas Instruments Inc
> + *
> + * 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.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#ifndef __TI_SSP_H__
> +#define __TI_SSP_H__
> +
> +struct ti_ssp_dev_data {
> +	const char	*dev_name;
> +	void		*pdata;
> +	size_t		pdata_size;
> +};
> +
> +struct ti_ssp_data {
> +	unsigned long		out_clock;
> +	struct ti_ssp_dev_data	dev_data[2];
> +};
> +
> +/*
> + * Sequencer port IO pin configuration bits.  These do not correlate 1-1 with
> + * the hardware.  The iosel field in the port data combines iosel1 and iosel2,
> + * and is therefore not a direct map to register space.  It is best to use the
> + * macros below to construct iosel values.
> + *
> + * least significant 16 bits --> iosel1
> + * most significant 16 bits  --> iosel2
> + */
> +
> +#define SSP_IN			0x0000
> +#define SSP_DATA		0x0001
> +#define SSP_CLOCK		0x0002
> +#define SSP_CHIPSEL		0x0003
> +#define SSP_OUT			0x0004
> +#define SSP_PIN_SEL(pin, v)	((v) << ((pin) * 3))
> +#define SSP_PIN_MASK(pin)	SSP_PIN_SEL(pin, 0x7)
> +#define SSP_INPUT_SEL(pin)	((pin) << 16)
> +
> +/* Sequencer port config bits */
> +#define SSP_EARLY_DIN		BIT(8)
> +#define SSP_DELAY_DOUT		BIT(9)
> +
> +/* Sequence map definitions */
> +#define SSP_CLK_HIGH		BIT(0)
> +#define SSP_CLK_LOW		0
> +#define SSP_DATA_HIGH		BIT(1)
> +#define SSP_DATA_LOW		0
> +#define SSP_CS_HIGH		BIT(2)
> +#define SSP_CS_LOW		0
> +#define SSP_OUT_MODE		BIT(3)
> +#define SSP_IN_MODE		0
> +#define SSP_DATA_REG		BIT(4)
> +#define SSP_ADDR_REG		0
> +
> +#define SSP_OPCODE_DIRECT	((0x0) << 5)
> +#define SSP_OPCODE_TOGGLE	((0x1) << 5)
> +#define SSP_OPCODE_SHIFT	((0x2) << 5)
> +#define SSP_OPCODE_BRANCH0	((0x4) << 5)
> +#define SSP_OPCODE_BRANCH1	((0x5) << 5)
> +#define SSP_OPCODE_BRANCH	((0x6) << 5)
> +#define SSP_OPCODE_STOP		((0x7) << 5)
> +#define SSP_BRANCH(addr)	((addr) << 8)
> +#define SSP_COUNT(cycles)	((cycles) << 8)
> +
> +int ti_ssp_raw_read(struct device *dev);
> +int ti_ssp_raw_write(struct device *dev, u32 val);
> +int ti_ssp_load(struct device *dev, int offs, u32* prog, int len);
> +int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output);
> +int ti_ssp_set_mode(struct device *dev, int mode);
> +int ti_ssp_set_iosel(struct device *dev, u32 iosel);
> +
> +#endif /* __TI_SSP_H__ */

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v8 01/11] mfd: add driver for sequencer serial port
  2011-01-19 17:43   ` Kevin Hilman
@ 2011-01-31  0:40     ` Samuel Ortiz
  2011-03-17  7:33       ` Nori, Sekhar
  0 siblings, 1 reply; 20+ messages in thread
From: Samuel Ortiz @ 2011-01-31  0:40 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Andrew Morton, davinci-linux-open-source, spi-devel-general,
	rpurdie, dbrownell, linux-arm-kernel, linux-kernel,
	Cyril Chemparathy

Hi Kevin,

On Wed, Jan 19, 2011 at 09:43:43AM -0800, Kevin Hilman wrote:
> Samuel,
> 
> Cyril Chemparathy <cyril@ti.com> writes:
> 
> > TI's sequencer serial port (TI-SSP) is a jack-of-all-trades type of serial port
> > device.  It has a built-in programmable execution engine that can be programmed
> > to operate as almost any serial bus (I2C, SPI, EasyScale, and others).
> >
> > This patch adds a driver for this controller device.  The driver does not
> > expose a user-land interface.  Protocol drivers built on top of this layer are
> > expected to remain in-kernel.
> >
> > Signed-off-by: Cyril Chemparathy <cyril@ti.com>
> 
> Any comments on this driver?
The driver looks fine.


> With your ack, I'll be happy to merge this via the davinci tree with the
> rest of the series.
Please go ahead and add my Acked-by: Samuel Ortiz <sameo@linux.intel.com>

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply	[flat|nested] 20+ messages in thread

* RE: [PATCH v8 03/11] gpio: add ti-ssp gpio driver
       [not found]     ` <1295378505-15221-4-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
@ 2011-02-28 12:34       ` Nori, Sekhar
  2011-03-17 18:45         ` Grant Likely
  0 siblings, 1 reply; 20+ messages in thread
From: Nori, Sekhar @ 2011-02-28 12:34 UTC (permalink / raw)
  To: grant.likely-s3s/WqlpOiPyB63q8FvJNQ
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW

Hi Grant,

On Wed, Jan 19, 2011 at 00:51:37, Chemparathy, Cyril wrote:
> TI's SSP controller pins can be directly read and written to behave like a
> GPIO.  This patch adds a GPIO driver that exposes such functionality.

Can you please review and ack the GPIO part of this
series too?

I see that you have already acked the SPI part of this work.

Thanks,
Sekhar

> 
> Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
> ---
>  drivers/gpio/Kconfig       |   10 ++
>  drivers/gpio/Makefile      |    1 +
>  drivers/gpio/ti-ssp-gpio.c |  207 ++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/ti_ssp.h |    4 +
>  4 files changed, 222 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/gpio/ti-ssp-gpio.c
> 
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index 3143ac7..05bbe4c 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -128,6 +128,16 @@ config GPIO_VX855
>  	  additional drivers must be enabled in order to use the
>  	  functionality of the device.
>  
> +config GPIO_TI_SSP
> +	tristate "TI Sequencer Serial Port - GPIO Support"
> +	depends on MFD_TI_SSP
> +	help
> +	  Say yes here to support a GPIO interface on TI SSP port pins.
> +	  Each SSP port translates into 4 GPIOs.
> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called ti-ssp-gpio.
> +
>  comment "I2C GPIO expanders:"
>  
>  config GPIO_MAX7300
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index bdf3dde..0e2a844 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -26,6 +26,7 @@ obj-$(CONFIG_GPIO_PL061)	+= pl061.o
>  obj-$(CONFIG_GPIO_STMPE)	+= stmpe-gpio.o
>  obj-$(CONFIG_GPIO_TC35892)	+= tc35892-gpio.o
>  obj-$(CONFIG_GPIO_TIMBERDALE)	+= timbgpio.o
> +obj-$(CONFIG_GPIO_TI_SSP)	+= ti-ssp-gpio.o
>  obj-$(CONFIG_GPIO_TWL4030)	+= twl4030-gpio.o
>  obj-$(CONFIG_GPIO_UCB1400)	+= ucb1400_gpio.o
>  obj-$(CONFIG_GPIO_XILINX)	+= xilinx_gpio.o
> diff --git a/drivers/gpio/ti-ssp-gpio.c b/drivers/gpio/ti-ssp-gpio.c
> new file mode 100644
> index 0000000..edc3142
> --- /dev/null
> +++ b/drivers/gpio/ti-ssp-gpio.c
> @@ -0,0 +1,207 @@
> +/*
> + * Sequencer Serial Port (SSP) based virtual GPIO driver
> + *
> + * Copyright (C) 2010 Texas Instruments Inc
> + *
> + * 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.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <linux/platform_device.h>
> +#include <linux/mfd/ti_ssp.h>
> +
> +struct ti_ssp_gpio_chip {
> +	struct gpio_chip		chip;
> +	struct device			*dev;
> +	spinlock_t			lock;
> +	u8				out;
> +	u32				iosel;
> +};
> +
> +#define to_ssp_gpio_chip(c) container_of(c, struct ti_ssp_gpio_chip, chip)
> +
> +static int ti_ssp_gpio_dir_in(struct gpio_chip *chip, unsigned gpio_num)
> +{
> +	struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip);
> +	int error = 0;
> +
> +	spin_lock(&gpio->lock);
> +
> +	gpio->iosel &= ~SSP_PIN_MASK(gpio_num);
> +	gpio->iosel |=  SSP_PIN_SEL(gpio_num, SSP_IN);
> +
> +	error = ti_ssp_set_iosel(gpio->dev, gpio->iosel);
> +
> +	spin_unlock(&gpio->lock);
> +
> +	return error;
> +}
> +
> +static int ti_ssp_gpio_dir_out(struct gpio_chip *chip, unsigned gpio_num,
> +			       int val)
> +{
> +	struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip);
> +	int error;
> +
> +	spin_lock(&gpio->lock);
> +
> +	gpio->iosel &= ~SSP_PIN_MASK(gpio_num);
> +	gpio->iosel |=  SSP_PIN_SEL(gpio_num, SSP_OUT);
> +
> +	error = ti_ssp_set_iosel(gpio->dev, gpio->iosel);
> +
> +	if (error < 0)
> +		goto error;
> +
> +	if (val)
> +		gpio->out |= BIT(gpio_num);
> +	else
> +		gpio->out &= ~BIT(gpio_num);
> +
> +	error = ti_ssp_raw_write(gpio->dev, gpio->out);
> +
> +error:
> +	spin_unlock(&gpio->lock);
> +	return error;
> +}
> +
> +static int ti_ssp_gpio_get(struct gpio_chip *chip, unsigned gpio_num)
> +{
> +	struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip);
> +	int ret;
> +
> +	spin_lock(&gpio->lock);
> +
> +	ret = ti_ssp_raw_read(gpio->dev);
> +	if (ret >= 0)
> +		ret = !!(ret & BIT(gpio_num));
> +
> +	spin_unlock(&gpio->lock);
> +	return ret;
> +}
> +
> +static void ti_ssp_gpio_set(struct gpio_chip *chip, unsigned gpio_num, int val)
> +{
> +	struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip);
> +
> +	spin_lock(&gpio->lock);
> +
> +	if (val)
> +		gpio->out |= BIT(gpio_num);
> +	else
> +		gpio->out &= ~BIT(gpio_num);
> +
> +	ti_ssp_raw_write(gpio->dev, gpio->out);
> +
> +	spin_unlock(&gpio->lock);
> +}
> +
> +static int __devinit ti_ssp_gpio_probe(struct platform_device *pdev)
> +{
> +	const struct ti_ssp_gpio_data *pdata = pdev->dev.platform_data;
> +	struct device *dev = &pdev->dev;
> +	struct ti_ssp_gpio_chip *gpio;
> +	int error;
> +
> +	if (!pdata) {
> +		dev_err(dev, "platform data not found\n");
> +		return -EINVAL;
> +	}
> +
> +	gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
> +	if (!gpio) {
> +		dev_err(dev, "cannot allocate driver data\n");
> +		return -ENOMEM;
> +	}
> +
> +	gpio->dev = dev;
> +	gpio->iosel = SSP_PIN_SEL(0, SSP_IN) | SSP_PIN_SEL(1, SSP_IN) |
> +		      SSP_PIN_SEL(2, SSP_IN) | SSP_PIN_SEL(3, SSP_IN);
> +	error = ti_ssp_set_iosel(gpio->dev, gpio->iosel);
> +	if (error < 0) {
> +		dev_err(dev, "gpio io setup failed (%d)\n", error);
> +		goto error;
> +	}
> +
> +	spin_lock_init(&gpio->lock);
> +	platform_set_drvdata(pdev, gpio);
> +
> +	gpio->chip.base  = pdata->start;
> +	gpio->chip.ngpio = 4;
> +	gpio->chip.dev   = &pdev->dev;
> +	gpio->chip.label = "ti_ssp_gpio";
> +	gpio->chip.owner = THIS_MODULE;
> +	gpio->chip.get   = ti_ssp_gpio_get;
> +	gpio->chip.set   = ti_ssp_gpio_set;
> +	gpio->chip.direction_input  = ti_ssp_gpio_dir_in;
> +	gpio->chip.direction_output = ti_ssp_gpio_dir_out;
> +
> +	error = gpiochip_add(&gpio->chip);
> +	if (error < 0) {
> +		dev_err(dev, "gpio chip registration failed (%d)\n", error);
> +		goto error;
> +	}
> +
> +	dev_info(dev, "ssp gpio interface registered\n");
> +	return 0;
> +
> +error:
> +	kfree(gpio);
> +	return error;
> +}
> +
> +static int __devexit ti_ssp_gpio_remove(struct platform_device *pdev)
> +{
> +	struct ti_ssp_gpio_chip *gpio = platform_get_drvdata(pdev);
> +	int error;
> +
> +	error = gpiochip_remove(&gpio->chip);
> +	if (error < 0)
> +		return error;
> +	kfree(gpio);
> +	return 0;
> +}
> +
> +static struct platform_driver ti_ssp_gpio_driver = {
> +	.probe		= ti_ssp_gpio_probe,
> +	.remove		= __devexit_p(ti_ssp_gpio_remove),
> +	.driver		= {
> +		.name	= "ti-ssp-gpio",
> +		.owner	= THIS_MODULE,
> +	},
> +};
> +
> +static int __init ti_ssp_gpio_init(void)
> +{
> +	return platform_driver_register(&ti_ssp_gpio_driver);
> +}
> +module_init(ti_ssp_gpio_init);
> +
> +static void __exit ti_ssp_gpio_exit(void)
> +{
> +	platform_driver_unregister(&ti_ssp_gpio_driver);
> +}
> +module_exit(ti_ssp_gpio_exit);
> +
> +MODULE_DESCRIPTION("GPIO interface for TI-SSP");
> +MODULE_AUTHOR("Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:ti-ssp-gpio");
> diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h
> index dbb4b43..10c65bb 100644
> --- a/include/linux/mfd/ti_ssp.h
> +++ b/include/linux/mfd/ti_ssp.h
> @@ -38,6 +38,10 @@ struct ti_ssp_spi_data {
>  	void		(*select)(int cs);
>  };
>  
> +struct ti_ssp_gpio_data {
> +	int		start;
> +};
> +
>  /*
>   * Sequencer port IO pin configuration bits.  These do not correlate 1-1 with
>   * the hardware.  The iosel field in the port data combines iosel1 and iosel2,
> -- 
> 1.7.1
> 
> _______________________________________________
> Davinci-linux-open-source mailing list
> Davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org
> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source
> 

^ permalink raw reply	[flat|nested] 20+ messages in thread

* RE: [PATCH v8 01/11] mfd: add driver for sequencer serial port
  2011-01-31  0:40     ` Samuel Ortiz
@ 2011-03-17  7:33       ` Nori, Sekhar
  0 siblings, 0 replies; 20+ messages in thread
From: Nori, Sekhar @ 2011-03-17  7:33 UTC (permalink / raw)
  To: Chemparathy, Cyril
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f, Samuel Ortiz,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Andrew Morton, linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW

Hi Cyril,

On Mon, Jan 31, 2011 at 06:10:02, Samuel Ortiz wrote:
> Hi Kevin,
> 
> On Wed, Jan 19, 2011 at 09:43:43AM -0800, Kevin Hilman wrote:
> > Samuel,
> > 
> > Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org> writes:
> > 
> > > TI's sequencer serial port (TI-SSP) is a jack-of-all-trades type of serial port
> > > device.  It has a built-in programmable execution engine that can be programmed
> > > to operate as almost any serial bus (I2C, SPI, EasyScale, and others).
> > >
> > > This patch adds a driver for this controller device.  The driver does not
> > > expose a user-land interface.  Protocol drivers built on top of this layer are
> > > expected to remain in-kernel.
> > >
> > > Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
> > 
> > Any comments on this driver?
> The driver looks fine.
> 
> 
> > With your ack, I'll be happy to merge this via the davinci tree with the
> > rest of the series.
> Please go ahead and add my Acked-by: Samuel Ortiz <sameo-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>

Patches in this series which have been Acked by respective maintainers
have been included in the 2.6.39 pull request Kevin sent to Russell.

Once 2.6.39-rc1 is out, can you please plan to rebase and repost the
left out patches and ask the respective maintainers for their review and
ack?

Thanks,
Sekhar

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v8 03/11] gpio: add ti-ssp gpio driver
  2011-02-28 12:34       ` Nori, Sekhar
@ 2011-03-17 18:45         ` Grant Likely
       [not found]           ` <20110317184514.GP9597-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
  0 siblings, 1 reply; 20+ messages in thread
From: Grant Likely @ 2011-03-17 18:45 UTC (permalink / raw)
  To: Nori, Sekhar
  Cc: linux-arm-kernel, linux-kernel, Chemparathy, Cyril,
	davinci-linux-open-source, spi-devel-general, sameo, rpurdie,
	dbrownell

On Mon, Feb 28, 2011 at 06:04:32PM +0530, Nori, Sekhar wrote:
> Hi Grant,
> 
> On Wed, Jan 19, 2011 at 00:51:37, Chemparathy, Cyril wrote:
> > TI's SSP controller pins can be directly read and written to behave like a
> > GPIO.  This patch adds a GPIO driver that exposes such functionality.
> 
> Can you please review and ack the GPIO part of this
> series too?
> 
> I see that you have already acked the SPI part of this work.

Acked-by: Grant Likely <grant.likely@secretlab.ca>

Sorry for the delay on this.  I can take it through my tree if you
like.  It's a new driver, so I don't have any concerns about taking it
now even though the merge window is already open..

g.

> 
> Thanks,
> Sekhar
> 
> > 
> > Signed-off-by: Cyril Chemparathy <cyril@ti.com>
> > ---
> >  drivers/gpio/Kconfig       |   10 ++
> >  drivers/gpio/Makefile      |    1 +
> >  drivers/gpio/ti-ssp-gpio.c |  207 ++++++++++++++++++++++++++++++++++++++++++++
> >  include/linux/mfd/ti_ssp.h |    4 +
> >  4 files changed, 222 insertions(+), 0 deletions(-)
> >  create mode 100644 drivers/gpio/ti-ssp-gpio.c
> > 
> > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> > index 3143ac7..05bbe4c 100644
> > --- a/drivers/gpio/Kconfig
> > +++ b/drivers/gpio/Kconfig
> > @@ -128,6 +128,16 @@ config GPIO_VX855
> >  	  additional drivers must be enabled in order to use the
> >  	  functionality of the device.
> >  
> > +config GPIO_TI_SSP
> > +	tristate "TI Sequencer Serial Port - GPIO Support"
> > +	depends on MFD_TI_SSP
> > +	help
> > +	  Say yes here to support a GPIO interface on TI SSP port pins.
> > +	  Each SSP port translates into 4 GPIOs.
> > +
> > +	  This driver can also be built as a module. If so, the module
> > +	  will be called ti-ssp-gpio.
> > +
> >  comment "I2C GPIO expanders:"
> >  
> >  config GPIO_MAX7300
> > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> > index bdf3dde..0e2a844 100644
> > --- a/drivers/gpio/Makefile
> > +++ b/drivers/gpio/Makefile
> > @@ -26,6 +26,7 @@ obj-$(CONFIG_GPIO_PL061)	+= pl061.o
> >  obj-$(CONFIG_GPIO_STMPE)	+= stmpe-gpio.o
> >  obj-$(CONFIG_GPIO_TC35892)	+= tc35892-gpio.o
> >  obj-$(CONFIG_GPIO_TIMBERDALE)	+= timbgpio.o
> > +obj-$(CONFIG_GPIO_TI_SSP)	+= ti-ssp-gpio.o
> >  obj-$(CONFIG_GPIO_TWL4030)	+= twl4030-gpio.o
> >  obj-$(CONFIG_GPIO_UCB1400)	+= ucb1400_gpio.o
> >  obj-$(CONFIG_GPIO_XILINX)	+= xilinx_gpio.o
> > diff --git a/drivers/gpio/ti-ssp-gpio.c b/drivers/gpio/ti-ssp-gpio.c
> > new file mode 100644
> > index 0000000..edc3142
> > --- /dev/null
> > +++ b/drivers/gpio/ti-ssp-gpio.c
> > @@ -0,0 +1,207 @@
> > +/*
> > + * Sequencer Serial Port (SSP) based virtual GPIO driver
> > + *
> > + * Copyright (C) 2010 Texas Instruments Inc
> > + *
> > + * 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.
> > + *
> > + * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> > + */
> > +
> > +#include <linux/init.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/io.h>
> > +#include <linux/err.h>
> > +#include <linux/slab.h>
> > +#include <linux/gpio.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/mfd/ti_ssp.h>
> > +
> > +struct ti_ssp_gpio_chip {
> > +	struct gpio_chip		chip;
> > +	struct device			*dev;
> > +	spinlock_t			lock;
> > +	u8				out;
> > +	u32				iosel;
> > +};
> > +
> > +#define to_ssp_gpio_chip(c) container_of(c, struct ti_ssp_gpio_chip, chip)
> > +
> > +static int ti_ssp_gpio_dir_in(struct gpio_chip *chip, unsigned gpio_num)
> > +{
> > +	struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip);
> > +	int error = 0;
> > +
> > +	spin_lock(&gpio->lock);
> > +
> > +	gpio->iosel &= ~SSP_PIN_MASK(gpio_num);
> > +	gpio->iosel |=  SSP_PIN_SEL(gpio_num, SSP_IN);
> > +
> > +	error = ti_ssp_set_iosel(gpio->dev, gpio->iosel);
> > +
> > +	spin_unlock(&gpio->lock);
> > +
> > +	return error;
> > +}
> > +
> > +static int ti_ssp_gpio_dir_out(struct gpio_chip *chip, unsigned gpio_num,
> > +			       int val)
> > +{
> > +	struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip);
> > +	int error;
> > +
> > +	spin_lock(&gpio->lock);
> > +
> > +	gpio->iosel &= ~SSP_PIN_MASK(gpio_num);
> > +	gpio->iosel |=  SSP_PIN_SEL(gpio_num, SSP_OUT);
> > +
> > +	error = ti_ssp_set_iosel(gpio->dev, gpio->iosel);
> > +
> > +	if (error < 0)
> > +		goto error;
> > +
> > +	if (val)
> > +		gpio->out |= BIT(gpio_num);
> > +	else
> > +		gpio->out &= ~BIT(gpio_num);
> > +
> > +	error = ti_ssp_raw_write(gpio->dev, gpio->out);
> > +
> > +error:
> > +	spin_unlock(&gpio->lock);
> > +	return error;
> > +}
> > +
> > +static int ti_ssp_gpio_get(struct gpio_chip *chip, unsigned gpio_num)
> > +{
> > +	struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip);
> > +	int ret;
> > +
> > +	spin_lock(&gpio->lock);
> > +
> > +	ret = ti_ssp_raw_read(gpio->dev);
> > +	if (ret >= 0)
> > +		ret = !!(ret & BIT(gpio_num));
> > +
> > +	spin_unlock(&gpio->lock);
> > +	return ret;
> > +}
> > +
> > +static void ti_ssp_gpio_set(struct gpio_chip *chip, unsigned gpio_num, int val)
> > +{
> > +	struct ti_ssp_gpio_chip *gpio = to_ssp_gpio_chip(chip);
> > +
> > +	spin_lock(&gpio->lock);
> > +
> > +	if (val)
> > +		gpio->out |= BIT(gpio_num);
> > +	else
> > +		gpio->out &= ~BIT(gpio_num);
> > +
> > +	ti_ssp_raw_write(gpio->dev, gpio->out);
> > +
> > +	spin_unlock(&gpio->lock);
> > +}
> > +
> > +static int __devinit ti_ssp_gpio_probe(struct platform_device *pdev)
> > +{
> > +	const struct ti_ssp_gpio_data *pdata = pdev->dev.platform_data;
> > +	struct device *dev = &pdev->dev;
> > +	struct ti_ssp_gpio_chip *gpio;
> > +	int error;
> > +
> > +	if (!pdata) {
> > +		dev_err(dev, "platform data not found\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
> > +	if (!gpio) {
> > +		dev_err(dev, "cannot allocate driver data\n");
> > +		return -ENOMEM;
> > +	}
> > +
> > +	gpio->dev = dev;
> > +	gpio->iosel = SSP_PIN_SEL(0, SSP_IN) | SSP_PIN_SEL(1, SSP_IN) |
> > +		      SSP_PIN_SEL(2, SSP_IN) | SSP_PIN_SEL(3, SSP_IN);
> > +	error = ti_ssp_set_iosel(gpio->dev, gpio->iosel);
> > +	if (error < 0) {
> > +		dev_err(dev, "gpio io setup failed (%d)\n", error);
> > +		goto error;
> > +	}
> > +
> > +	spin_lock_init(&gpio->lock);
> > +	platform_set_drvdata(pdev, gpio);
> > +
> > +	gpio->chip.base  = pdata->start;
> > +	gpio->chip.ngpio = 4;
> > +	gpio->chip.dev   = &pdev->dev;
> > +	gpio->chip.label = "ti_ssp_gpio";
> > +	gpio->chip.owner = THIS_MODULE;
> > +	gpio->chip.get   = ti_ssp_gpio_get;
> > +	gpio->chip.set   = ti_ssp_gpio_set;
> > +	gpio->chip.direction_input  = ti_ssp_gpio_dir_in;
> > +	gpio->chip.direction_output = ti_ssp_gpio_dir_out;
> > +
> > +	error = gpiochip_add(&gpio->chip);
> > +	if (error < 0) {
> > +		dev_err(dev, "gpio chip registration failed (%d)\n", error);
> > +		goto error;
> > +	}
> > +
> > +	dev_info(dev, "ssp gpio interface registered\n");
> > +	return 0;
> > +
> > +error:
> > +	kfree(gpio);
> > +	return error;
> > +}
> > +
> > +static int __devexit ti_ssp_gpio_remove(struct platform_device *pdev)
> > +{
> > +	struct ti_ssp_gpio_chip *gpio = platform_get_drvdata(pdev);
> > +	int error;
> > +
> > +	error = gpiochip_remove(&gpio->chip);
> > +	if (error < 0)
> > +		return error;
> > +	kfree(gpio);
> > +	return 0;
> > +}
> > +
> > +static struct platform_driver ti_ssp_gpio_driver = {
> > +	.probe		= ti_ssp_gpio_probe,
> > +	.remove		= __devexit_p(ti_ssp_gpio_remove),
> > +	.driver		= {
> > +		.name	= "ti-ssp-gpio",
> > +		.owner	= THIS_MODULE,
> > +	},
> > +};
> > +
> > +static int __init ti_ssp_gpio_init(void)
> > +{
> > +	return platform_driver_register(&ti_ssp_gpio_driver);
> > +}
> > +module_init(ti_ssp_gpio_init);
> > +
> > +static void __exit ti_ssp_gpio_exit(void)
> > +{
> > +	platform_driver_unregister(&ti_ssp_gpio_driver);
> > +}
> > +module_exit(ti_ssp_gpio_exit);
> > +
> > +MODULE_DESCRIPTION("GPIO interface for TI-SSP");
> > +MODULE_AUTHOR("Cyril Chemparathy <cyril@ti.com>");
> > +MODULE_LICENSE("GPL");
> > +MODULE_ALIAS("platform:ti-ssp-gpio");
> > diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h
> > index dbb4b43..10c65bb 100644
> > --- a/include/linux/mfd/ti_ssp.h
> > +++ b/include/linux/mfd/ti_ssp.h
> > @@ -38,6 +38,10 @@ struct ti_ssp_spi_data {
> >  	void		(*select)(int cs);
> >  };
> >  
> > +struct ti_ssp_gpio_data {
> > +	int		start;
> > +};
> > +
> >  /*
> >   * Sequencer port IO pin configuration bits.  These do not correlate 1-1 with
> >   * the hardware.  The iosel field in the port data combines iosel1 and iosel2,
> > -- 
> > 1.7.1
> > 
> > _______________________________________________
> > Davinci-linux-open-source mailing list
> > Davinci-linux-open-source@linux.davincidsp.com
> > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source
> > 
> 

^ permalink raw reply	[flat|nested] 20+ messages in thread

* RE: [PATCH v8 03/11] gpio: add ti-ssp gpio driver
       [not found]           ` <20110317184514.GP9597-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
@ 2011-03-18  6:30             ` Nori, Sekhar
  0 siblings, 0 replies; 20+ messages in thread
From: Nori, Sekhar @ 2011-03-18  6:30 UTC (permalink / raw)
  To: Grant Likely
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

Hi Grant,

On Fri, Mar 18, 2011 at 00:15:14, Grant Likely wrote:
> On Mon, Feb 28, 2011 at 06:04:32PM +0530, Nori, Sekhar wrote:
> > Hi Grant,
> > 
> > On Wed, Jan 19, 2011 at 00:51:37, Chemparathy, Cyril wrote:
> > > TI's SSP controller pins can be directly read and written to behave like a
> > > GPIO.  This patch adds a GPIO driver that exposes such functionality.
> > 
> > Can you please review and ack the GPIO part of this
> > series too?
> > 
> > I see that you have already acked the SPI part of this work.
> 
> Acked-by: Grant Likely <grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org>
> 
> Sorry for the delay on this.  I can take it through my tree if you
> like.  It's a new driver, so I don't have any concerns about taking it
> now even though the merge window is already open..

Please queue this for the 2.6.40 cycle. I just noticed that with
the 2.6.39 merge, the mfd portion of this needs a linux/sched.h
include to build successfully. That would be fixed in the 2.6.39-rc cycle.

Thanks,
Sekhar

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v8 01/11] mfd: add driver for sequencer serial port
       [not found] ` <1295291725-32509-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
@ 2011-01-17 19:15   ` Cyril Chemparathy
  0 siblings, 0 replies; 20+ messages in thread
From: Cyril Chemparathy @ 2011-01-17 19:15 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f

TI's sequencer serial port (TI-SSP) is a jack-of-all-trades type of serial port
device.  It has a built-in programmable execution engine that can be programmed
to operate as almost any serial bus (I2C, SPI, EasyScale, and others).

This patch adds a driver for this controller device.  The driver does not
expose a user-land interface.  Protocol drivers built on top of this layer are
expected to remain in-kernel.

Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
---
 drivers/mfd/Kconfig        |   11 +
 drivers/mfd/Makefile       |    1 +
 drivers/mfd/ti-ssp.c       |  476 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/ti_ssp.h |   87 ++++++++
 4 files changed, 575 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mfd/ti-ssp.c
 create mode 100644 include/linux/mfd/ti_ssp.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3a1493b..a4b4b70 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -81,6 +81,17 @@ config MFD_DM355EVM_MSP
 	  boards.  MSP430 firmware manages resets and power sequencing,
 	  inputs from buttons and the IR remote, LEDs, an RTC, and more.
 
+config MFD_TI_SSP
+	tristate "TI Sequencer Serial Port support"
+	depends on ARCH_DAVINCI_TNETV107X
+	select MFD_CORE
+	---help---
+	  Say Y here if you want support for the Sequencer Serial Port
+	  in a Texas Instruments TNETV107X SoC.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ti-ssp.
+
 config HTC_EGPIO
 	bool "HTC EGPIO support"
 	depends on GENERIC_HARDIRQS && GPIOLIB && ARM
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f54b365..f64cf13 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_HTC_I2CPLD)	+= htc-i2cpld.o
 
 obj-$(CONFIG_MFD_DAVINCI_VOICECODEC)	+= davinci_voicecodec.o
 obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
+obj-$(CONFIG_MFD_TI_SSP)	+= ti-ssp.o
 
 obj-$(CONFIG_MFD_STMPE)		+= stmpe.o
 obj-$(CONFIG_MFD_TC35892)	+= tc35892.o
diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c
new file mode 100644
index 0000000..af9ab0e
--- /dev/null
+++ b/drivers/mfd/ti-ssp.c
@@ -0,0 +1,476 @@
+/*
+ * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
+ *
+ * Copyright (C) 2010 Texas Instruments Inc
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ti_ssp.h>
+
+/* Register Offsets */
+#define REG_REV		0x00
+#define REG_IOSEL_1	0x04
+#define REG_IOSEL_2	0x08
+#define REG_PREDIV	0x0c
+#define REG_INTR_ST	0x10
+#define REG_INTR_EN	0x14
+#define REG_TEST_CTRL	0x18
+
+/* Per port registers */
+#define PORT_CFG_2	0x00
+#define PORT_ADDR	0x04
+#define PORT_DATA	0x08
+#define PORT_CFG_1	0x0c
+#define PORT_STATE	0x10
+
+#define SSP_PORT_CONFIG_MASK	(SSP_EARLY_DIN | SSP_DELAY_DOUT)
+#define SSP_PORT_CLKRATE_MASK	0x0f
+
+#define SSP_SEQRAM_WR_EN	BIT(4)
+#define SSP_SEQRAM_RD_EN	BIT(5)
+#define SSP_START		BIT(15)
+#define SSP_BUSY		BIT(10)
+#define SSP_PORT_ASL		BIT(7)
+#define SSP_PORT_CFO1		BIT(6)
+
+#define SSP_PORT_SEQRAM_SIZE	32
+
+static const int ssp_port_base[]   = {0x040, 0x080};
+static const int ssp_port_seqram[] = {0x100, 0x180};
+
+struct ti_ssp {
+	struct resource		*res;
+	struct device		*dev;
+	void __iomem		*regs;
+	spinlock_t		lock;
+	struct clk		*clk;
+	int			irq;
+	wait_queue_head_t	wqh;
+
+	/*
+	 * Some of the iosel2 register bits always read-back as 0, we need to
+	 * remember these values so that we don't clobber previously set
+	 * values.
+	 */
+	u32			iosel2;
+};
+
+static inline struct ti_ssp *dev_to_ssp(struct device *dev)
+{
+	return dev_get_drvdata(dev->parent);
+}
+
+static inline int dev_to_port(struct device *dev)
+{
+	return to_platform_device(dev)->id;
+}
+
+/* Register Access Helpers, rmw() functions need to run locked */
+static inline u32 ssp_read(struct ti_ssp *ssp, int reg)
+{
+	return __raw_readl(ssp->regs + reg);
+}
+
+static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val)
+{
+	__raw_writel(val, ssp->regs + reg);
+}
+
+static inline void ssp_rmw(struct ti_ssp *ssp, int reg, u32 mask, u32 bits)
+{
+	ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~mask) | bits);
+}
+
+static inline u32 ssp_port_read(struct ti_ssp *ssp, int port, int reg)
+{
+	return ssp_read(ssp, ssp_port_base[port] + reg);
+}
+
+static inline void ssp_port_write(struct ti_ssp *ssp, int port, int reg,
+				  u32 val)
+{
+	ssp_write(ssp, ssp_port_base[port] + reg, val);
+}
+
+static inline void ssp_port_rmw(struct ti_ssp *ssp, int port, int reg,
+				u32 mask, u32 bits)
+{
+	ssp_rmw(ssp, ssp_port_base[port] + reg, mask, bits);
+}
+
+static inline void ssp_port_clr_bits(struct ti_ssp *ssp, int port, int reg,
+				     u32 bits)
+{
+	ssp_port_rmw(ssp, port, reg, bits, 0);
+}
+
+static inline void ssp_port_set_bits(struct ti_ssp *ssp, int port, int reg,
+				     u32 bits)
+{
+	ssp_port_rmw(ssp, port, reg, 0, bits);
+}
+
+/* Called to setup port clock mode, caller must hold ssp->lock */
+static int __set_mode(struct ti_ssp *ssp, int port, int mode)
+{
+	mode &= SSP_PORT_CONFIG_MASK;
+	ssp_port_rmw(ssp, port, PORT_CFG_1, SSP_PORT_CONFIG_MASK, mode);
+
+	return 0;
+}
+
+int ti_ssp_set_mode(struct device *dev, int mode)
+{
+	struct ti_ssp *ssp = dev_to_ssp(dev);
+	int port = dev_to_port(dev);
+	int ret;
+
+	spin_lock(&ssp->lock);
+	ret = __set_mode(ssp, port, mode);
+	spin_unlock(&ssp->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(ti_ssp_set_mode);
+
+/* Called to setup iosel2, caller must hold ssp->lock */
+static void __set_iosel2(struct ti_ssp *ssp, u32 mask, u32 val)
+{
+	ssp->iosel2 = (ssp->iosel2 & ~mask) | val;
+	ssp_write(ssp, REG_IOSEL_2, ssp->iosel2);
+}
+
+/* Called to setup port iosel, caller must hold ssp->lock */
+static void __set_iosel(struct ti_ssp *ssp, int port, u32 iosel)
+{
+	unsigned val, shift = port ? 16 : 0;
+
+	/* IOSEL1 gets the least significant 16 bits */
+	val = ssp_read(ssp, REG_IOSEL_1);
+	val &= 0xffff << (port ? 0 : 16);
+	val |= (iosel & 0xffff) << (port ? 16 : 0);
+	ssp_write(ssp, REG_IOSEL_1, val);
+
+	/* IOSEL2 gets the most significant 16 bits */
+	val = (iosel >> 16) & 0x7;
+	__set_iosel2(ssp, 0x7 << shift, val << shift);
+}
+
+int ti_ssp_set_iosel(struct device *dev, u32 iosel)
+{
+	struct ti_ssp *ssp = dev_to_ssp(dev);
+	int port = dev_to_port(dev);
+
+	spin_lock(&ssp->lock);
+	__set_iosel(ssp, port, iosel);
+	spin_unlock(&ssp->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ti_ssp_set_iosel);
+
+int ti_ssp_load(struct device *dev, int offs, u32* prog, int len)
+{
+	struct ti_ssp *ssp = dev_to_ssp(dev);
+	int port = dev_to_port(dev);
+	int i;
+
+	if (len > SSP_PORT_SEQRAM_SIZE)
+		return -ENOSPC;
+
+	spin_lock(&ssp->lock);
+
+	/* Enable SeqRAM access */
+	ssp_port_set_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
+
+	/* Copy code */
+	for (i = 0; i < len; i++) {
+		__raw_writel(prog[i], ssp->regs + offs + 4*i +
+			     ssp_port_seqram[port]);
+	}
+
+	/* Disable SeqRAM access */
+	ssp_port_clr_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
+
+	spin_unlock(&ssp->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ti_ssp_load);
+
+int ti_ssp_raw_read(struct device *dev)
+{
+	struct ti_ssp *ssp = dev_to_ssp(dev);
+	int port = dev_to_port(dev);
+	int shift = port ? 27 : 11;
+
+	return (ssp_read(ssp, REG_IOSEL_2) >> shift) & 0xf;
+}
+EXPORT_SYMBOL(ti_ssp_raw_read);
+
+int ti_ssp_raw_write(struct device *dev, u32 val)
+{
+	struct ti_ssp *ssp = dev_to_ssp(dev);
+	int port = dev_to_port(dev), shift;
+
+	spin_lock(&ssp->lock);
+
+	shift = port ? 22 : 6;
+	val &= 0xf;
+	__set_iosel2(ssp, 0xf << shift, val << shift);
+
+	spin_unlock(&ssp->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ti_ssp_raw_write);
+
+static inline int __xfer_done(struct ti_ssp *ssp, int port)
+{
+	return !(ssp_port_read(ssp, port, PORT_CFG_1) & SSP_BUSY);
+}
+
+int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output)
+{
+	struct ti_ssp *ssp = dev_to_ssp(dev);
+	int port = dev_to_port(dev);
+	int ret;
+
+	if (pc & ~(0x3f))
+		return -EINVAL;
+
+	/* Grab ssp->lock to serialize rmw on ssp registers */
+	spin_lock(&ssp->lock);
+
+	ssp_port_write(ssp, port, PORT_ADDR, input >> 16);
+	ssp_port_write(ssp, port, PORT_DATA, input & 0xffff);
+	ssp_port_rmw(ssp, port, PORT_CFG_1, 0x3f, pc);
+
+	/* grab wait queue head lock to avoid race with the isr */
+	spin_lock_irq(&ssp->wqh.lock);
+
+	/* kick off sequence execution in hardware */
+	ssp_port_set_bits(ssp, port, PORT_CFG_1, SSP_START);
+
+	/* drop ssp lock; no register writes beyond this */
+	spin_unlock(&ssp->lock);
+
+	ret = wait_event_interruptible_locked_irq(ssp->wqh,
+						  __xfer_done(ssp, port));
+	spin_unlock_irq(&ssp->wqh.lock);
+
+	if (ret < 0)
+		return ret;
+
+	if (output) {
+		*output = (ssp_port_read(ssp, port, PORT_ADDR) << 16) |
+			  (ssp_port_read(ssp, port, PORT_DATA) &  0xffff);
+	}
+
+	ret = ssp_port_read(ssp, port, PORT_STATE) & 0x3f; /* stop address */
+
+	return ret;
+}
+EXPORT_SYMBOL(ti_ssp_run);
+
+static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data)
+{
+	struct ti_ssp *ssp = dev_data;
+
+	spin_lock(&ssp->wqh.lock);
+
+	ssp_write(ssp, REG_INTR_ST, 0x3);
+	wake_up_locked(&ssp->wqh);
+
+	spin_unlock(&ssp->wqh.lock);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit ti_ssp_probe(struct platform_device *pdev)
+{
+	static struct ti_ssp *ssp;
+	const struct ti_ssp_data *pdata = pdev->dev.platform_data;
+	int error = 0, prediv = 0xff, id;
+	unsigned long sysclk;
+	struct device *dev = &pdev->dev;
+	struct mfd_cell cells[2];
+
+	ssp = kzalloc(sizeof(*ssp), GFP_KERNEL);
+	if (!ssp) {
+		dev_err(dev, "cannot allocate device info\n");
+		return -ENOMEM;
+	}
+
+	ssp->dev = dev;
+	dev_set_drvdata(dev, ssp);
+
+	ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!ssp->res) {
+		error = -ENODEV;
+		dev_err(dev, "cannot determine register area\n");
+		goto error_res;
+	}
+
+	if (!request_mem_region(ssp->res->start, resource_size(ssp->res),
+				pdev->name)) {
+		error = -ENOMEM;
+		dev_err(dev, "cannot claim register memory\n");
+		goto error_res;
+	}
+
+	ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res));
+	if (!ssp->regs) {
+		error = -ENOMEM;
+		dev_err(dev, "cannot map register memory\n");
+		goto error_map;
+	}
+
+	ssp->clk = clk_get(dev, NULL);
+	if (IS_ERR(ssp->clk)) {
+		error = PTR_ERR(ssp->clk);
+		dev_err(dev, "cannot claim device clock\n");
+		goto error_clk;
+	}
+
+	ssp->irq = platform_get_irq(pdev, 0);
+	if (ssp->irq < 0) {
+		error = -ENODEV;
+		dev_err(dev, "unknown irq\n");
+		goto error_irq;
+	}
+
+	error = request_threaded_irq(ssp->irq, NULL, ti_ssp_interrupt, 0,
+				     dev_name(dev), ssp);
+	if (error < 0) {
+		dev_err(dev, "cannot acquire irq\n");
+		goto error_irq;
+	}
+
+	spin_lock_init(&ssp->lock);
+	init_waitqueue_head(&ssp->wqh);
+
+	/* Power on and initialize SSP */
+	error = clk_enable(ssp->clk);
+	if (error) {
+		dev_err(dev, "cannot enable device clock\n");
+		goto error_enable;
+	}
+
+	/* Reset registers to a sensible known state */
+	ssp_write(ssp, REG_IOSEL_1, 0);
+	ssp_write(ssp, REG_IOSEL_2, 0);
+	ssp_write(ssp, REG_INTR_EN, 0x3);
+	ssp_write(ssp, REG_INTR_ST, 0x3);
+	ssp_write(ssp, REG_TEST_CTRL, 0);
+	ssp_port_write(ssp, 0, PORT_CFG_1, SSP_PORT_ASL);
+	ssp_port_write(ssp, 1, PORT_CFG_1, SSP_PORT_ASL);
+	ssp_port_write(ssp, 0, PORT_CFG_2, SSP_PORT_CFO1);
+	ssp_port_write(ssp, 1, PORT_CFG_2, SSP_PORT_CFO1);
+
+	sysclk = clk_get_rate(ssp->clk);
+	if (pdata && pdata->out_clock)
+		prediv = (sysclk / pdata->out_clock) - 1;
+	prediv = clamp(prediv, 0, 0xff);
+	ssp_rmw(ssp, REG_PREDIV, 0xff, prediv);
+
+	memset(cells, 0, sizeof(cells));
+	for (id = 0; id < 2; id++) {
+		const struct ti_ssp_dev_data *data = &pdata->dev_data[id];
+
+		cells[id].id		= id;
+		cells[id].name		= data->dev_name;
+		cells[id].platform_data	= data->pdata;
+		cells[id].data_size	= data->pdata_size;
+	}
+
+	error = mfd_add_devices(dev, 0, cells, 2, NULL, 0);
+	if (error < 0) {
+		dev_err(dev, "cannot add mfd cells\n");
+		goto error_enable;
+	}
+
+	return 0;
+
+error_enable:
+	free_irq(ssp->irq, ssp);
+error_irq:
+	clk_put(ssp->clk);
+error_clk:
+	iounmap(ssp->regs);
+error_map:
+	release_mem_region(ssp->res->start, resource_size(ssp->res));
+error_res:
+	kfree(ssp);
+	return error;
+}
+
+static int __devexit ti_ssp_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ti_ssp *ssp = dev_get_drvdata(dev);
+
+	mfd_remove_devices(dev);
+	clk_disable(ssp->clk);
+	free_irq(ssp->irq, ssp);
+	clk_put(ssp->clk);
+	iounmap(ssp->regs);
+	release_mem_region(ssp->res->start, resource_size(ssp->res));
+	kfree(ssp);
+	dev_set_drvdata(dev, NULL);
+	return 0;
+}
+
+static struct platform_driver ti_ssp_driver = {
+	.probe		= ti_ssp_probe,
+	.remove		= __devexit_p(ti_ssp_remove),
+	.driver		= {
+		.name	= "ti-ssp",
+		.owner	= THIS_MODULE,
+	}
+};
+
+static int __init ti_ssp_init(void)
+{
+	return platform_driver_register(&ti_ssp_driver);
+}
+module_init(ti_ssp_init);
+
+static void __exit ti_ssp_exit(void)
+{
+	platform_driver_unregister(&ti_ssp_driver);
+}
+module_exit(ti_ssp_exit);
+
+MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ti-ssp");
diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h
new file mode 100644
index 0000000..021fe09
--- /dev/null
+++ b/include/linux/mfd/ti_ssp.h
@@ -0,0 +1,87 @@
+/*
+ * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
+ *
+ * Copyright (C) 2010 Texas Instruments Inc
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __TI_SSP_H__
+#define __TI_SSP_H__
+
+struct ti_ssp_dev_data {
+	const char	*dev_name;
+	void		*pdata;
+	size_t		pdata_size;
+};
+
+struct ti_ssp_data {
+	unsigned long		out_clock;
+	struct ti_ssp_dev_data	dev_data[2];
+};
+
+/*
+ * Sequencer port IO pin configuration bits.  These do not correlate 1-1 with
+ * the hardware.  The iosel field in the port data combines iosel1 and iosel2,
+ * and is therefore not a direct map to register space.  It is best to use the
+ * macros below to construct iosel values.
+ *
+ * least significant 16 bits --> iosel1
+ * most significant 16 bits  --> iosel2
+ */
+
+#define SSP_IN			0x0000
+#define SSP_DATA		0x0001
+#define SSP_CLOCK		0x0002
+#define SSP_CHIPSEL		0x0003
+#define SSP_OUT			0x0004
+#define SSP_PIN_SEL(pin, v)	((v) << ((pin) * 3))
+#define SSP_PIN_MASK(pin)	SSP_PIN_SEL(pin, 0x7)
+#define SSP_INPUT_SEL(pin)	((pin) << 16)
+
+/* Sequencer port config bits */
+#define SSP_EARLY_DIN		BIT(8)
+#define SSP_DELAY_DOUT		BIT(9)
+
+/* Sequence map definitions */
+#define SSP_CLK_HIGH		BIT(0)
+#define SSP_CLK_LOW		0
+#define SSP_DATA_HIGH		BIT(1)
+#define SSP_DATA_LOW		0
+#define SSP_CS_HIGH		BIT(2)
+#define SSP_CS_LOW		0
+#define SSP_OUT_MODE		BIT(3)
+#define SSP_IN_MODE		0
+#define SSP_DATA_REG		BIT(4)
+#define SSP_ADDR_REG		0
+
+#define SSP_OPCODE_DIRECT	((0x0) << 5)
+#define SSP_OPCODE_TOGGLE	((0x1) << 5)
+#define SSP_OPCODE_SHIFT	((0x2) << 5)
+#define SSP_OPCODE_BRANCH0	((0x4) << 5)
+#define SSP_OPCODE_BRANCH1	((0x5) << 5)
+#define SSP_OPCODE_BRANCH	((0x6) << 5)
+#define SSP_OPCODE_STOP		((0x7) << 5)
+#define SSP_BRANCH(addr)	((addr) << 8)
+#define SSP_COUNT(cycles)	((cycles) << 8)
+
+int ti_ssp_raw_read(struct device *dev);
+int ti_ssp_raw_write(struct device *dev, u32 val);
+int ti_ssp_load(struct device *dev, int offs, u32* prog, int len);
+int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output);
+int ti_ssp_set_mode(struct device *dev, int mode);
+int ti_ssp_set_iosel(struct device *dev, u32 iosel);
+
+#endif /* __TI_SSP_H__ */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2011-03-18  6:30 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-18 19:21 [PATCH v8 00/11] tnetv107x ssp drivers Cyril Chemparathy
2011-01-18 19:21 ` [PATCH v8 01/11] mfd: add driver for sequencer serial port Cyril Chemparathy
2011-01-19 17:43   ` Kevin Hilman
2011-01-31  0:40     ` Samuel Ortiz
2011-03-17  7:33       ` Nori, Sekhar
2011-01-18 19:21 ` [PATCH v8 02/11] spi: add ti-ssp spi master driver Cyril Chemparathy
2011-01-18 19:21 ` [PATCH v8 05/11] davinci: add tnetv107x ssp platform device Cyril Chemparathy
     [not found] ` <1295378505-15221-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
2011-01-18 19:21   ` [PATCH v8 03/11] gpio: add ti-ssp gpio driver Cyril Chemparathy
     [not found]     ` <1295378505-15221-4-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
2011-02-28 12:34       ` Nori, Sekhar
2011-03-17 18:45         ` Grant Likely
     [not found]           ` <20110317184514.GP9597-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
2011-03-18  6:30             ` Nori, Sekhar
2011-01-18 19:21   ` [PATCH v8 04/11] backlight: add support for tps6116x controller Cyril Chemparathy
2011-01-19 17:42     ` Kevin Hilman
2011-01-18 19:21   ` [PATCH v8 06/11] davinci: add ssp config for tnetv107x evm board Cyril Chemparathy
2011-01-18 19:21   ` [PATCH v8 08/11] davinci: add tnetv107x evm regulators Cyril Chemparathy
2011-01-18 19:21   ` [PATCH v8 10/11] davinci: add tnetv107x evm backlight device Cyril Chemparathy
2011-01-18 19:21   ` [PATCH v8 11/11] davinci: add tnetv107x evm i2c eeprom device Cyril Chemparathy
2011-01-18 19:21 ` [PATCH v8 07/11] davinci: add spi devices on tnetv107x evm Cyril Chemparathy
2011-01-18 19:21 ` [PATCH v8 09/11] davinci: add tnetv107x evm ti-ssp gpio device Cyril Chemparathy
  -- strict thread matches above, loose matches on Subject: below --
2011-01-17 19:15 [PATCH v8 00/11] tnetv107x ssp drivers Cyril Chemparathy
     [not found] ` <1295291725-32509-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
2011-01-17 19:15   ` [PATCH v8 01/11] mfd: add driver for sequencer serial port Cyril Chemparathy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).