linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/12] tnetv107x ssp driver stack
@ 2010-10-14 18:38 Cyril Chemparathy
       [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  0 siblings, 1 reply; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-14 18:38 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lrg-kDsPt+C1G03kYMGBc/C6ZA, dbrownell

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                           |
   +----------------------------------------------------------+


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

 arch/arm/mach-davinci/board-tnetv107x-evm.c    |  211 ++++++
 arch/arm/mach-davinci/devices-tnetv107x.c      |   25 +
 arch/arm/mach-davinci/include/mach/ti_ssp.h    |  103 +++
 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                     |  234 +++++++
 drivers/misc/Kconfig                           |   11 +
 drivers/misc/Makefile                          |    1 +
 drivers/misc/ti_ssp.c                          |  443 +++++++++++++
 drivers/regulator/Kconfig                      |   10 +
 drivers/regulator/Makefile                     |    1 +
 drivers/regulator/tps6524x-regulator.c         |  812 ++++++++++++++++++++++++
 drivers/spi/Kconfig                            |    6 +
 drivers/spi/Makefile                           |    1 +
 drivers/spi/spi_ti_ssp.c                       |  408 ++++++++++++
 drivers/video/backlight/Kconfig                |    7 +
 drivers/video/backlight/Makefile               |    2 +-
 drivers/video/backlight/tps6116x.c             |  339 ++++++++++
 20 files changed, 2627 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/mach-davinci/include/mach/ti_ssp.h
 create mode 100644 drivers/gpio/ti-ssp-gpio.c
 create mode 100644 drivers/misc/ti_ssp.c
 create mode 100644 drivers/regulator/tps6524x-regulator.c
 create mode 100644 drivers/spi/spi_ti_ssp.c
 create mode 100644 drivers/video/backlight/tps6116x.c

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

* [PATCH 01/12] misc: add driver for sequencer serial port
       [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
@ 2010-10-14 18:38   ` Cyril Chemparathy
       [not found]     ` <1287081535-2864-2-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2010-10-14 18:38   ` [PATCH 02/12] davinci: add tnetv107x ssp platform device Cyril Chemparathy
                     ` (10 subsequent siblings)
  11 siblings, 1 reply; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-14 18:38 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lrg-kDsPt+C1G03kYMGBc/C6ZA, dbrownell

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>
---
 arch/arm/mach-davinci/include/mach/ti_ssp.h |   92 ++++++
 drivers/misc/Kconfig                        |   11 +
 drivers/misc/Makefile                       |    1 +
 drivers/misc/ti_ssp.c                       |  443 +++++++++++++++++++++++++++
 4 files changed, 547 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-davinci/include/mach/ti_ssp.h
 create mode 100644 drivers/misc/ti_ssp.c

diff --git a/arch/arm/mach-davinci/include/mach/ti_ssp.h b/arch/arm/mach-davinci/include/mach/ti_ssp.h
new file mode 100644
index 0000000..8365101
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/ti_ssp.h
@@ -0,0 +1,92 @@
+/*
+ * 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_data {
+	unsigned long		out_clock;
+};
+
+struct ti_ssp_port_data {
+	const char	*ssp_dev_name;
+	int		port;
+	unsigned long	iosel; /* see note below */
+	unsigned long	config;
+};
+
+struct ti_ssp_port;
+
+/*
+ * 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)
+
+struct ti_ssp_port *ti_ssp_open(const struct ti_ssp_port_data *data);
+int ti_ssp_close(struct ti_ssp_port *dev);
+int ti_ssp_dumpregs(struct ti_ssp_port *dev);
+int ti_ssp_raw_read(struct ti_ssp_port *dev);
+int ti_ssp_raw_write(struct ti_ssp_port *dev, u32 val);
+int ti_ssp_load(struct ti_ssp_port *dev, int offs, u32* prog, int len);
+int ti_ssp_run(struct ti_ssp_port *dev, u32 pc, u32 input, u32 *output);
+int ti_ssp_set_mode(struct ti_ssp_port *dev, int mode);
+int ti_ssp_set_iosel(struct ti_ssp_port *dev, u32 iosel);
+
+#endif /* __TI_SSP_H__ */
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b743312..9fb8470 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -390,6 +390,17 @@ config BMP085
 	  To compile this driver as a module, choose M here: the
 	  module will be called bmp085.
 
+config TI_SSP
+	depends on ARCH_DAVINCI_TNETV107X
+	tristate "Sequencer Serial Port support"
+	default y
+	---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.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 42eab95..7568100 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_SENSORS_TSL2550)	+= tsl2550.o
 obj-$(CONFIG_EP93XX_PWM)	+= ep93xx_pwm.o
 obj-$(CONFIG_DS1682)		+= ds1682.o
 obj-$(CONFIG_TI_DAC7512)	+= ti_dac7512.o
+obj-$(CONFIG_TI_SSP)		+= ti_ssp.o
 obj-$(CONFIG_C2PORT)		+= c2port/
 obj-$(CONFIG_IWMC3200TOP)      += iwmc3200top/
 obj-$(CONFIG_HMC6352)		+= hmc6352.o
