linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 00/12] tnetv107x ssp drivers
@ 2010-11-15 19:12 Cyril Chemparathy
       [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  0 siblings, 1 reply; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-15 19:12 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, lrg-kDsPt+C1G03kYMGBc/C6ZA,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E, rpurdie
  Cc: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Cyril Chemparathy,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io

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

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

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

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

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

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

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

Cyril Chemparathy (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 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    |  192 +++++++
 arch/arm/mach-davinci/devices-tnetv107x.c      |   25 +
 arch/arm/mach-davinci/include/mach/tnetv107x.h |    2 +
 arch/arm/mach-davinci/tnetv107x.c              |    2 +-
 drivers/mfd/Kconfig                            |   31 +
 drivers/mfd/Makefile                           |    3 +
 drivers/mfd/ti-ssp-gpio.c                      |  205 +++++++
 drivers/mfd/ti-ssp-spi.c                       |  402 ++++++++++++++
 drivers/mfd/ti-ssp.c                           |  475 ++++++++++++++++
 drivers/regulator/Kconfig                      |   10 +
 drivers/regulator/Makefile                     |    1 +
 drivers/regulator/tps6524x-regulator.c         |  692 ++++++++++++++++++++++++
 drivers/video/backlight/Kconfig                |    7 +
 drivers/video/backlight/Makefile               |    2 +-
 drivers/video/backlight/tps6116x.c             |  339 ++++++++++++
 include/linux/mfd/ti_ssp.h                     |   97 ++++
 16 files changed, 2483 insertions(+), 2 deletions(-)
 create mode 100644 drivers/mfd/ti-ssp-gpio.c
 create mode 100644 drivers/mfd/ti-ssp-spi.c
 create mode 100644 drivers/mfd/ti-ssp.c
 create mode 100644 drivers/regulator/tps6524x-regulator.c
 create mode 100644 drivers/video/backlight/tps6116x.c
 create mode 100644 include/linux/mfd/ti_ssp.h


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* [PATCH v5 01/12] misc: add driver for sequencer serial port
       [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
@ 2010-11-15 19:12   ` Cyril Chemparathy
       [not found]     ` <1289848334-8695-2-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2010-11-15 19:12   ` [PATCH v5 02/12] davinci: add tnetv107x ssp platform device Cyril Chemparathy
                     ` (10 subsequent siblings)
  11 siblings, 1 reply; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-15 19:12 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, lrg-kDsPt+C1G03kYMGBc/C6ZA,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E, rpurdie
  Cc: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Cyril Chemparathy,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io

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

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

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

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


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* [PATCH v5 02/12] davinci: add tnetv107x ssp platform device
       [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2010-11-15 19:12   ` [PATCH v5 01/12] misc: add driver for sequencer serial port Cyril Chemparathy
@ 2010-11-15 19:12   ` Cyril Chemparathy
  2010-11-15 19:12   ` [PATCH v5 03/12] davinci: add ssp config for tnetv107x evm board Cyril Chemparathy
                     ` (9 subsequent siblings)
  11 siblings, 0 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-15 19:12 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, lrg-kDsPt+C1G03kYMGBc/C6ZA,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E, rpurdie
  Cc: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Cyril Chemparathy,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io

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


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* [PATCH v5 03/12] davinci: add ssp config for tnetv107x evm board
       [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2010-11-15 19:12   ` [PATCH v5 01/12] misc: add driver for sequencer serial port Cyril Chemparathy
  2010-11-15 19:12   ` [PATCH v5 02/12] davinci: add tnetv107x ssp platform device Cyril Chemparathy
@ 2010-11-15 19:12   ` Cyril Chemparathy
  2010-11-15 19:12   ` [PATCH v5 04/12] spi: add ti-ssp spi master driver Cyril Chemparathy
                     ` (8 subsequent siblings)
  11 siblings, 0 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-15 19:12 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, lrg-kDsPt+C1G03kYMGBc/C6ZA,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E, rpurdie
  Cc: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Cyril Chemparathy,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io

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

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

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


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* [PATCH v5 04/12] spi: add ti-ssp spi master driver
       [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (2 preceding siblings ...)
  2010-11-15 19:12   ` [PATCH v5 03/12] davinci: add ssp config for tnetv107x evm board Cyril Chemparathy
@ 2010-11-15 19:12   ` Cyril Chemparathy
  2010-11-15 21:59     ` Ryan Mallon
       [not found]     ` <1289848334-8695-5-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2010-11-15 19:12   ` [PATCH v5 05/12] davinci: add spi devices on tnetv107x evm Cyril Chemparathy
                     ` (7 subsequent siblings)
  11 siblings, 2 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-15 19:12 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, lrg-kDsPt+C1G03kYMGBc/C6ZA,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E, rpurdie
  Cc: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Cyril Chemparathy,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io

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>
---
 drivers/mfd/Kconfig        |   10 +
 drivers/mfd/Makefile       |    1 +
 drivers/mfd/ti-ssp-spi.c   |  402 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/ti_ssp.h |    6 +
 4 files changed, 419 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mfd/ti-ssp-spi.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6bedf53..7dcc03a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -92,6 +92,16 @@ config MFD_TI_SSP
 	  To compile this driver as a module, choose M here: the
 	  module will be called ti-ssp.
 
+config MFD_TI_SSP_SPI
+	tristate "TI Sequencer Serial Port - SPI Support"
+	depends on SPI_MASTER && MFD_TI_SSP
+	help
+	  This selects an SPI master implementation using a TI sequencer
+	  serial port.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ti-ssp-spi.
+
 config HTC_EGPIO
 	bool "HTC EGPIO support"
 	depends on GENERIC_HARDIRQS && GPIOLIB && ARM
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 098a932..ba97f48 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_HTC_I2CPLD)	+= htc-i2cpld.o
 obj-$(CONFIG_MFD_DAVINCI_VOICECODEC)	+= davinci_voicecodec.o
 obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
 obj-$(CONFIG_MFD_TI_SSP)	+= ti-ssp.o
+obj-$(CONFIG_MFD_TI_SSP_SPI)	+= ti-ssp-spi.o
 
 obj-$(CONFIG_MFD_STMPE)		+= stmpe.o
 obj-$(CONFIG_MFD_TC35892)	+= tc35892.o
diff --git a/drivers/mfd/ti-ssp-spi.c b/drivers/mfd/ti-ssp-spi.c
new file mode 100644
index 0000000..d381a51
--- /dev/null
+++ b/drivers/mfd/ti-ssp-spi.c
@@ -0,0 +1,402 @@
+/*
+ * Sequencer Serial Port (SSP) based SPI master driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/ti_ssp.h>
+
+#define MODE_BITS	(SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
+
+struct ti_ssp_spi {
+	const struct ti_ssp_spi_data	*pdata;
+	struct spi_master		*master;
+	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;
+	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->dev, hw->pc_rd, 0, &ret);
+	return ret;
+}
+
+static void do_write_data(struct ti_ssp_spi *hw, u32 data)
+{
+	ti_ssp_run(hw->dev, 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->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL);
+	hw->cs_active = cs_active;
+}
+
+#define __SHIFT_OUT(bits)	(SSP_OPCODE_SHIFT | SSP_OUT_MODE | \
+				 cs_en | clk | SSP_COUNT((bits) * 2 - 1))
+#define __SHIFT_IN(bits)	(SSP_OPCODE_SHIFT | SSP_IN_MODE  | \
+				 cs_en | clk | SSP_COUNT((bits) * 2 - 1))
+
+static int 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->dev, 0, seqram, idx);
+	if (error < 0)
+		return error;
+
+	error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ?
+					  0 : SSP_EARLY_DIN));
+	if (error < 0)
+		return error;
+
+	hw->bpw = bpw;
+	hw->mode = mode;
+
+	return error;
+}
+
+static void ti_ssp_spi_work(struct work_struct *work)
+{
+	struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work);
+
+	spin_lock(&hw->lock);
+
+	 while (!list_empty(&hw->msg_queue)) {
+		struct spi_message	*m;
+		struct spi_device	*spi;
+		struct spi_transfer	*t = NULL;
+		int			status = 0;
+
+		m = container_of(hw->msg_queue.next, struct spi_message,
+				 queue);
+
+		list_del_init(&m->queue);
+
+		spin_unlock(&hw->lock);
+
+		spi = m->spi;
+
+		if (hw->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);
+
+			xfer_status = do_transfer(hw, m, t);
+			if (xfer_status < 0)
+				status = xfer_status;
+
+			if (t->delay_usecs)
+				udelay(t->delay_usecs);
+
+			if (t->cs_change)
+				chip_select(hw, 0);
+		}
+
+		chip_select(hw, 0);
+		m->status = status;
+		m->complete(m->context);
+
+		spin_lock(&hw->lock);
+	}
+
+	if (hw->shutdown)
+		complete(&hw->complete);
+
+	spin_unlock(&hw->lock);
+}
+
+static int ti_ssp_spi_setup(struct spi_device *spi)
+{
+	if (spi->bits_per_word > 32)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
+{
+	struct ti_ssp_spi	*hw;
+	struct spi_transfer	*t;
+	int			error = 0;
+
+	m->actual_length = 0;
+	m->status = -EINPROGRESS;
+
+	hw = spi_master_get_devdata(spi->master);
+
+	if (list_empty(&m->transfers) || !m->complete)
+		return -EINVAL;
+
+	list_for_each_entry(t, &m->transfers, transfer_list) {
+		if (t->len && !(t->rx_buf || t->tx_buf)) {
+			dev_err(&spi->dev, "invalid xfer, no buffer\n");
+			return -EINVAL;
+		}
+
+		if (t->len && t->rx_buf && t->tx_buf) {
+			dev_err(&spi->dev, "invalid xfer, full duplex\n");
+			return -EINVAL;
+		}
+
+		if (t->bits_per_word > 32) {
+			dev_err(&spi->dev, "invalid xfer width %d\n",
+				t->bits_per_word);
+			return -EINVAL;
+		}
+	}
+
+	spin_lock(&hw->lock);
+	if (hw->shutdown) {
+		error = -ESHUTDOWN;
+		goto error_unlock;
+	}
+	list_add_tail(&m->queue, &hw->msg_queue);
+	queue_work(hw->workqueue, &hw->work);
+error_unlock:
+	spin_unlock(&hw->lock);
+	return error;
+}
+
+static int __devinit ti_ssp_spi_probe(struct platform_device *pdev)
+{
+	const struct ti_ssp_spi_data *pdata;
+	struct ti_ssp_spi *hw;
+	struct spi_master *master;
+	struct device *dev = &pdev->dev;
+	int error = 0;
+
+	pdata = dev->platform_data;
+	if (!pdata) {
+		dev_err(dev, "platform data not found\n");
+		return -EINVAL;
+	}
+
+	master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi));
+	if (!master) {
+		dev_err(dev, "cannot allocate SPI master\n");
+		return -ENOMEM;
+	}
+
+	hw = spi_master_get_devdata(master);
+	platform_set_drvdata(pdev, hw);
+
+	hw->master = master;
+	hw->dev = dev;
+	hw->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;
+	}
+
+	error = ti_ssp_set_iosel(hw->dev, hw->pdata->iosel);
+	if (error < 0) {
+		dev_err(dev, "io setup failed\n");
+		goto error_iosel;
+	}
+
+	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:
+error_iosel:
+	destroy_workqueue(hw->workqueue);
+error_wq:
+	spi_master_put(master);
+	return error;
+}
+
+static int __devexit ti_ssp_spi_remove(struct platform_device *pdev)
+{
+	struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
+	int error;
+
+	hw->shutdown = 1;
+	while (!list_empty(&hw->msg_queue)) {
+		error = wait_for_completion_interruptible(&hw->complete);
+		if (error < 0) {
+			hw->shutdown = 0;
+			return error;
+		}
+	}
+	destroy_workqueue(hw->workqueue);
+	spi_unregister_master(hw->master);
+
+	return 0;
+}
+
+static struct platform_driver ti_ssp_spi_driver = {
+	.probe		= ti_ssp_spi_probe,
+	.remove		= __devexit_p(ti_ssp_spi_remove),
+	.driver		= {
+		.name	= "ti-ssp-spi",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ti_ssp_spi_init(void)
+{
+	return platform_driver_register(&ti_ssp_spi_driver);
+}
+subsys_initcall(ti_ssp_spi_init);
+
+static void __exit ti_ssp_spi_exit(void)
+{
+	platform_driver_unregister(&ti_ssp_spi_driver);
+}
+module_exit(ti_ssp_spi_exit);
+
+MODULE_DESCRIPTION("SSP SPI Master");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ti-ssp-spi");
diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h
index 021fe09..dbb4b43 100644
--- a/include/linux/mfd/ti_ssp.h
+++ b/include/linux/mfd/ti_ssp.h
@@ -32,6 +32,12 @@ struct ti_ssp_data {
 	struct ti_ssp_dev_data	dev_data[2];
 };
 
+struct ti_ssp_spi_data {
+	unsigned long	iosel;
+	int		num_cs;
+	void		(*select)(int cs);
+};
+
 /*
  * Sequencer port IO pin configuration bits.  These do not correlate 1-1 with
  * the hardware.  The iosel field in the port data combines iosel1 and iosel2,
-- 
1.7.1


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* [PATCH v5 05/12] davinci: add spi devices on tnetv107x evm
       [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (3 preceding siblings ...)
  2010-11-15 19:12   ` [PATCH v5 04/12] spi: add ti-ssp spi master driver Cyril Chemparathy
@ 2010-11-15 19:12   ` Cyril Chemparathy
  2010-11-15 19:12   ` [PATCH v5 06/12] regulator: add driver for tps6524x regulator Cyril Chemparathy
                     ` (6 subsequent siblings)
  11 siblings, 0 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-15 19:12 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, lrg-kDsPt+C1G03kYMGBc/C6ZA,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E, rpurdie
  Cc: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Cyril Chemparathy,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io

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

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


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* [PATCH v5 06/12] regulator: add driver for tps6524x regulator
       [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (4 preceding siblings ...)
  2010-11-15 19:12   ` [PATCH v5 05/12] davinci: add spi devices on tnetv107x evm Cyril Chemparathy
@ 2010-11-15 19:12   ` Cyril Chemparathy
  2010-11-15 19:12   ` [PATCH v5 07/12] davinci: add tnetv107x evm regulators Cyril Chemparathy
                     ` (5 subsequent siblings)
  11 siblings, 0 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-15 19:12 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, lrg-kDsPt+C1G03kYMGBc/C6ZA,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E, rpurdie
  Cc: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Cyril Chemparathy,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io

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

Acked-by: Mark Brown <broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
---
 drivers/regulator/Kconfig              |   10 +
 drivers/regulator/Makefile             |    1 +
 drivers/regulator/tps6524x-regulator.c |  692 ++++++++++++++++++++++++++++++++
 3 files changed, 703 insertions(+), 0 deletions(-)
 create mode 100644 drivers/regulator/tps6524x-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 172951b..a6f8536 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 SPI
+	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..6d6cc5e
--- /dev/null
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -0,0 +1,692 @@
+/*
+ * 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_reg(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 __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_reg(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;
+
+	if (selector < 0 || selector >= info->n_voltages)
+		return -EINVAL;
+
+	return 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 (WARN_ON(ret >= info->n_voltages))
+		return -EIO;
+
+	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)
+{
+	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_ILIMSEL)
+		return info->fixed_ilimsel;
+
+	ret = read_field(hw, &info->ilimsel);
+	if (ret < 0)
+		return ret;
+	if (WARN_ON(ret >= info->n_ilimsels))
+		return -EIO;
+
+	return info->ilimsels[ret];
+}
+
+static int enable_supply(struct regulator_dev *rdev)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+
+	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)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+
+	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)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+
+	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,
+};
+
+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])
+			regulator_unregister(hw->rdev[i]);
+		hw->rdev[i] = NULL;
+	}
+	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 -EINVAL;
+	}
+
+	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);
+
+	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",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init pmic_driver_init(void)
+{
+	return spi_register_driver(&pmic_driver);
+}
+subsys_initcall_sync(pmic_driver_init);
+
+static void __exit pmic_driver_exit(void)
+{
+	spi_unregister_driver(&pmic_driver);
+}
+module_exit(pmic_driver_exit);
+
+MODULE_DESCRIPTION("TPS6524X PMIC Driver");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:tps6524x");
-- 
1.7.1


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* [PATCH v5 07/12] davinci: add tnetv107x evm regulators
       [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (5 preceding siblings ...)
  2010-11-15 19:12   ` [PATCH v5 06/12] regulator: add driver for tps6524x regulator Cyril Chemparathy
@ 2010-11-15 19:12   ` Cyril Chemparathy
  2010-11-15 19:12   ` [PATCH v5 08/12] gpio: add ti-ssp gpio driver Cyril Chemparathy
                     ` (4 subsequent siblings)
  11 siblings, 0 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-15 19:12 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, lrg-kDsPt+C1G03kYMGBc/C6ZA,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E, rpurdie
  Cc: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Cyril Chemparathy,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io

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

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

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


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* [PATCH v5 08/12] gpio: add ti-ssp gpio driver
       [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (6 preceding siblings ...)
  2010-11-15 19:12   ` [PATCH v5 07/12] davinci: add tnetv107x evm regulators Cyril Chemparathy
@ 2010-11-15 19:12   ` Cyril Chemparathy
       [not found]     ` <1289848334-8695-9-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  2010-11-15 19:12   ` [PATCH v5 09/12] davinci: add tnetv107x evm ti-ssp gpio device Cyril Chemparathy
                     ` (3 subsequent siblings)
  11 siblings, 1 reply; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-15 19:12 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, lrg-kDsPt+C1G03kYMGBc/C6ZA,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E, rpurdie
  Cc: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Cyril Chemparathy,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io

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

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

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 7dcc03a..b193580 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -102,6 +102,16 @@ config MFD_TI_SSP_SPI
 	  To compile this driver as a module, choose M here: the
 	  module will be called ti-ssp-spi.
 
+config MFD_TI_SSP_GPIO
+	tristate "TI Sequencer Serial Port - GPIO Support"
+	depends on GPIOLIB && MFD_TI_SSP
+	help
+	  Say yes here to support a GPIO interface on TI SSP port pins.
+	  Each SSP port translates into 4 GPIOs.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called ti-ssp-gpio.
+
 config HTC_EGPIO
 	bool "HTC EGPIO support"
 	depends on GENERIC_HARDIRQS && GPIOLIB && ARM
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index ba97f48..87b5de8 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_MFD_DAVINCI_VOICECODEC)	+= davinci_voicecodec.o
 obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
 obj-$(CONFIG_MFD_TI_SSP)	+= ti-ssp.o
 obj-$(CONFIG_MFD_TI_SSP_SPI)	+= ti-ssp-spi.o
+obj-$(CONFIG_MFD_TI_SSP_GPIO)	+= ti-ssp-gpio.o
 
 obj-$(CONFIG_MFD_STMPE)		+= stmpe.o
 obj-$(CONFIG_MFD_TC35892)	+= tc35892.o
diff --git a/drivers/mfd/ti-ssp-gpio.c b/drivers/mfd/ti-ssp-gpio.c
new file mode 100644
index 0000000..a3e909b
--- /dev/null
+++ b/drivers/mfd/ti-ssp-gpio.c
@@ -0,0 +1,205 @@
+/*
+ * Sequencer Serial Port (SSP) based virtual GPIO driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/ti_ssp.h>
+
+struct ti_ssp_gpio {
+	struct gpio_chip		chip;
+#define chip2gpio(chip)	container_of(chip, struct ti_ssp_gpio, chip)
+	struct device			*dev;
+	spinlock_t			lock;
+	u8				out;
+	u32				iosel;
+};
+
+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->iosel &= ~SSP_PIN_MASK(gpio_num);
+	gpio->iosel |=  SSP_PIN_SEL(gpio_num, SSP_IN);
+
+	error = ti_ssp_set_iosel(gpio->dev, gpio->iosel);
+
+	spin_unlock(&gpio->lock);
+
+	return error;
+}
+
+static int 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->iosel &= ~SSP_PIN_MASK(gpio_num);
+	gpio->iosel |=  SSP_PIN_SEL(gpio_num, SSP_OUT);
+
+	error = ti_ssp_set_iosel(gpio->dev, gpio->iosel);
+
+	if (error < 0)
+		goto error;
+
+	if (val)
+		gpio->out |= BIT(gpio_num);
+	else
+		gpio->out &= ~BIT(gpio_num);
+
+	error = ti_ssp_raw_write(gpio->dev, gpio->out);
+
+error:
+	spin_unlock(&gpio->lock);
+	return error;
+}
+
+static int value_get(struct gpio_chip *chip, unsigned gpio_num)
+{
+	struct ti_ssp_gpio *gpio = chip2gpio(chip);
+	int ret;
+
+	spin_lock(&gpio->lock);
+
+	ret = ti_ssp_raw_read(gpio->dev);
+	if (ret >= 0)
+		ret = (ret & BIT(gpio_num)) ? 1 : 0;
+
+	spin_unlock(&gpio->lock);
+	return ret;
+}
+
+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 (val)
+		gpio->out |= BIT(gpio_num);
+	else
+		gpio->out &= ~BIT(gpio_num);
+
+	ti_ssp_raw_write(gpio->dev, gpio->out);
+
+	spin_unlock(&gpio->lock);
+}
+
+static int __devinit ti_ssp_gpio_probe(struct platform_device *pdev)
+{
+	const struct ti_ssp_gpio_data *pdata = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct ti_ssp_gpio *gpio;
+	int error;
+
+	if (!pdata) {
+		dev_err(dev, "platform data not found\n");
+		return -EINVAL;
+	}
+
+	gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
+	if (!gpio) {
+		dev_err(dev, "cannot allocate driver data\n");
+		return -ENOMEM;
+	}
+
+	gpio->dev = dev;
+	gpio->iosel = SSP_PIN_SEL(0, SSP_IN) | SSP_PIN_SEL(1, SSP_IN) |
+		      SSP_PIN_SEL(2, SSP_IN) | SSP_PIN_SEL(3, SSP_IN);
+	error = ti_ssp_set_iosel(gpio->dev, gpio->iosel);
+	if (error < 0) {
+		dev_err(dev, "gpio io setup failed (%d)\n", error);
+		goto error;
+	}
+
+	spin_lock_init(&gpio->lock);
+	platform_set_drvdata(pdev, gpio);
+
+	gpio->chip.base  = pdata->start;
+	gpio->chip.ngpio = 4;
+	gpio->chip.dev   = &pdev->dev;
+	gpio->chip.label = "ti_ssp_gpio";
+	gpio->chip.owner = THIS_MODULE;
+	gpio->chip.get   = 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;
+	kfree(gpio);
+	return 0;
+}
+
+static struct platform_driver ti_ssp_gpio_driver = {
+	.probe		= ti_ssp_gpio_probe,
+	.remove		= __devexit_p(ti_ssp_gpio_remove),
+	.driver		= {
+		.name	= "ti-ssp-gpio",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ti_ssp_gpio_init(void)
+{
+	return platform_driver_register(&ti_ssp_gpio_driver);
+}
+subsys_initcall(ti_ssp_gpio_init);
+
+static void __exit ti_ssp_gpio_exit(void)
+{
+	platform_driver_unregister(&ti_ssp_gpio_driver);
+}
+module_exit(ti_ssp_gpio_exit);
+
+MODULE_DESCRIPTION("GPIO interface for TI-SSP");
+MODULE_AUTHOR("Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ti-ssp-gpio");
diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h
index dbb4b43..10c65bb 100644
--- a/include/linux/mfd/ti_ssp.h
+++ b/include/linux/mfd/ti_ssp.h
@@ -38,6 +38,10 @@ struct ti_ssp_spi_data {
 	void		(*select)(int cs);
 };
 
+struct ti_ssp_gpio_data {
+	int		start;
+};
+
 /*
  * Sequencer port IO pin configuration bits.  These do not correlate 1-1 with
  * the hardware.  The iosel field in the port data combines iosel1 and iosel2,
-- 
1.7.1


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* [PATCH v5 09/12] davinci: add tnetv107x evm ti-ssp gpio device
       [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (7 preceding siblings ...)
  2010-11-15 19:12   ` [PATCH v5 08/12] gpio: add ti-ssp gpio driver Cyril Chemparathy
@ 2010-11-15 19:12   ` Cyril Chemparathy
  2010-11-15 19:12   ` [PATCH v5 10/12] backlight: add support for tps6116x controller Cyril Chemparathy
                     ` (2 subsequent siblings)
  11 siblings, 0 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-15 19:12 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, lrg-kDsPt+C1G03kYMGBc/C6ZA,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E, rpurdie
  Cc: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Cyril Chemparathy,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io

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

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


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* [PATCH v5 10/12] backlight: add support for tps6116x controller
       [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (8 preceding siblings ...)
  2010-11-15 19:12   ` [PATCH v5 09/12] davinci: add tnetv107x evm ti-ssp gpio device Cyril Chemparathy
@ 2010-11-15 19:12   ` Cyril Chemparathy
  2010-11-15 19:12   ` [PATCH v5 11/12] davinci: add tnetv107x evm backlight device Cyril Chemparathy
  2010-11-15 19:12   ` [PATCH v5 12/12] davinci: add tnetv107x evm i2c eeprom device Cyril Chemparathy
  11 siblings, 0 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-15 19:12 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, lrg-kDsPt+C1G03kYMGBc/C6ZA,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E, rpurdie
  Cc: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Cyril Chemparathy,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io

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..a54bb15
--- /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;
+	struct mutex			lock;
+	int				intensity;
+	struct backlight_properties	props;
+	struct backlight_device		*bl;
+	struct regulator		*regulator;
+	bool				power;
+	bool				gpio_initialized;
+	bool				suspended;
+};
+
+static int __set_power(struct tps6116x *hw, bool power)
+{
+	unsigned long flags;
+	int error;
+
+	if (power == hw->power)
+		return 0; /* nothing to do */
+
+	/* disabling is simple... choke power */
+	if (!power) {
+		error = regulator_disable(hw->regulator);
+		goto done;
+	}
+
+	/* set ctrl pin init state for easyscale detection */
+	gpio_set_value(hw->gpio, 0);
+
+	error = regulator_enable(hw->regulator);
+	if (error < 0)
+		goto done;
+
+	udelay(T_POWER_SETTLE);
+
+	/*
+	 * Now that the controller is powered up, we need to put it into 1-wire
+	 * mode.  This is a timing sensitive operation, hence the irq disable.
+	 * Ideally, this should happen rarely, and mostly at init, so disabling
+	 * interrupts for the duration should not be a problem.
+	 */
+	local_irq_save(flags);
+
+	gpio_set_value(hw->gpio, 1);
+	udelay(T_ES_DELAY);
+	gpio_set_value(hw->gpio, 0);
+	udelay(T_ES_DETECT);
+	gpio_set_value(hw->gpio, 1);
+
+	local_irq_restore(flags);
+
+done:
+	if (error >= 0)
+		hw->power = power;
+
+	return error;
+}
+
+static void __write_byte(struct tps6116x *hw, u8 data)
+{
+	int bit;
+
+	gpio_set_value(hw->gpio, 1);
+	udelay(T_START);
+
+	for (bit = 0; bit < 8; bit++, data <<= 1) {
+		int val = data & 0x80;
+		int t_lo = val ? T_INACTIVE : T_ACTIVE;
+		int t_hi = val ? T_ACTIVE : T_INACTIVE;
+
+		gpio_set_value(hw->gpio, 0);
+		udelay(t_lo);
+		gpio_set_value(hw->gpio, 1);
+		udelay(t_hi);
+	}
+
+	gpio_set_value(hw->gpio, 0);
+	udelay(T_EOS);
+	gpio_set_value(hw->gpio, 1);
+}
+
+static void __set_intensity(struct tps6116x *hw, int intensity)
+{
+	unsigned long flags;
+
+	intensity = clamp(intensity, 0, TPS6116X_MAX_INTENSITY);
+
+	local_irq_save(flags);
+	__write_byte(hw, CMD_SET);
+	__write_byte(hw, intensity);
+	local_irq_restore(flags);
+}
+
+static int set_intensity(struct tps6116x *hw, int intensity)
+{
+	int error = 0;
+
+	if (intensity == hw->intensity)
+		return 0;
+
+	mutex_lock(&hw->lock);
+
+	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 = true;
+	}
+
+	error = __set_power(hw, intensity ? true : false);
+	if (error < 0)
+		goto error;
+
+	if (intensity > 0)
+		__set_intensity(hw, intensity);
+
+	hw->intensity = intensity;
+error:
+	mutex_unlock(&hw->lock);
+
+	return error;
+}
+
+static 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);
+
+	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 = true;
+	update_status(hw->bl);
+	return 0;
+}
+
+static int tps6116x_resume(struct platform_device *pdev)
+{
+	struct tps6116x *hw = platform_get_drvdata(pdev);
+	hw->suspended = false;
+	update_status(hw->bl);
+	return 0;
+}
+
+static struct platform_driver tps6116x_driver = {
+	.probe		= tps6116x_probe,
+	.remove		= __devexit_p(tps6116x_remove),
+	.suspend	= tps6116x_suspend,
+	.resume		= tps6116x_resume,
+	.driver		= {
+		.name	= "tps6116x",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init tps6116x_init(void)
+{
+	return platform_driver_register(&tps6116x_driver);
+}
+module_init(tps6116x_init);
+
+static void __exit tps6116x_exit(void)
+{
+	platform_driver_unregister(&tps6116x_driver);
+}
+module_exit(tps6116x_exit);
+
+MODULE_DESCRIPTION("SSP TPS6116X Driver");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tps6116x");
-- 
1.7.1


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* [PATCH v5 11/12] davinci: add tnetv107x evm backlight device
       [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (9 preceding siblings ...)
  2010-11-15 19:12   ` [PATCH v5 10/12] backlight: add support for tps6116x controller Cyril Chemparathy
@ 2010-11-15 19:12   ` Cyril Chemparathy
  2010-11-15 19:12   ` [PATCH v5 12/12] davinci: add tnetv107x evm i2c eeprom device Cyril Chemparathy
  11 siblings, 0 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-15 19:12 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, lrg-kDsPt+C1G03kYMGBc/C6ZA,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E, rpurdie
  Cc: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Cyril Chemparathy,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io

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

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


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* [PATCH v5 12/12] davinci: add tnetv107x evm i2c eeprom device
       [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
                     ` (10 preceding siblings ...)
  2010-11-15 19:12   ` [PATCH v5 11/12] davinci: add tnetv107x evm backlight device Cyril Chemparathy
@ 2010-11-15 19:12   ` Cyril Chemparathy
  11 siblings, 0 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-15 19:12 UTC (permalink / raw)
  To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA, lrg-kDsPt+C1G03kYMGBc/C6ZA,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E, rpurdie
  Cc: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Cyril Chemparathy,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io

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

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

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


------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
  2010-11-15 19:12   ` [PATCH v5 04/12] spi: add ti-ssp spi master driver Cyril Chemparathy
@ 2010-11-15 21:59     ` Ryan Mallon
       [not found]     ` <1289848334-8695-5-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
  1 sibling, 0 replies; 37+ messages in thread
From: Ryan Mallon @ 2010-11-15 21:59 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: davinci-linux-open-source, dbrownell, sameo, khilman,
	linus.ml.walleij, broonie, grant.likely, rpurdie, alan,
	spi-devel-general, akpm, linux-arm-kernel, lrg

On 11/16/2010 08:12 AM, 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@ti.com>
> ---
>  drivers/mfd/Kconfig        |   10 +
>  drivers/mfd/Makefile       |    1 +
>  drivers/mfd/ti-ssp-spi.c   |  402 ++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/ti_ssp.h |    6 +
>  4 files changed, 419 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/mfd/ti-ssp-spi.c

This should live in drivers/spi rather than drivers/mfd. Each of the
drivers which use the TI-SSP core are single function drivers and having
them in the appropriate directory makes them easier to find.

The SSP core driver could either live in drivers/mfd or drivers/misc
atmel-ssc.c is in drivers/misc for example.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan@bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

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

* Re: [PATCH v5 08/12] gpio: add ti-ssp gpio driver
       [not found]     ` <1289848334-8695-9-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
@ 2010-11-15 22:38       ` Ryan Mallon
       [not found]         ` <4CE1B651.1060006-7Wk5F4Od5/oYd5yxfr4S2w@public.gmane.org>
  0 siblings, 1 reply; 37+ messages in thread
From: Ryan Mallon @ 2010-11-15 22:38 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On 11/16/2010 08:12 AM, Cyril Chemparathy wrote:
> TI's SSP controller pins can be directly read and written to behave like a
> GPIO.  This patch adds a GPIO driver that exposes such functionality.
> 
> Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
> ---
>  drivers/mfd/Kconfig        |   10 ++
>  drivers/mfd/Makefile       |    1 +
>  drivers/mfd/ti-ssp-gpio.c  |  205 ++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/ti_ssp.h |    4 +
>  4 files changed, 220 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/mfd/ti-ssp-gpio.c

Should go under drivers/gpio. This is not a multifunction driver.

> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <linux/platform_device.h>
> +#include <linux/mfd/ti_ssp.h>
> +
> +struct ti_ssp_gpio {

This is a confusing name because it sounds like this struct maps to a
single gpio rather than bank. Perhaps a better name is ti_ssp_gpio_chip?

> +	struct gpio_chip		chip;
> +#define chip2gpio(chip)	container_of(chip, struct ti_ssp_gpio, chip)

Please don't put #define's in the middle of a struct. Move it either
before or after the structure definition. It is also confusingly named,
something like to_ti_ssp_gpio_chip might be better.

> +static int value_get(struct gpio_chip *chip, unsigned gpio_num)
> +{
> +	struct ti_ssp_gpio *gpio = chip2gpio(chip);
> +	int ret;
> +
> +	spin_lock(&gpio->lock);
> +
> +	ret = ti_ssp_raw_read(gpio->dev);
> +	if (ret >= 0)
> +		ret = (ret & BIT(gpio_num)) ? 1 : 0;

		ret = !!(ret & BIT(gpio_num));

> +
> +	spin_unlock(&gpio->lock);
> +	return ret;
> +}

> +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->iosel = SSP_PIN_SEL(0, SSP_IN) | SSP_PIN_SEL(1, SSP_IN) |
> +		      SSP_PIN_SEL(2, SSP_IN) | SSP_PIN_SEL(3, SSP_IN);
> +	error = ti_ssp_set_iosel(gpio->dev, gpio->iosel);
> +	if (error < 0) {
> +		dev_err(dev, "gpio io setup failed (%d)\n", error);
> +		goto error;
> +	}
> +
> +	spin_lock_init(&gpio->lock);
> +	platform_set_drvdata(pdev, gpio);
> +
> +	gpio->chip.base  = pdata->start;
> +	gpio->chip.ngpio = 4;

Is this always four or can the SSP peripheral be configured to have
varying numbers of gpios. Maybe the number of gpios should be passed via
platform data?

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

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan-7Wk5F4Od5/oYd5yxfr4S2w@public.gmane.org         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

------------------------------------------------------------------------------
Centralized Desktop Delivery: Dell and VMware Reference Architecture
Simplifying enterprise desktop deployment and management using
Dell EqualLogic storage and VMware View: A highly scalable, end-to-end
client virtualization framework. Read more!
http://p.sf.net/sfu/dell-eql-dev2dev

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

* Re: [PATCH v5 01/12] misc: add driver for sequencer serial port
       [not found]     ` <1289848334-8695-2-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
@ 2010-11-16  7:10       ` Grant Likely
       [not found]         ` <20101116071047.GE4074-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
  0 siblings, 1 reply; 37+ messages in thread
From: Grant Likely @ 2010-11-16  7:10 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Mon, Nov 15, 2010 at 02:12:03PM -0500, 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>
> ---
>  drivers/mfd/Kconfig        |   11 +
>  drivers/mfd/Makefile       |    1 +
>  drivers/mfd/ti-ssp.c       |  475 ++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/ti_ssp.h |   87 ++++++++
>  4 files changed, 574 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/mfd/ti-ssp.c
>  create mode 100644 include/linux/mfd/ti_ssp.h
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index db51ea1..6bedf53 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -81,6 +81,17 @@ config MFD_DM355EVM_MSP
>  	  boards.  MSP430 firmware manages resets and power sequencing,
>  	  inputs from buttons and the IR remote, LEDs, an RTC, and more.
>  
> +config MFD_TI_SSP
> +	tristate "TI Sequencer Serial Port support"
> +	depends on ARCH_DAVINCI_TNETV107X
> +	select MFD_CORE
> +	---help---
> +	  Say Y here if you want support for the Sequencer Serial Port
> +	  in a Texas Instruments TNETV107X SoC.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called ti-ssp.
> +
>  config HTC_EGPIO
>  	bool "HTC EGPIO support"
>  	depends on GENERIC_HARDIRQS && GPIOLIB && ARM
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index feaeeae..098a932 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_HTC_I2CPLD)	+= htc-i2cpld.o
>  
>  obj-$(CONFIG_MFD_DAVINCI_VOICECODEC)	+= davinci_voicecodec.o
>  obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
> +obj-$(CONFIG_MFD_TI_SSP)	+= ti-ssp.o
>  
>  obj-$(CONFIG_MFD_STMPE)		+= stmpe.o
>  obj-$(CONFIG_MFD_TC35892)	+= tc35892.o
> diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c
> new file mode 100644
> index 0000000..ac3171a
> --- /dev/null
> +++ b/drivers/mfd/ti-ssp.c
> @@ -0,0 +1,475 @@
> +/*
> + * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
> + *
> + * Copyright (C) 2010 Texas Instruments Inc
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/wait.h>
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/device.h>
> +#include <linux/spinlock.h>
> +#include <linux/platform_device.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/ti_ssp.h>
> +
> +/* Register Offsets */
> +#define REG_REV		0x00
> +#define REG_IOSEL_1	0x04
> +#define REG_IOSEL_2	0x08
> +#define REG_PREDIV	0x0c
> +#define REG_INTR_ST	0x10
> +#define REG_INTR_EN	0x14
> +#define REG_TEST_CTRL	0x18
> +
> +/* Per port registers */
> +#define PORT_CFG_2	0x00
> +#define PORT_ADDR	0x04
> +#define PORT_DATA	0x08
> +#define PORT_CFG_1	0x0c
> +#define PORT_STATE	0x10
> +
> +#define SSP_PORT_CONFIG_MASK	(SSP_EARLY_DIN | SSP_DELAY_DOUT)
> +#define SSP_PORT_CLKRATE_MASK	0x0f
> +
> +#define SSP_SEQRAM_WR_EN	BIT(4)
> +#define SSP_SEQRAM_RD_EN	BIT(5)
> +#define SSP_START		BIT(15)
> +#define SSP_BUSY		BIT(10)
> +#define SSP_PORT_ASL		BIT(7)
> +#define SSP_PORT_CFO1		BIT(6)
> +
> +#define SSP_PORT_SEQRAM_SIZE	32
> +
> +static const int ssp_port_base[]   = {0x040, 0x080};
> +static const int ssp_port_seqram[] = {0x100, 0x180};
> +
> +struct ti_ssp {
> +	struct resource		*res;
> +	struct device		*dev;
> +	void __iomem		*regs;
> +	spinlock_t		lock;
> +	struct clk		*clk;
> +	int			irq;
> +	wait_queue_head_t	wqh;
> +};
> +
> +static inline struct ti_ssp *dev_to_ssp(struct device *dev)
> +{
> +	return dev_get_drvdata(dev->parent);
> +}
> +
> +static inline int dev_to_port(struct device *dev)
> +{
> +	return to_platform_device(dev)->id;
> +}
> +
> +/* Register Access Helpers, rmw() functions need to run locked */
> +static inline u32 ssp_read(struct ti_ssp *ssp, int reg)
> +{
> +	return __raw_readl(ssp->regs + reg);
> +}
> +
> +static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val)
> +{
> +	__raw_writel(val, ssp->regs + reg);
> +}

I'm pretty sure it was resolved that __raw_ versions should not be
used here.

> +
> +static inline void ssp_rmw(struct ti_ssp *ssp, int reg, u32 mask, u32 bits)
> +{
> +	u32 val = ssp_read(ssp, reg);
> +	val &= ~mask;
> +	val |= bits;
> +	ssp_write(ssp, reg, val);

or simply:
	ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~mask) | bits);

> +}
> +
> +static inline u32 ssp_port_read(struct ti_ssp *ssp, int port, int reg)
> +{
> +	return ssp_read(ssp, ssp_port_base[port] + reg);
> +}
> +
> +static inline void ssp_port_write(struct ti_ssp *ssp, int port, int reg,
> +				  u32 val)
> +{
> +	ssp_write(ssp, ssp_port_base[port] + reg, val);
> +}
> +
> +static inline void ssp_port_rmw(struct ti_ssp *ssp, int port, int reg,
> +				u32 mask, u32 bits)
> +{
> +	ssp_rmw(ssp, ssp_port_base[port] + reg, mask, bits);
> +}
> +
> +static inline void ssp_port_clr_bits(struct ti_ssp *ssp, int port, int reg,
> +				     u32 bits)
> +{
> +	ssp_port_rmw(ssp, port, reg, bits, 0);
> +}
> +
> +static inline void ssp_port_set_bits(struct ti_ssp *ssp, int port, int reg,
> +				     u32 bits)
> +{
> +	ssp_port_rmw(ssp, port, reg, 0, bits);
> +}
> +
> +/* Called to setup port clock mode, caller must hold ssp->lock */
> +static int __set_mode(struct ti_ssp *ssp, int port, int mode)
> +{
> +	mode &= SSP_PORT_CONFIG_MASK;
> +	ssp_port_rmw(ssp, port, PORT_CFG_1, SSP_PORT_CONFIG_MASK, mode);
> +
> +	return 0;
> +}
> +
> +int ti_ssp_set_mode(struct device *dev, int mode)
> +{
> +	struct ti_ssp *ssp = dev_to_ssp(dev);
> +	int port = dev_to_port(dev);
> +	int ret;
> +
> +	spin_lock(&ssp->lock);
> +	ret = __set_mode(ssp, port, mode);
> +	spin_unlock(&ssp->lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(ti_ssp_set_mode);
> +
> +/* Called to setup port iosel, caller must hold ssp->lock */
> +static int __set_iosel(struct ti_ssp *ssp, int port, u32 iosel)
> +{
> +	unsigned val;
> +
> +	/* IOSEL1 gets the least significant 16 bits */
> +	val = ssp_read(ssp, REG_IOSEL_1);
> +	val &= 0xffff << (port ? 0 : 16);
> +	val |= (iosel & 0xffff) << (port ? 16 : 0);
> +	ssp_write(ssp, REG_IOSEL_1, val);
> +
> +	/* IOSEL2 gets the most significant 16 bits */
> +	val = ssp_read(ssp, REG_IOSEL_2);
> +	val &= 0x0007 << (port ? 0 : 16);
> +	val |= (iosel & 0x00070000) >> (port ? 0 : 16);
> +	ssp_write(ssp, REG_IOSEL_2, val);
> +
> +	return 0;
> +}
> +
> +int ti_ssp_set_iosel(struct device *dev, u32 iosel)
> +{
> +	struct ti_ssp *ssp = dev_to_ssp(dev);
> +	int port = dev_to_port(dev);
> +	int ret;
> +
> +	spin_lock(&ssp->lock);
> +	ret = __set_iosel(ssp, port, iosel);
> +	spin_unlock(&ssp->lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(ti_ssp_set_iosel);
> +
> +int ti_ssp_load(struct device *dev, int offs, u32* prog, int len)
> +{
> +	struct ti_ssp *ssp = dev_to_ssp(dev);
> +	int port = dev_to_port(dev);
> +	int i;
> +
> +	if (len > SSP_PORT_SEQRAM_SIZE)
> +		return -ENOSPC;
> +
> +	spin_lock(&ssp->lock);
> +
> +	/* Enable SeqRAM access */
> +	ssp_port_set_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
> +
> +	/* Copy code */
> +	for (i = 0; i < len; i++) {
> +		__raw_writel(prog[i], ssp->regs + offs + 4*i +
> +			     ssp_port_seqram[port]);
> +	}
> +
> +	/* Disable SeqRAM access */
> +	ssp_port_clr_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
> +
> +	spin_unlock(&ssp->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ti_ssp_load);
> +
> +int ti_ssp_raw_read(struct device *dev)
> +{
> +	struct ti_ssp *ssp = dev_to_ssp(dev);
> +	int port = dev_to_port(dev);
> +	u32 val;
> +
> +	val = ssp_read(ssp, REG_IOSEL_2);
> +	val >>= (port ? 27 : 11);
> +
> +	return val & 0x0f;
> +}
> +EXPORT_SYMBOL(ti_ssp_raw_read);
> +
> +int ti_ssp_raw_write(struct device *dev, u32 val)
> +{
> +	struct ti_ssp *ssp = dev_to_ssp(dev);
> +	int port = dev_to_port(dev);
> +	u32 mask;
> +
> +	spin_lock(&ssp->lock);
> +
> +	val &= 0x0f;
> +	val <<= (port ? 22 : 6);
> +	mask = 0x0f << (port ? 22 : 6);
> +	ssp_rmw(ssp, REG_IOSEL_2, mask, val);
> +
> +	spin_unlock(&ssp->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ti_ssp_raw_write);
> +
> +static inline int __xfer_done(struct ti_ssp *ssp, int port)
> +{
> +	return !(ssp_port_read(ssp, port, PORT_CFG_1) & SSP_BUSY);
> +}
> +
> +int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output)
> +{
> +	struct ti_ssp *ssp = dev_to_ssp(dev);
> +	int port = dev_to_port(dev);
> +	int ret;
> +
> +	if (pc & ~(0x3f))
> +		return -EINVAL;
> +
> +	/* Grab ssp->lock to serialize rmw on ssp registers */
> +	spin_lock(&ssp->lock);
> +
> +	ssp_port_write(ssp, port, PORT_ADDR, input >> 16);
> +	ssp_port_write(ssp, port, PORT_DATA, input & 0xffff);
> +	ssp_port_rmw(ssp, port, PORT_CFG_1, 0x3f, pc);
> +
> +	/* grab wait queue head lock to avoid race with the isr */
> +	spin_lock_irq(&ssp->wqh.lock);
> +
> +	/* kick off sequence execution in hardware */
> +	ssp_port_set_bits(ssp, port, PORT_CFG_1, SSP_START);
> +
> +	/* drop ssp lock; no register writes beyond this */
> +	spin_unlock(&ssp->lock);
> +
> +	ret = wait_event_interruptible_locked_irq(ssp->wqh,
> +						  __xfer_done(ssp, port));
> +	spin_unlock_irq(&ssp->wqh.lock);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	if (output) {
> +		*output = (ssp_port_read(ssp, port, PORT_ADDR) << 16) |
> +			  (ssp_port_read(ssp, port, PORT_DATA) &  0xffff);
> +	}
> +
> +	ret = ssp_port_read(ssp, port, PORT_STATE) & 0x3f; /* stop address */
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(ti_ssp_run);
> +
> +static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data)
> +{
> +	struct ti_ssp *ssp = dev_data;
> +
> +	spin_lock(&ssp->wqh.lock);
> +
> +	ssp_write(ssp, REG_INTR_ST, 0x3);
> +	wake_up_locked(&ssp->wqh);
> +
> +	spin_unlock(&ssp->wqh.lock);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int __devinit ti_ssp_probe(struct platform_device *pdev)
> +{
> +	static struct ti_ssp *ssp;
> +	const struct ti_ssp_data *pdata = pdev->dev.platform_data;
> +	int error = 0, prediv = 0xff, id;
> +	unsigned long sysclk;
> +	struct device *dev = &pdev->dev;
> +	struct mfd_cell cells[2];
> +
> +	ssp = kzalloc(sizeof(*ssp), GFP_KERNEL);
> +	if (!ssp) {
> +		dev_err(dev, "cannot allocate device info\n");
> +		return -ENOMEM;
> +	}
> +
> +	ssp->dev = dev;
> +	dev_set_drvdata(dev, ssp);
> +
> +	ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!ssp->res) {
> +		error = -ENODEV;
> +		dev_err(dev, "cannot determine register area\n");
> +		goto error_res;
> +	}
> +
> +	if (!request_mem_region(ssp->res->start, resource_size(ssp->res),
> +				pdev->name)) {
> +		error = -ENOMEM;
> +		dev_err(dev, "cannot claim register memory\n");
> +		goto error_res;
> +	}
> +
> +	ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res));
> +	if (!ssp->regs) {
> +		error = -ENOMEM;
> +		dev_err(dev, "cannot map register memory\n");
> +		goto error_map;
> +	}
> +
> +	ssp->clk = clk_get(dev, NULL);
> +	if (IS_ERR(ssp->clk)) {
> +		error = PTR_ERR(ssp->clk);
> +		dev_err(dev, "cannot claim device clock\n");
> +		goto error_clk;
> +	}
> +
> +	ssp->irq = platform_get_irq(pdev, 0);
> +	if (ssp->irq < 0) {
> +		error = -ENODEV;
> +		dev_err(dev, "unknown irq\n");
> +		goto error_irq;
> +	}
> +
> +	error = request_threaded_irq(ssp->irq, NULL, ti_ssp_interrupt, 0,
> +				   dev_name(dev), ssp);
> +	if (error < 0) {
> +		dev_err(dev, "cannot acquire irq\n");
> +		goto error_irq;
> +	}
> +
> +	spin_lock_init(&ssp->lock);
> +	init_waitqueue_head(&ssp->wqh);
> +
> +	/* Power on and initialize SSP */
> +	error = clk_enable(ssp->clk);
> +	if (error) {
> +		dev_err(dev, "cannot enable device clock\n");
> +		goto error_enable;
> +	}
> +
> +	/* Reset registers to a sensible known state */
> +	ssp_write(ssp, REG_IOSEL_1, 0);
> +	ssp_write(ssp, REG_IOSEL_2, 0);
> +	ssp_write(ssp, REG_INTR_EN, 0x3);
> +	ssp_write(ssp, REG_INTR_ST, 0x3);
> +	ssp_write(ssp, REG_TEST_CTRL, 0);
> +	ssp_port_write(ssp, 0, PORT_CFG_1, SSP_PORT_ASL);
> +	ssp_port_write(ssp, 1, PORT_CFG_1, SSP_PORT_ASL);
> +	ssp_port_write(ssp, 0, PORT_CFG_2, SSP_PORT_CFO1);
> +	ssp_port_write(ssp, 1, PORT_CFG_2, SSP_PORT_CFO1);
> +
> +	sysclk = clk_get_rate(ssp->clk);
> +	if (pdata && pdata->out_clock)
> +		prediv = (sysclk / pdata->out_clock) - 1;
> +	prediv = clamp(prediv, 0, 0xff);
> +	ssp_rmw(ssp, REG_PREDIV, 0xff, prediv);
> +
> +	memset(cells, 0, sizeof(cells));
> +	for (id = 0; id < 2; id++) {
> +		const struct ti_ssp_dev_data *data = &pdata->dev_data[id];
> +
> +		cells[id].id		= id;
> +		cells[id].name		= data->dev_name;
> +		cells[id].platform_data	= data->pdata;
> +		cells[id].data_size	= data->pdata_size;
> +	}
> +
> +	error = mfd_add_devices(dev, 0, cells, 2, NULL, 0);
> +	if (error < 0) {
> +		dev_err(dev, "cannot add mfd cells\n");
> +		goto error_enable;
> +	}
> +
> +	return 0;
> +
> +error_enable:
> +	free_irq(ssp->irq, ssp);
> +error_irq:
> +	clk_put(ssp->clk);
> +error_clk:
> +	iounmap(ssp->regs);
> +error_map:
> +	release_mem_region(ssp->res->start, resource_size(ssp->res));
> +error_res:
> +	kfree(ssp);
> +	return error;
> +}
> +
> +static int __devexit ti_ssp_remove(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct ti_ssp *ssp = dev_get_drvdata(dev);
> +
> +	mfd_remove_devices(dev);
> +	clk_disable(ssp->clk);
> +	free_irq(ssp->irq, ssp);
> +	clk_put(ssp->clk);
> +	iounmap(ssp->regs);
> +	release_mem_region(ssp->res->start, resource_size(ssp->res));
> +	kfree(ssp);
> +	dev_set_drvdata(dev, NULL);
> +	return 0;
> +}
> +
> +static struct platform_driver ti_ssp_driver = {
> +	.probe		= ti_ssp_probe,
> +	.remove		= __devexit_p(ti_ssp_remove),
> +	.driver		= {
> +		.name	= "ti-ssp",
> +		.owner	= THIS_MODULE,
> +	}
> +};
> +
> +static int __init ti_ssp_init(void)
> +{
> +	return platform_driver_register(&ti_ssp_driver);
> +}
> +arch_initcall_sync(ti_ssp_init);

This should be module_init().  More on this when I reply to the spi
driver.

> +
> +static void __exit ti_ssp_exit(void)
> +{
> +	platform_driver_unregister(&ti_ssp_driver);
> +}
> +module_exit(ti_ssp_exit);
> +
> +MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
> +MODULE_AUTHOR("Cyril Chemparathy");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:ti-ssp");
> diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h
> new file mode 100644
> index 0000000..021fe09
> --- /dev/null
> +++ b/include/linux/mfd/ti_ssp.h
> @@ -0,0 +1,87 @@
> +/*
> + * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
> + *
> + * Copyright (C) 2010 Texas Instruments Inc
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#ifndef __TI_SSP_H__
> +#define __TI_SSP_H__
> +
> +struct ti_ssp_dev_data {
> +	const char	*dev_name;
> +	void		*pdata;
> +	size_t		pdata_size;
> +};
> +
> +struct ti_ssp_data {
> +	unsigned long		out_clock;
> +	struct ti_ssp_dev_data	dev_data[2];
> +};
> +
> +/*
> + * Sequencer port IO pin configuration bits.  These do not correlate 1-1 with
> + * the hardware.  The iosel field in the port data combines iosel1 and iosel2,
> + * and is therefore not a direct map to register space.  It is best to use the
> + * macros below to construct iosel values.
> + *
> + * least significant 16 bits --> iosel1
> + * most significant 16 bits  --> iosel2
> + */
> +
> +#define SSP_IN			0x0000
> +#define SSP_DATA		0x0001
> +#define SSP_CLOCK		0x0002
> +#define SSP_CHIPSEL		0x0003
> +#define SSP_OUT			0x0004
> +#define SSP_PIN_SEL(pin, v)	((v) << ((pin) * 3))
> +#define SSP_PIN_MASK(pin)	SSP_PIN_SEL(pin, 0x7)
> +#define SSP_INPUT_SEL(pin)	((pin) << 16)
> +
> +/* Sequencer port config bits */
> +#define SSP_EARLY_DIN		BIT(8)
> +#define SSP_DELAY_DOUT		BIT(9)
> +
> +/* Sequence map definitions */
> +#define SSP_CLK_HIGH		BIT(0)
> +#define SSP_CLK_LOW		0
> +#define SSP_DATA_HIGH		BIT(1)
> +#define SSP_DATA_LOW		0
> +#define SSP_CS_HIGH		BIT(2)
> +#define SSP_CS_LOW		0
> +#define SSP_OUT_MODE		BIT(3)
> +#define SSP_IN_MODE		0
> +#define SSP_DATA_REG		BIT(4)
> +#define SSP_ADDR_REG		0
> +
> +#define SSP_OPCODE_DIRECT	((0x0) << 5)
> +#define SSP_OPCODE_TOGGLE	((0x1) << 5)
> +#define SSP_OPCODE_SHIFT	((0x2) << 5)
> +#define SSP_OPCODE_BRANCH0	((0x4) << 5)
> +#define SSP_OPCODE_BRANCH1	((0x5) << 5)
> +#define SSP_OPCODE_BRANCH	((0x6) << 5)
> +#define SSP_OPCODE_STOP		((0x7) << 5)
> +#define SSP_BRANCH(addr)	((addr) << 8)
> +#define SSP_COUNT(cycles)	((cycles) << 8)
> +
> +int ti_ssp_raw_read(struct device *dev);
> +int ti_ssp_raw_write(struct device *dev, u32 val);
> +int ti_ssp_load(struct device *dev, int offs, u32* prog, int len);
> +int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output);
> +int ti_ssp_set_mode(struct device *dev, int mode);
> +int ti_ssp_set_iosel(struct device *dev, u32 iosel);
> +
> +#endif /* __TI_SSP_H__ */
> -- 
> 1.7.1
> 

------------------------------------------------------------------------------
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/msIE9-sfdev2dev

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
       [not found]     ` <1289848334-8695-5-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
@ 2010-11-16  7:22       ` Grant Likely
       [not found]         ` <20101116072225.GF4074-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
  0 siblings, 1 reply; 37+ messages in thread
From: Grant Likely @ 2010-11-16  7:22 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Mon, Nov 15, 2010 at 02:12:06PM -0500, 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>
[...]
> +static int __init ti_ssp_spi_init(void)
> +{
> +	return platform_driver_register(&ti_ssp_spi_driver);
> +}
> +subsys_initcall(ti_ssp_spi_init);

After discussions about device init dependencies at plumbers, and
since this is the first SPI device driver I've reviewed since that
dicussion, this driver gets to be the first to implement the proposed
policy.  :-)

Change this to module_initcall().  Many spi and i2c drivers use
module or subsys_initcall to try and influence driver probe order so
that certain regulator chips get registered before the devices that
try to use them.  This approach is insane.

Instead, it is now incumbent on the board support code to ensure that
any device that depends on another device (including i2c or spi
regulators) will defer registration until the prerequisite devices are
bound to drivers.

I don't *think* this change will affect anything in this particular
patch series, but if it does then let me know and I'll help you work out
how to fix it using a bus notifier.

g.


------------------------------------------------------------------------------
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/msIE9-sfdev2dev

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
       [not found]         ` <20101116072225.GF4074-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
@ 2010-11-16  7:47           ` Grant Likely
  2010-11-16 11:34             ` Mark Brown
       [not found]             ` <AANLkTi=utWumLKo9QVWXpkC8WxpgaNJJs+dj=pa2eq-q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  2010-11-16 14:19           ` David Brownell
  1 sibling, 2 replies; 37+ messages in thread
From: Grant Likely @ 2010-11-16  7:47 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Tue, Nov 16, 2010 at 12:22 AM, Grant Likely
<grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org> wrote:
> On Mon, Nov 15, 2010 at 02:12:06PM -0500, 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>
> [...]
>> +static int __init ti_ssp_spi_init(void)
>> +{
>> +     return platform_driver_register(&ti_ssp_spi_driver);
>> +}
>> +subsys_initcall(ti_ssp_spi_init);
>
> After discussions about device init dependencies at plumbers, and
> since this is the first SPI device driver I've reviewed since that
> dicussion, this driver gets to be the first to implement the proposed
> policy.  :-)
>
> Change this to module_initcall().  Many spi and i2c drivers use
> module or subsys_initcall to try and influence driver probe order so
> that certain regulator chips get registered before the devices that
> try to use them.  This approach is insane.
>
> Instead, it is now incumbent on the board support code to ensure that
> any device that depends on another device (including i2c or spi
> regulators) will defer registration until the prerequisite devices are
> bound to drivers.
>
> I don't *think* this change will affect anything in this particular
> patch series, but if it does then let me know and I'll help you work out
> how to fix it using a bus notifier.

Oh, wait, spoke too soon.  You do add a regulator in this series, so
this change will require a fixup.  The solution is to register an
bus_notifier to the spi bus type before you start registering devices.
It also requires deferring the musb_hdrc.1 and tps6116x registrations
until the bus_notifier callback gets called with an indication that
the regulator is bound.  It will look something like this:

static int tnetv107x_spi_notifier_call(struct notifier_block *nb,
				unsigned long event, void *__dev)
{
	struct device *dev = __dev;

	if ((event == BUS_NOTIFY_BOUND_DRIVER) && (dev == (the-regulator))) {
		register-the-remaining-devices();
		return NOTIFY_STOP;
	};
	return NOTIFY_DONE;
}

static struct notifier_block tnetv107x_spi_nb = {
	.notifier_call = tnetv107x_spi_notifier_call,
};

and then in the device registration code, before registering the
regulator:

	bus_register_notifier(&spi_bus_type, &tnetv107x_spi_nb);

Let me know if you have any trouble.

g.

------------------------------------------------------------------------------
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/msIE9-sfdev2dev

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
  2010-11-16  7:47           ` Grant Likely
@ 2010-11-16 11:34             ` Mark Brown
       [not found]               ` <20101116113409.GH3338-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
       [not found]             ` <AANLkTi=utWumLKo9QVWXpkC8WxpgaNJJs+dj=pa2eq-q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  1 sibling, 1 reply; 37+ messages in thread
From: Mark Brown @ 2010-11-16 11:34 UTC (permalink / raw)
  To: Grant Likely
  Cc: davinci-linux-open-source, dbrownell, sameo, khilman,
	linus.ml.walleij, rpurdie, linux-arm-kernel, Cyril Chemparathy,
	spi-devel-general, akpm, alan, lrg

On Tue, Nov 16, 2010 at 12:47:04AM -0700, Grant Likely wrote:
> On Tue, Nov 16, 2010 at 12:22 AM, Grant Likely

> > Instead, it is now incumbent on the board support code to ensure that
> > any device that depends on another device (including i2c or spi
> > regulators) will defer registration until the prerequisite devices are
> > bound to drivers.

You did also say you were going to write helpers to make this easier - I
do fear that we're going to end up with far too much boiler plate code
in machine drivers if we have to open code this.  I guess device tree is
going to need the helpers anyway :)

> > I don't *think* this change will affect anything in this particular
> > patch series, but if it does then let me know and I'll help you work out
> > how to fix it using a bus notifier.

> Oh, wait, spoke too soon.  You do add a regulator in this series, so
> this change will require a fixup.  The solution is to register an
> bus_notifier to the spi bus type before you start registering devices.

> It also requires deferring the musb_hdrc.1 and tps6116x registrations
> until the bus_notifier callback gets called with an indication that
> the regulator is bound.  It will look something like this:

Did you come up with a way of handling situations like cpufreq where we
have no device to wait for?

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
       [not found]         ` <20101116072225.GF4074-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
  2010-11-16  7:47           ` Grant Likely
@ 2010-11-16 14:19           ` David Brownell
  1 sibling, 0 replies; 37+ messages in thread
From: David Brownell @ 2010-11-16 14:19 UTC (permalink / raw)
  To: Grant Likely
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	linus.ml.walleij-Re5JQEeQqe8AvxtiuMwx3w,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Tue, 2010-11-16 at 00:22 -0700, Grant Likely wrote:

> 
> After discussions about device init dependencies at plumbers, and
> since this is the first SPI device driver I've reviewed since that
> dicussion, this driver gets to be the first to implement the proposed
> policy.  :-)
> 
> Change this to module_initcall().  Many spi and i2c drivers use
> module or subsys_initcall to try and influence driver probe order so
> that certain regulator chips get registered before the devices that
> try to use them.  This approach is insane.

Last I observed the issue ... the situation was that various core
drivers were required to be able to say that a key subsystem was
functional ... with said subsystem required to boot properly.

The dependency being, that is, driver on subsystem (but that subsystem
needed a core/bus driver running before it could work.

What's insane is that Linux *STILL* has no clean way to express that
type of system dependency ... where driver dependencies are pure side
effects.  (Albeit ones that never change on many platforms, but where
board-specific differences are routine, and have the same kind of
indirect dependencies.


- Dave

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

* Re: [PATCH v5 01/12] misc: add driver for sequencer serial port
       [not found]         ` <20101116071047.GE4074-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
@ 2010-11-16 16:15           ` Cyril Chemparathy
       [not found]             ` <4CE2AE3C.4040805-l0cyMroinI0@public.gmane.org>
  0 siblings, 1 reply; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-16 16:15 UTC (permalink / raw)
  To: Grant Likely
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On 11/16/2010 02:10 AM, Grant Likely wrote:
> On Mon, Nov 15, 2010 at 02:12:03PM -0500, 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.
>>
[...]
>> +static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val)
>> +{
>> +     __raw_writel(val, ssp->regs + reg);
>> +}
> 
> I'm pretty sure it was resolved that __raw_ versions should not be
> used here.

The endian-swap done by writel/readl are incorrect since these devices
are meant to be accessed native-endian at all times.

See [1] below for Russell King's earlier response on this.  In this
case, I don't think memory-device ordering matters, and therefore the
__raw_ variants should be ok.  Should I just insert barriers into the
read/write wrappers here?

[...]

Regards
Cyril.

[1] http://kerneltrap.org/mailarchive/linux-kernel/2010/10/22/4636289

------------------------------------------------------------------------------
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/msIE9-sfdev2dev

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

* Re: [PATCH v5 08/12] gpio: add ti-ssp gpio driver
       [not found]         ` <4CE1B651.1060006-7Wk5F4Od5/oYd5yxfr4S2w@public.gmane.org>
@ 2010-11-16 19:38           ` Cyril Chemparathy
  0 siblings, 0 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-16 19:38 UTC (permalink / raw)
  To: Ryan Mallon
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On 11/15/2010 05:38 PM, Ryan Mallon wrote:
> On 11/16/2010 08:12 AM, Cyril Chemparathy wrote:
>> TI's SSP controller pins can be directly read and written to behave like a
>> GPIO.  This patch adds a GPIO driver that exposes such functionality.
>>
>> Signed-off-by: Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org>
>> ---
[...]
>> +	spin_lock_init(&gpio->lock);
>> +	platform_set_drvdata(pdev, gpio);
>> +
>> +	gpio->chip.base  = pdata->start;
>> +	gpio->chip.ngpio = 4;
> 
> Is this always four or can the SSP peripheral be configured to have
> varying numbers of gpios. Maybe the number of gpios should be passed via
> platform data?
> 

This can only be 4 (hw defined per-port limit).

I have changed as per your other comments, and will post an update.

Thanks
Cyril.

------------------------------------------------------------------------------
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/msIE9-sfdev2dev

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

* Re: [PATCH v5 01/12] misc: add driver for sequencer serial port
       [not found]             ` <4CE2AE3C.4040805-l0cyMroinI0@public.gmane.org>
@ 2010-11-16 20:35               ` Grant Likely
       [not found]                 ` <AANLkTik76EY8Xh01YP2Tep6k1ETPO+3idmNuk3pVikJG-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 37+ messages in thread
From: Grant Likely @ 2010-11-16 20:35 UTC (permalink / raw)
  To: cyril-l0cyMroinI0
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Tue, Nov 16, 2010 at 9:15 AM, Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org> wrote:
> On 11/16/2010 02:10 AM, Grant Likely wrote:
>> On Mon, Nov 15, 2010 at 02:12:03PM -0500, 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.
>>>
> [...]
>>> +static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val)
>>> +{
>>> +     __raw_writel(val, ssp->regs + reg);
>>> +}
>>
>> I'm pretty sure it was resolved that __raw_ versions should not be
>> used here.
>
> The endian-swap done by writel/readl are incorrect since these devices
> are meant to be accessed native-endian at all times.
>
> See [1] below for Russell King's earlier response on this.  In this
> case, I don't think memory-device ordering matters, and therefore the
> __raw_ variants should be ok.  Should I just insert barriers into the
> read/write wrappers here?

I'll let Russel make the decision here; but I must admit I'm puzzled.
Are you running an ARMEB machine?  the le32_to_cpu macros should be
no-ops on little endian.  If you do still use the __raw variants, then
at the very least the reason for doing so must be well documented.

Personally, I'd rather see the appropriate macros added to io.h
ioread32be()/iowrite32be() perhaps?  Or am I missing something subtle
about the hardware behaviour?

g.

------------------------------------------------------------------------------
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/msIE9-sfdev2dev

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
       [not found]               ` <20101116113409.GH3338-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
@ 2010-11-16 20:45                 ` Grant Likely
       [not found]                   ` <20101116204554.GB5016-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
  0 siblings, 1 reply; 37+ messages in thread
From: Grant Likely @ 2010-11-16 20:45 UTC (permalink / raw)
  To: Mark Brown
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Cyril Chemparathy,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Tue, Nov 16, 2010 at 11:34:09AM +0000, Mark Brown wrote:
> On Tue, Nov 16, 2010 at 12:47:04AM -0700, Grant Likely wrote:
> > On Tue, Nov 16, 2010 at 12:22 AM, Grant Likely
> 
> > > Instead, it is now incumbent on the board support code to ensure that
> > > any device that depends on another device (including i2c or spi
> > > regulators) will defer registration until the prerequisite devices are
> > > bound to drivers.
> 
> You did also say you were going to write helpers to make this easier - I
> do fear that we're going to end up with far too much boiler plate code
> in machine drivers if we have to open code this.  I guess device tree is
> going to need the helpers anyway :)

Yup, and I will, but as can be seen the boilerplate required is
actually pretty minimal, and I'd like to have a couple of platforms to
work with before actually settling on what the helpers need to look
like.

> 
> > > I don't *think* this change will affect anything in this particular
> > > patch series, but if it does then let me know and I'll help you work out
> > > how to fix it using a bus notifier.
> 
> > Oh, wait, spoke too soon.  You do add a regulator in this series, so
> > this change will require a fixup.  The solution is to register an
> > bus_notifier to the spi bus type before you start registering devices.
> 
> > It also requires deferring the musb_hdrc.1 and tps6116x registrations
> > until the bus_notifier callback gets called with an indication that
> > the regulator is bound.  It will look something like this:
> 
> Did you come up with a way of handling situations like cpufreq where we
> have no device to wait for?

Haven't dug into it yet.

g.


------------------------------------------------------------------------------
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/msIE9-sfdev2dev

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

* Re: [PATCH v5 01/12] misc: add driver for sequencer serial port
       [not found]                 ` <AANLkTik76EY8Xh01YP2Tep6k1ETPO+3idmNuk3pVikJG-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2010-11-16 21:19                   ` Cyril Chemparathy
  2010-11-16 22:23                   ` Russell King - ARM Linux
  1 sibling, 0 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-16 21:19 UTC (permalink / raw)
  To: Grant Likely
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	linus.ml.walleij-Re5JQEeQqe8AvxtiuMwx3w,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On 11/16/2010 03:35 PM, Grant Likely wrote:
> On Tue, Nov 16, 2010 at 9:15 AM, Cyril Chemparathy <cyril-l0cyMroinI0@public.gmane.org> wrote:
>> On 11/16/2010 02:10 AM, Grant Likely wrote:
>>> On Mon, Nov 15, 2010 at 02:12:03PM -0500, 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.
>>>>
>> [...]
>>>> +static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val)
>>>> +{
>>>> +     __raw_writel(val, ssp->regs + reg);
>>>> +}
>>>
>>> I'm pretty sure it was resolved that __raw_ versions should not be
>>> used here.
>>
>> The endian-swap done by writel/readl are incorrect since these devices
>> are meant to be accessed native-endian at all times.
>>
>> See [1] below for Russell King's earlier response on this.  In this
>> case, I don't think memory-device ordering matters, and therefore the
>> __raw_ variants should be ok.  Should I just insert barriers into the
>> read/write wrappers here?
> 
> I'll let Russel make the decision here; but I must admit I'm puzzled.
> Are you running an ARMEB machine?  the le32_to_cpu macros should be
> no-ops on little endian.  If you do still use the __raw variants, then
> at the very least the reason for doing so must be well documented.
> 
> Personally, I'd rather see the appropriate macros added to io.h
> ioread32be()/iowrite32be() perhaps?  Or am I missing something subtle
> about the hardware behaviour?
> 

As with most of the davinci series devices, the tnetv107x SOC can
"theoretically" run both big and little endian.  Since the CPU and SOC
endian-ness are tied, on-chip peripherals are to be accessed
native-endian (i.e. without swap) at all times.

However, many of these parts do not "officially" support big-endian, and
this is the case with tnetv107x as well.  Even so, it would be best not
to break this, just in case these h/w blocks get reused on some future
big-endian capable derivative.

Further, I found this to be common practice across many davinci drivers:

$ find . -name '*davinci*' | xargs grep __raw_ | cut -d: -f1 | uniq
./drivers/input/keyboard/davinci_keyscan.c
./drivers/mtd/nand/davinci_nand.c
./drivers/mfd/davinci_voicecodec.c
./drivers/i2c/busses/i2c-davinci.c
./drivers/usb/musb/davinci.c
./drivers/net/davinci_mdio.c
./drivers/net/davinci_cpdma.c
./sound/soc/davinci/davinci-mcasp.c
./sound/soc/davinci/davinci-i2s.c

Regards
Cyril.

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

* Re: [PATCH v5 01/12] misc: add driver for sequencer serial port
       [not found]                 ` <AANLkTik76EY8Xh01YP2Tep6k1ETPO+3idmNuk3pVikJG-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  2010-11-16 21:19                   ` Cyril Chemparathy
@ 2010-11-16 22:23                   ` Russell King - ARM Linux
       [not found]                     ` <20101116222340.GF21926-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
  1 sibling, 1 reply; 37+ messages in thread
From: Russell King - ARM Linux @ 2010-11-16 22:23 UTC (permalink / raw)
  To: Grant Likely
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	linus.ml.walleij-Re5JQEeQqe8AvxtiuMwx3w,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Tue, Nov 16, 2010 at 01:35:40PM -0700, Grant Likely wrote:
> I'll let Russel make the decision here; but I must admit I'm puzzled.
                 ^
Grr.

I'm ambivalent over it, provided that the author realises that the
__raw variants have no ordering guarantees other than their accesses
being ordered only with respect to themselves and nothing else.

If we do want to go down the route of creating some official native
endian accessors, then I'm fine with that too.

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
       [not found]                   ` <20101116204554.GB5016-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
@ 2010-11-16 22:48                     ` Mark Brown
  0 siblings, 0 replies; 37+ messages in thread
From: Mark Brown @ 2010-11-16 22:48 UTC (permalink / raw)
  To: Grant Likely
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	linus.ml.walleij-Re5JQEeQqe8AvxtiuMwx3w,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Tue, Nov 16, 2010 at 01:45:54PM -0700, Grant Likely wrote:
> On Tue, Nov 16, 2010 at 11:34:09AM +0000, Mark Brown wrote:

> > You did also say you were going to write helpers to make this easier - I
> > do fear that we're going to end up with far too much boiler plate code
> > in machine drivers if we have to open code this.  I guess device tree is
> > going to need the helpers anyway :)

> Yup, and I will, but as can be seen the boilerplate required is
> actually pretty minimal, and I'd like to have a couple of platforms to
> work with before actually settling on what the helpers need to look
> like.

Yeah, but I do have a bit of nervousness about the scalability of open
coding and the possibility that we'll come up with a better approach so
I'd be a bit more comfortable if we didn't have code in random board
files as they're always the hardest thing to update.

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

* Re: [PATCH v5 01/12] misc: add driver for sequencer serial port
       [not found]                     ` <20101116222340.GF21926-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
@ 2010-11-16 23:57                       ` Grant Likely
  0 siblings, 0 replies; 37+ messages in thread
From: Grant Likely @ 2010-11-16 23:57 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	linus.ml.walleij-Re5JQEeQqe8AvxtiuMwx3w,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Tue, Nov 16, 2010 at 3:23 PM, Russell King - ARM Linux
<linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org> wrote:
> On Tue, Nov 16, 2010 at 01:35:40PM -0700, Grant Likely wrote:
>> I'll let Russel make the decision here; but I must admit I'm puzzled.
>                 ^
> Grr.

Sorry; typo.  I *do* know how to spell your name.  :-)  I owe you a
pint and we'll call it even.