diff --git a/drivers/misc/ti_ssp.c b/drivers/misc/ti_ssp.c
new file mode 100644
index 0000000..edbc94d
--- /dev/null
+++ b/drivers/misc/ti_ssp.c
@@ -0,0 +1,443 @@
+/*
+ * 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 <mach/ti_ssp.h>
+
+/* Register Offsets */
+#define SSP_REG_REV		0x00
+#define SSP_REG_IOSEL_1		0x04
+#define SSP_REG_IOSEL_2		0x08
+#define SSP_REG_PREDIV		0x0c
+#define SSP_REG_INTR_STAT	0x10
+#define SSP_REG_INTR_EN		0x14
+#define SSP_REG_TEST_CTRL	0x18
+
+/* Per port registers */
+#define SSP_PORT_REG_CFG_2	0x00
+#define SSP_PORT_REG_ADDR	0x04
+#define SSP_PORT_REG_DATA	0x08
+#define SSP_PORT_REG_CFG_1	0x0c
+#define SSP_PORT_REG_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};
+
+/* Register Access Macros */
+#define ssp_read(ssp, reg)	 __raw_readl((ssp)->regs + SSP_REG_##reg)
+#define ssp_write(ssp, reg, val) __raw_writel(val, (ssp)->regs + SSP_REG_##reg)
+
+#define ssp_rmw(ssp, reg, mask, bits)				\
+	ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~(mask)) | (bits))
+
+#define ssp_port_read(ssp, port, reg)				\
+	__raw_readl((ssp)->regs + ssp_port_base[port] +		\
+		    SSP_PORT_REG_##reg)
+
+#define ssp_port_write(ssp, port, reg, val)			\
+	__raw_writel(val, (ssp)->regs + ssp_port_base[port] +	\
+		     SSP_PORT_REG_##reg)
+
+#define ssp_port_rmw(ssp, port, reg, mask, bits)		\
+	ssp_port_write(ssp, port, reg,				\
+		       (ssp_port_read(ssp, port, reg) & ~(mask)) | (bits))
+
+#define ssp_port_clr_bits(ssp, port, reg, bits)	\
+	ssp_port_rmw(ssp, port, reg, bits, 0)
+
+#define ssp_port_set_bits(ssp, port, reg, bits)	\
+	ssp_port_rmw(ssp, port, reg, 0, bits)
+
+struct ti_ssp {
+	struct resource			*res;
+	void __iomem			*regs;
+	struct timer_list		timer;
+	struct ti_ssp_port		*ports[2];
+	spinlock_t			lock;
+	struct clk			*clk;
+	struct device			*dev;
+};
+
+struct ti_ssp_port {
+	int		num;
+	struct ti_ssp	*ssp;
+	spinlock_t	lock;
+};
+
+struct ti_ssp_port *ti_ssp_open(const struct ti_ssp_port_data *data)
+{
+	struct ti_ssp		*ssp;
+	struct ti_ssp_port	*port;
+	struct device		*dev;
+	int			error = 0;
+
+	dev = bus_find_device_by_name(&platform_bus_type, NULL,
+				      data->ssp_dev_name);
+	if (!dev || !dev->driver)
+		return ERR_PTR(-ENODEV);
+
+	if (!get_device(dev))
+		return ERR_PTR(-ENODEV);
+
+	ssp = platform_get_drvdata(to_platform_device(dev));
+	if (!ssp) {
+		error = -ENODEV;
+		goto error_put;
+	}
+
+	port = kzalloc(sizeof(*port), GFP_KERNEL);
+	if (!port) {
+		error = -ENOMEM;
+		goto error_put;
+	}
+
+	port->num = data->port;
+	port->ssp = ssp;
+	spin_lock_init(&port->lock);
+
+	spin_lock(&ssp->lock);
+
+	if (ssp->ports[port->num]) {
+		error = -EBUSY;
+		goto error_unlock;
+	}
+
+	ssp->ports[port->num] = port;
+
+	spin_unlock(&ssp->lock);
+
+	ti_ssp_set_iosel(port, data->iosel);
+
+	spin_lock(&port->lock);
+	ssp_port_rmw(ssp, port->num, CFG_1, SSP_PORT_CONFIG_MASK,
+		     data->config);
+	ssp_port_rmw(ssp, port->num, CFG_2, SSP_PORT_CLKRATE_MASK, 0);
+	spin_unlock(&port->lock);
+
+	return port;
+
+error_unlock:
+	spin_unlock(&ssp->lock);
+error_put:
+	put_device(dev);
+	return ERR_PTR(error);
+}
+EXPORT_SYMBOL(ti_ssp_open);
+
+int ti_ssp_close(struct ti_ssp_port *port)
+{
+	if (!port || !port->ssp)
+		return -EINVAL;
+	port->ssp->ports[port->num] = NULL;
+	put_device(port->ssp->dev);
+	kfree(port);
+	return 0;
+}
+EXPORT_SYMBOL(ti_ssp_close);
+
+int ti_ssp_set_mode(struct ti_ssp_port *port, int mode)
+{
+	if (!port || !port->ssp)
+		return -EINVAL;
+
+	spin_lock(&port->lock);
+	mode &= SSP_PORT_CONFIG_MASK;
+	ssp_port_rmw(port->ssp, port->num, CFG_1, SSP_PORT_CONFIG_MASK, mode);
+	spin_unlock(&port->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ti_ssp_set_mode);
+
+int ti_ssp_set_iosel(struct ti_ssp_port *port, u32 iosel)
+{
+	unsigned int		val;
+
+	if (!port || !port->ssp)
+		return -EINVAL;
+
+	spin_lock(&port->lock);
+
+	/* IOSEL1 gets the least significant 16 bits */
+	val = ssp_read(port->ssp, IOSEL_1);
+	val &= 0xffff << (port->num ? 0 : 16);
+	val |= (iosel & 0xffff) << (port->num ? 16 : 0);
+	ssp_write(port->ssp, IOSEL_1, val);
+
+	/* IOSEL2 gets the most significant 16 bits */
+	val = ssp_read(port->ssp, IOSEL_2);
+	val &= 0x0007 << (port->num ? 0 : 16);
+	val |= (iosel & 0x00070000) >> (port->num ? 0 : 16);
+	ssp_write(port->ssp, IOSEL_2, val);
+
+	spin_unlock(&port->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ti_ssp_set_iosel);
+
+int ti_ssp_load(struct ti_ssp_port *port, int offs, u32* prog, int len)
+{
+	int i;
+
+	if (!port || !port->ssp)
+		return -EINVAL;
+
+	if (len > SSP_PORT_SEQRAM_SIZE)
+		return -ENOSPC;
+
+	spin_lock(&port->lock);
+
+	/* Enable SeqRAM access */
+	ssp_port_set_bits(port->ssp, port->num, CFG_2, SSP_SEQRAM_WR_EN);
+
+	/* Copy code */
+	for (i = 0; i < len; i++) {
+		__raw_writel(prog[i], port->ssp->regs + offs + 4*i +
+			     ssp_port_seqram[port->num]);
+	}
+
+	/* Disable SeqRAM access */
+	ssp_port_clr_bits(port->ssp, port->num, CFG_2, SSP_SEQRAM_WR_EN);
+
+	spin_unlock(&port->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ti_ssp_load);
+
+int ti_ssp_raw_read(struct ti_ssp_port *port)
+{
+	u32 val;
+
+	if (!port || !port->ssp)
+		return -EINVAL;
+
+	val = ssp_read(port->ssp, IOSEL_2);
+	val >>= (port->num ? 27 : 11);
+
+	return val & 0x0f;
+}
+EXPORT_SYMBOL(ti_ssp_raw_read);
+
+int ti_ssp_raw_write(struct ti_ssp_port *port, u32 val)
+{
+	u32 mask;
+
+	if (!port || !port->ssp)
+		return -EINVAL;
+
+	spin_lock(&port->ssp->lock);
+	val &= 0x0f;
+	val <<= (port->num ? 22 : 6);
+	mask = 0x0f;
+	mask <<= (port->num ? 22 : 6);
+	ssp_rmw(port->ssp, IOSEL_2, mask, val);
+	spin_unlock(&port->ssp->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ti_ssp_raw_write);
+
+int ti_ssp_run(struct ti_ssp_port *port, u32 pc, u32 input, u32 *output)
+{
+	struct ti_ssp *ssp;
+	int count;
+
+	if (!port || !port->ssp)
+		return -EINVAL;
+	ssp = port->ssp;
+
+	if (pc & ~(0x3f))
+		return -EINVAL;
+
+	ssp_port_write(ssp, port->num, ADDR, input >> 16);
+	ssp_port_write(ssp, port->num, DATA, input & 0xffff);
+	ssp_port_rmw(ssp, port->num, CFG_1, 0x3f, pc);
+
+	ssp_port_set_bits(ssp, port->num, CFG_1, SSP_START);
+
+	for (count = 10000; count; count--) {
+		if ((ssp_port_read(ssp, port->num, CFG_1) & SSP_BUSY) == 0)
+			break;
+		udelay(1);
+	}
+
+	if (output) {
+		*(output) = (ssp_port_read(ssp, port->num, ADDR) << 16) |
+			    (ssp_port_read(ssp, port->num, DATA) &  0xffff);
+	}
+
+	if (!count) {
+		dev_err(ssp->dev, "timed out waiting for SSP operation\n");
+		return -EIO;
+	}
+
+	/* return stop address */
+	return ssp_port_read(ssp, port->num, STATE) & 0x3f;
+}
+EXPORT_SYMBOL(ti_ssp_run);
+
+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 ret = 0, prediv = 0xff;
+	unsigned long sysclk;
+	struct device *dev = &pdev->dev;
+
+	ssp = kzalloc(sizeof(*ssp), GFP_KERNEL);
+	if (!ssp) {
+		dev_err(dev, "cannot allocate device info\n");
+		return -ENOMEM;
+	}
+
+	ssp->dev = dev;
+	platform_set_drvdata(pdev, ssp);
+
+	ret = -ENODEV;
+	ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!ssp->res) {
+		dev_err(dev, "cannot determine register area\n");
+		goto error_res;
+	}
+
+	ret = -EINVAL;
+	if (!request_mem_region(ssp->res->start, resource_size(ssp->res),
+				pdev->name)) {
+		dev_err(dev, "cannot claim register memory\n");
+		goto error_res;
+	}
+
+	ret = -ENOMEM;
+	ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res));
+	if (!ssp->regs) {
+		dev_err(dev, "cannot map register memory\n");
+		goto error_map;
+	}
+
+	ret = -EINVAL;
+	ssp->clk = clk_get(dev, NULL);
+	if (IS_ERR(ssp->clk)) {
+		dev_err(dev, "cannot claim device clock\n");
+		goto error_clk;
+	}
+
+	spin_lock_init(&ssp->lock);
+
+	platform_set_drvdata(pdev, ssp);
+
+	/* Power on and initialize SSP */
+	ret = clk_enable(ssp->clk);
+	if (ret)
+		goto error_enable;
+
+	/* Reset registers to a sensible known state */
+	ssp_write(ssp, IOSEL_1, 0);
+	ssp_write(ssp, IOSEL_2, 0);
+	ssp_write(ssp, INTR_EN, 0);
+	ssp_write(ssp, TEST_CTRL, 0);
+	ssp_port_write(ssp, 0, CFG_1, SSP_PORT_ASL);
+	ssp_port_write(ssp, 1, CFG_1, SSP_PORT_ASL);
+	ssp_port_write(ssp, 0, CFG_2, SSP_PORT_CFO1);
+	ssp_port_write(ssp, 1, 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, PREDIV, 0xff, prediv);
+
+	return 0;
+
+error_enable:
+	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 ret;
+}
+
+static int __devexit ti_ssp_remove(struct platform_device *pdev)
+{
+	struct ti_ssp *ssp = platform_get_drvdata(pdev);
+
+	clk_disable(ssp->clk);
+	clk_put(ssp->clk);
+	iounmap(ssp->regs);
+	release_mem_region(ssp->res->start, resource_size(ssp->res));
+	kfree(ssp);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver ti_ssp_driver = {
+	.probe		= ti_ssp_probe,
+	.remove		= __devexit_p(ti_ssp_remove),
+	.driver.name	= "ti-ssp",
+	.driver.owner	= THIS_MODULE,
+};
+
+static int __init ti_ssp_init(void)
+{
+	return platform_driver_register(&ti_ssp_driver);
+}
+
+static void __exit ti_ssp_exit(void)
+{
+	platform_driver_unregister(&ti_ssp_driver);
+}
+
+arch_initcall_sync(ti_ssp_init);
+module_exit(ti_ssp_exit);
+
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
+MODULE_ALIAS("platform:ti_ssp");
+MODULE_LICENSE("GPL");
-- 
1.7.0.4

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

* [PATCH 02/12] davinci: add tnetv107x ssp platform device
       [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2010-10-14 18:38   ` [PATCH 01/12] misc: add driver for sequencer serial port Cyril Chemparathy
@ 2010-10-14 18:38   ` Cyril Chemparathy
  2010-10-14 18:38   ` [PATCH 03/12] davinci: add ssp config for tnetv107x evm board Cyril Chemparathy
                     ` (9 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-14 18:38 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lrg-kDsPt+C1G03kYMGBc/C6ZA, dbrownell

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-l0cyMroinI0@public.gmane.org>
---
 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 c9a86d8..0d0522b 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;
@@ -367,4 +387,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..c1df563 100644
--- a/arch/arm/mach-davinci/include/mach/tnetv107x.h
+++ b/arch/arm/mach-davinci/include/mach/tnetv107x.h
@@ -38,12 +38,14 @@
 #include <mach/mmc.h>
 #include <mach/nand.h>
 #include <mach/serial.h>
+#include <mach/ti_ssp.h>
 
 struct tnetv107x_device_info {
 	struct davinci_uart_config	*serial_config;
 	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 daeae06..fcf30e7 100644
--- a/arch/arm/mach-davinci/tnetv107x.c
+++ b/arch/arm/mach-davinci/tnetv107x.c
@@ -277,7 +277,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.0.4

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

* [PATCH 03/12] davinci: add ssp config for tnetv107x evm board
       [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2010-10-14 18:38   ` [PATCH 01/12] misc: add driver for sequencer serial port Cyril Chemparathy
  2010-10-14 18:38   ` [PATCH 02/12] davinci: add tnetv107x ssp platform device Cyril Chemparathy
@ 2010-10-14 18:38   ` Cyril Chemparathy
  2010-10-14 18:38   ` [PATCH 04/12] spi: add ti-ssp spi master driver Cyril Chemparathy
                     ` (8 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-14 18:38 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lrg-kDsPt+C1G03kYMGBc/C6ZA,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: Cyril Chemparathy

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 |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index 5afa8fc..c2c467b 100644
--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -33,6 +33,7 @@
 #include <mach/edma.h>
 #include <mach/mux.h>
 #include <mach/cp_intc.h>
+#include <mach/ti_ssp.h>
 #include <mach/tnetv107x.h>
 
 #define EVM_MMC_WP_GPIO		21
@@ -99,6 +100,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 +203,23 @@ static struct matrix_keypad_platform_data keypad_config = {
 	.no_autorepeat	= 0,
 };
 
+static struct ti_ssp_data ssp_config = {
+	.out_clock = 250 * 1000,
+};
+
 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.0.4


------------------------------------------------------------------------------
Beautiful is writing same markup. Internet Explorer 9 supports
standards for HTML5, CSS3, SVG 1.1,  ECMAScript5, and DOM L2 & L3.
Spend less time writing and  rewriting code and more time creating great
experiences on the web. Be a part of the beta today.
http://p.sf.net/sfu/beautyoftheweb

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

* [PATCH 04/12] spi: add ti-ssp spi master driver
       [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (2 preceding siblings ...)
  2010-10-14 18:38   ` [PATCH 03/12] davinci: add ssp config for tnetv107x evm board Cyril Chemparathy
@ 2010-10-14 18:38   ` Cyril Chemparathy
       [not found]     ` <1287081535-2864-5-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2010-10-14 18:38   ` [PATCH 05/12] davinci: add spi devices on tnetv107x evm Cyril Chemparathy
                     ` (7 subsequent siblings)
  11 siblings, 1 reply; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-14 18:38 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lrg-kDsPt+C1G03kYMGBc/C6ZA,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: Cyril Chemparathy

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

Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
---
 arch/arm/mach-davinci/include/mach/ti_ssp.h |    6 +
 drivers/spi/Kconfig                         |    6 +
 drivers/spi/Makefile                        |    1 +
 drivers/spi/spi_ti_ssp.c                    |  408 +++++++++++++++++++++++++++
 4 files changed, 421 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/spi_ti_ssp.c

diff --git a/arch/arm/mach-davinci/include/mach/ti_ssp.h b/arch/arm/mach-davinci/include/mach/ti_ssp.h
index 8365101..532b0a3 100644
--- a/arch/arm/mach-davinci/include/mach/ti_ssp.h
+++ b/arch/arm/mach-davinci/include/mach/ti_ssp.h
@@ -32,6 +32,12 @@ struct ti_ssp_port_data {
 	unsigned long	config;
 };
 
+struct ti_ssp_spi_data {
+	struct ti_ssp_port_data	port_data;
+	int			num_cs;
+	void			(*select)(int cs);
+};
+
 struct ti_ssp_port;
 
 /*
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 91c2f4f..c1937e4 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -298,6 +298,12 @@ config SPI_STMP3XXX
 	help
 	  SPI driver for Freescale STMP37xx/378x SoC SSP interface
 
+config SPI_TI_SSP
+	tristate "TI SSP Controller SPI Driver"
+	depends on SPI_MASTER && TI_SSP
+	help
+	  SPI master implementation using a TI sequencer serial port.
+
 config SPI_TXX9
 	tristate "Toshiba TXx9 SPI controller"
 	depends on GENERIC_GPIO && CPU_TX49XX
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index e9cbd18..953aba7 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_TXX9)			+= spi_txx9.o
+obj-$(CONFIG_SPI_TI_SSP)		+= spi_ti_ssp.o
 obj-$(CONFIG_SPI_XILINX)		+= xilinx_spi.o
 obj-$(CONFIG_SPI_XILINX_OF)		+= xilinx_spi_of.o
 obj-$(CONFIG_SPI_XILINX_PLTFM)		+= xilinx_spi_pltfm.o
diff --git a/drivers/spi/spi_ti_ssp.c b/drivers/spi/spi_ti_ssp.c
new file mode 100644
index 0000000..132684c
--- /dev/null
+++ b/drivers/spi/spi_ti_ssp.c
@@ -0,0 +1,408 @@
+/*
+ * 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 <mach/ti_ssp.h>
+
+#define MODE_BITS	(SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
+
+struct ti_ssp_spi {
+	struct spi_master		*master;
+	const struct ti_ssp_spi_data	*pdata;
+	struct device			*dev;
+	spinlock_t			lock;
+	struct list_head		msg_queue;
+	struct completion		complete;
+	int				shutdown:1;
+	struct workqueue_struct		*workqueue;
+	struct work_struct		work;
+	u8				mode, bpw;
+	int				cs_active;
+	struct ti_ssp_port		*ssp;
+	u32				pc_en, pc_dis, pc_wr, pc_rd;
+};
+
+static u32 do_read_data(struct ti_ssp_spi *hw)
+{
+	u32 ret;
+
+	ti_ssp_run(hw->ssp, hw->pc_rd, 0, &ret);
+	return ret;
+}
+
+static void do_write_data(struct ti_ssp_spi *hw, u32 data)
+{
+	ti_ssp_run(hw->ssp, hw->pc_wr, data << (32 - hw->bpw), NULL);
+}
+
+static int do_transfer(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)
+				do_write_data(hw, *tx++);
+			if (t->rx_buf)
+				*rx++ = do_read_data(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)
+				do_write_data(hw, *tx++);
+			if (t->rx_buf)
+				*rx++ = do_read_data(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)
+				do_write_data(hw, *tx++);
+			if (t->rx_buf)
+				*rx++ = do_read_data(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 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->ssp, 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 setup_xfer(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->ssp, 0, seqram, idx);
+	if (error < 0)
+		return error;
+
+	error = ti_ssp_set_mode(hw->ssp, ((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_irq(&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);
+
+		spi = m->spi;
+
+		if (hw->pdata->select)
+			hw->pdata->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 (setup_xfer(hw, bpw, spi->mode) < 0)
+				break;
+
+			chip_select(hw, 1);
+
+			spin_unlock_irq(&hw->lock);
+
+			xfer_status = do_transfer(hw, m, t);
+			if (xfer_status < 0)
+				status = xfer_status;
+
+			if (t->delay_usecs)
+				udelay(t->delay_usecs);
+
+			spin_lock_irq(&hw->lock);
+
+			if (t->cs_change)
+				chip_select(hw, 0);
+		}
+
+		chip_select(hw, 0);
+		m->status = status;
+		m->complete(m->context);
+	}
+
+	if (hw->shutdown)
+		complete(&hw->complete);
+
+	spin_unlock_irq(&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;
+	unsigned long		flags;
+	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_irqsave(&hw->lock, flags);
+	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_irqrestore(&hw->lock, flags);
+	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->pdata = pdata;
+
+	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;
+	}
+
+	hw->ssp = ti_ssp_open(&hw->pdata->port_data);
+	if (IS_ERR(hw->ssp)) {
+		error = PTR_ERR(hw->ssp);
+		dev_err(dev, "ssp open failed (%d)\n", error);
+		goto error_open;
+	}
+
+	master->bus_num		= pdev->id;
+	master->num_chipselect	= hw->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:
+	ti_ssp_close(hw->ssp);
+error_open:
+	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;
+		}
+	}
+
+	ti_ssp_close(hw->ssp);
+	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",
+	.driver.owner	= THIS_MODULE,
+};
+
+static int __init ti_ssp_spi_init(void)
+{
+	return platform_driver_register(&ti_ssp_spi_driver);
+}
+
+static void __exit ti_ssp_spi_exit(void)
+{
+	platform_driver_unregister(&ti_ssp_spi_driver);
+}
+
+subsys_initcall(ti_ssp_spi_init);
+module_exit(ti_ssp_spi_exit);
+
+MODULE_DESCRIPTION("SSP SPI Master");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_ALIAS("platform:spi_ti_ssp");
+MODULE_LICENSE("GPL");
-- 
1.7.0.4


------------------------------------------------------------------------------
Beautiful is writing same markup. Internet Explorer 9 supports
standards for HTML5, CSS3, SVG 1.1,  ECMAScript5, and DOM L2 & L3.
Spend less time writing and  rewriting code and more time creating great
experiences on the web. Be a part of the beta today.
http://p.sf.net/sfu/beautyoftheweb

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

* [PATCH 05/12] davinci: add spi devices on tnetv107x evm
       [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (3 preceding siblings ...)
  2010-10-14 18:38   ` [PATCH 04/12] spi: add ti-ssp spi master driver Cyril Chemparathy
@ 2010-10-14 18:38   ` Cyril Chemparathy
  2010-10-14 18:38   ` [PATCH 06/12] regulator: add driver for tps6524x regulator Cyril Chemparathy
                     ` (6 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-14 18:38 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lrg-kDsPt+C1G03kYMGBc/C6ZA,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: Cyril Chemparathy

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

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

diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index c2c467b..52378bf 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>
@@ -38,6 +39,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)
 {
@@ -215,6 +217,52 @@ static struct tnetv107x_device_info evm_device_info __initconst = {
 	.ssp_config		= &ssp_config,
 };
 
+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 = {
+	.port_data = {
+		.ssp_dev_name = "ti-ssp",
+		.port = 1,
+		.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),
+	},
+	.num_cs		= 2,
+	.select		= spi_select_device,
+};
+
+static struct platform_device spi_master_device = {
+	.name		= "ti-ssp-spi",
+	.id		= 0,
+	.dev.platform_data = &spi_master_data,
+};
+
+static struct spi_board_info spi_info[] __initconst = {
+};
+
 static __init void tnetv107x_evm_board_init(void)
 {
 	davinci_cfg_reg_list(sdio1_pins);
@@ -222,6 +270,9 @@ static __init void tnetv107x_evm_board_init(void)
 	davinci_cfg_reg_list(ssp_pins);
 
 	tnetv107x_devices_init(&evm_device_info);
+
+	platform_device_register(&spi_master_device);
+	spi_register_board_info(spi_info, ARRAY_SIZE(spi_info));
 }
 
 #ifdef CONFIG_SERIAL_8250_CONSOLE
-- 
1.7.0.4


------------------------------------------------------------------------------
Beautiful is writing same markup. Internet Explorer 9 supports
standards for HTML5, CSS3, SVG 1.1,  ECMAScript5, and DOM L2 & L3.
Spend less time writing and  rewriting code and more time creating great
experiences on the web. Be a part of the beta today.
http://p.sf.net/sfu/beautyoftheweb

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

* [PATCH 06/12] regulator: add driver for tps6524x regulator
       [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (4 preceding siblings ...)
  2010-10-14 18:38   ` [PATCH 05/12] davinci: add spi devices on tnetv107x evm Cyril Chemparathy
@ 2010-10-14 18:38   ` Cyril Chemparathy
       [not found]     ` <1287081535-2864-7-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2010-10-14 18:38   ` [PATCH 07/12] davinci: add tnetv107x evm regulators Cyril Chemparathy
                     ` (5 subsequent siblings)
  11 siblings, 1 reply; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-14 18:38 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lrg-kDsPt+C1G03kYMGBc/C6ZA,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: Cyril Chemparathy

TPS6524X provides three step-down converters and two general-purpose LDO
voltage regulators.  This device is interfaced using SPI.

Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
---
 drivers/regulator/Kconfig              |   10 +
 drivers/regulator/Makefile             |    1 +
 drivers/regulator/tps6524x-regulator.c |  812 ++++++++++++++++++++++++++++++++
 3 files changed, 823 insertions(+), 0 deletions(-)
 create mode 100644 drivers/regulator/tps6524x-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 172951b..7875c2e 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -235,5 +235,15 @@ config REGULATOR_TPS6586X
 	help
 	  This driver supports TPS6586X voltage regulator chips.
 
+config REGULATOR_TPS6524X
+	tristate "TI TPS6524X Power regulators"
+	depends on TI_SSP
+	help
+	  This driver supports TPS6524X voltage regulator chips. TPS6524X
+	  provides three step-down converters and two general-purpose LDO
+	  voltage regulators.  This device is interfaced using a customized
+	  serial interface currently supported on the sequencer serial
+	  port controller.
+
 endif
 
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 8285fd8..a8e5bc0 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
 
 obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
+obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
 obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_AB8500)	+= ab8500.o
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
new file mode 100644
index 0000000..03cfe57
--- /dev/null
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -0,0 +1,812 @@
+/*
+ * Regulator driver for TPS6524x PMIC
+ *
+ * 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/module.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#define REG_LDO_SET		0x0
+#define LDO_ILIM_MASK		1	/* 0 = 400-800, 1 = 900-1500 */
+#define LDO_VSEL_MASK		0x0f
+#define LDO2_ILIM_SHIFT		12
+#define LDO2_VSEL_SHIFT		4
+#define LDO1_ILIM_SHIFT		8
+#define LDO1_VSEL_SHIFT		0
+
+#define REG_BLOCK_EN		0x1
+#define BLOCK_MASK		1
+#define BLOCK_LDO1_SHIFT	0
+#define BLOCK_LDO2_SHIFT	1
+#define BLOCK_LCD_SHIFT		2
+#define BLOCK_USB_SHIFT		3
+
+#define REG_DCDC_SET		0x2
+#define DCDC_VDCDC_MASK		0x1f
+#define DCDC_VDCDC1_SHIFT	0
+#define DCDC_VDCDC2_SHIFT	5
+#define DCDC_VDCDC3_SHIFT	10
+
+#define REG_DCDC_EN		0x3
+#define DCDCDCDC_EN_MASK	0x1
+#define DCDCDCDC1_EN_SHIFT	0
+#define DCDCDCDC1_PG_MSK	BIT(1)
+#define DCDCDCDC2_EN_SHIFT	2
+#define DCDCDCDC2_PG_MSK	BIT(3)
+#define DCDCDCDC3_EN_SHIFT	4
+#define DCDCDCDC3_PG_MSK	BIT(5)
+
+#define REG_USB			0x4
+#define USB_ILIM_SHIFT		0
+#define USB_ILIM_MASK		0x3
+#define USB_TSD_SHIFT		2
+#define USB_TSD_MASK		0x3
+#define USB_TWARN_SHIFT		4
+#define USB_TWARN_MASK		0x3
+#define USB_IWARN_SD		BIT(6)
+#define USB_FAST_LOOP		BIT(7)
+
+#define REG_ALARM		0x5
+#define ALARM_LDO1		BIT(0)
+#define ALARM_DCDC1		BIT(1)
+#define ALARM_DCDC2		BIT(2)
+#define ALARM_DCDC3		BIT(3)
+#define ALARM_LDO2		BIT(4)
+#define ALARM_USB_WARN		BIT(5)
+#define ALARM_USB_ALARM		BIT(6)
+#define ALARM_LCD		BIT(9)
+#define ALARM_TEMP_WARM		BIT(10)
+#define ALARM_TEMP_HOT		BIT(11)
+#define ALARM_NRST		BIT(14)
+#define ALARM_POWERUP		BIT(15)
+
+#define REG_INT_ENABLE		0x6
+#define INT_LDO1		BIT(0)
+#define INT_DCDC1		BIT(1)
+#define INT_DCDC2		BIT(2)
+#define INT_DCDC3		BIT(3)
+#define INT_LDO2		BIT(4)
+#define INT_USB_WARN		BIT(5)
+#define INT_USB_ALARM		BIT(6)
+#define INT_LCD			BIT(9)
+#define INT_TEMP_WARM		BIT(10)
+#define INT_TEMP_HOT		BIT(11)
+#define INT_GLOBAL_EN		BIT(15)
+
+#define REG_INT_STATUS		0x7
+#define STATUS_LDO1		BIT(0)
+#define STATUS_DCDC1		BIT(1)
+#define STATUS_DCDC2		BIT(2)
+#define STATUS_DCDC3		BIT(3)
+#define STATUS_LDO2		BIT(4)
+#define STATUS_USB_WARN		BIT(5)
+#define STATUS_USB_ALARM	BIT(6)
+#define STATUS_LCD		BIT(9)
+#define STATUS_TEMP_WARM	BIT(10)
+#define STATUS_TEMP_HOT		BIT(11)
+
+#define REG_SOFTWARE_RESET	0xb
+#define REG_WRITE_ENABLE	0xd
+#define REG_REV_ID		0xf
+
+#define N_DCDC			3
+#define N_LDO			2
+#define N_SWITCH		2
+#define N_REGULATORS		(3 /* DCDC */ + \
+				 2 /* LDO */  + \
+				 2 /* switch */)
+
+#define FIXED_ILIMSEL		BIT(0)
+#define FIXED_VOLTAGE		BIT(1)
+
+#define CMD_READ(reg)		((reg) << 6)
+#define CMD_WRITE(reg)		(BIT(5) | (reg) << 6)
+#define STAT_CLK		BIT(3)
+#define STAT_WRITE		BIT(2)
+#define STAT_INVALID		BIT(1)
+#define STAT_WP			BIT(0)
+
+struct field {
+	int		reg;
+	int		shift;
+	int		mask;
+};
+
+struct supply_info {
+	const char	*name;
+	int		n_voltages;
+	const int	*voltages;
+	int		fixed_voltage;
+	int		n_ilimsels;
+	const int	*ilimsels;
+	int		fixed_ilimsel;
+	int		flags;
+	struct field	enable, voltage, ilimsel;
+};
+
+struct tps6524x {
+	struct device		*dev;
+	struct spi_device	*spi;
+	struct mutex		lock;
+	struct regulator_desc	desc[N_REGULATORS];
+	struct regulator_dev	*rdev[N_REGULATORS];
+};
+
+static int __read_reg(struct tps6524x *hw, int reg)
+{
+	int error = 0;
+	u16 cmd = CMD_READ(reg), in;
+	u8 status;
+	struct spi_message m;
+	struct spi_transfer t[3];
+
+	spi_message_init(&m);
+	memset(t, 0, sizeof(t));
+
+	t[0].tx_buf = &cmd;
+	t[0].len = 2;
+	t[0].bits_per_word = 12;
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].rx_buf = &in;
+	t[1].len = 2;
+	t[1].bits_per_word = 16;
+	spi_message_add_tail(&t[1], &m);
+
+	t[2].rx_buf = &status;
+	t[2].len = 1;
+	t[2].bits_per_word = 4;
+	spi_message_add_tail(&t[2], &m);
+
+	error = spi_sync(hw->spi, &m);
+	if (error < 0)
+		return error;
+
+	dev_dbg(hw->dev, "read reg %d, data %x, status %x\n",
+		reg, in, status);
+
+	if (!(status & STAT_CLK) || (status & STAT_WRITE))
+		return -EIO;
+
+	if (status & STAT_INVALID)
+		return -EINVAL;
+
+	return in;
+}
+
+static int read(struct tps6524x *hw, int reg)
+{
+	int ret;
+
+	mutex_lock(&hw->lock);
+	ret = __read_reg(hw, reg);
+	mutex_unlock(&hw->lock);
+
+	return ret;
+}
+
+static int __write_reg(struct tps6524x *hw, int reg, int val)
+{
+	int error = 0;
+	u16 cmd = CMD_WRITE(reg), out = val;
+	u8 status;
+	struct spi_message m;
+	struct spi_transfer t[3];
+
+	spi_message_init(&m);
+	memset(t, 0, sizeof(t));
+
+	t[0].tx_buf = &cmd;
+	t[0].len = 2;
+	t[0].bits_per_word = 12;
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].tx_buf = &out;
+	t[1].len = 2;
+	t[1].bits_per_word = 16;
+	spi_message_add_tail(&t[1], &m);
+
+	t[2].rx_buf = &status;
+	t[2].len = 1;
+	t[2].bits_per_word = 4;
+	spi_message_add_tail(&t[2], &m);
+
+	error = spi_sync(hw->spi, &m);
+	if (error < 0)
+		return error;
+
+	dev_dbg(hw->dev, "wrote reg %d, data %x, status %x\n",
+		reg, out, status);
+
+	if (!(status & STAT_CLK) || !(status & STAT_WRITE))
+		return -EIO;
+
+	if (status & (STAT_INVALID | STAT_WP))
+		return -EINVAL;
+
+	return error;
+}
+
+static int write(struct tps6524x *hw, int reg, int val)
+{
+	int ret;
+
+	mutex_lock(&hw->lock);
+	ret = __write_reg(hw, reg, val);
+	mutex_unlock(&hw->lock);
+
+	return ret;
+}
+
+static int __rmw_reg(struct tps6524x *hw, int reg, int mask, int val)
+{
+	int ret;
+
+	ret = __read_reg(hw, reg);
+	if (ret < 0)
+		return ret;
+
+	ret &= ~mask;
+	ret |= val;
+
+	ret = __write_reg(hw, reg, ret);
+
+	return (ret < 0) ? ret : 0;
+}
+
+static int rmw_protect(struct tps6524x *hw, int reg, int mask, int val)
+{
+	int ret;
+
+	mutex_lock(&hw->lock);
+
+	ret = __write_reg(hw, REG_WRITE_ENABLE, 1);
+	if (ret) {
+		dev_err(hw->dev, "failed to set write enable\n");
+		goto error;
+	}
+
+	ret = __rmw_reg(hw, reg, mask, val);
+	if (ret)
+		dev_err(hw->dev, "failed to rmw register %d\n", reg);
+
+	ret = __write_reg(hw, REG_WRITE_ENABLE, 0);
+	if (ret) {
+		dev_err(hw->dev, "failed to clear write enable\n");
+		goto error;
+	}
+
+error:
+	mutex_unlock(&hw->lock);
+
+	return ret;
+}
+
+static int read_field(struct tps6524x *hw, const struct field *field)
+{
+	int tmp;
+
+	tmp = read(hw, field->reg);
+	if (tmp < 0)
+		return tmp;
+
+	return (tmp >> field->shift) & field->mask;
+}
+
+static int write_field(struct tps6524x *hw, const struct field *field,
+		       int val)
+{
+	if (val & ~field->mask)
+		return -EOVERFLOW;
+
+	return rmw_protect(hw, field->reg,
+				    field->mask << field->shift,
+				    val << field->shift);
+}
+
+static const int dcdc1_voltages[] = {
+	 800000,  825000,  850000,  875000,
+	 900000,  925000,  950000,  975000,
+	1000000, 1025000, 1050000, 1075000,
+	1100000, 1125000, 1150000, 1175000,
+	1200000, 1225000, 1250000, 1275000,
+	1300000, 1325000, 1350000, 1375000,
+	1400000, 1425000, 1450000, 1475000,
+	1500000, 1525000, 1550000, 1575000,
+};
+
+static const int dcdc2_voltages[] = {
+	1400000, 1450000, 1500000, 1550000,
+	1600000, 1650000, 1700000, 1750000,
+	1800000, 1850000, 1900000, 1950000,
+	2000000, 2050000, 2100000, 2150000,
+	2200000, 2250000, 2300000, 2350000,
+	2400000, 2450000, 2500000, 2550000,
+	2600000, 2650000, 2700000, 2750000,
+	2800000, 2850000, 2900000, 2950000,
+};
+
+static const int dcdc3_voltages[] = {
+	2400000, 2450000, 2500000, 2550000, 2600000,
+	2650000, 2700000, 2750000, 2800000, 2850000,
+	2900000, 2950000, 3000000, 3050000, 3100000,
+	3150000, 3200000, 3250000, 3300000, 3350000,
+	3400000, 3450000, 3500000, 3550000, 3600000,
+};
+
+static const int ldo1_voltages[] = {
+	4300000, 4350000, 4400000, 4450000,
+	4500000, 4550000, 4600000, 4650000,
+	4700000, 4750000, 4800000, 4850000,
+	4900000, 4950000, 5000000, 5050000,
+};
+
+static const int ldo2_voltages[] = {
+	1100000, 1150000, 1200000, 1250000,
+	1300000, 1700000, 1750000, 1800000,
+	1850000, 1900000, 3150000, 3200000,
+	3250000, 3300000, 3350000, 3400000,
+};
+
+static const int ldo_ilimsel[] = {
+	400000, 1500000
+};
+
+static const int usb_ilimsel[] = {
+	200000, 400000, 800000, 1000000
+};
+
+#define __MK_FIELD(_reg, _mask, _shift) \
+	{ .reg = (_reg), .mask = (_mask), .shift = (_shift), }
+
+static const struct supply_info supply_info[N_REGULATORS] = {
+	{
+		.name		= "DCDC1",
+		.flags		= FIXED_ILIMSEL,
+		.n_voltages	= ARRAY_SIZE(dcdc1_voltages),
+		.voltages	= dcdc1_voltages,
+		.fixed_ilimsel	= 2400000,
+		.enable		= __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
+					     DCDCDCDC1_EN_SHIFT),
+		.voltage	= __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
+					     DCDC_VDCDC1_SHIFT),
+	},
+	{
+		.name		= "DCDC2",
+		.flags		= FIXED_ILIMSEL,
+		.n_voltages	= ARRAY_SIZE(dcdc2_voltages),
+		.voltages	= dcdc2_voltages,
+		.fixed_ilimsel	= 1200000,
+		.enable		= __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
+					     DCDCDCDC2_EN_SHIFT),
+		.voltage	= __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
+					     DCDC_VDCDC2_SHIFT),
+	},
+	{
+		.name		= "DCDC3",
+		.flags		= FIXED_ILIMSEL,
+		.n_voltages	= ARRAY_SIZE(dcdc3_voltages),
+		.voltages	= dcdc3_voltages,
+		.fixed_ilimsel	= 1200000,
+		.enable		= __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
+					DCDCDCDC3_EN_SHIFT),
+		.voltage	= __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
+					     DCDC_VDCDC3_SHIFT),
+	},
+	{
+		.name		= "LDO1",
+		.n_voltages	= ARRAY_SIZE(ldo1_voltages),
+		.voltages	= ldo1_voltages,
+		.n_ilimsels	= ARRAY_SIZE(ldo_ilimsel),
+		.ilimsels	= ldo_ilimsel,
+		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
+					     BLOCK_LDO1_SHIFT),
+		.voltage	= __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK,
+					     LDO1_VSEL_SHIFT),
+		.ilimsel	= __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK,
+					     LDO1_ILIM_SHIFT),
+	},
+	{
+		.name		= "LDO2",
+		.n_voltages	= ARRAY_SIZE(ldo2_voltages),
+		.voltages	= ldo2_voltages,
+		.n_ilimsels	= ARRAY_SIZE(ldo_ilimsel),
+		.ilimsels	= ldo_ilimsel,
+		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
+					     BLOCK_LDO2_SHIFT),
+		.voltage	= __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK,
+					     LDO2_VSEL_SHIFT),
+		.ilimsel	= __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK,
+					     LDO2_ILIM_SHIFT),
+	},
+	{
+		.name		= "USB",
+		.flags		= FIXED_VOLTAGE,
+		.fixed_voltage	= 5000000,
+		.n_ilimsels	= ARRAY_SIZE(usb_ilimsel),
+		.ilimsels	= usb_ilimsel,
+		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
+					     BLOCK_USB_SHIFT),
+		.ilimsel	= __MK_FIELD(REG_USB, USB_ILIM_MASK,
+					     USB_ILIM_SHIFT),
+	},
+	{
+		.name		= "LCD",
+		.flags		= FIXED_VOLTAGE | FIXED_ILIMSEL,
+		.fixed_voltage	= 5000000,
+		.fixed_ilimsel	=  400000,
+		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
+					     BLOCK_LCD_SHIFT),
+	},
+};
+
+static int list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	if (info->flags & FIXED_VOLTAGE)
+		return selector ? -EINVAL : info->fixed_voltage;
+	else
+		return (selector < 0 || selector >= info->n_voltages) ?
+			-EINVAL : info->voltages[selector];
+}
+
+static int set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+	int i;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	if (info->flags & FIXED_VOLTAGE)
+		return -EINVAL;
+
+	for (i = 0; i < info->n_voltages; i++)
+		if (min_uV <= info->voltages[i] &&
+		    max_uV >= info->voltages[i])
+			break;
+
+	if (i >= info->n_voltages)
+		return -EINVAL;
+
+	return write_field(hw, &info->voltage, i);
+}
+
+static int get_voltage(struct regulator_dev *rdev)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+	int ret;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	if (info->flags & FIXED_VOLTAGE)
+		return info->fixed_voltage;
+
+	ret = read_field(hw, &info->voltage);
+	if (ret < 0)
+		return ret;
+	if (ret >= info->n_voltages)
+		return -EINVAL;
+	return info->voltages[ret];
+}
+
+static int set_current_limit(struct regulator_dev *rdev, int min_uA,
+			     int max_uA)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+	int i;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	if (info->flags & FIXED_ILIMSEL)
+		return -EINVAL;
+
+	for (i = 0; i < info->n_ilimsels; i++)
+		if (min_uA <= info->ilimsels[i] &&
+		    max_uA >= info->ilimsels[i])
+			break;
+
+	if (i >= info->n_ilimsels)
+		return -EINVAL;
+
+	return write_field(hw, &info->ilimsel, i);
+}
+
+static int get_current_limit(struct regulator_dev *rdev)
+{
+	struct tps6524x		*hw;
+	const struct supply_info	*info;
+	int ret;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	if (info->flags & FIXED_ILIMSEL)
+		return info->fixed_ilimsel;
+
+	ret = read_field(hw, &info->ilimsel);
+	if (ret < 0)
+		return ret;
+	if (ret >= info->n_ilimsels)
+		return -EINVAL;
+	return info->ilimsels[ret];
+}
+
+static int enable_supply(struct regulator_dev *rdev)
+{
+	struct tps6524x		*hw;
+	const struct supply_info	*info;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	return write_field(hw, &info->enable, 1);
+}
+
+static int disable_supply(struct regulator_dev *rdev)
+{
+	struct tps6524x		*hw;
+	const struct supply_info	*info;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	return write_field(hw, &info->enable, 0);
+}
+
+static int is_supply_enabled(struct regulator_dev *rdev)
+{
+	struct tps6524x		*hw;
+	const struct supply_info	*info;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	return read_field(hw, &info->enable);
+}
+
+static struct regulator_ops regulator_ops = {
+	.is_enabled		= is_supply_enabled,
+	.enable			= enable_supply,
+	.disable		= disable_supply,
+	.get_voltage		= get_voltage,
+	.set_voltage		= set_voltage,
+	.list_voltage		= list_voltage,
+	.set_current_limit	= set_current_limit,
+	.get_current_limit	= get_current_limit,
+};
+
+struct reg_map {
+	struct device_attribute *attr;
+	int reg;
+};
+
+static ssize_t show_reg(struct device *dev, struct device_attribute *attr,
+			char *buf);
+static ssize_t store_reg(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t size);
+
+static DEVICE_ATTR(ldo_set,	0664, show_reg, store_reg);
+static DEVICE_ATTR(block_en,	0664, show_reg, store_reg);
+static DEVICE_ATTR(dcdc_set,	0664, show_reg, store_reg);
+static DEVICE_ATTR(dcdc_en,	0664, show_reg, store_reg);
+static DEVICE_ATTR(usb,		0664, show_reg, store_reg);
+static DEVICE_ATTR(alarm,	0664, show_reg, store_reg);
+static DEVICE_ATTR(int_enable,	0664, show_reg, store_reg);
+static DEVICE_ATTR(int_status,	0664, show_reg, store_reg);
+static DEVICE_ATTR(rev_id,	0664, show_reg, store_reg);
+static DEVICE_ATTR(write_enable,   0664, show_reg, store_reg);
+static DEVICE_ATTR(software_reset, 0664, show_reg, store_reg);
+
+static struct attribute *regs[] = {
+	&dev_attr_ldo_set.attr,
+	&dev_attr_block_en.attr,
+	&dev_attr_dcdc_set.attr,
+	&dev_attr_dcdc_en.attr,
+	&dev_attr_usb.attr,
+	&dev_attr_alarm.attr,
+	&dev_attr_int_enable.attr,
+	&dev_attr_int_status.attr,
+	&dev_attr_software_reset.attr,
+	&dev_attr_write_enable.attr,
+	&dev_attr_rev_id.attr,
+	NULL,
+};
+
+static struct reg_map reg_map[] = {
+	{&dev_attr_ldo_set,	   REG_LDO_SET		},
+	{&dev_attr_block_en,	   REG_BLOCK_EN		},
+	{&dev_attr_dcdc_set,	   REG_DCDC_SET		},
+	{&dev_attr_dcdc_en,	   REG_DCDC_EN		},
+	{&dev_attr_usb,		   REG_USB		},
+	{&dev_attr_alarm,	   REG_ALARM		},
+	{&dev_attr_int_enable,	   REG_INT_ENABLE	},
+	{&dev_attr_int_status,	   REG_INT_STATUS	},
+	{&dev_attr_software_reset, REG_SOFTWARE_RESET	},
+	{&dev_attr_write_enable,   REG_WRITE_ENABLE	},
+	{&dev_attr_rev_id,	   REG_REV_ID		},
+	{NULL, -1},
+};
+
+static int reg_addr(struct device_attribute *attr)
+{
+	int i;
+
+	for (i = 0; reg_map[i].attr; i++) {
+		if (reg_map[i].attr == attr)
+			return reg_map[i].reg;
+	}
+	return -EINVAL;
+}
+
+static ssize_t show_reg(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	int r, ret;
+	struct tps6524x *hw = dev_get_drvdata(dev);
+
+	BUG_ON(!hw);
+
+	r = reg_addr(attr);
+	if (r < 0)
+		return r;
+
+	ret = snprintf(buf, PAGE_SIZE, "%08x\n", read(hw, r));
+
+	return ret;
+}
+
+static ssize_t store_reg(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t size)
+{
+	int r, v;
+	struct tps6524x *hw = dev_get_drvdata(dev);
+
+	BUG_ON(!hw);
+
+	r = reg_addr(attr);
+	if (r < 0)
+		return r;
+
+	if (sscanf(buf, "%d", &v) != 1)
+		return -EINVAL;
+
+	r = write(hw, r, v);
+
+	if (r < 0)
+		return r;
+
+	return size;
+}
+
+static const struct attribute_group registers = {
+	.name  = "registers",
+	.attrs = regs,
+};
+
+static int __devexit pmic_remove(struct spi_device *spi)
+{
+	struct tps6524x *hw = spi_get_drvdata(spi);
+	int i;
+
+	if (!hw)
+		return 0;
+	for (i = 0; i < N_REGULATORS; i++) {
+		if (!hw->rdev[i])
+			continue;
+		regulator_unregister(hw->rdev[i]);
+		hw->rdev[i] = NULL;
+	}
+	sysfs_remove_group(&hw->dev->kobj, &registers);
+	spi_set_drvdata(spi, NULL);
+	kfree(hw);
+	return 0;
+}
+
+static int __devinit pmic_probe(struct spi_device *spi)
+{
+	struct tps6524x *hw;
+	struct device *dev = &spi->dev;
+	const struct supply_info *info = supply_info;
+	struct regulator_init_data *init_data;
+	int ret = 0, i;
+
+	init_data = dev->platform_data;
+	if (!init_data) {
+		dev_err(dev, "could not find regulator platform data\n");
+		return -EIO;
+	}
+
+	hw = kzalloc(sizeof(struct tps6524x), GFP_KERNEL);
+	if (!hw) {
+		dev_err(dev, "cannot allocate regulator private data\n");
+		return -ENOMEM;
+	}
+	spi_set_drvdata(spi, hw);
+
+	memset(hw, 0, sizeof(struct tps6524x));
+	hw->dev = dev;
+	hw->spi = spi_dev_get(spi);
+	mutex_init(&hw->lock);
+
+	ret = sysfs_create_group(&dev->kobj, &registers);
+	if (ret)
+		dev_err(dev, "failed to create sysfs entries\n");
+
+	for (i = 0; i < N_REGULATORS; i++, info++, init_data++) {
+		hw->desc[i].name	= info->name;
+		hw->desc[i].id		= i;
+		hw->desc[i].n_voltages	= info->n_voltages;
+		hw->desc[i].ops		= &regulator_ops;
+		hw->desc[i].type	= REGULATOR_VOLTAGE;
+		hw->desc[i].owner	= THIS_MODULE;
+
+		if (info->flags & FIXED_VOLTAGE)
+			hw->desc[i].n_voltages = 1;
+
+		hw->rdev[i] = regulator_register(&hw->desc[i], dev,
+						 init_data, hw);
+		if (IS_ERR(hw->rdev[i])) {
+			ret = PTR_ERR(hw->rdev[i]);
+			hw->rdev[i] = NULL;
+			goto fail;
+		}
+	}
+
+	return 0;
+
+fail:
+	pmic_remove(spi);
+	return ret;
+}
+
+static struct spi_driver pmic_driver = {
+	.probe		= pmic_probe,
+	.remove		= __devexit_p(pmic_remove),
+	.driver.name	= "tps6524x",
+	.driver.owner	= THIS_MODULE,
+};
+
+static int __init pmic_driver_init(void)
+{
+	return spi_register_driver(&pmic_driver);
+}
+
+static void __exit pmic_driver_exit(void)
+{
+	spi_unregister_driver(&pmic_driver);
+}
+
+subsys_initcall_sync(pmic_driver_init);
+module_exit(pmic_driver_exit);
+
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_DESCRIPTION("TPS6524X PMIC Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:tps6524x");
-- 
1.7.0.4


------------------------------------------------------------------------------
Beautiful is writing same markup. Internet Explorer 9 supports
standards for HTML5, CSS3, SVG 1.1,  ECMAScript5, and DOM L2 & L3.
Spend less time writing and  rewriting code and more time creating great
experiences on the web. Be a part of the beta today.
http://p.sf.net/sfu/beautyoftheweb

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

* [PATCH 07/12] davinci: add tnetv107x evm regulators
       [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (5 preceding siblings ...)
  2010-10-14 18:38   ` [PATCH 06/12] regulator: add driver for tps6524x regulator Cyril Chemparathy
@ 2010-10-14 18:38   ` Cyril Chemparathy
       [not found]     ` <1287081535-2864-8-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2010-10-14 18:38   ` [PATCH 08/12] gpio: add ti-ssp virtual gpio driver Cyril Chemparathy
                     ` (4 subsequent siblings)
  11 siblings, 1 reply; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-14 18:38 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lrg-kDsPt+C1G03kYMGBc/C6ZA, dbrownell

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 |   91 +++++++++++++++++++++++++++
 1 files changed, 91 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index 52378bf..2f13544 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>
@@ -260,7 +263,95 @@ static struct platform_device spi_master_device = {
 	.dev.platform_data = &spi_master_data,
 };
 
+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,
+			.min_uA		= 400000,
+			.max_uA		= 1500000,
+			.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_uV		= 5000000,
+			.max_uV		= 5000000,
+			.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",
+			.min_uV		= 5000000,
+			.max_uV		= 5000000,
+			.valid_ops_mask	= REGULATOR_CHANGE_STATUS,
+		},
+	},
+};
+
 static struct spi_board_info spi_info[] __initconst = {
+	{
+		.modalias	= "tps6524x",
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.mode		= SPI_MODE_0,
+		.platform_data	= regulators,
+	},
 };
 
 static __init void tnetv107x_evm_board_init(void)
-- 
1.7.0.4

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

* [PATCH 08/12] gpio: add ti-ssp virtual gpio driver
       [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (6 preceding siblings ...)
  2010-10-14 18:38   ` [PATCH 07/12] davinci: add tnetv107x evm regulators Cyril Chemparathy
@ 2010-10-14 18:38   ` Cyril Chemparathy
  2010-10-14 18:38   ` [PATCH 09/12] davinci: add tnetv107x evm ti-ssp gpio device Cyril Chemparathy
                     ` (3 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-14 18:38 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lrg-kDsPt+C1G03kYMGBc/C6ZA,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: Cyril Chemparathy

This patch adds a GPIO driver based on TI's SSP device.  This driver does not
support GPIO-IRQs.

Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
---
 arch/arm/mach-davinci/include/mach/ti_ssp.h |    5 +
 drivers/gpio/Kconfig                        |   10 ++
 drivers/gpio/Makefile                       |    1 +
 drivers/gpio/ti-ssp-gpio.c                  |  234 +++++++++++++++++++++++++++
 4 files changed, 250 insertions(+), 0 deletions(-)
 create mode 100644 drivers/gpio/ti-ssp-gpio.c

diff --git a/arch/arm/mach-davinci/include/mach/ti_ssp.h b/arch/arm/mach-davinci/include/mach/ti_ssp.h
index 532b0a3..4392b43 100644
--- a/arch/arm/mach-davinci/include/mach/ti_ssp.h
+++ b/arch/arm/mach-davinci/include/mach/ti_ssp.h
@@ -38,6 +38,11 @@ struct ti_ssp_spi_data {
 	void			(*select)(int cs);
 };
 
+struct ti_ssp_gpio_data {
+	struct ti_ssp_port_data	port_data;
+	int			start;
+};
+
 struct ti_ssp_port;
 
 /*
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 510aa20..e400761 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -111,6 +111,16 @@ config GPIO_SCH
 	  This driver can also be built as a module. If so, the module
 	  will be called sch-gpio.
 
+config GPIO_TI_SSP
+	tristate "TI SSP Controller GPIO Driver"
+	depends on GPIOLIB && TI_SSP
+	help
+	  Say yes here to support a virtual GPIO interface on TI SSP ports.
+	  Each SSP port translates into 4 GPIOs, with no IRQ support.
+
+	  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 fc6019d..98b4551 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -23,6 +23,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..fea4b50
--- /dev/null
+++ b/drivers/gpio/ti-ssp-gpio.c
@@ -0,0 +1,234 @@
+/*
+ * 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 <mach/ti_ssp.h>
+
+struct ti_ssp_gpio {
+	const struct ti_ssp_gpio_data	*pdata;
+	struct ti_ssp_port_data		port_data;
+	struct gpio_chip		chip;
+#define chip2gpio(chip)	container_of(chip, struct ti_ssp_gpio, chip)
+	struct device			*dev;
+	spinlock_t			lock;
+	struct ti_ssp_port		*ssp;
+	u8				out;
+};
+
+static int attach_ssp(struct ti_ssp_gpio *gpio)
+{
+	struct ti_ssp_port *ssp;
+
+	if (gpio->ssp)
+		return 0;
+
+	ssp = ti_ssp_open(&gpio->port_data);
+	if (IS_ERR(ssp))
+		return PTR_ERR(ssp);
+	gpio->ssp = ssp;
+
+	return 0;
+}
+
+static int direction_in(struct gpio_chip *chip, unsigned gpio_num)
+{
+	struct ti_ssp_gpio *gpio = chip2gpio(chip);
+	int error = 0;
+
+	spin_lock(&gpio->lock);
+
+	gpio->port_data.iosel &= ~SSP_PIN_MASK(gpio_num);
+	gpio->port_data.iosel |=  SSP_PIN_SEL(gpio_num, SSP_IN);
+
+	if (!gpio->ssp)
+		error = attach_ssp(gpio);
+	else
+		error = ti_ssp_set_iosel(gpio->ssp, gpio->port_data.iosel);
+
+	spin_unlock(&gpio->lock);
+
+	return error;
+}
+
+static int direction_out(struct gpio_chip *chip, unsigned gpio_num, int val)
+{
+	struct ti_ssp_gpio *gpio = chip2gpio(chip);
+	int error;
+
+	spin_lock(&gpio->lock);
+
+	gpio->port_data.iosel &= ~SSP_PIN_MASK(gpio_num);
+	gpio->port_data.iosel |=  SSP_PIN_SEL(gpio_num, SSP_OUT);
+
+	if (!gpio->ssp)
+		error = attach_ssp(gpio);
+	else
+		error = ti_ssp_set_iosel(gpio->ssp, gpio->port_data.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->ssp, gpio->out);
+
+error:
+	spin_unlock(&gpio->lock);
+	return error;
+}
+
+static int value_get(struct gpio_chip *chip, unsigned gpio_num)
+{
+	struct ti_ssp_gpio *gpio = chip2gpio(chip);
+	int error;
+
+	spin_lock(&gpio->lock);
+
+	error = attach_ssp(gpio);
+	if (error < 0)
+		goto error;
+
+	error = ti_ssp_raw_read(gpio->ssp);
+	if (error >= 0)
+		error = (error & BIT(gpio_num)) ? 1 : 0;
+
+error:
+	spin_unlock(&gpio->lock);
+	return error;
+}
+
+static void value_set(struct gpio_chip *chip, unsigned gpio_num, int val)
+{
+	struct ti_ssp_gpio *gpio = chip2gpio(chip);
+
+	spin_lock(&gpio->lock);
+	if (attach_ssp(gpio) < 0)
+		return;
+	if (val)
+		gpio->out |= BIT(gpio_num);
+	else
+		gpio->out &= ~BIT(gpio_num);
+	ti_ssp_raw_write(gpio->ssp, 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 *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->pdata = pdata;
+	gpio->port_data = pdata->port_data;
+	gpio->port_data.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);
+	spin_lock_init(&gpio->lock);
+	platform_set_drvdata(pdev, gpio);
+
+	gpio->chip.base  = gpio->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   = value_get;
+	gpio->chip.set   = value_set;
+	gpio->chip.direction_input  = direction_in;
+	gpio->chip.direction_output = direction_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 *gpio = platform_get_drvdata(pdev);
+	int error;
+
+	error = gpiochip_remove(&gpio->chip);
+	if (error < 0)
+		return error;
+
+	if (gpio->ssp)
+		ti_ssp_close(gpio->ssp);
+	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",
+	.driver.owner	= THIS_MODULE,
+};
+
+static int __init ti_ssp_gpio_init(void)
+{
+	return platform_driver_register(&ti_ssp_gpio_driver);
+}
+
+static void __exit ti_ssp_gpio_exit(void)
+{
+	platform_driver_unregister(&ti_ssp_gpio_driver);
+}
+
+subsys_initcall(ti_ssp_gpio_init);
+module_exit(ti_ssp_gpio_exit);
+
+MODULE_AUTHOR("Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>");
+MODULE_DESCRIPTION("GPIO interface for Texas Instruments SSP");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ti-ssp-gpio");
-- 
1.7.0.4


------------------------------------------------------------------------------
Beautiful is writing same markup. Internet Explorer 9 supports
standards for HTML5, CSS3, SVG 1.1,  ECMAScript5, and DOM L2 & L3.
Spend less time writing and  rewriting code and more time creating great
experiences on the web. Be a part of the beta today.
http://p.sf.net/sfu/beautyoftheweb

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

* [PATCH 09/12] davinci: add tnetv107x evm ti-ssp gpio device
       [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (7 preceding siblings ...)
  2010-10-14 18:38   ` [PATCH 08/12] gpio: add ti-ssp virtual gpio driver Cyril Chemparathy
@ 2010-10-14 18:38   ` Cyril Chemparathy
  2010-10-14 18:38   ` [PATCH 10/12] backlight: add support for tps6116x controller Cyril Chemparathy
                     ` (2 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-14 18:38 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lrg-kDsPt+C1G03kYMGBc/C6ZA,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: 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-l0cyMroinI0@public.gmane.org>
---
 arch/arm/mach-davinci/board-tnetv107x-evm.c |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index 2f13544..7b4f86e 100644
--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -40,6 +40,8 @@
 #include <mach/ti_ssp.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
@@ -263,6 +265,25 @@ static struct platform_device spi_master_device = {
 	.dev.platform_data = &spi_master_data,
 };
 
+static struct ti_ssp_gpio_data ssp_gpio_data = {
+	.port_data = {
+		.ssp_dev_name = "ti-ssp",
+		.port = 0,
+		.iosel = SSP_PIN_SEL(0, SSP_OUT)	|
+			 SSP_PIN_SEL(1, SSP_OUT)	|
+			 SSP_PIN_SEL(2, SSP_OUT)	|
+			 SSP_PIN_SEL(3, SSP_OUT)	|
+			 SSP_INPUT_SEL(3),
+	},
+	.start		= SSP_GPIO_START,
+};
+
+static struct platform_device ssp_gpio_device = {
+	.name		= "ti-ssp-gpio",
+	.id		= 0,
+	.dev.platform_data = &ssp_gpio_data,
+};
+
 static struct regulator_consumer_supply usb_consumers[] = {
 	REGULATOR_SUPPLY("vbus", "musb_hdrc.1"),
 };
@@ -363,6 +384,8 @@ static __init void tnetv107x_evm_board_init(void)
 	tnetv107x_devices_init(&evm_device_info);
 
 	platform_device_register(&spi_master_device);
+	platform_device_register(&ssp_gpio_device);
+
 	spi_register_board_info(spi_info, ARRAY_SIZE(spi_info));
 }
 
-- 
1.7.0.4


------------------------------------------------------------------------------
Beautiful is writing same markup. Internet Explorer 9 supports
standards for HTML5, CSS3, SVG 1.1,  ECMAScript5, and DOM L2 & L3.
Spend less time writing and  rewriting code and more time creating great
experiences on the web. Be a part of the beta today.
http://p.sf.net/sfu/beautyoftheweb

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

* [PATCH 10/12] backlight: add support for tps6116x controller
       [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (8 preceding siblings ...)
  2010-10-14 18:38   ` [PATCH 09/12] davinci: add tnetv107x evm ti-ssp gpio device Cyril Chemparathy
@ 2010-10-14 18:38   ` Cyril Chemparathy
  2010-10-14 18:38   ` [PATCH 11/12] davinci: add tnetv107x evm backlight device Cyril Chemparathy
  2010-10-14 18:38   ` [PATCH 12/12] davinci: add tnetv107x evm i2c eeprom device Cyril Chemparathy
  11 siblings, 0 replies; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-14 18:38 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lrg-kDsPt+C1G03kYMGBc/C6ZA,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: Cyril Chemparathy

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 |  339 ++++++++++++++++++++++++++++++++++++
 3 files changed, 347 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..62c776f
--- /dev/null
+++ b/drivers/video/backlight/tps6116x.c
@@ -0,0 +1,339 @@
+/*
+ * 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, gpio_initialized;
+	struct mutex			lock;
+	int				intensity;
+	int				power;
+	struct backlight_properties	props;
+	struct backlight_device		*bl;
+	int				suspended:1;
+	struct regulator		*regulator;
+};
+
+static int __set_power(struct tps6116x *hw, int power)
+{
+	unsigned long flags;
+	int error;
+
+	power = !!power;
+	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);
+
+	if (!hw->gpio_initialized) {
+		error = gpio_request_one(hw->gpio, GPIOF_DIR_OUT,
+					 dev_name(hw->dev));
+		if (error < 0)
+			goto error;
+		hw->gpio_initialized = 1;
+	}
+
+	error = __set_power(hw, intensity ? 1 : 0);
+	if (error < 0)
+		goto error;
+
+	if (intensity > 0)
+		__set_intensity(hw, intensity);
+
+	hw->intensity = intensity;
+error:
+	mutex_unlock(&hw->lock);
+
+	return error;
+}
+
+static ssize_t intensity_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct tps6116x *hw = dev_get_drvdata(dev);
+	ssize_t len = 0;
+
+	len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", hw->intensity);
+
+	return len;
+}
+
+static ssize_t intensity_store(struct device *dev,
+			       struct device_attribute *attr, const char *buf,
+			       size_t count)
+{
+	struct tps6116x *hw = dev_get_drvdata(dev);
+	unsigned long intensity;
+	int error;
+
+	error = strict_strtoul(buf, 10, &intensity);
+	if (error < 0)
+		return error;
+
+	error = set_intensity(hw, intensity);
+	if (error < 0)
+		return error;
+
+	return count;
+}
+
+DEVICE_ATTR(intensity, S_IWUSR | S_IRUGO, intensity_show, intensity_store);
+
+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)
+		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 = {
+	.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) {
+		error = -ENOMEM;
+		dev_err(dev, "cannot allocate driver data\n");
+		goto fail0;
+	}
+	platform_set_drvdata(pdev, hw);
+
+	memset(hw, 0, sizeof(struct tps6116x));
+	hw->gpio = (int)dev->platform_data;
+	hw->dev = dev;
+
+	mutex_init(&hw->lock);
+
+	error = device_create_file(dev, &dev_attr_intensity);
+	if (error < 0) {
+		dev_err(dev, "cannot create device attributes\n");
+		goto fail1;
+	}
+
+	hw->regulator = regulator_get(dev, "vlcd");
+	if (IS_ERR(hw->regulator)) {
+		error = PTR_ERR(hw->regulator);
+		dev_err(dev, "cannot claim regulator\n");
+		goto fail2;
+	}
+
+	memset(&props, 0, sizeof(props));
+	props.max_brightness = TPS6116X_MAX_INTENSITY;
+	props.brightness     = TPS6116X_DEFAULT_INTENSITY;
+
+	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 fail3;
+	}
+
+	dev_info(dev, "registered backlight controller\n");
+	return 0;
+
+fail3:
+	regulator_put(hw->regulator);
+fail2:
+	device_remove_file(dev, &dev_attr_intensity);
+fail1:
+	kfree(hw);
+	platform_set_drvdata(pdev, NULL);
+fail0:
+	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);
+	device_remove_file(hw->dev, &dev_attr_intensity);
+	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 = 1;
+	update_status(hw->bl);
+	return 0;
+}
+
+static int tps6116x_resume(struct platform_device *pdev)
+{
+	struct tps6116x *hw = platform_get_drvdata(pdev);
+	hw->suspended = 0;
+	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",
+	.driver.owner	= THIS_MODULE,
+};
+
+static int __init tps6116x_init(void)
+{
+	return platform_driver_register(&tps6116x_driver);
+}
+
+static void __exit tps6116x_exit(void)
+{
+	platform_driver_unregister(&tps6116x_driver);
+}
+
+module_init(tps6116x_init);
+module_exit(tps6116x_exit);
+
+MODULE_DESCRIPTION("SSP TPS6116X Driver");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tps6116x");
-- 
1.7.0.4


------------------------------------------------------------------------------
Beautiful is writing same markup. Internet Explorer 9 supports
standards for HTML5, CSS3, SVG 1.1,  ECMAScript5, and DOM L2 & L3.
Spend less time writing and  rewriting code and more time creating great
experiences on the web. Be a part of the beta today.
http://p.sf.net/sfu/beautyoftheweb

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

* [PATCH 11/12] davinci: add tnetv107x evm backlight device
       [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (9 preceding siblings ...)
  2010-10-14 18:38   ` [PATCH 10/12] backlight: add support for tps6116x controller Cyril Chemparathy
@ 2010-10-14 18:38   ` Cyril Chemparathy
  2010-10-14 18:38   ` [PATCH 12/12] davinci: add tnetv107x evm i2c eeprom device Cyril Chemparathy
  11 siblings, 0 replies; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-14 18:38 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lrg-kDsPt+C1G03kYMGBc/C6ZA,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: Cyril Chemparathy

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 |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index 7b4f86e..0a1e9c8 100644
--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -45,6 +45,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)
 {
@@ -375,6 +376,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);
@@ -385,6 +392,7 @@ static __init void tnetv107x_evm_board_init(void)
 
 	platform_device_register(&spi_master_device);
 	platform_device_register(&ssp_gpio_device);