g.

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
       [not found]             ` <AANLkTi=utWumLKo9QVWXpkC8WxpgaNJJs+dj=pa2eq-q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2010-11-17  0:17               ` Cyril Chemparathy
  2010-11-17 13:31                 ` Mark Brown
       [not found]                 ` <4CE31F0E.7050103-l0cyMroinI0@public.gmane.org>
  0 siblings, 2 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-17  0:17 UTC (permalink / raw)
  To: Grant Likely
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	linus.ml.walleij-Re5JQEeQqe8AvxtiuMwx3w,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On 11/16/2010 02:47 AM, Grant Likely wrote:
> On Tue, Nov 16, 2010 at 12:22 AM, Grant Likely
> <grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org> wrote:
>> On Mon, Nov 15, 2010 at 02:12:06PM -0500, 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>
>> [...]
>>> +static int __init ti_ssp_spi_init(void)
>>> +{
>>> +     return platform_driver_register(&ti_ssp_spi_driver);
>>> +}
>>> +subsys_initcall(ti_ssp_spi_init);
>>
>> After discussions about device init dependencies at plumbers, and
>> since this is the first SPI device driver I've reviewed since that
>> dicussion, this driver gets to be the first to implement the proposed
>> policy.  :-)
>>
>> Change this to module_initcall().  Many spi and i2c drivers use
>> module or subsys_initcall to try and influence driver probe order so
>> that certain regulator chips get registered before the devices that
>> try to use them.  This approach is insane.
>>
>> Instead, it is now incumbent on the board support code to ensure that
>> any device that depends on another device (including i2c or spi
>> regulators) will defer registration until the prerequisite devices are
>> bound to drivers.
>>
>> I don't *think* this change will affect anything in this particular
>> patch series, but if it does then let me know and I'll help you work out
>> how to fix it using a bus notifier.
> 
> Oh, wait, spoke too soon.  You do add a regulator in this series, so
> this change will require a fixup.  The solution is to register an
> bus_notifier to the spi bus type before you start registering devices.
> It also requires deferring the musb_hdrc.1 and tps6116x registrations
> until the bus_notifier callback gets called with an indication that
> the regulator is bound.  It will look something like this:
> 
> static int tnetv107x_spi_notifier_call(struct notifier_block *nb,
> 				unsigned long event, void *__dev)
> {
> 	struct device *dev = __dev;
> 
> 	if ((event == BUS_NOTIFY_BOUND_DRIVER) && (dev == (the-regulator))) {
> 		register-the-remaining-devices();
> 		return NOTIFY_STOP;
> 	};
> 	return NOTIFY_DONE;
> }
> 
> static struct notifier_block tnetv107x_spi_nb = {
> 	.notifier_call = tnetv107x_spi_notifier_call,
> };
> 
> and then in the device registration code, before registering the
> regulator:
> 
> 	bus_register_notifier(&spi_bus_type, &tnetv107x_spi_nb);
> 
> Let me know if you have any trouble.