+	platform_device_register(&backlight_device);
 
 	spi_register_board_info(spi_info, ARRAY_SIZE(spi_info));
 }
-- 
1.7.0.4


------------------------------------------------------------------------------
Beautiful is writing same markup. Internet Explorer 9 supports
standards for HTML5, CSS3, SVG 1.1,  ECMAScript5, and DOM L2 & L3.
Spend less time writing and  rewriting code and more time creating great
experiences on the web. Be a part of the beta today.
http://p.sf.net/sfu/beautyoftheweb

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

* [PATCH 12/12] davinci: add tnetv107x evm i2c eeprom device
       [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (10 preceding siblings ...)
  2010-10-14 18:38   ` [PATCH 11/12] davinci: add tnetv107x evm backlight device Cyril Chemparathy
@ 2010-10-14 18:38   ` Cyril Chemparathy
  11 siblings, 0 replies; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-14 18:38 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lrg-kDsPt+C1G03kYMGBc/C6ZA,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
  Cc: Cyril Chemparathy

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 |   35 +++++++++++++++++++++++----
 1 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index 0a1e9c8..2e3d842 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>
@@ -45,6 +48,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)
@@ -270,11 +275,6 @@ static struct ti_ssp_gpio_data ssp_gpio_data = {
 	.port_data = {
 		.ssp_dev_name = "ti-ssp",
 		.port = 0,
-		.iosel = SSP_PIN_SEL(0, SSP_OUT)	|
-			 SSP_PIN_SEL(1, SSP_OUT)	|
-			 SSP_PIN_SEL(2, SSP_OUT)	|
-			 SSP_PIN_SEL(3, SSP_OUT)	|
-			 SSP_INPUT_SEL(3),
 	},
 	.start		= SSP_GPIO_START,
 };