The ability to wait on multiple devices may come handy.  In this
particular case the backlight driver depends on both ssp-gpio and
regulator devices.  Ideally, boards should be able to do something like...

platform_device_register_after(&backlight_device, "spi1.0");
platform_device_register_after(&backlight_device, "ti-ssp-gpio.0");

... and the device should get automatically registered once its
dependencies have been met.


Crude and incomplete code follows:

struct platform_device_depend {
	struct list_head node;
	const char *dev_name;
	struct platform_device *pdev;
};

LIST_HEAD(platform_device_depend);

static int platform_device_register_after(struct platform_device *pdev,
					  const char *dev_name)
{
	struct platform_device_depend *dep;

	dep = kzalloc(sizeof(*dep), GFP_KERNEL);
	if (!dep)
		return -ENOMEM;
	dep->dev_name = dev_name;
	dep->pdev = pdev;
	list_add_tail(&dep->node, &platform_device_depend);
	return 0;
}

static int platform_device_try_register(struct platform_device *pdev)
{
	struct platform_device_depend *dep;

	list_for_each_entry(dep, &platform_device_depend, node) {
		if (dep->pdev == pdev)
			return -EBUSY;
	}
	return platform_device_register(pdev);
}

static int bus_notifier_func(struct notifier_block *nb,
			     unsigned long event, void *__dev)
{
	struct platform_device_depend *dep, *tmp;
	struct device *dev = __dev;

	if (event != BUS_NOTIFY_BOUND_DRIVER)
		return NOTIFY_DONE;

	list_for_each_entry_safe(dep, tmp, &platform_device_depend,
				 node) {
		if (strcmp(dep->dev_name, dev_name(dev)) != 0)
			continue;
		list_del(&dep->node);
		platform_device_try_register(dep->pdev);
		kfree(dep);
	}

	return NOTIFY_OK;
}

Regards
Cyril.

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
  2010-11-17  0:17               ` Cyril Chemparathy
@ 2010-11-17 13:31                 ` Mark Brown
       [not found]                   ` <20101117133136.GA19488-HF5t3jzXg/6ND3a5+9QAFujbO/Zr0HzV@public.gmane.org>
       [not found]                 ` <4CE31F0E.7050103-l0cyMroinI0@public.gmane.org>
  1 sibling, 1 reply; 37+ messages in thread
From: Mark Brown @ 2010-11-17 13:31 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: davinci-linux-open-source, dbrownell, sameo, khilman,
	linus.ml.walleij, Grant Likely, rpurdie, alan, spi-devel-general,
	akpm, linux-arm-kernel, lrg

On Tue, Nov 16, 2010 at 07:17:18PM -0500, Cyril Chemparathy wrote:

> The ability to wait on multiple devices may come handy.  In this

This is essential for any helpers, otherwise we can't cope easily with
mixes of GPIO and power or with regulators from multiple chips (like an
extra DCDC, for example).

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
       [not found]                   ` <20101117133136.GA19488-HF5t3jzXg/6ND3a5+9QAFujbO/Zr0HzV@public.gmane.org>
@ 2010-11-17 15:25                     ` David Brownell
       [not found]                       ` <781931.83221.qm-g47maUHHHF+ORdMXk8NaZPu2YVrzzGjVVpNB7YpNyf8@public.gmane.org>
  0 siblings, 1 reply; 37+ messages in thread
From: David Brownell @ 2010-11-17 15:25 UTC (permalink / raw)
  To: Cyril Chemparathy, Mark Brown
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	linus.ml.walleij-Re5JQEeQqe8AvxtiuMwx3w, Grant Likely,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	lrg-kDsPt+C1G03kYMGBc/C6ZA


> On Tue, Nov 16, 2010 at 07:17:18PM
> -0500, Cyril Chemparathy wrote:
> 
> > The ability to wait on multiple devices may come
> handy.

... You mean you'd like to add such a 
mechanism to the framework? 

Or do you want a driver-specific
mechanism (non-portable)?


 If I had
to do that, I'd just use existing
kernel mechanisms to wait, and then
issue SPI transactions as needed.
Portable, straightforward.

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
       [not found]                 ` <4CE31F0E.7050103-l0cyMroinI0@public.gmane.org>