@@ -382,6 +382,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);
@@ -393,8 +416,10 @@ static __init void tnetv107x_evm_board_init(void)
 	platform_device_register(&spi_master_device);
 	platform_device_register(&ssp_gpio_device);
 	platform_device_register(&backlight_device);
+	platform_device_register(&i2c_device);
 
 	spi_register_board_info(spi_info, ARRAY_SIZE(spi_info));
+	i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info));
 }
 
 #ifdef CONFIG_SERIAL_8250_CONSOLE
-- 
1.7.0.4


------------------------------------------------------------------------------
Beautiful is writing same markup. Internet Explorer 9 supports
standards for HTML5, CSS3, SVG 1.1,  ECMAScript5, and DOM L2 & L3.
Spend less time writing and  rewriting code and more time creating great
experiences on the web. Be a part of the beta today.
http://p.sf.net/sfu/beautyoftheweb

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

* Re: [PATCH 06/12] regulator: add driver for tps6524x regulator
       [not found]     ` <1287081535-2864-7-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
@ 2010-10-14 21:03       ` Mark Brown
       [not found]         ` <20101014210323.GB14479-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
  2010-10-16 10:00       ` Mark Brown
  1 sibling, 1 reply; 21+ messages in thread
From: Mark Brown @ 2010-10-14 21:03 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Thu, Oct 14, 2010 at 02:38:49PM -0400, Cyril Chemparathy wrote:
> TPS6524X provides three step-down converters and two general-purpose LDO
> voltage regulators.  This device is interfaced using SPI.
> 
> Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>