@ 2010-11-17 16:11                   ` Grant Likely
       [not found]                     ` <20101117161130.GC5757-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
  0 siblings, 1 reply; 37+ messages in thread
From: Grant Likely @ 2010-11-17 16:11 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	linus.ml.walleij-Re5JQEeQqe8AvxtiuMwx3w,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	Rafael J. Wysocki, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b, Greg Kroah-Hartman,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Tue, Nov 16, 2010 at 07:17:18PM -0500, Cyril Chemparathy wrote:
> On 11/16/2010 02:47 AM, Grant Likely wrote:
> > On Tue, Nov 16, 2010 at 12:22 AM, Grant Likely
> > <grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org> wrote:
> >> On Mon, Nov 15, 2010 at 02:12:06PM -0500, 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>
> >> [...]
> >>> +static int __init ti_ssp_spi_init(void)
> >>> +{
> >>> +     return platform_driver_register(&ti_ssp_spi_driver);
> >>> +}
> >>> +subsys_initcall(ti_ssp_spi_init);
> >>
> >> After discussions about device init dependencies at plumbers, and
> >> since this is the first SPI device driver I've reviewed since that
> >> dicussion, this driver gets to be the first to implement the proposed
> >> policy.  :-)
> >>
> >> Change this to module_initcall().  Many spi and i2c drivers use
> >> module or subsys_initcall to try and influence driver probe order so
> >> that certain regulator chips get registered before the devices that
> >> try to use them.  This approach is insane.
> >>
> >> Instead, it is now incumbent on the board support code to ensure that
> >> any device that depends on another device (including i2c or spi
> >> regulators) will defer registration until the prerequisite devices are
> >> bound to drivers.
> >>
> >> I don't *think* this change will affect anything in this particular
> >> patch series, but if it does then let me know and I'll help you work out
> >> how to fix it using a bus notifier.
> > 
> > Oh, wait, spoke too soon.  You do add a regulator in this series, so
> > this change will require a fixup.  The solution is to register an
> > bus_notifier to the spi bus type before you start registering devices.
> > It also requires deferring the musb_hdrc.1 and tps6116x registrations
> > until the bus_notifier callback gets called with an indication that
> > the regulator is bound.  It will look something like this:
> > 
> > static int tnetv107x_spi_notifier_call(struct notifier_block *nb,
> > 				unsigned long event, void *__dev)
> > {
> > 	struct device *dev = __dev;
> > 
> > 	if ((event == BUS_NOTIFY_BOUND_DRIVER) && (dev == (the-regulator))) {
> > 		register-the-remaining-devices();
> > 		return NOTIFY_STOP;
> > 	};
> > 	return NOTIFY_DONE;
> > }
> > 
> > static struct notifier_block tnetv107x_spi_nb = {
> > 	.notifier_call = tnetv107x_spi_notifier_call,
> > };
> > 
> > and then in the device registration code, before registering the
> > regulator:
> > 
> > 	bus_register_notifier(&spi_bus_type, &tnetv107x_spi_nb);
> > 
> > Let me know if you have any trouble.
> 
> The ability to wait on multiple devices may come handy.  In this
> particular case the backlight driver depends on both ssp-gpio and
> regulator devices.  Ideally, boards should be able to do something like...
> 
> platform_device_register_after(&backlight_device, "spi1.0");
> platform_device_register_after(&backlight_device, "ti-ssp-gpio.0");

[cc'ing Rafael and Greg since they are certain to be interested in
this discussion]

It's a good start.  However, I think it can be done more generically

To start, I'm not a fan of matching by name.  It's fragile because it
makes assumptions about how devices will be names when they actually
appear (ie. Sometimes .id is dynamically assigned).  Ideally I'd
prefer to have direct references (ie. pointers) to the devices that
need to be registered, which *shouldn't* be difficult to handle.  That
guarantees that the correct device is always referenced.  (aside: the
device-tree use case provides this information by having direct
'phandle' references between dependencies.)

Also, any dependency tracking must work across bus_types.  It is not
sufficient to only handle the platform_devices use-case.  All bus
types have this need.

I see a few potential approaches.

Option 1: Add a list of prerequisite devices to struct device and
modify driver core so that it defers binding to a driver until all the
prerequisites are already bound.  This can probably be implemented
in a way that works for all bus types transparently.  Before binding
a driver, the driver core would increase the ref count on each of the
prereq devices, and decrease it again when the driver is removed.

Option 2: On a per-bus_type basis have a separate registration and the
bus type code would hold the device unregistered in a pending list.
This option would also add a prerequisites list to struct device.

Option 3: Don't try to handle it in the bus_type or driver core code
at all, but rather provide board support code with helpers to make
waiting for other devices easy.  Even in this case I think it is
probably still a good idea for the dependant devices to increment
the refcount of the prereq devices.