This looks mostly good but...

> +static int read(struct tps6524x *hw, int reg)
> +{

I suspect you may run into a namespace issue with this in the future.

> +static const int dcdc1_voltages[] = {
> +	 800000,  825000,  850000,  875000,
> +	 900000,  925000,  950000,  975000,
> +	1000000, 1025000, 1050000, 1075000,
> +	1100000, 1125000, 1150000, 1175000,
> +	1200000, 1225000, 1250000, 1275000,
> +	1300000, 1325000, 1350000, 1375000,
> +	1400000, 1425000, 1450000, 1475000,
> +	1500000, 1525000, 1550000, 1575000,

Looks like you could just do the maths for most of these tables, might
be a bit clearer/simpler?  Not a major issue either way, though.

> +static int list_voltage(struct regulator_dev *rdev, unsigned selector)
> +{
> +	const struct supply_info *info;
> +	struct tps6524x *hw;
> +
> +	hw	= rdev_get_drvdata(rdev);
> +	info	= &supply_info[rdev_get_id(rdev)];
> +
> +	if (info->flags & FIXED_VOLTAGE)
> +		return selector ? -EINVAL : info->fixed_voltage;
> +	else
> +		return (selector < 0 || selector >= info->n_voltages) ?
> +			-EINVAL : info->voltages[selector];

I'm not sure the ternery operator is helping legibility here - if
statements might be more legible.

> +	ret = read_field(hw, &info->voltage);
> +	if (ret < 0)
> +		return ret;
> +	if (ret >= info->n_voltages)
> +		return -EINVAL;

Shouldn't this be warning somehow - if we can't understand the register
setting that'd be a driver bug, -EINVAL makes it sound like an invalid
parameter was supplied.  Similarly for the current limit.

> +static ssize_t show_reg(struct device *dev, struct device_attribute *attr,
> +			char *buf);
> +static ssize_t store_reg(struct device *dev, struct device_attribute *attr,
> +			 const char *buf, size_t size);
> +
> +static DEVICE_ATTR(ldo_set,	0664, show_reg, store_reg);
> +static DEVICE_ATTR(block_en,	0664, show_reg, store_reg);
> +static DEVICE_ATTR(dcdc_set,	0664, show_reg, store_reg);
> +static DEVICE_ATTR(dcdc_en,	0664, show_reg, store_reg);
> +static DEVICE_ATTR(usb,		0664, show_reg, store_reg);
> +static DEVICE_ATTR(alarm,	0664, show_reg, store_reg);
> +static DEVICE_ATTR(int_enable,	0664, show_reg, store_reg);
> +static DEVICE_ATTR(int_status,	0664, show_reg, store_reg);
> +static DEVICE_ATTR(rev_id,	0664, show_reg, store_reg);
> +static DEVICE_ATTR(write_enable,   0664, show_reg, store_reg);
> +static DEVICE_ATTR(software_reset, 0664, show_reg, store_reg);

Large chunks of this looks like it's exporting functionality which is
part of the regulator API to userspace, replicating functionality which
the API provides.  Please either remove or replace with standard
functionality.

The USB setting should be integrated with the USB subsystem, assuming
it's changing a USB current limit.

> +	init_data = dev->platform_data;
> +	if (!init_data) {
> +		dev_err(dev, "could not find regulator platform data\n");
> +		return -EIO;
> +	}

EIO doesn't look right here...

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

* Re: [PATCH 07/12] davinci: add tnetv107x evm regulators
       [not found]     ` <1287081535-2864-8-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
@ 2010-10-14 21:05       ` Mark Brown
  0 siblings, 0 replies; 21+ messages in thread
From: Mark Brown @ 2010-10-14 21:05 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Thu, Oct 14, 2010 at 02:38:50PM -0400, Cyril Chemparathy wrote:

> +	{
> +		.num_consumer_supplies	= ARRAY_SIZE(usb_consumers),
> +		.consumer_supplies	= usb_consumers,
> +		.constraints		= {
> +			.name		= "USB",
> +			.min_uV		= 5000000,
> +			.max_uV		= 5000000,
> +			.min_uA		= 200000,
> +			.max_uA		= 1000000,

Are you *sure* about the min_uA here - what would be the goal of
enforcing a minimum current draw?  For a voltage regulator current limit
usually only an upper limit would be specified.  The same applies to
several other machine drivers in the series.

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

* Re: [PATCH 01/12] misc: add driver for sequencer serial port
       [not found]     ` <1287081535-2864-2-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
@ 2010-10-16  5:00       ` Grant Likely
       [not found]         ` <20101016050055.GH21170-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
  0 siblings, 1 reply; 21+ messages in thread
From: Grant Likely @ 2010-10-16  5:00 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Thu, Oct 14, 2010 at 02:38:44PM -0400, Cyril Chemparathy wrote:
> 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>

Hi Cyril,

Overall the driver looks pretty clean, but I have an issue with the
usage model (see below).

> ---
>  arch/arm/mach-davinci/include/mach/ti_ssp.h |   92 ++++++
>  drivers/misc/Kconfig                        |   11 +
>  drivers/misc/Makefile                       |    1 +
>  drivers/misc/ti_ssp.c                       |  443 +++++++++++++++++++++++++++
>  4 files changed, 547 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-davinci/include/mach/ti_ssp.h
>  create mode 100644 drivers/misc/ti_ssp.c
> 
> diff --git a/arch/arm/mach-davinci/include/mach/ti_ssp.h b/arch/arm/mach-davinci/include/mach/ti_ssp.h
> new file mode 100644
> index 0000000..8365101
> --- /dev/null
> +++ b/arch/arm/mach-davinci/include/mach/ti_ssp.h
> @@ -0,0 +1,92 @@
> +/*
> + * 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_data {
> +	unsigned long		out_clock;
> +};
> +
> +struct ti_ssp_port_data {
> +	const char	*ssp_dev_name;
> +	int		port;
> +	unsigned long	iosel; /* see note below */
> +	unsigned long	config;
> +};
> +
> +struct ti_ssp_port;
> +
> +/*
> + * 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)
> +
> +struct ti_ssp_port *ti_ssp_open(const struct ti_ssp_port_data *data);
> +int ti_ssp_close(struct ti_ssp_port *dev);
> +int ti_ssp_dumpregs(struct ti_ssp_port *dev);
> +int ti_ssp_raw_read(struct ti_ssp_port *dev);
> +int ti_ssp_raw_write(struct ti_ssp_port *dev, u32 val);
> +int ti_ssp_load(struct ti_ssp_port *dev, int offs, u32* prog, int len);
> +int ti_ssp_run(struct ti_ssp_port *dev, u32 pc, u32 input, u32 *output);
> +int ti_ssp_set_mode(struct ti_ssp_port *dev, int mode);
> +int ti_ssp_set_iosel(struct ti_ssp_port *dev, u32 iosel);
> +
> +#endif /* __TI_SSP_H__ */
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index b743312..9fb8470 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -390,6 +390,17 @@ config BMP085
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called bmp085.
>  
> +config TI_SSP
> +	depends on ARCH_DAVINCI_TNETV107X
> +	tristate "Sequencer Serial Port support"
> +	default y
> +	---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.
> +
>  source "drivers/misc/c2port/Kconfig"
>  source "drivers/misc/eeprom/Kconfig"
>  source "drivers/misc/cb710/Kconfig"
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index 42eab95..7568100 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -28,6 +28,7 @@ obj-$(CONFIG_SENSORS_TSL2550)	+= tsl2550.o
>  obj-$(CONFIG_EP93XX_PWM)	+= ep93xx_pwm.o
>  obj-$(CONFIG_DS1682)		+= ds1682.o
>  obj-$(CONFIG_TI_DAC7512)	+= ti_dac7512.o
> +obj-$(CONFIG_TI_SSP)		+= ti_ssp.o
>  obj-$(CONFIG_C2PORT)		+= c2port/
>  obj-$(CONFIG_IWMC3200TOP)      += iwmc3200top/
>  obj-$(CONFIG_HMC6352)		+= hmc6352.o
> diff --git a/drivers/misc/ti_ssp.c b/drivers/misc/ti_ssp.c
> new file mode 100644
> index 0000000..edbc94d
> --- /dev/null
> +++ b/drivers/misc/ti_ssp.c
> @@ -0,0 +1,443 @@
> +/*
> + * 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 <mach/ti_ssp.h>
> +
> +/* Register Offsets */
> +#define SSP_REG_REV		0x00
> +#define SSP_REG_IOSEL_1		0x04
> +#define SSP_REG_IOSEL_2		0x08
> +#define SSP_REG_PREDIV		0x0c
> +#define SSP_REG_INTR_STAT	0x10
> +#define SSP_REG_INTR_EN		0x14
> +#define SSP_REG_TEST_CTRL	0x18
> +
> +/* Per port registers */
> +#define SSP_PORT_REG_CFG_2	0x00
> +#define SSP_PORT_REG_ADDR	0x04
> +#define SSP_PORT_REG_DATA	0x08
> +#define SSP_PORT_REG_CFG_1	0x0c
> +#define SSP_PORT_REG_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};
> +
> +/* Register Access Macros */
> +#define ssp_read(ssp, reg)	 __raw_readl((ssp)->regs + SSP_REG_##reg)
> +#define ssp_write(ssp, reg, val) __raw_writel(val, (ssp)->regs + SSP_REG_##reg)
> +
> +#define ssp_rmw(ssp, reg, mask, bits)				\
> +	ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~(mask)) | (bits))
> +
> +#define ssp_port_read(ssp, port, reg)				\
> +	__raw_readl((ssp)->regs + ssp_port_base[port] +		\
> +		    SSP_PORT_REG_##reg)
> +
> +#define ssp_port_write(ssp, port, reg, val)			\
> +	__raw_writel(val, (ssp)->regs + ssp_port_base[port] +	\
> +		     SSP_PORT_REG_##reg)
> +
> +#define ssp_port_rmw(ssp, port, reg, mask, bits)		\
> +	ssp_port_write(ssp, port, reg,				\
> +		       (ssp_port_read(ssp, port, reg) & ~(mask)) | (bits))
> +
> +#define ssp_port_clr_bits(ssp, port, reg, bits)	\
> +	ssp_port_rmw(ssp, port, reg, bits, 0)
> +
> +#define ssp_port_set_bits(ssp, port, reg, bits)	\
> +	ssp_port_rmw(ssp, port, reg, 0, bits)

Consider programming in c rather than preprocessor.  You could use
static inlines here.

> +
> +struct ti_ssp {
> +	struct resource			*res;
> +	void __iomem			*regs;
> +	struct timer_list		timer;
> +	struct ti_ssp_port		*ports[2];
> +	spinlock_t			lock;
> +	struct clk			*clk;
> +	struct device			*dev;
> +};
> +
> +struct ti_ssp_port {
> +	int		num;
> +	struct ti_ssp	*ssp;
> +	spinlock_t	lock;
> +};
> +
> +struct ti_ssp_port *ti_ssp_open(const struct ti_ssp_port_data *data)
> +{
> +	struct ti_ssp		*ssp;
> +	struct ti_ssp_port	*port;
> +	struct device		*dev;
> +	int			error = 0;
> +
> +	dev = bus_find_device_by_name(&platform_bus_type, NULL,
> +				      data->ssp_dev_name);
> +	if (!dev || !dev->driver)
> +		return ERR_PTR(-ENODEV);
> +
> +	if (!get_device(dev))
> +		return ERR_PTR(-ENODEV);
> +
> +	ssp = platform_get_drvdata(to_platform_device(dev));
> +	if (!ssp) {
> +		error = -ENODEV;
> +		goto error_put;
> +	}
> +
> +	port = kzalloc(sizeof(*port), GFP_KERNEL);
> +	if (!port) {
> +		error = -ENOMEM;
> +		goto error_put;
> +	}
> +
> +	port->num = data->port;
> +	port->ssp = ssp;
> +	spin_lock_init(&port->lock);
> +
> +	spin_lock(&ssp->lock);
> +
> +	if (ssp->ports[port->num]) {
> +		error = -EBUSY;
> +		goto error_unlock;
> +	}
> +
> +	ssp->ports[port->num] = port;
> +
> +	spin_unlock(&ssp->lock);
> +
> +	ti_ssp_set_iosel(port, data->iosel);
> +
> +	spin_lock(&port->lock);
> +	ssp_port_rmw(ssp, port->num, CFG_1, SSP_PORT_CONFIG_MASK,
> +		     data->config);
> +	ssp_port_rmw(ssp, port->num, CFG_2, SSP_PORT_CLKRATE_MASK, 0);
> +	spin_unlock(&port->lock);
> +
> +	return port;
> +
> +error_unlock:
> +	spin_unlock(&ssp->lock);
> +error_put:
> +	put_device(dev);
> +	return ERR_PTR(error);
> +}
> +EXPORT_SYMBOL(ti_ssp_open);

I'm not thrilled with the ti_ssp_open()/ti_ssp_close() usage model.
It appears that the usage model is the board code registers an pile
of platform_devices, one for the ssp, and one for each of the
behaviours on top of it.  Then the various driver instances have to
figure out how to find each other and whether or not they are related.
Am I correct?

Rather than doing an end-run around the Linux driver model, I strongly
recommend using the model to solve your problem.  Register only the
ssp platform_device in the board support code and pass it data about
the intended behaviour (via platform data).  When it gets probed, it
can then register additional platform devices which will get probed by
the requested driver.  That way the specific ssp device instance data
can be passed reliably to the spi/i2c/whatever driver without any
ambiguity, without any uncertainty about whether a port is 'busy', and
without the need of these open/close routines.

(Hint: The trick is to set the platform_device's pdev->dev.parent
pointer to make use of the Linux device model's hierarchy).

> +
> +int ti_ssp_close(struct ti_ssp_port *port)
> +{
> +	if (!port || !port->ssp)
> +		return -EINVAL;
> +	port->ssp->ports[port->num] = NULL;
> +	put_device(port->ssp->dev);
> +	kfree(port);
> +	return 0;
> +}
> +EXPORT_SYMBOL(ti_ssp_close);
> +
> +int ti_ssp_set_mode(struct ti_ssp_port *port, int mode)
> +{
> +	if (!port || !port->ssp)
> +		return -EINVAL;
> +
> +	spin_lock(&port->lock);
> +	mode &= SSP_PORT_CONFIG_MASK;
> +	ssp_port_rmw(port->ssp, port->num, CFG_1, SSP_PORT_CONFIG_MASK, mode);
> +	spin_unlock(&port->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ti_ssp_set_mode);
> +
> +int ti_ssp_set_iosel(struct ti_ssp_port *port, u32 iosel)
> +{
> +	unsigned int		val;
> +
> +	if (!port || !port->ssp)
> +		return -EINVAL;
> +
> +	spin_lock(&port->lock);
> +
> +	/* IOSEL1 gets the least significant 16 bits */
> +	val = ssp_read(port->ssp, IOSEL_1);
> +	val &= 0xffff << (port->num ? 0 : 16);
> +	val |= (iosel & 0xffff) << (port->num ? 16 : 0);
> +	ssp_write(port->ssp, IOSEL_1, val);
> +
> +	/* IOSEL2 gets the most significant 16 bits */
> +	val = ssp_read(port->ssp, IOSEL_2);
> +	val &= 0x0007 << (port->num ? 0 : 16);
> +	val |= (iosel & 0x00070000) >> (port->num ? 0 : 16);
> +	ssp_write(port->ssp, IOSEL_2, val);
> +
> +	spin_unlock(&port->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ti_ssp_set_iosel);
> +
> +int ti_ssp_load(struct ti_ssp_port *port, int offs, u32* prog, int len)
> +{
> +	int i;
> +
> +	if (!port || !port->ssp)
> +		return -EINVAL;
> +
> +	if (len > SSP_PORT_SEQRAM_SIZE)
> +		return -ENOSPC;
> +
> +	spin_lock(&port->lock);
> +
> +	/* Enable SeqRAM access */
> +	ssp_port_set_bits(port->ssp, port->num, CFG_2, SSP_SEQRAM_WR_EN);
> +
> +	/* Copy code */
> +	for (i = 0; i < len; i++) {
> +		__raw_writel(prog[i], port->ssp->regs + offs + 4*i +
> +			     ssp_port_seqram[port->num]);
> +	}
> +
> +	/* Disable SeqRAM access */
> +	ssp_port_clr_bits(port->ssp, port->num, CFG_2, SSP_SEQRAM_WR_EN);
> +
> +	spin_unlock(&port->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ti_ssp_load);
> +
> +int ti_ssp_raw_read(struct ti_ssp_port *port)
> +{
> +	u32 val;
> +
> +	if (!port || !port->ssp)
> +		return -EINVAL;
> +
> +	val = ssp_read(port->ssp, IOSEL_2);
> +	val >>= (port->num ? 27 : 11);
> +
> +	return val & 0x0f;
> +}
> +EXPORT_SYMBOL(ti_ssp_raw_read);
> +
> +int ti_ssp_raw_write(struct ti_ssp_port *port, u32 val)
> +{
> +	u32 mask;
> +
> +	if (!port || !port->ssp)
> +		return -EINVAL;
> +
> +	spin_lock(&port->ssp->lock);
> +	val &= 0x0f;
> +	val <<= (port->num ? 22 : 6);
> +	mask = 0x0f;
> +	mask <<= (port->num ? 22 : 6);
> +	ssp_rmw(port->ssp, IOSEL_2, mask, val);
> +	spin_unlock(&port->ssp->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ti_ssp_raw_write);
> +
> +int ti_ssp_run(struct ti_ssp_port *port, u32 pc, u32 input, u32 *output)
> +{
> +	struct ti_ssp *ssp;
> +	int count;
> +
> +	if (!port || !port->ssp)
> +		return -EINVAL;
> +	ssp = port->ssp;
> +
> +	if (pc & ~(0x3f))
> +		return -EINVAL;
> +
> +	ssp_port_write(ssp, port->num, ADDR, input >> 16);
> +	ssp_port_write(ssp, port->num, DATA, input & 0xffff);
> +	ssp_port_rmw(ssp, port->num, CFG_1, 0x3f, pc);
> +
> +	ssp_port_set_bits(ssp, port->num, CFG_1, SSP_START);
> +
> +	for (count = 10000; count; count--) {
> +		if ((ssp_port_read(ssp, port->num, CFG_1) & SSP_BUSY) == 0)
> +			break;
> +		udelay(1);
> +	}
> +
> +	if (output) {
> +		*(output) = (ssp_port_read(ssp, port->num, ADDR) << 16) |
> +			    (ssp_port_read(ssp, port->num, DATA) &  0xffff);
> +	}
> +
> +	if (!count) {
> +		dev_err(ssp->dev, "timed out waiting for SSP operation\n");
> +		return -EIO;
> +	}
> +
> +	/* return stop address */
> +	return ssp_port_read(ssp, port->num, STATE) & 0x3f;
> +}
> +EXPORT_SYMBOL(ti_ssp_run);
> +
> +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 ret = 0, prediv = 0xff;
> +	unsigned long sysclk;
> +	struct device *dev = &pdev->dev;
> +
> +	ssp = kzalloc(sizeof(*ssp), GFP_KERNEL);
> +	if (!ssp) {
> +		dev_err(dev, "cannot allocate device info\n");
> +		return -ENOMEM;
> +	}
> +
> +	ssp->dev = dev;
> +	platform_set_drvdata(pdev, ssp);
> +
> +	ret = -ENODEV;
> +	ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!ssp->res) {
> +		dev_err(dev, "cannot determine register area\n");
> +		goto error_res;
> +	}
> +
> +	ret = -EINVAL;
> +	if (!request_mem_region(ssp->res->start, resource_size(ssp->res),
> +				pdev->name)) {
> +		dev_err(dev, "cannot claim register memory\n");
> +		goto error_res;
> +	}
> +
> +	ret = -ENOMEM;
> +	ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res));
> +	if (!ssp->regs) {
> +		dev_err(dev, "cannot map register memory\n");
> +		goto error_map;
> +	}
> +
> +	ret = -EINVAL;
> +	ssp->clk = clk_get(dev, NULL);
> +	if (IS_ERR(ssp->clk)) {
> +		dev_err(dev, "cannot claim device clock\n");
> +		goto error_clk;
> +	}
> +
> +	spin_lock_init(&ssp->lock);
> +
> +	platform_set_drvdata(pdev, ssp);
> +
> +	/* Power on and initialize SSP */
> +	ret = clk_enable(ssp->clk);
> +	if (ret)
> +		goto error_enable;
> +
> +	/* Reset registers to a sensible known state */
> +	ssp_write(ssp, IOSEL_1, 0);
> +	ssp_write(ssp, IOSEL_2, 0);
> +	ssp_write(ssp, INTR_EN, 0);
> +	ssp_write(ssp, TEST_CTRL, 0);
> +	ssp_port_write(ssp, 0, CFG_1, SSP_PORT_ASL);
> +	ssp_port_write(ssp, 1, CFG_1, SSP_PORT_ASL);
> +	ssp_port_write(ssp, 0, CFG_2, SSP_PORT_CFO1);
> +	ssp_port_write(ssp, 1, 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, PREDIV, 0xff, prediv);
> +
> +	return 0;
> +
> +error_enable:
> +	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 ret;
> +}
> +
> +static int __devexit ti_ssp_remove(struct platform_device *pdev)
> +{
> +	struct ti_ssp *ssp = platform_get_drvdata(pdev);
> +
> +	clk_disable(ssp->clk);
> +	clk_put(ssp->clk);
> +	iounmap(ssp->regs);
> +	release_mem_region(ssp->res->start, resource_size(ssp->res));
> +	kfree(ssp);
> +	platform_set_drvdata(pdev, NULL);
> +	return 0;
> +}
> +
> +static struct platform_driver ti_ssp_driver = {
> +	.probe		= ti_ssp_probe,
> +	.remove		= __devexit_p(ti_ssp_remove),
> +	.driver.name	= "ti-ssp",
> +	.driver.owner	= THIS_MODULE,
> +};

Personally, I prefer the following form (comment goes for the whole series):

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);
> +}
> +
> +static void __exit ti_ssp_exit(void)
> +{
> +	platform_driver_unregister(&ti_ssp_driver);
> +}
> +
> +arch_initcall_sync(ti_ssp_init);

Keep the initicall line together with the ti_ssp_init definition (goes
for the whole series).

> +module_exit(ti_ssp_exit);
> +
> +MODULE_AUTHOR("Cyril Chemparathy");
> +MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
> +MODULE_ALIAS("platform:ti_ssp");
> +MODULE_LICENSE("GPL");
> -- 
> 1.7.0.4
> 
> 
> ------------------------------------------------------------------------------
> Beautiful is writing same markup. Internet Explorer 9 supports
> standards for HTML5, CSS3, SVG 1.1,  ECMAScript5, and DOM L2 & L3.
> Spend less time writing and  rewriting code and more time creating great
> experiences on the web. Be a part of the beta today.
> http://p.sf.net/sfu/beautyoftheweb
> _______________________________________________
> spi-devel-general mailing list
> spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
> https://lists.sourceforge.net/lists/listinfo/spi-devel-general

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

* Re: [PATCH 04/12] spi: add ti-ssp spi master driver
       [not found]     ` <1287081535-2864-5-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
@ 2010-10-16  5:05       ` Grant Likely
  0 siblings, 0 replies; 21+ messages in thread
From: Grant Likely @ 2010-10-16  5:05 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Thu, Oct 14, 2010 at 02:38:47PM -0400, Cyril Chemparathy wrote:
> This patch adds an SPI master implementation that operates on top of an
> underlying TI-SSP port.
> 
> Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>

The driver looks good, but as mentioned in my previous comment, I'd
like to see the usage model fixed to make proper use of the linux
driver model before I ack it.

g.

> ---
>  arch/arm/mach-davinci/include/mach/ti_ssp.h |    6 +
>  drivers/spi/Kconfig                         |    6 +
>  drivers/spi/Makefile                        |    1 +
>  drivers/spi/spi_ti_ssp.c                    |  408 +++++++++++++++++++++++++++
>  4 files changed, 421 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/spi/spi_ti_ssp.c
> 
> diff --git a/arch/arm/mach-davinci/include/mach/ti_ssp.h b/arch/arm/mach-davinci/include/mach/ti_ssp.h
> index 8365101..532b0a3 100644
> --- a/arch/arm/mach-davinci/include/mach/ti_ssp.h
> +++ b/arch/arm/mach-davinci/include/mach/ti_ssp.h
> @@ -32,6 +32,12 @@ struct ti_ssp_port_data {
>  	unsigned long	config;
>  };
>  
> +struct ti_ssp_spi_data {
> +	struct ti_ssp_port_data	port_data;
> +	int			num_cs;
> +	void			(*select)(int cs);
> +};
> +
>  struct ti_ssp_port;
>  
>  /*
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index 91c2f4f..c1937e4 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -298,6 +298,12 @@ config SPI_STMP3XXX
>  	help
>  	  SPI driver for Freescale STMP37xx/378x SoC SSP interface
>  
> +config SPI_TI_SSP
> +	tristate "TI SSP Controller SPI Driver"
> +	depends on SPI_MASTER && TI_SSP
> +	help
> +	  SPI master implementation using a TI sequencer serial port.
> +
>  config SPI_TXX9
>  	tristate "Toshiba TXx9 SPI controller"
>  	depends on GENERIC_GPIO && CPU_TX49XX
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index e9cbd18..953aba7 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_TXX9)			+= spi_txx9.o
> +obj-$(CONFIG_SPI_TI_SSP)		+= spi_ti_ssp.o
>  obj-$(CONFIG_SPI_XILINX)		+= xilinx_spi.o
>  obj-$(CONFIG_SPI_XILINX_OF)		+= xilinx_spi_of.o
>  obj-$(CONFIG_SPI_XILINX_PLTFM)		+= xilinx_spi_pltfm.o
> diff --git a/drivers/spi/spi_ti_ssp.c b/drivers/spi/spi_ti_ssp.c
> new file mode 100644
> index 0000000..132684c
> --- /dev/null
> +++ b/drivers/spi/spi_ti_ssp.c
> @@ -0,0 +1,408 @@
> +/*
> + * 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 <mach/ti_ssp.h>
> +
> +#define MODE_BITS	(SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
> +
> +struct ti_ssp_spi {
> +	struct spi_master		*master;
> +	const struct ti_ssp_spi_data	*pdata;
> +	struct device			*dev;
> +	spinlock_t			lock;
> +	struct list_head		msg_queue;
> +	struct completion		complete;
> +	int				shutdown:1;
> +	struct workqueue_struct		*workqueue;
> +	struct work_struct		work;
> +	u8				mode, bpw;
> +	int				cs_active;
> +	struct ti_ssp_port		*ssp;
> +	u32				pc_en, pc_dis, pc_wr, pc_rd;
> +};
> +
> +static u32 do_read_data(struct ti_ssp_spi *hw)
> +{
> +	u32 ret;
> +
> +	ti_ssp_run(hw->ssp, hw->pc_rd, 0, &ret);
> +	return ret;
> +}
> +
> +static void do_write_data(struct ti_ssp_spi *hw, u32 data)
> +{
> +	ti_ssp_run(hw->ssp, hw->pc_wr, data << (32 - hw->bpw), NULL);
> +}
> +
> +static int do_transfer(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)
> +				do_write_data(hw, *tx++);
> +			if (t->rx_buf)
> +				*rx++ = do_read_data(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)
> +				do_write_data(hw, *tx++);
> +			if (t->rx_buf)
> +				*rx++ = do_read_data(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)
> +				do_write_data(hw, *tx++);
> +			if (t->rx_buf)
> +				*rx++ = do_read_data(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 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->ssp, 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 setup_xfer(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->ssp, 0, seqram, idx);
> +	if (error < 0)
> +		return error;
> +
> +	error = ti_ssp_set_mode(hw->ssp, ((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_irq(&hw->lock);
> +
> +	 while (!list_empty(&hw->msg_queue)) {

Errant space ' ' before while statement.

> +		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);
> +
> +		spi = m->spi;
> +
> +		if (hw->pdata->select)
> +			hw->pdata->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 (setup_xfer(hw, bpw, spi->mode) < 0)
> +				break;
> +
> +			chip_select(hw, 1);
> +
> +			spin_unlock_irq(&hw->lock);
> +
> +			xfer_status = do_transfer(hw, m, t);
> +			if (xfer_status < 0)
> +				status = xfer_status;
> +
> +			if (t->delay_usecs)
> +				udelay(t->delay_usecs);
> +
> +			spin_lock_irq(&hw->lock);
> +
> +			if (t->cs_change)
> +				chip_select(hw, 0);
> +		}
> +
> +		chip_select(hw, 0);
> +		m->status = status;
> +		m->complete(m->context);
> +	}
> +
> +	if (hw->shutdown)
> +		complete(&hw->complete);
> +
> +	spin_unlock_irq(&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;
> +	unsigned long		flags;
> +	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_irqsave(&hw->lock, flags);
> +	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_irqrestore(&hw->lock, flags);
> +	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->pdata = pdata;
> +
> +	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;
> +	}
> +
> +	hw->ssp = ti_ssp_open(&hw->pdata->port_data);
> +	if (IS_ERR(hw->ssp)) {
> +		error = PTR_ERR(hw->ssp);
> +		dev_err(dev, "ssp open failed (%d)\n", error);
> +		goto error_open;
> +	}
> +
> +	master->bus_num		= pdev->id;
> +	master->num_chipselect	= hw->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:
> +	ti_ssp_close(hw->ssp);
> +error_open:
> +	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;
> +		}
> +	}
> +
> +	ti_ssp_close(hw->ssp);
> +	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",
> +	.driver.owner	= THIS_MODULE,
> +};
> +
> +static int __init ti_ssp_spi_init(void)
> +{
> +	return platform_driver_register(&ti_ssp_spi_driver);
> +}
> +
> +static void __exit ti_ssp_spi_exit(void)
> +{
> +	platform_driver_unregister(&ti_ssp_spi_driver);
> +}
> +
> +subsys_initcall(ti_ssp_spi_init);
> +module_exit(ti_ssp_spi_exit);
> +
> +MODULE_DESCRIPTION("SSP SPI Master");
> +MODULE_AUTHOR("Cyril Chemparathy");
> +MODULE_ALIAS("platform:spi_ti_ssp");
> +MODULE_LICENSE("GPL");
> -- 
> 1.7.0.4
> 
> 
> ------------------------------------------------------------------------------
> Beautiful is writing same markup. Internet Explorer 9 supports
> standards for HTML5, CSS3, SVG 1.1,  ECMAScript5, and DOM L2 & L3.
> Spend less time writing and  rewriting code and more time creating great
> experiences on the web. Be a part of the beta today.
> http://p.sf.net/sfu/beautyoftheweb
> _______________________________________________
> spi-devel-general mailing list
> spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
> https://lists.sourceforge.net/lists/listinfo/spi-devel-general

------------------------------------------------------------------------------
Download new Adobe(R) Flash(R) Builder(TM) 4
The new Adobe(R) Flex(R) 4 and Flash(R) Builder(TM) 4 (formerly 
Flex(R) Builder(TM)) enable the development of rich applications that run
across multiple browsers and platforms. Download your free trials today!
http://p.sf.net/sfu/adobe-dev2dev

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

* Re: [PATCH 06/12] regulator: add driver for tps6524x regulator
       [not found]     ` <1287081535-2864-7-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2010-10-14 21:03       ` Mark Brown
@ 2010-10-16 10:00       ` Mark Brown
  1 sibling, 0 replies; 21+ messages in thread
From: Mark Brown @ 2010-10-16 10:00 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Thu, Oct 14, 2010 at 02:38:49PM -0400, Cyril Chemparathy wrote:
> TPS6524X provides three step-down converters and two general-purpose LDO
> voltage regulators.  This device is interfaced using SPI.
> 
> Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>

My review comments from the previous posting do not appear to have been
addressed or responded to?

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

* Re: [PATCH 06/12] regulator: add driver for tps6524x regulator
       [not found]         ` <20101014210323.GB14479-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
@ 2010-10-18 12:50           ` Cyril Chemparathy
  0 siblings, 0 replies; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-18 12:50 UTC (permalink / raw)
  To: Mark Brown
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

Hi Mark,

Thanks for the feedback.  I agree with your comments, and I will make
the necessary changes before posting a v2.

The one exception being...

[...]
>> +static const int dcdc1_voltages[] = {
>> +	 800000,  825000,  850000,  875000,
>> +	 900000,  925000,  950000,  975000,
>> +	1000000, 1025000, 1050000, 1075000,
>> +	1100000, 1125000, 1150000, 1175000,
>> +	1200000, 1225000, 1250000, 1275000,
>> +	1300000, 1325000, 1350000, 1375000,
>> +	1400000, 1425000, 1450000, 1475000,
>> +	1500000, 1525000, 1550000, 1575000,
> 
> Looks like you could just do the maths for most of these tables, might
> be a bit clearer/simpler?  Not a major issue either way, though.

... not all of the supplies are linear (e.g. ldo2).  Rather than have to
deal with both cases (linear and non-linear), enumerating the list of
voltages appeared to be simpler.

[...]

Regards
Cyril.

------------------------------------------------------------------------------
Download new Adobe(R) Flash(R) Builder(TM) 4
The new Adobe(R) Flex(R) 4 and Flash(R) Builder(TM) 4 (formerly 
Flex(R) Builder(TM)) enable the development of rich applications that run
across multiple browsers and platforms. Download your free trials today!
http://p.sf.net/sfu/adobe-dev2dev

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

* Re: [PATCH 01/12] misc: add driver for sequencer serial port
       [not found]         ` <20101016050055.GH21170-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
@ 2010-10-18 13:56           ` Cyril Chemparathy
       [not found]             ` <4CBC520B.9070502-l0cyMroinI0@public.gmane.org>
  0 siblings, 1 reply; 21+ messages in thread
From: Cyril Chemparathy @ 2010-10-18 13:56 UTC (permalink / raw)
  To: Grant Likely
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

Hi Grant,

Thanks for the feedback, I will send out an updated v2 with the proposed
changes.

[...]
>> +EXPORT_SYMBOL(ti_ssp_open);
> 
> I'm not thrilled with the ti_ssp_open()/ti_ssp_close() usage model.
> It appears that the usage model is the board code registers an pile
> of platform_devices, one for the ssp, and one for each of the
> behaviours on top of it.  Then the various driver instances have to
> figure out how to find each other and whether or not they are related.
> Am I correct?
> 
> Rather than doing an end-run around the Linux driver model, I strongly
> recommend using the model to solve your problem.  Register only the
> ssp platform_device in the board support code and pass it data about
> the intended behaviour (via platform data).  When it gets probed, it
> can then register additional platform devices which will get probed by
> the requested driver.  That way the specific ssp device instance data
> can be passed reliably to the spi/i2c/whatever driver without any
> ambiguity, without any uncertainty about whether a port is 'busy', and
> without the need of these open/close routines.
> 
> (Hint: The trick is to set the platform_device's pdev->dev.parent
> pointer to make use of the Linux device model's hierarchy).

I am not very thrilled with this approach either :-)  I had looked at a
few other instances where something similar was being done (spi, i2c,
mdio, etc.), but felt that defining a new bus type would be an overkill
for this.

For reference, could you please point me to some other place where
something similar is being done?

Regards
Cyril.

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

* Re: [PATCH 01/12] misc: add driver for sequencer serial port
       [not found]             ` <4CBC520B.9070502-l0cyMroinI0@public.gmane.org>
@ 2010-10-18 14:59               ` Grant Likely
  0 siblings, 0 replies; 21+ messages in thread
From: Grant Likely @ 2010-10-18 14:59 UTC (permalink / raw)
  To: cyril-l0cyMroinI0
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Mon, Oct 18, 2010 at 7:56 AM, Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org> wrote:
> Hi Grant,
>
> Thanks for the feedback, I will send out an updated v2 with the proposed
> changes.
>
> [...]
>>> +EXPORT_SYMBOL(ti_ssp_open);
>>
>> I'm not thrilled with the ti_ssp_open()/ti_ssp_close() usage model.
>> It appears that the usage model is the board code registers an pile
>> of platform_devices, one for the ssp, and one for each of the
>> behaviours on top of it.  Then the various driver instances have to
>> figure out how to find each other and whether or not they are related.
>> Am I correct?
>>
>> Rather than doing an end-run around the Linux driver model, I strongly
>> recommend using the model to solve your problem.  Register only the
>> ssp platform_device in the board support code and pass it data about
>> the intended behaviour (via platform data).  When it gets probed, it
>> can then register additional platform devices which will get probed by
>> the requested driver.  That way the specific ssp device instance data
>> can be passed reliably to the spi/i2c/whatever driver without any
>> ambiguity, without any uncertainty about whether a port is 'busy', and
>> without the need of these open/close routines.
>>
>> (Hint: The trick is to set the platform_device's pdev->dev.parent
>> pointer to make use of the Linux device model's hierarchy).
>
> I am not very thrilled with this approach either :-)  I had looked at a
> few other instances where something similar was being done (spi, i2c,
> mdio, etc.), but felt that defining a new bus type would be an overkill
> for this.

Nope!  you don't need to define a new bus type.  Just continue to use
platform bus.  If you set the dev->parent pointer before registering
the device then the device model with have the appropriate hierarchy.

> For reference, could you please point me to some other place where
> something similar is being done?

Most of the multifunction devices operating in this way (though those
implementations are probably more convoluted than they need to be.
Take a look.  If you still have trouble with it let me know and I'll
draft an example for you.

g.

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

end of thread, other threads:[~2010-10-18 14:59 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-10-14 18:38 [PATCH 00/12] tnetv107x ssp driver stack Cyril Chemparathy
     [not found] ` <1287081535-2864-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
2010-10-14 18:38   ` [PATCH 01/12] misc: add driver for sequencer serial port Cyril Chemparathy
     [not found]     ` <1287081535-2864-2-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
2010-10-16  5:00       ` Grant Likely
     [not found]         ` <20101016050055.GH21170-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
2010-10-18 13:56           ` Cyril Chemparathy
     [not found]             ` <4CBC520B.9070502-l0cyMroinI0@public.gmane.org>
2010-10-18 14:59               ` Grant Likely
2010-10-14 18:38   ` [PATCH 02/12] davinci: add tnetv107x ssp platform device Cyril Chemparathy
2010-10-14 18:38   ` [PATCH 03/12] davinci: add ssp config for tnetv107x evm board Cyril Chemparathy
2010-10-14 18:38   ` [PATCH 04/12] spi: add ti-ssp spi master driver Cyril Chemparathy
     [not found]     ` <1287081535-2864-5-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
2010-10-16  5:05       ` Grant Likely
2010-10-14 18:38   ` [PATCH 05/12] davinci: add spi devices on tnetv107x evm Cyril Chemparathy
2010-10-14 18:38   ` [PATCH 06/12] regulator: add driver for tps6524x regulator Cyril Chemparathy
     [not found]     ` <1287081535-2864-7-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
2010-10-14 21:03       ` Mark Brown
     [not found]         ` <20101014210323.GB14479-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
2010-10-18 12:50           ` Cyril Chemparathy
2010-10-16 10:00       ` Mark Brown
2010-10-14 18:38   ` [PATCH 07/12] davinci: add tnetv107x evm regulators Cyril Chemparathy
     [not found]     ` <1287081535-2864-8-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
2010-10-14 21:05       ` Mark Brown
2010-10-14 18:38   ` [PATCH 08/12] gpio: add ti-ssp virtual gpio driver Cyril Chemparathy
2010-10-14 18:38   ` [PATCH 09/12] davinci: add tnetv107x evm ti-ssp gpio device Cyril Chemparathy
2010-10-14 18:38   ` [PATCH 10/12] backlight: add support for tps6116x controller Cyril Chemparathy
2010-10-14 18:38   ` [PATCH 11/12] davinci: add tnetv107x evm backlight device Cyril Chemparathy
2010-10-14 18:38   ` [PATCH 12/12] davinci: add tnetv107x evm i2c eeprom device 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).