Perhaps something that is used like:

void do_second_registration(void)
{
	/* register list of dependant devices */
}

and then in the primary registration function:
	...
	device_notify_when_bound(&prereq_pdev->dev,
				 do_second_registration);
	platform_device_add(prereq_pdev);
	...

which would reduce the boilerplate, but remain flexible.  However,
while flexable, option 3 doesn't solve the dependency tracking
problem, and it still requires some gymnastics to handle multiple
dependencies.

On a related issue, it may also be desirable for each device to
maintain a list of devices that have claimed dependency on it for the
purpose of debugability.

...

some other random comments below.

> 
> ... and the device should get automatically registered once its
> dependencies have been met.

unfortunately it also means that the device is in limbo between when
it is "registered" by board support code, and when it is actually
registered.  ie. It won't show up in sysfs.

> 
> 
> Crude and incomplete code follows:
> 
> struct platform_device_depend {
> 	struct list_head node;
> 	const char *dev_name;
> 	struct platform_device *pdev;
> };
> 
> LIST_HEAD(platform_device_depend);
> 
> static int platform_device_register_after(struct platform_device *pdev,
> 					  const char *dev_name)
> {
> 	struct platform_device_depend *dep;
> 
> 	dep = kzalloc(sizeof(*dep), GFP_KERNEL);
> 	if (!dep)
> 		return -ENOMEM;
> 	dep->dev_name = dev_name;
> 	dep->pdev = pdev;
> 	list_add_tail(&dep->node, &platform_device_depend);
> 	return 0;
> }
> 
> static int platform_device_try_register(struct platform_device *pdev)
> {
> 	struct platform_device_depend *dep;
> 
> 	list_for_each_entry(dep, &platform_device_depend, node) {
> 		if (dep->pdev == pdev)
> 			return -EBUSY;
> 	}
> 	return platform_device_register(pdev);
> }
> 
> static int bus_notifier_func(struct notifier_block *nb,
> 			     unsigned long event, void *__dev)
> {
> 	struct platform_device_depend *dep, *tmp;
> 	struct device *dev = __dev;
> 
> 	if (event != BUS_NOTIFY_BOUND_DRIVER)
> 		return NOTIFY_DONE;
> 
> 	list_for_each_entry_safe(dep, tmp, &platform_device_depend,
> 				 node) {
> 		if (strcmp(dep->dev_name, dev_name(dev)) != 0)
> 			continue;
> 		list_del(&dep->node);
> 		platform_device_try_register(dep->pdev);

Unfortunately this approach means the board support code will never
know if there is a problem with registering the device.

> 		kfree(dep);
> 	}
> 
> 	return NOTIFY_OK;

If it is part of the core platform_bus_type code, then there is no
need to use a notifier.  The hook can be added directly.

g.

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
       [not found]                     ` <20101117161130.GC5757-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
@ 2010-11-17 17:23                       ` Mark Brown
  2010-11-17 17:35                       ` Cyril Chemparathy
  2010-11-18  5:46                       ` Greg KH
  2 siblings, 0 replies; 37+ messages in thread
From: Mark Brown @ 2010-11-17 17:23 UTC (permalink / raw)
  To: Grant Likely
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR, Greg Kroah-Hartman,
	Rafael J. Wysocki, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Cyril Chemparathy,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Wed, Nov 17, 2010 at 09:11:30AM -0700, Grant Likely wrote:

> To start, I'm not a fan of matching by name.  It's fragile because it
> makes assumptions about how devices will be names when they actually
> appear (ie. Sometimes .id is dynamically assigned).  Ideally I'd
> prefer to have direct references (ie. pointers) to the devices that
> need to be registered, which *shouldn't* be difficult to handle.  That

Pointers are a complete pain for buses where things are dynamically
instantiated, the things you have to point at in machine data aren't the
things that end up appearing during device registration when the struct
device gets dynamically allocated so you need some way of translating
them.  This is why everyone ends up using dev_name for this sort of
thing ATM, it's easy to put into the code and match against the actual
struct device at runtime without needing to know about bus types.

> guarantees that the correct device is always referenced.  (aside: the
> device-tree use case provides this information by having direct
> 'phandle' references between dependencies.)

Device tree makes this a lot easier.

> Option 1: Add a list of prerequisite devices to struct device and
> modify driver core so that it defers binding to a driver until all the
> prerequisites are already bound.  This can probably be implemented
> in a way that works for all bus types transparently.  Before binding
> a driver, the driver core would increase the ref count on each of the
> prereq devices, and decrease it again when the driver is removed.

> Option 2: On a per-bus_type basis have a separate registration and the
> bus type code would hold the device unregistered in a pending list.
> This option would also add a prerequisites list to struct device.

Per bus type sounds like a lot of hassle going through all the bus types
but we may need to do that to handle autoprobable buses like USB.  I do
like the idea that the core would know what's going on so that things do
become visible for the debuggabilty reasons you mention, though helpers
could also provide similar infrastructure.

> Option 3: Don't try to handle it in the bus_type or driver core code
> at all, but rather provide board support code with helpers to make
> waiting for other devices easy.  Even in this case I think it is
> probably still a good idea for the dependant devices to increment
> the refcount of the prereq devices.

Agreed on the refcounting.

------------------------------------------------------------------------------
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/msIE9-sfdev2dev

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
       [not found]                     ` <20101117161130.GC5757-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
  2010-11-17 17:23                       ` Mark Brown
@ 2010-11-17 17:35                       ` Cyril Chemparathy
  2010-11-18  5:46                       ` Greg KH
  2 siblings, 0 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-17 17:35 UTC (permalink / raw)
  To: Grant Likely
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	Rafael J. Wysocki, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b, Greg Kroah-Hartman,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On 11/17/2010 11:11 AM, Grant Likely wrote:
[...]
> To start, I'm not a fan of matching by name.  It's fragile because it
> makes assumptions about how devices will be names when they actually
> appear (ie. Sometimes .id is dynamically assigned).  Ideally I'd
> prefer to have direct references (ie. pointers) to the devices that
> need to be registered, which *shouldn't* be difficult to handle.  That
> guarantees that the correct device is always referenced.  (aside: the
> device-tree use case provides this information by having direct
> 'phandle' references between dependencies.)

The pointer approach is possibly problematic with devices that get
registered by other drivers/masters (mfd, spi, i2c, etc.).  With these
devices the board doesn't really have a reference to the device in question.

Something along the following lines may be better:

int device_requires(struct device *dev, const char *res);
int device_provides(struct device *provider, const char *res);

where res is a string of the form "gpio:25", "regulator:vlcd", or even
"dev:<dev_name>".

device_requires() would typically be used by board implementations, and
device_provides() would be called by gpiolib, regulator core, device
core, etc.

I guess this is somewhat along the lines of an earlier discussion on the
PPC list ([1] below), except that the drivers don't get probed until
specified prereqs are available.

Regards
Cyril.

[1] http://www.spinics.net/lists/linux-embedded/msg02764.html

------------------------------------------------------------------------------
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/msIE9-sfdev2dev

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
       [not found]                       ` <781931.83221.qm-g47maUHHHF+ORdMXk8NaZPu2YVrzzGjVVpNB7YpNyf8@public.gmane.org>
@ 2010-11-17 17:54                         ` Cyril Chemparathy
  0 siblings, 0 replies; 37+ messages in thread
From: Cyril Chemparathy @ 2010-11-17 17:54 UTC (permalink / raw)
  To: David Brownell
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	linus.ml.walleij-Re5JQEeQqe8AvxtiuMwx3w, Mark Brown,
	Grant Likely, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On 11/17/2010 10:25 AM, David Brownell wrote:
> 
>> On Tue, Nov 16, 2010 at 07:17:18PM
>> -0500, Cyril Chemparathy wrote:
>>
>>> The ability to wait on multiple devices may come
>> handy.
> 
> ... You mean you'd like to add such a 
> mechanism to the framework? 

Ideally in the framework.  This appears to be a common enough problem
across platforms.

Regards
Cyril.

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
       [not found]                     ` <20101117161130.GC5757-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
  2010-11-17 17:23                       ` Mark Brown
  2010-11-17 17:35                       ` Cyril Chemparathy
@ 2010-11-18  5:46                       ` Greg KH
  2010-11-25 23:32                         ` Rafael J. Wysocki
  2 siblings, 1 reply; 37+ messages in thread
From: Greg KH @ 2010-11-18  5:46 UTC (permalink / raw)
  To: Grant Likely
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f,
	sameo-VuQAYsv1563Yd54FQh9/CA,
	khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	Rafael J. Wysocki, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Cyril Chemparathy,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	alan-qBU/x9rampVanCEyBjwyrvXRex20P6io,
	lrg-kDsPt+C1G03kYMGBc/C6ZA

On Wed, Nov 17, 2010 at 09:11:30AM -0700, Grant Likely wrote:
> Also, any dependency tracking must work across bus_types.  It is not
> sufficient to only handle the platform_devices use-case.  All bus
> types have this need.

Agreed.

> I see a few potential approaches.
> 
> Option 1: Add a list of prerequisite devices to struct device and
> modify driver core so that it defers binding to a driver until all the
> prerequisites are already bound.  This can probably be implemented
> in a way that works for all bus types transparently.  Before binding
> a driver, the driver core would increase the ref count on each of the
> prereq devices, and decrease it again when the driver is removed.

I see loops happening easily that prevent any device from being bound.
That could get tricky to debug :(

> Option 2: On a per-bus_type basis have a separate registration and the
> bus type code would hold the device unregistered in a pending list.
> This option would also add a prerequisites list to struct device.

When would we process the "pending list"?

I can see something like this working, up to a point.  Once device (or
driver) registration is complete, we would walk the lists of busses and
see if anything new wants to be bound again, now that something new has
shown up, instead of just walking the single bus.

But then we have the issue of devices that never are bound to anything,
it could get a little "noisy" with them never binding, but we can't rely
on the fact that not all devices are not bound to know when to stop
trying.

This might be the simplest to try out as we do almost all of this today
in the driver core (walk the list and try to bind all unbound devices to
a new driver.)  Just extend that walking to walk all other busses as
well.  But this would require that the drivers know when they can't bind
to a device due to something not being set up properly, which I don't
know if is always true.

> Option 3: Don't try to handle it in the bus_type or driver core code
> at all, but rather provide board support code with helpers to make
> waiting for other devices easy.  Even in this case I think it is
> probably still a good idea for the dependant devices to increment
> the refcount of the prereq devices.
> 
> Perhaps something that is used like:
> 
> void do_second_registration(void)
> {
> 	/* register list of dependant devices */
> }
> 
> and then in the primary registration function:
> 	...
> 	device_notify_when_bound(&prereq_pdev->dev,
> 				 do_second_registration);
> 	platform_device_add(prereq_pdev);
> 	...
> 
> which would reduce the boilerplate, but remain flexible.  However,
> while flexable, option 3 doesn't solve the dependency tracking
> problem, and it still requires some gymnastics to handle multiple
> dependencies.
> 
> On a related issue, it may also be desirable for each device to
> maintain a list of devices that have claimed dependency on it for the
> purpose of debugability.

That might be the simplest as each "board type" knows which devices it
wants to register and in what order, right?

Hm, what about the case for dynamic devices that want to turn on and off
different parts and bring them up in specific order depending on what
"mode" the user wanted at the moment?  That would force stuff to be hard
coded in wierd ways I imagine.

Ick, not a simple problem...

greg k-h

------------------------------------------------------------------------------
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/msIE9-sfdev2dev

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

* Re: [PATCH v5 04/12] spi: add ti-ssp spi master driver
  2010-11-18  5:46                       ` Greg KH
@ 2010-11-25 23:32                         ` Rafael J. Wysocki
  0 siblings, 0 replies; 37+ messages in thread
From: Rafael J. Wysocki @ 2010-11-25 23:32 UTC (permalink / raw)
  To: Greg KH
  Cc: davinci-linux-open-source, dbrownell, sameo, khilman,
	linus.ml.walleij, broonie, Grant Likely, rpurdie,
	linux-arm-kernel, Cyril Chemparathy, spi-devel-general, akpm,
	alan, lrg

On Thursday, November 18, 2010, Greg KH wrote:
> On Wed, Nov 17, 2010 at 09:11:30AM -0700, Grant Likely wrote:
> > Also, any dependency tracking must work across bus_types.  It is not
> > sufficient to only handle the platform_devices use-case.  All bus
> > types have this need.
> 
> Agreed.
> 
> > I see a few potential approaches.
> > 
> > Option 1: Add a list of prerequisite devices to struct device and
> > modify driver core so that it defers binding to a driver until all the
> > prerequisites are already bound.  This can probably be implemented
> > in a way that works for all bus types transparently.  Before binding
> > a driver, the driver core would increase the ref count on each of the
> > prereq devices, and decrease it again when the driver is removed.
> 
> I see loops happening easily that prevent any device from being bound.
> That could get tricky to debug :(
> 
> > Option 2: On a per-bus_type basis have a separate registration and the
> > bus type code would hold the device unregistered in a pending list.
> > This option would also add a prerequisites list to struct device.
> 
> When would we process the "pending list"?
> 
> I can see something like this working, up to a point.  Once device (or
> driver) registration is complete, we would walk the lists of busses and
> see if anything new wants to be bound again, now that something new has
> shown up, instead of just walking the single bus.
> 
> But then we have the issue of devices that never are bound to anything,
> it could get a little "noisy" with them never binding, but we can't rely
> on the fact that not all devices are not bound to know when to stop
> trying.
> 
> This might be the simplest to try out as we do almost all of this today
> in the driver core (walk the list and try to bind all unbound devices to
> a new driver.)  Just extend that walking to walk all other busses as
> well.  But this would require that the drivers know when they can't bind
> to a device due to something not being set up properly, which I don't
> know if is always true.
> 
> > Option 3: Don't try to handle it in the bus_type or driver core code
> > at all, but rather provide board support code with helpers to make
> > waiting for other devices easy.  Even in this case I think it is
> > probably still a good idea for the dependant devices to increment
> > the refcount of the prereq devices.

That's necessary IMO.

> > Perhaps something that is used like:
> > 
> > void do_second_registration(void)
> > {
> > 	/* register list of dependant devices */
> > }
> > 
> > and then in the primary registration function:
> > 	...
> > 	device_notify_when_bound(&prereq_pdev->dev,
> > 				 do_second_registration);
> > 	platform_device_add(prereq_pdev);
> > 	...
> > 
> > which would reduce the boilerplate, but remain flexible.  However,
> > while flexable, option 3 doesn't solve the dependency tracking
> > problem, and it still requires some gymnastics to handle multiple
> > dependencies.
> > 
> > On a related issue, it may also be desirable for each device to
> > maintain a list of devices that have claimed dependency on it for the
> > purpose of debugability.
> 
> That might be the simplest as each "board type" knows which devices it
> wants to register and in what order, right?

Ironically enough, we also have this problem in ACPI where there are power
resources that "regular" devices may depend on in pretty much the same way
as discussed here.  Those power resources are represented as devices, so the
problem is really analogous.

In ACPI, though, basically all devices are registered by the same routine that
walks the namespace (which is a tree-like structure) and registers all devices
it finds there.  Before registering a device it examines its properties and,
among other things, it finds what power resources the device depends on.  Then,
it may invoke itself in a recursive way to register those power resources before
registering the device (the recurrence is one-level only, because power
resources cannot depend on anything else).  Since the driver for power
resources has been already registered at that point, we know it will bind to
the power resource device objects as soon as they are registered.  This is done
in a patch series I posted yesterday, actaully.

I'm not sure if this approach can be generalized somehow, but in the ACPI
case it works just fine.

Thanks,
Rafael

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

end of thread, other threads:[~2010-11-25 23:32 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-11-15 19:12 [PATCH v5 00/12] tnetv107x ssp drivers Cyril Chemparathy
     [not found] ` <1289848334-8695-1-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
2010-11-15 19:12   ` [PATCH v5 01/12] misc: add driver for sequencer serial port Cyril Chemparathy
     [not found]     ` <1289848334-8695-2-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
2010-11-16  7:10       ` Grant Likely
     [not found]         ` <20101116071047.GE4074-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
2010-11-16 16:15           ` Cyril Chemparathy
     [not found]             ` <4CE2AE3C.4040805-l0cyMroinI0@public.gmane.org>
2010-11-16 20:35               ` Grant Likely
     [not found]                 ` <AANLkTik76EY8Xh01YP2Tep6k1ETPO+3idmNuk3pVikJG-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-11-16 21:19                   ` Cyril Chemparathy
2010-11-16 22:23                   ` Russell King - ARM Linux
     [not found]                     ` <20101116222340.GF21926-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
2010-11-16 23:57                       ` Grant Likely
2010-11-15 19:12   ` [PATCH v5 02/12] davinci: add tnetv107x ssp platform device Cyril Chemparathy
2010-11-15 19:12   ` [PATCH v5 03/12] davinci: add ssp config for tnetv107x evm board Cyril Chemparathy
2010-11-15 19:12   ` [PATCH v5 04/12] spi: add ti-ssp spi master driver Cyril Chemparathy
2010-11-15 21:59     ` Ryan Mallon
     [not found]     ` <1289848334-8695-5-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
2010-11-16  7:22       ` Grant Likely
     [not found]         ` <20101116072225.GF4074-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
2010-11-16  7:47           ` Grant Likely
2010-11-16 11:34             ` Mark Brown
     [not found]               ` <20101116113409.GH3338-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2010-11-16 20:45                 ` Grant Likely
     [not found]                   ` <20101116204554.GB5016-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
2010-11-16 22:48                     ` Mark Brown
     [not found]             ` <AANLkTi=utWumLKo9QVWXpkC8WxpgaNJJs+dj=pa2eq-q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-11-17  0:17               ` Cyril Chemparathy
2010-11-17 13:31                 ` Mark Brown
     [not found]                   ` <20101117133136.GA19488-HF5t3jzXg/6ND3a5+9QAFujbO/Zr0HzV@public.gmane.org>
2010-11-17 15:25                     ` David Brownell
     [not found]                       ` <781931.83221.qm-g47maUHHHF+ORdMXk8NaZPu2YVrzzGjVVpNB7YpNyf8@public.gmane.org>
2010-11-17 17:54                         ` Cyril Chemparathy
     [not found]                 ` <4CE31F0E.7050103-l0cyMroinI0@public.gmane.org>
2010-11-17 16:11                   ` Grant Likely
     [not found]                     ` <20101117161130.GC5757-MrY2KI0G/OVr83L8+7iqerDks+cytr/Z@public.gmane.org>
2010-11-17 17:23                       ` Mark Brown
2010-11-17 17:35                       ` Cyril Chemparathy
2010-11-18  5:46                       ` Greg KH
2010-11-25 23:32                         ` Rafael J. Wysocki
2010-11-16 14:19           ` David Brownell
2010-11-15 19:12   ` [PATCH v5 05/12] davinci: add spi devices on tnetv107x evm Cyril Chemparathy
2010-11-15 19:12   ` [PATCH v5 06/12] regulator: add driver for tps6524x regulator Cyril Chemparathy
2010-11-15 19:12   ` [PATCH v5 07/12] davinci: add tnetv107x evm regulators Cyril Chemparathy
2010-11-15 19:12   ` [PATCH v5 08/12] gpio: add ti-ssp gpio driver Cyril Chemparathy
     [not found]     ` <1289848334-8695-9-git-send-email-cyril-l0cyMroinI0@public.gmane.org>
2010-11-15 22:38       ` Ryan Mallon
     [not found]         ` <4CE1B651.1060006-7Wk5F4Od5/oYd5yxfr4S2w@public.gmane.org>
2010-11-16 19:38           ` Cyril Chemparathy
2010-11-15 19:12   ` [PATCH v5 09/12] davinci: add tnetv107x evm ti-ssp gpio device Cyril Chemparathy
2010-11-15 19:12   ` [PATCH v5 10/12] backlight: add support for tps6116x controller Cyril Chemparathy
2010-11-15 19:12   ` [PATCH v5 11/12] davinci: add tnetv107x evm backlight device Cyril Chemparathy
2010-11-15 19:12   ` [PATCH v5 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).