All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv3 00/14] OMAP SSI driver / N900 modem support
@ 2014-03-29  0:31 Sebastian Reichel
  2014-03-29  0:31 ` [PATCHv3 01/14] Documentation: HSI: Add some general description for the HSI subsystem Sebastian Reichel
                   ` (14 more replies)
  0 siblings, 15 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

Hi,

This is the seventh round of the OMAP SSI driver patches. The plan is
to get it merged into 3.16.

Changes since PATCHv2 [0]:
 * Readded generic HSI client binding and Nokia N900 modem support.
   They are also intended to be added in 3.16 and useful for testing
   the SSI driver, so I think it makes sense to keep them in one
   patchset.
 * Updated the DT binding for the modem. A HSI port has only a single
   child now, which describes the connected remote device. This better
   fits the DT model of strictly describing hardware, since a HSI port
   is a point2point interface.  The driver can instantiate other
   drivers as needed.
 * Moved channel description from the drivers into DT.
 * I added Signed-off-by: Carlos Chinea <carlos.chinea@nokia.com> to the
   omap-ssi and ssi-protocol driver addtions, since the initial driver
   was from him.
 * I updated my email address.
 * Added DTS changes to ease reviewing/testing the patchset.

I did *not* implement proper PM for the Nokia N900 modem in kernel
space, since that would break all existing userlands (ofono, fso-gsmd
and Nokia's closed source binaries). I think this should be implemented
later.

Please send feedback (e.g. Tested-By or Reviewed-By :)), so that I can
send a pull request for 3.16. You can either apply this patchset or
use the n900-modem-support branch available on [1].

For testing the patchset you should build the kernel with all config
entries in the HSI subsystem activated and boot using the updated
device tree information, since platform data based booting is not
supported. Testing the patchset with ofono works like this:

 # provide cmt device for ofono
 ln -sf /sys/bus/hsi/n900-modem /dev/cmt
 # start ofono
 ofono --nodetach --debug
 # enable the modem
 mdbus2 -s org.ofono /n900_0 org.ofono.Modem.SetProperty Powered true
 # enable modem's RF parts
 mdbus2 -s org.ofono /n900_0 org.ofono.Modem.SetProperty Online true
 # scan for available networks (takes some time)
 mdbus2 -s org.ofono /n900_0 org.ofono.NetworkRegistration.Scan

TODO (post-merge):
* Central Message Queue
  I did not yet implement a central message queue in the HSI framework.
  I will do this after Nokia N900 modem is working in the mainline kernel.
* Remove the hwmod DT hack
  This depends on some future work merging hwmod data into DT.
* Implement proper context loss detection
* Implement N900 modem PM

[0] https://lkml.org/lkml/2014/3/9/139
[1] git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi.git

-- Sebastian

Sebastian Reichel (14):
  Documentation: HSI: Add some general description for the HSI subsystem
  MAINTAINERS: update HSI entry
  HSI: hsi-char: fix driver for multiport scenarios
  HSI: method to unregister clients from an hsi port
  HSI: Add channel resource support to HSI clients
  HSI: export method to (un)register clients
  HSI: Add common DT binding for HSI client devices
  HSI: Introduce OMAP SSI driver
  Documentation: DT: omap-ssi binding documentation
  HSI: Introduce driver for SSI Protocol
  HSI: Introduce Nokia N900 modem driver
  ARM: dts: omap3 clocks: simplify ssi aliases
  DTS: ARM: OMAP3-N900: Add SSI support
  DTS: ARM: OMAP3-N900: Add modem support

 .../devicetree/bindings/hsi/client-devices.txt     |   44 +
 .../devicetree/bindings/hsi/nokia-modem.txt        |   58 +
 Documentation/devicetree/bindings/hsi/omap-ssi.txt |   85 ++
 Documentation/hsi.txt                              |   75 ++
 MAINTAINERS                                        |    4 +-
 arch/arm/boot/dts/omap3-n900.dts                   |   65 +
 arch/arm/boot/dts/omap3.dtsi                       |   55 +
 arch/arm/boot/dts/omap3430es1-clocks.dtsi          |   10 +-
 arch/arm/boot/dts/omap34xx.dtsi                    |   11 +
 .../boot/dts/omap36xx-omap3430es2plus-clocks.dtsi  |   10 +-
 arch/arm/boot/dts/omap36xx.dtsi                    |   11 +
 drivers/hsi/Kconfig                                |    1 +
 drivers/hsi/Makefile                               |    1 +
 drivers/hsi/clients/Kconfig                        |   17 +
 drivers/hsi/clients/Makefile                       |    4 +-
 drivers/hsi/clients/hsi_char.c                     |   14 +-
 drivers/hsi/clients/nokia-modem.c                  |  272 ++++
 drivers/hsi/clients/ssi_protocol.c                 | 1188 +++++++++++++++++
 drivers/hsi/controllers/Kconfig                    |   19 +
 drivers/hsi/controllers/Makefile                   |    6 +
 drivers/hsi/controllers/omap_ssi.c                 |  621 +++++++++
 drivers/hsi/controllers/omap_ssi.h                 |  166 +++
 drivers/hsi/controllers/omap_ssi_port.c            | 1401 ++++++++++++++++++++
 drivers/hsi/controllers/omap_ssi_regs.h            |  171 +++
 drivers/hsi/hsi.c                                  |  267 +++-
 include/linux/hsi/hsi.h                            |   30 +-
 include/linux/hsi/ssi_protocol.h                   |   42 +
 27 files changed, 4619 insertions(+), 29 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/hsi/client-devices.txt
 create mode 100644 Documentation/devicetree/bindings/hsi/nokia-modem.txt
 create mode 100644 Documentation/devicetree/bindings/hsi/omap-ssi.txt
 create mode 100644 Documentation/hsi.txt
 create mode 100644 drivers/hsi/clients/nokia-modem.c
 create mode 100644 drivers/hsi/clients/ssi_protocol.c
 create mode 100644 drivers/hsi/controllers/Kconfig
 create mode 100644 drivers/hsi/controllers/Makefile
 create mode 100644 drivers/hsi/controllers/omap_ssi.c
 create mode 100644 drivers/hsi/controllers/omap_ssi.h
 create mode 100644 drivers/hsi/controllers/omap_ssi_port.c
 create mode 100644 drivers/hsi/controllers/omap_ssi_regs.h
 create mode 100644 include/linux/hsi/ssi_protocol.h

-- 
1.9.0


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

* [PATCHv3 01/14] Documentation: HSI: Add some general description for the HSI subsystem
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
@ 2014-03-29  0:31 ` Sebastian Reichel
  2014-04-19 19:05     ` Pavel Machek
  2014-03-29  0:31 ` [PATCHv3 02/14] MAINTAINERS: update HSI entry Sebastian Reichel
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

Add a document, which gives a rough introduction about what HSI
is and how its handled by the Linux kernel.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 Documentation/hsi.txt | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)
 create mode 100644 Documentation/hsi.txt

diff --git a/Documentation/hsi.txt b/Documentation/hsi.txt
new file mode 100644
index 0000000..6ac6cd5
--- /dev/null
+++ b/Documentation/hsi.txt
@@ -0,0 +1,75 @@
+HSI - High-speed Synchronous Serial Interface
+
+1. Introduction
+~~~~~~~~~~~~~~~
+
+High Speed Syncronous Interface (HSI) is a fullduplex, low latency protocol,
+that is optimized for die-level interconnect between an Application Processor
+and a Baseband chipset. It has been specified by the MIPI alliance in 2003 and
+implemented by multiple vendors since then.
+
+The HSI interface supports full duplex communication over multiple channels
+(typically 8) and is capable of reaching speeds up to 200 Mbit/s.
+
+The serial protocol uses two signals, DATA and FLAG as combined data and clock
+signals and an additional READY signal for flow control. An additional WAKE
+signal can be used to wakeup the chips from standby modes. The signals are
+commonly prefixed by AC for signals going from the application die to the
+cellular die and CA for signals going the other way around.
+
++------------+                                 +---------------+
+|  Cellular  |                                 |  Application  |
+|    Die     |                                 |      Die      |
+|            | - - - - - - CAWAKE - - - - - - >|               |
+|           T|------------ CADATA ------------>|R              |
+|           X|------------ CAFLAG ------------>|X              |
+|            |<----------- ACREADY ------------|               |
+|            |                                 |               |
+|            |                                 |               |
+|            |< - - - - -  ACWAKE - - - - - - -|               |
+|           R|<----------- ACDATA -------------|T              |
+|           X|<----------- ACFLAG -------------|X              |
+|            |------------ CAREADY ----------->|               |
+|            |                                 |               |
+|            |                                 |               |
++------------+                                 +---------------+
+
+2. HSI Subsystem in Linux
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In the Linux kernel the hsi subsystem is supposed to be used for HSI devices.
+The hsi subsystem contains drivers for hsi controllers including support for
+multi-port controllers and provides a generic API for using the HSI ports.
+
+It also contains HSI client drivers, which make use of the generic API to
+implement a protocol used on the HSI interface. These client drivers can
+use an arbitrary number of channels.
+
+3. hsi-char Device
+~~~~~~~~~~~~~~~~~~
+
+Each port automatically registers a generic client driver called hsi_char,
+which provides a charecter device for userspace representing the HSI port.
+It can be used to communicate via HSI from userspace. Userspace may
+configure the hsi_char device using the following ioctl commands:
+
+* HSC_RESET:
+ - flush the HSI port
+
+* HSC_SET_PM
+ - enable or disable the client.
+
+* HSC_SEND_BREAK
+ - send break
+
+* HSC_SET_RX
+ - set RX configuration
+
+* HSC_GET_RX
+ - get RX configuration
+
+* HSC_SET_TX
+ - set TX configuration
+
+* HSC_GET_TX
+ - get TX configuration
-- 
1.9.0


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

* [PATCHv3 02/14] MAINTAINERS: update HSI entry
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
  2014-03-29  0:31 ` [PATCHv3 01/14] Documentation: HSI: Add some general description for the HSI subsystem Sebastian Reichel
@ 2014-03-29  0:31 ` Sebastian Reichel
  2014-04-19 19:06   ` Pavel Machek
  2014-03-29  0:31 ` [PATCHv3 03/14] HSI: hsi-char: fix driver for multiport scenarios Sebastian Reichel
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

Add git tree for hsi subsystem, update Sebastian Reichel's e-mail
address and add Documentation/hsi.txt as maintained file.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 MAINTAINERS | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 82640e6..b376b79 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4117,9 +4117,11 @@ S:	Maintained
 F:	fs/hpfs/
 
 HSI SUBSYSTEM
-M:	Sebastian Reichel <sre@debian.org>
+M:	Sebastian Reichel <sre@kernel.org>
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi.git
 S:	Maintained
 F:	Documentation/ABI/testing/sysfs-bus-hsi
+F:	Documentation/hsi.txt
 F:	drivers/hsi/
 F:	include/linux/hsi/
 F:	include/uapi/linux/hsi/
-- 
1.9.0


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

* [PATCHv3 03/14] HSI: hsi-char: fix driver for multiport scenarios
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
  2014-03-29  0:31 ` [PATCHv3 01/14] Documentation: HSI: Add some general description for the HSI subsystem Sebastian Reichel
  2014-03-29  0:31 ` [PATCHv3 02/14] MAINTAINERS: update HSI entry Sebastian Reichel
@ 2014-03-29  0:31 ` Sebastian Reichel
  2014-04-19 19:06   ` Pavel Machek
  2014-03-29  0:31 ` [PATCHv3 04/14] HSI: method to unregister clients from an hsi port Sebastian Reichel
                   ` (11 subsequent siblings)
  14 siblings, 1 reply; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

Fix return code check of alloc_chrdev_region, which
returns 0 on success.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 drivers/hsi/clients/hsi_char.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hsi/clients/hsi_char.c b/drivers/hsi/clients/hsi_char.c
index e61e5f9..3073320 100644
--- a/drivers/hsi/clients/hsi_char.c
+++ b/drivers/hsi/clients/hsi_char.c
@@ -705,7 +705,7 @@ static int hsc_probe(struct device *dev)
 	if (!hsc_major) {
 		ret = alloc_chrdev_region(&hsc_dev, hsc_baseminor,
 						HSC_DEVS, devname);
-		if (ret > 0)
+		if (ret == 0)
 			hsc_major = MAJOR(hsc_dev);
 	} else {
 		hsc_dev = MKDEV(hsc_major, hsc_baseminor);
-- 
1.9.0


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

* [PATCHv3 04/14] HSI: method to unregister clients from an hsi port
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
                   ` (2 preceding siblings ...)
  2014-03-29  0:31 ` [PATCHv3 03/14] HSI: hsi-char: fix driver for multiport scenarios Sebastian Reichel
@ 2014-03-29  0:31 ` Sebastian Reichel
  2014-04-19 19:07     ` Pavel Machek
  2014-03-29  0:31 ` [PATCHv3 05/14] HSI: Add channel resource support to HSI clients Sebastian Reichel
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

This exports a method to unregister all clients from
an hsi port.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 drivers/hsi/hsi.c       | 10 ++++++++++
 include/linux/hsi/hsi.h |  1 +
 2 files changed, 11 insertions(+)

diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
index 749f7b5..e96a987 100644
--- a/drivers/hsi/hsi.c
+++ b/drivers/hsi/hsi.c
@@ -130,6 +130,16 @@ static void hsi_port_release(struct device *dev)
 }
 
 /**
+ * hsi_unregister_port - Unregister an HSI port
+ * @port: The HSI port to unregister
+ */
+void hsi_port_unregister_clients(struct hsi_port *port)
+{
+	device_for_each_child(&port->device, NULL, hsi_remove_client);
+}
+EXPORT_SYMBOL_GPL(hsi_port_unregister_clients);
+
+/**
  * hsi_unregister_controller - Unregister an HSI controller
  * @hsi: The HSI controller to register
  */
diff --git a/include/linux/hsi/hsi.h b/include/linux/hsi/hsi.h
index 0dca785..2b1912f 100644
--- a/include/linux/hsi/hsi.h
+++ b/include/linux/hsi/hsi.h
@@ -282,6 +282,7 @@ struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags);
 void hsi_put_controller(struct hsi_controller *hsi);
 int hsi_register_controller(struct hsi_controller *hsi);
 void hsi_unregister_controller(struct hsi_controller *hsi);
+void hsi_port_unregister_clients(struct hsi_port *port);
 
 static inline void hsi_controller_set_drvdata(struct hsi_controller *hsi,
 								void *data)
-- 
1.9.0


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

* [PATCHv3 05/14] HSI: Add channel resource support to HSI clients
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
                   ` (3 preceding siblings ...)
  2014-03-29  0:31 ` [PATCHv3 04/14] HSI: method to unregister clients from an hsi port Sebastian Reichel
@ 2014-03-29  0:31 ` Sebastian Reichel
  2014-04-19 19:11     ` Pavel Machek
  2014-03-29  0:31 ` [PATCHv3 06/14] HSI: export method to (un)register clients Sebastian Reichel
                   ` (9 subsequent siblings)
  14 siblings, 1 reply; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

Make HSI channel ids platform data, which can be provided
by platform data.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 drivers/hsi/clients/hsi_char.c | 12 +++++------
 drivers/hsi/hsi.c              | 49 +++++++++++++++++++++++++++++++++++++++++-
 include/linux/hsi/hsi.h        | 24 +++++++++++++++++----
 3 files changed, 74 insertions(+), 11 deletions(-)

diff --git a/drivers/hsi/clients/hsi_char.c b/drivers/hsi/clients/hsi_char.c
index 3073320..57f70c2 100644
--- a/drivers/hsi/clients/hsi_char.c
+++ b/drivers/hsi/clients/hsi_char.c
@@ -367,7 +367,7 @@ static int hsc_rx_set(struct hsi_client *cl, struct hsc_rx_config *rxc)
 		return -EINVAL;
 	tmp = cl->rx_cfg;
 	cl->rx_cfg.mode = rxc->mode;
-	cl->rx_cfg.channels = rxc->channels;
+	cl->rx_cfg.num_hw_channels = rxc->channels;
 	cl->rx_cfg.flow = rxc->flow;
 	ret = hsi_setup(cl);
 	if (ret < 0) {
@@ -383,7 +383,7 @@ static int hsc_rx_set(struct hsi_client *cl, struct hsc_rx_config *rxc)
 static inline void hsc_rx_get(struct hsi_client *cl, struct hsc_rx_config *rxc)
 {
 	rxc->mode = cl->rx_cfg.mode;
-	rxc->channels = cl->rx_cfg.channels;
+	rxc->channels = cl->rx_cfg.num_hw_channels;
 	rxc->flow = cl->rx_cfg.flow;
 }
 
@@ -402,7 +402,7 @@ static int hsc_tx_set(struct hsi_client *cl, struct hsc_tx_config *txc)
 		return -EINVAL;
 	tmp = cl->tx_cfg;
 	cl->tx_cfg.mode = txc->mode;
-	cl->tx_cfg.channels = txc->channels;
+	cl->tx_cfg.num_hw_channels = txc->channels;
 	cl->tx_cfg.speed = txc->speed;
 	cl->tx_cfg.arb_mode = txc->arb_mode;
 	ret = hsi_setup(cl);
@@ -417,7 +417,7 @@ static int hsc_tx_set(struct hsi_client *cl, struct hsc_tx_config *txc)
 static inline void hsc_tx_get(struct hsi_client *cl, struct hsc_tx_config *txc)
 {
 	txc->mode = cl->tx_cfg.mode;
-	txc->channels = cl->tx_cfg.channels;
+	txc->channels = cl->tx_cfg.num_hw_channels;
 	txc->speed = cl->tx_cfg.speed;
 	txc->arb_mode = cl->tx_cfg.arb_mode;
 }
@@ -435,7 +435,7 @@ static ssize_t hsc_read(struct file *file, char __user *buf, size_t len,
 		return -EINVAL;
 	if (len > max_data_size)
 		len = max_data_size;
-	if (channel->ch >= channel->cl->rx_cfg.channels)
+	if (channel->ch >= channel->cl->rx_cfg.num_hw_channels)
 		return -ECHRNG;
 	if (test_and_set_bit(HSC_CH_READ, &channel->flags))
 		return -EBUSY;
@@ -492,7 +492,7 @@ static ssize_t hsc_write(struct file *file, const char __user *buf, size_t len,
 		return -EINVAL;
 	if (len > max_data_size)
 		len = max_data_size;
-	if (channel->ch >= channel->cl->tx_cfg.channels)
+	if (channel->ch >= channel->cl->tx_cfg.num_hw_channels)
 		return -ECHRNG;
 	if (test_and_set_bit(HSC_CH_WRITE, &channel->flags))
 		return -EBUSY;
diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
index e96a987..9d1130d 100644
--- a/drivers/hsi/hsi.c
+++ b/drivers/hsi/hsi.c
@@ -62,18 +62,39 @@ static struct bus_type hsi_bus_type = {
 
 static void hsi_client_release(struct device *dev)
 {
-	kfree(to_hsi_client(dev));
+	struct hsi_client *cl = to_hsi_client(dev);
+
+	if (cl->tx_cfg.channels)
+		kfree(cl->tx_cfg.channels);
+	if (cl->rx_cfg.channels && cl->rx_cfg.channels != cl->tx_cfg.channels)
+		kfree(cl->rx_cfg.channels);
+
+	kfree(cl);
 }
 
 static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info)
 {
 	struct hsi_client *cl;
+	size_t size;
 
 	cl = kzalloc(sizeof(*cl), GFP_KERNEL);
 	if (!cl)
 		return;
+
 	cl->tx_cfg = info->tx_cfg;
+	if (cl->tx_cfg.channels) {
+		size = cl->tx_cfg.num_channels * sizeof(*cl->tx_cfg.channels);
+		cl->tx_cfg.channels = kzalloc(size , GFP_KERNEL);
+		memcpy(cl->tx_cfg.channels, info->tx_cfg.channels, size);
+	}
+
 	cl->rx_cfg = info->rx_cfg;
+	if (cl->rx_cfg.channels) {
+		size = cl->rx_cfg.num_channels * sizeof(*cl->rx_cfg.channels);
+		cl->rx_cfg.channels = kzalloc(size , GFP_KERNEL);
+		memcpy(cl->rx_cfg.channels, info->rx_cfg.channels, size);
+	}
+
 	cl->device.bus = &hsi_bus_type;
 	cl->device.parent = &port->device;
 	cl->device.release = hsi_client_release;
@@ -502,6 +523,32 @@ int hsi_event(struct hsi_port *port, unsigned long event)
 }
 EXPORT_SYMBOL_GPL(hsi_event);
 
+/**
+ * hsi_get_channel_id_by_name - acquire channel id by channel name
+ * @cl: HSI client, which uses the channel
+ * @name: name the channel is known under
+ *
+ * Clients can call this function to get the hsi channel ids similar to
+ * requesting IRQs or GPIOs by name. This function assumes the same
+ * channel configuration is used for RX and TX.
+ *
+ * Returns -errno on error or channel id on success.
+ */
+int hsi_get_channel_id_by_name(struct hsi_client *cl, char *name)
+{
+	int i;
+
+	if (!cl->rx_cfg.channels)
+		return -ENOENT;
+
+	for (i=0; i < cl->rx_cfg.num_channels; i++)
+		if (!strcmp(cl->rx_cfg.channels[i].name, name))
+			return cl->rx_cfg.channels[i].id;
+
+	return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(hsi_get_channel_id_by_name);
+
 static int __init hsi_init(void)
 {
 	return bus_register(&hsi_bus_type);
diff --git a/include/linux/hsi/hsi.h b/include/linux/hsi/hsi.h
index 2b1912f..50a85a9 100644
--- a/include/linux/hsi/hsi.h
+++ b/include/linux/hsi/hsi.h
@@ -68,17 +68,31 @@ enum {
 };
 
 /**
+ * struct hsi_channel - channel resource used by the hsi clients
+ * @id: Channel number
+ * @name: Channel name
+ */
+struct hsi_channel {
+	unsigned int	id;
+	const char	*name;
+};
+
+/**
  * struct hsi_config - Configuration for RX/TX HSI modules
  * @mode: Bit transmission mode (STREAM or FRAME)
- * @channels: Number of channels to use [1..16]
+ * @channels: Channel resources used by the client
+ * @num_channels: Number of channel resources
+ * @num_hw_channels: Number of channels the transceiver is configured for [1..16]
  * @speed: Max bit transmission speed (Kbit/s)
  * @flow: RX flow type (SYNCHRONIZED or PIPELINE)
  * @arb_mode: Arbitration mode for TX frame (Round robin, priority)
  */
 struct hsi_config {
-	unsigned int	mode;
-	unsigned int	channels;
-	unsigned int	speed;
+	unsigned int		mode;
+	struct hsi_channel	*channels;
+	unsigned int		num_channels;
+	unsigned int		num_hw_channels;
+	unsigned int		speed;
 	union {
 		unsigned int	flow;		/* RX only */
 		unsigned int	arb_mode;	/* TX only */
@@ -306,6 +320,8 @@ static inline struct hsi_port *hsi_find_port_num(struct hsi_controller *hsi,
  */
 int hsi_async(struct hsi_client *cl, struct hsi_msg *msg);
 
+int hsi_get_channel_id_by_name(struct hsi_client *cl, char *name);
+
 /**
  * hsi_id - Get HSI controller ID associated to a client
  * @cl: Pointer to a HSI client
-- 
1.9.0


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

* [PATCHv3 06/14] HSI: export method to (un)register clients
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
                   ` (4 preceding siblings ...)
  2014-03-29  0:31 ` [PATCHv3 05/14] HSI: Add channel resource support to HSI clients Sebastian Reichel
@ 2014-03-29  0:31 ` Sebastian Reichel
  2014-04-19 19:13     ` Pavel Machek
  2014-03-29  0:31 ` [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices Sebastian Reichel
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

Expose method for registering and unregistering HSI clients, so that
client drivers can register other client drivers.

This is useful for HSI drivers, which want to use the functionality
of other HSI drivers. For example the N900 modem driver can load HSI
drivers for mcsaab protocol and speech protocol.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 drivers/hsi/hsi.c       | 11 ++++++++---
 include/linux/hsi/hsi.h |  3 +++
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
index 9d1130d..07e1639 100644
--- a/drivers/hsi/hsi.c
+++ b/drivers/hsi/hsi.c
@@ -72,14 +72,15 @@ static void hsi_client_release(struct device *dev)
 	kfree(cl);
 }
 
-static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info)
+struct hsi_client *hsi_new_client(struct hsi_port *port,
+						struct hsi_board_info *info)
 {
 	struct hsi_client *cl;
 	size_t size;
 
 	cl = kzalloc(sizeof(*cl), GFP_KERNEL);
 	if (!cl)
-		return;
+		return NULL;
 
 	cl->tx_cfg = info->tx_cfg;
 	if (cl->tx_cfg.channels) {
@@ -106,7 +107,10 @@ static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info)
 		pr_err("hsi: failed to register client: %s\n", info->name);
 		put_device(&cl->device);
 	}
+
+	return cl;
 }
+EXPORT_SYMBOL_GPL(hsi_new_client);
 
 static void hsi_scan_board_info(struct hsi_controller *hsi)
 {
@@ -122,12 +126,13 @@ static void hsi_scan_board_info(struct hsi_controller *hsi)
 		}
 }
 
-static int hsi_remove_client(struct device *dev, void *data __maybe_unused)
+int hsi_remove_client(struct device *dev, void *data __maybe_unused)
 {
 	device_unregister(dev);
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(hsi_remove_client);
 
 static int hsi_remove_port(struct device *dev, void *data __maybe_unused)
 {
diff --git a/include/linux/hsi/hsi.h b/include/linux/hsi/hsi.h
index 50a85a9..57ee40f 100644
--- a/include/linux/hsi/hsi.h
+++ b/include/linux/hsi/hsi.h
@@ -296,6 +296,9 @@ struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags);
 void hsi_put_controller(struct hsi_controller *hsi);
 int hsi_register_controller(struct hsi_controller *hsi);
 void hsi_unregister_controller(struct hsi_controller *hsi);
+struct hsi_client *hsi_new_client(struct hsi_port *port,
+						struct hsi_board_info *info);
+int hsi_remove_client(struct device *dev, void *data);
 void hsi_port_unregister_clients(struct hsi_port *port);
 
 static inline void hsi_controller_set_drvdata(struct hsi_controller *hsi,
-- 
1.9.0


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

* [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
                   ` (5 preceding siblings ...)
  2014-03-29  0:31 ` [PATCHv3 06/14] HSI: export method to (un)register clients Sebastian Reichel
@ 2014-03-29  0:31 ` Sebastian Reichel
  2014-04-19 19:16     ` Pavel Machek
  2014-04-21 16:52   ` Rob Herring
  2014-03-29  0:31 ` [PATCHv3 08/14] HSI: Introduce OMAP SSI driver Sebastian Reichel
                   ` (7 subsequent siblings)
  14 siblings, 2 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

Implement and document generic DT bindings for HSI clients.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 .../devicetree/bindings/hsi/client-devices.txt     |  44 +++++
 drivers/hsi/hsi.c                                  | 197 ++++++++++++++++++++-
 include/linux/hsi/hsi.h                            |   2 +
 3 files changed, 241 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/hsi/client-devices.txt

diff --git a/Documentation/devicetree/bindings/hsi/client-devices.txt b/Documentation/devicetree/bindings/hsi/client-devices.txt
new file mode 100644
index 0000000..7504cb1
--- /dev/null
+++ b/Documentation/devicetree/bindings/hsi/client-devices.txt
@@ -0,0 +1,44 @@
+Each HSI port is supposed to have one child node, which
+symbols the remote device connected to the HSI port. The
+following properties are standardized for HSI clients:
+
+Required HSI configuration properties:
+
+- reg:			A list of channel ids
+
+- hsi-rx-mode:		Receiver Bit transmission mode ("stream" or "frame")
+- hsi-tx-mode:		Transmitter Bit transmission mode ("stream" or "frame")
+- hsi-mode:		May be used instead hsi-rx-mode and hsi-tx-mode if
+			the transmission mode is the same for receiver and
+			transmitter
+- hsi-speed-kbps:	Max bit transmission speed in kbit/s
+- hsi-flow:		RX flow type ("synchronized" or "pipeline")
+- hsi-arb-mode:		Arbitration mode for TX frame ("round-robin", "priority")
+
+Optional HSI configuration properties:
+
+- reg-names:		A list with one name per channel specified in the
+			reg property
+
+
+Device Tree node example for an HSI client:
+
+hsi-controller {
+	hsi-port {
+		modem: hsi-client {
+			compatible = "nokia,n900-modem";
+
+			reg = <0>, <1>, <2>, <3>;
+			reg-names = "mcsaab-control",
+				    "speech-control",
+				    "speech-data",
+				    "mcsaab-data";
+			hsi-speed-kbps = <55000>;
+			hsi-mode = "frame";
+			hsi-flow = "synchronized";
+			hsi-arb-mode = "round-robin";
+
+			/* more client specific properties */
+		};
+	};
+};
diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
index 07e1639..5973906 100644
--- a/drivers/hsi/hsi.c
+++ b/drivers/hsi/hsi.c
@@ -26,8 +26,14 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include "hsi_core.h"
 
+static struct hsi_board_info hsi_char_dev_info = {
+	.name = "hsi_char",
+};
+
 static ssize_t modalias_show(struct device *dev,
 			struct device_attribute *a __maybe_unused, char *buf)
 {
@@ -50,7 +56,13 @@ static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 static int hsi_bus_match(struct device *dev, struct device_driver *driver)
 {
-	return strcmp(dev_name(dev), driver->name) == 0;
+	if (of_driver_match_device(dev, driver))
+		return true;
+
+	if (strcmp(dev_name(dev), driver->name) == 0)
+		return true;
+
+	return false;
 }
 
 static struct bus_type hsi_bus_type = {
@@ -126,6 +138,187 @@ static void hsi_scan_board_info(struct hsi_controller *hsi)
 		}
 }
 
+static int hsi_of_property_parse_mode(struct device_node *client, char *name,
+				      unsigned int *result)
+{
+	const char *mode;
+	int err;
+
+	err = of_property_read_string(client, name, &mode);
+	if (err < 0)
+		return err;
+
+	if (strcmp(mode, "stream") == 0)
+		*result = HSI_MODE_STREAM;
+	else if (strcmp(mode, "frame") == 0)
+		*result = HSI_MODE_FRAME;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int hsi_of_property_parse_flow(struct device_node *client, char *name,
+				      unsigned int *result)
+{
+	const char *flow;
+	int err;
+
+	err = of_property_read_string(client, name, &flow);
+	if (err < 0)
+		return err;
+
+	if (strcmp(flow, "synchronized") == 0)
+		*result = HSI_FLOW_SYNC;
+	else if (strcmp(flow, "pipeline") == 0)
+		*result = HSI_FLOW_PIPE;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int hsi_of_property_parse_arb_mode(struct device_node *client,
+					  char *name, unsigned int *result)
+{
+	const char *arb_mode;
+	int err;
+
+	err = of_property_read_string(client, name, &arb_mode);
+	if (err < 0)
+		return err;
+
+	if (strcmp(arb_mode, "round-robin") == 0)
+		*result = HSI_ARB_RR;
+	else if (strcmp(arb_mode, "priority") == 0)
+		*result = HSI_ARB_PRIO;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static void hsi_add_client_from_dt(struct hsi_port *port,
+						struct device_node *client)
+{
+	struct hsi_client *cl;
+	struct hsi_channel *channels;
+	struct property *prop;
+	char name[32];
+	int length, cells, err, i, max_chan, mode;
+
+	cl = kzalloc(sizeof(*cl), GFP_KERNEL);
+	if (!cl)
+		return;
+
+	err = of_modalias_node(client, name, sizeof(name));
+	if (err)
+		goto err;
+
+	dev_set_name(&cl->device, "%s", name);
+
+	err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
+	if (err) {
+		err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
+						 &cl->rx_cfg.mode);
+		if (err)
+			goto err;
+
+		err = hsi_of_property_parse_mode(client, "hsi-tx-mode",
+						 &cl->tx_cfg.mode);
+		if (err)
+			goto err;
+	} else {
+		cl->rx_cfg.mode = mode;
+		cl->tx_cfg.mode = mode;
+	}
+
+	err = of_property_read_u32(client, "hsi-speed-kbps",
+				   &cl->tx_cfg.speed);
+	if (err)
+		goto err;
+	cl->rx_cfg.speed = cl->tx_cfg.speed;
+
+	err = hsi_of_property_parse_flow(client, "hsi-flow",
+					 &cl->rx_cfg.flow);
+	if (err)
+		goto err;
+
+	err = hsi_of_property_parse_arb_mode(client, "hsi-arb-mode",
+					     &cl->rx_cfg.arb_mode);
+	if (err)
+		goto err;
+
+	prop = of_find_property(client, "reg", &length);
+	if (!prop) {
+		err = -EINVAL;
+		goto err;
+	}
+
+	cells = length / sizeof(u32);
+
+	cl->rx_cfg.num_channels = cells;
+	cl->tx_cfg.num_channels = cells;
+
+	channels = kzalloc(cells * sizeof(*channels), GFP_KERNEL);
+	if (!channels) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	cl->tx_cfg.channels = channels;
+	cl->rx_cfg.channels = channels;
+
+	for (i=0; i < cells; i++) {
+		err = of_property_read_u32_index(client, "reg", i,
+							&channels[i].id);
+		if (err)
+			goto err2;
+
+		err = of_property_read_string_index(client, "reg-names", i,
+							&channels[i].name);
+		if (err)
+			channels[i].name = NULL;
+
+		if (channels[i].id > max_chan)
+			max_chan = channels[i].id;
+	}
+
+	cl->rx_cfg.num_hw_channels = max_chan + 1;
+	cl->tx_cfg.num_hw_channels = max_chan + 1;
+
+	cl->device.bus = &hsi_bus_type;
+	cl->device.parent = &port->device;
+	cl->device.release = hsi_client_release;
+	cl->device.of_node = client;
+
+	if (device_register(&cl->device) < 0) {
+		pr_err("hsi: failed to register client: %s\n", name);
+		put_device(&cl->device);
+		goto err2;
+	}
+
+	return;
+
+err2:
+	kfree(channels);
+err:
+	kfree(cl);
+	pr_err("hsi client: missing or incorrect of property: err=%d\n", err);
+}
+
+void hsi_add_clients_from_dt(struct hsi_port *port, struct device_node *clients)
+{
+	struct device_node *child;
+
+	/* register hsi-char device */
+	hsi_new_client(port, &hsi_char_dev_info);
+
+	for_each_available_child_of_node(clients, child)
+		hsi_add_client_from_dt(port, child);
+}
+EXPORT_SYMBOL_GPL(hsi_add_clients_from_dt);
+
 int hsi_remove_client(struct device *dev, void *data __maybe_unused)
 {
 	device_unregister(dev);
@@ -508,7 +701,7 @@ int hsi_unregister_port_event(struct hsi_client *cl)
 EXPORT_SYMBOL_GPL(hsi_unregister_port_event);
 
 /**
- * hsi_event -Notifies clients about port events
+ * hsi_event - Notifies clients about port events
  * @port: Port where the event occurred
  * @event: The event type
  *
diff --git a/include/linux/hsi/hsi.h b/include/linux/hsi/hsi.h
index 57ee40f..610c6f9 100644
--- a/include/linux/hsi/hsi.h
+++ b/include/linux/hsi/hsi.h
@@ -298,6 +298,8 @@ int hsi_register_controller(struct hsi_controller *hsi);
 void hsi_unregister_controller(struct hsi_controller *hsi);
 struct hsi_client *hsi_new_client(struct hsi_port *port,
 						struct hsi_board_info *info);
+void hsi_add_clients_from_dt(struct hsi_port *port,
+						struct device_node *clients);
 int hsi_remove_client(struct device *dev, void *data);
 void hsi_port_unregister_clients(struct hsi_port *port);
 
-- 
1.9.0


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

* [PATCHv3 08/14] HSI: Introduce OMAP SSI driver
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
                   ` (6 preceding siblings ...)
  2014-03-29  0:31 ` [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices Sebastian Reichel
@ 2014-03-29  0:31 ` Sebastian Reichel
  2014-04-19 19:30     ` Pavel Machek
  2014-03-29  0:31 ` [PATCHv3 09/14] Documentation: DT: omap-ssi binding documentation Sebastian Reichel
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel, Carlos Chinea

Add OMAP SSI driver to the HSI subsystem.

The Synchronous Serial Interface (SSI) is a legacy version
of HSI. As in the case of HSI, it is mainly used to connect
Application engines (APE) with cellular modem engines (CMT)
in cellular handsets.

It provides a multichannel, full-duplex, multi-core communication
with no reference clock. The OMAP SSI block is capable of reaching
speeds of 110 Mbit/s.

Signed-off-by: Carlos Chinea <carlos.chinea@nokia.com>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 drivers/hsi/Kconfig                     |    1 +
 drivers/hsi/Makefile                    |    1 +
 drivers/hsi/controllers/Kconfig         |   19 +
 drivers/hsi/controllers/Makefile        |    6 +
 drivers/hsi/controllers/omap_ssi.c      |  621 ++++++++++++++
 drivers/hsi/controllers/omap_ssi.h      |  166 ++++
 drivers/hsi/controllers/omap_ssi_port.c | 1401 +++++++++++++++++++++++++++++++
 drivers/hsi/controllers/omap_ssi_regs.h |  171 ++++
 8 files changed, 2386 insertions(+)
 create mode 100644 drivers/hsi/controllers/Kconfig
 create mode 100644 drivers/hsi/controllers/Makefile
 create mode 100644 drivers/hsi/controllers/omap_ssi.c
 create mode 100644 drivers/hsi/controllers/omap_ssi.h
 create mode 100644 drivers/hsi/controllers/omap_ssi_port.c
 create mode 100644 drivers/hsi/controllers/omap_ssi_regs.h

diff --git a/drivers/hsi/Kconfig b/drivers/hsi/Kconfig
index d94e38d..2c76de4 100644
--- a/drivers/hsi/Kconfig
+++ b/drivers/hsi/Kconfig
@@ -14,6 +14,7 @@ config HSI_BOARDINFO
 	bool
 	default y
 
+source "drivers/hsi/controllers/Kconfig"
 source "drivers/hsi/clients/Kconfig"
 
 endif # HSI
diff --git a/drivers/hsi/Makefile b/drivers/hsi/Makefile
index 9d5d33f..360371e 100644
--- a/drivers/hsi/Makefile
+++ b/drivers/hsi/Makefile
@@ -3,4 +3,5 @@
 #
 obj-$(CONFIG_HSI_BOARDINFO)	+= hsi_boardinfo.o
 obj-$(CONFIG_HSI)		+= hsi.o
+obj-y				+= controllers/
 obj-y				+= clients/
diff --git a/drivers/hsi/controllers/Kconfig b/drivers/hsi/controllers/Kconfig
new file mode 100644
index 0000000..037a344
--- /dev/null
+++ b/drivers/hsi/controllers/Kconfig
@@ -0,0 +1,19 @@
+#
+# HSI controllers configuration
+#
+comment "HSI controllers"
+
+config OMAP_SSI
+	tristate "OMAP SSI hardware driver"
+	depends on ARCH_OMAP && HSI
+	---help---
+	  SSI is a legacy version of HSI. It is usually used to connect
+	  an application engine with a cellular modem.
+	  If you say Y here, you will enable the OMAP SSI hardware driver.
+
+	  If unsure, say N.
+
+config OMAP_SSI_PORT
+	tristate
+	default m if OMAP_SSI=m
+	default y if OMAP_SSI=y
diff --git a/drivers/hsi/controllers/Makefile b/drivers/hsi/controllers/Makefile
new file mode 100644
index 0000000..d2665cf
--- /dev/null
+++ b/drivers/hsi/controllers/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for HSI controllers drivers
+#
+
+obj-$(CONFIG_OMAP_SSI)		+= omap_ssi.o
+obj-$(CONFIG_OMAP_SSI_PORT)	+= omap_ssi_port.o
diff --git a/drivers/hsi/controllers/omap_ssi.c b/drivers/hsi/controllers/omap_ssi.c
new file mode 100644
index 0000000..772f3e3
--- /dev/null
+++ b/drivers/hsi/controllers/omap_ssi.c
@@ -0,0 +1,621 @@
+/* OMAP SSI driver.
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ * Copyright (C) 2014 Sebastian Reichel <sre@kernel.org>
+ *
+ * Contact: Carlos Chinea <carlos.chinea@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/compiler.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/scatterlist.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_platform.h>
+#include <linux/hsi/hsi.h>
+#include <linux/idr.h>
+
+#include "omap_ssi_regs.h"
+#include "omap_ssi.h"
+
+/* For automatically allocated device IDs */
+static DEFINE_IDA(platform_omap_ssi_ida);
+
+#ifdef CONFIG_DEBUG_FS
+static int ssi_debug_show(struct seq_file *m, void *p __maybe_unused)
+{
+	struct hsi_controller *ssi = m->private;
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	void __iomem *sys = omap_ssi->sys;
+
+	pm_runtime_get_sync(ssi->device.parent);
+	seq_printf(m, "REVISION\t: 0x%08x\n",  readl(sys + SSI_REVISION_REG));
+	seq_printf(m, "SYSCONFIG\t: 0x%08x\n", readl(sys + SSI_SYSCONFIG_REG));
+	seq_printf(m, "SYSSTATUS\t: 0x%08x\n", readl(sys + SSI_SYSSTATUS_REG));
+	pm_runtime_put_sync(ssi->device.parent);
+
+	return 0;
+}
+
+static int ssi_debug_gdd_show(struct seq_file *m, void *p __maybe_unused)
+{
+	struct hsi_controller *ssi = m->private;
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	void __iomem *gdd = omap_ssi->gdd;
+	void __iomem *sys = omap_ssi->sys;
+	int lch;
+
+	pm_runtime_get_sync(ssi->device.parent);
+
+	seq_printf(m, "GDD_MPU_STATUS\t: 0x%08x\n",
+		readl(sys + SSI_GDD_MPU_IRQ_STATUS_REG));
+	seq_printf(m, "GDD_MPU_ENABLE\t: 0x%08x\n\n",
+		readl(sys + SSI_GDD_MPU_IRQ_ENABLE_REG));
+	seq_printf(m, "HW_ID\t\t: 0x%08x\n",
+				readl(gdd + SSI_GDD_HW_ID_REG));
+	seq_printf(m, "PPORT_ID\t: 0x%08x\n",
+				readl(gdd + SSI_GDD_PPORT_ID_REG));
+	seq_printf(m, "MPORT_ID\t: 0x%08x\n",
+				readl(gdd + SSI_GDD_MPORT_ID_REG));
+	seq_printf(m, "TEST\t\t: 0x%08x\n",
+				readl(gdd + SSI_GDD_TEST_REG));
+	seq_printf(m, "GCR\t\t: 0x%08x\n",
+				readl(gdd + SSI_GDD_GCR_REG));
+
+	for (lch = 0; lch < SSI_MAX_GDD_LCH; lch++) {
+		seq_printf(m, "\nGDD LCH %d\n=========\n", lch);
+		seq_printf(m, "CSDP\t\t: 0x%04x\n",
+				readw(gdd + SSI_GDD_CSDP_REG(lch)));
+		seq_printf(m, "CCR\t\t: 0x%04x\n",
+				readw(gdd + SSI_GDD_CCR_REG(lch)));
+		seq_printf(m, "CICR\t\t: 0x%04x\n",
+				readw(gdd + SSI_GDD_CICR_REG(lch)));
+		seq_printf(m, "CSR\t\t: 0x%04x\n",
+				readw(gdd + SSI_GDD_CSR_REG(lch)));
+		seq_printf(m, "CSSA\t\t: 0x%08x\n",
+				readl(gdd + SSI_GDD_CSSA_REG(lch)));
+		seq_printf(m, "CDSA\t\t: 0x%08x\n",
+				readl(gdd + SSI_GDD_CDSA_REG(lch)));
+		seq_printf(m, "CEN\t\t: 0x%04x\n",
+				readw(gdd + SSI_GDD_CEN_REG(lch)));
+		seq_printf(m, "CSAC\t\t: 0x%04x\n",
+				readw(gdd + SSI_GDD_CSAC_REG(lch)));
+		seq_printf(m, "CDAC\t\t: 0x%04x\n",
+				readw(gdd + SSI_GDD_CDAC_REG(lch)));
+		seq_printf(m, "CLNK_CTRL\t: 0x%04x\n",
+				readw(gdd + SSI_GDD_CLNK_CTRL_REG(lch)));
+	}
+
+	pm_runtime_put_sync(ssi->device.parent);
+
+	return 0;
+}
+
+static int ssi_regs_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ssi_debug_show, inode->i_private);
+}
+
+static int ssi_gdd_regs_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ssi_debug_gdd_show, inode->i_private);
+}
+
+static const struct file_operations ssi_regs_fops = {
+	.open		= ssi_regs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static const struct file_operations ssi_gdd_regs_fops = {
+	.open		= ssi_gdd_regs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init ssi_debug_add_ctrl(struct hsi_controller *ssi)
+{
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	struct dentry *dir;
+
+	/* SSI controller */
+	omap_ssi->dir = debugfs_create_dir(dev_name(&ssi->device), NULL);
+	if (IS_ERR(omap_ssi->dir))
+		return PTR_ERR(omap_ssi->dir);
+
+	debugfs_create_file("regs", S_IRUGO, omap_ssi->dir, ssi,
+								&ssi_regs_fops);
+	/* SSI GDD (DMA) */
+	dir = debugfs_create_dir("gdd", omap_ssi->dir);
+	if (IS_ERR(dir))
+		goto rback;
+	debugfs_create_file("regs", S_IRUGO, dir, ssi, &ssi_gdd_regs_fops);
+
+	return 0;
+rback:
+	debugfs_remove_recursive(omap_ssi->dir);
+
+	return PTR_ERR(dir);
+}
+
+static void ssi_debug_remove_ctrl(struct hsi_controller *ssi)
+{
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+	debugfs_remove_recursive(omap_ssi->dir);
+}
+#endif /* CONFIG_DEBUG_FS */
+
+/*
+ * FIXME: Horrible HACK needed until we remove the useless wakeline test
+ * in the CMT. To be removed !!!!
+ */
+void ssi_waketest(struct hsi_client *cl, unsigned int enable)
+{
+	struct hsi_port *port = hsi_get_port(cl);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+	omap_port->wktest = !!enable;
+	if (omap_port->wktest) {
+		pm_runtime_get_sync(ssi->device.parent);
+		writel_relaxed(SSI_WAKE(0),
+				omap_ssi->sys + SSI_SET_WAKE_REG(port->num));
+	} else {
+		writel_relaxed(SSI_WAKE(0),
+				omap_ssi->sys +	SSI_CLEAR_WAKE_REG(port->num));
+		pm_runtime_put_sync(ssi->device.parent);
+	}
+}
+EXPORT_SYMBOL_GPL(ssi_waketest);
+
+static void ssi_gdd_complete(struct hsi_controller *ssi, unsigned int lch)
+{
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	struct hsi_msg *msg = omap_ssi->gdd_trn[lch].msg;
+	struct hsi_port *port = to_hsi_port(msg->cl->device.parent);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	unsigned int dir;
+	u32 csr;
+	u32 val;
+
+	spin_lock(&omap_ssi->lock);
+
+	val = readl(omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
+	val &= ~SSI_GDD_LCH(lch);
+	writel_relaxed(val, omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
+
+	if (msg->ttype == HSI_MSG_READ) {
+		dir = DMA_FROM_DEVICE;
+		val = SSI_DATAAVAILABLE(msg->channel);
+		pm_runtime_put_sync(ssi->device.parent);
+	} else {
+		dir = DMA_TO_DEVICE;
+		val = SSI_DATAACCEPT(msg->channel);
+		/* Keep clocks reference for write pio event */
+	}
+	dma_unmap_sg(&ssi->device, msg->sgt.sgl, msg->sgt.nents, dir);
+	csr = readw(omap_ssi->gdd + SSI_GDD_CSR_REG(lch));
+	omap_ssi->gdd_trn[lch].msg = NULL; /* release GDD lch */
+	dev_dbg(&port->device, "DMA completed ch %d ttype %d\n",
+				msg->channel, msg->ttype);
+	spin_unlock(&omap_ssi->lock);
+	if (csr & SSI_CSR_TOUR) { /* Timeout error */
+		msg->status = HSI_STATUS_ERROR;
+		msg->actual_len = 0;
+		spin_lock(&omap_port->lock);
+		list_del(&msg->link); /* Dequeue msg */
+		spin_unlock(&omap_port->lock);
+		msg->complete(msg);
+		return;
+	}
+	spin_lock(&omap_port->lock);
+	val |= readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	writel_relaxed(val, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	spin_unlock(&omap_port->lock);
+
+	msg->status = HSI_STATUS_COMPLETED;
+	msg->actual_len = sg_dma_len(msg->sgt.sgl);
+}
+
+static void ssi_gdd_tasklet(unsigned long dev)
+{
+	struct hsi_controller *ssi = (struct hsi_controller *)dev;
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	void __iomem *sys = omap_ssi->sys;
+	unsigned int lch;
+	u32 status_reg;
+
+	pm_runtime_get_sync(ssi->device.parent);
+
+	status_reg = readl(sys + SSI_GDD_MPU_IRQ_STATUS_REG);
+	for (lch = 0; lch < SSI_MAX_GDD_LCH; lch++) {
+		if (status_reg & SSI_GDD_LCH(lch))
+			ssi_gdd_complete(ssi, lch);
+	}
+	writel_relaxed(status_reg, sys + SSI_GDD_MPU_IRQ_STATUS_REG);
+	status_reg = readl(sys + SSI_GDD_MPU_IRQ_STATUS_REG);
+
+	pm_runtime_put_sync(ssi->device.parent);
+
+	if (status_reg)
+		tasklet_hi_schedule(&omap_ssi->gdd_tasklet);
+	else
+		enable_irq(omap_ssi->gdd_irq);
+
+}
+
+static irqreturn_t ssi_gdd_isr(int irq, void *ssi)
+{
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+	tasklet_hi_schedule(&omap_ssi->gdd_tasklet);
+	disable_irq_nosync(irq);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned long ssi_get_clk_rate(struct hsi_controller *ssi)
+{
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	unsigned long rate = clk_get_rate(omap_ssi->fck);
+	return rate;
+}
+
+static int __init ssi_get_iomem(struct platform_device *pd,
+		const char *name, void __iomem **pbase, dma_addr_t *phy)
+{
+	struct resource *mem;
+	struct resource *ioarea;
+	void __iomem *base;
+	struct hsi_controller *ssi = platform_get_drvdata(pd);
+
+	mem = platform_get_resource_byname(pd, IORESOURCE_MEM, name);
+	if (!mem) {
+		dev_err(&pd->dev, "IO memory region missing (%s)\n", name);
+		return -ENXIO;
+	}
+	ioarea = devm_request_mem_region(&ssi->device, mem->start,
+					resource_size(mem), dev_name(&pd->dev));
+	if (!ioarea) {
+		dev_err(&pd->dev, "%s IO memory region request failed\n",
+								mem->name);
+		return -ENXIO;
+	}
+	base = devm_ioremap(&ssi->device, mem->start, resource_size(mem));
+	if (!base) {
+		dev_err(&pd->dev, "%s IO remap failed\n", mem->name);
+		return -ENXIO;
+	}
+	*pbase = base;
+
+	if (phy)
+		*phy = mem->start;
+
+	return 0;
+}
+
+static int __init ssi_add_controller(struct hsi_controller *ssi,
+						struct platform_device *pd)
+{
+	struct omap_ssi_controller *omap_ssi;
+	int err;
+
+	omap_ssi = devm_kzalloc(&ssi->device, sizeof(*omap_ssi), GFP_KERNEL);
+	if (!omap_ssi) {
+		dev_err(&pd->dev, "not enough memory for omap ssi\n");
+		return -ENOMEM;
+	}
+
+	ssi->id = ida_simple_get(&platform_omap_ssi_ida, 0, 0, GFP_KERNEL);
+	if (ssi->id < 0) {
+		err = ssi->id;
+		goto out_err;
+	}
+
+	ssi->owner = THIS_MODULE;
+	ssi->device.parent = &pd->dev;
+	dev_set_name(&ssi->device, "ssi%d", ssi->id);
+	hsi_controller_set_drvdata(ssi, omap_ssi);
+	omap_ssi->dev = &ssi->device;
+	err = ssi_get_iomem(pd, "sys", &omap_ssi->sys, NULL);
+	if (err < 0)
+		goto out_err;
+	err = ssi_get_iomem(pd, "gdd", &omap_ssi->gdd, NULL);
+	if (err < 0)
+		goto out_err;
+	omap_ssi->gdd_irq = platform_get_irq_byname(pd, "gdd_mpu");
+	if (omap_ssi->gdd_irq < 0) {
+		dev_err(&pd->dev, "GDD IRQ resource missing\n");
+		err = omap_ssi->gdd_irq;
+		goto out_err;
+	}
+	tasklet_init(&omap_ssi->gdd_tasklet, ssi_gdd_tasklet,
+							(unsigned long)ssi);
+	err = devm_request_irq(&ssi->device, omap_ssi->gdd_irq, ssi_gdd_isr,
+						0, "gdd_mpu", ssi);
+	if (err < 0) {
+		dev_err(&ssi->device, "Request GDD IRQ %d failed (%d)",
+							omap_ssi->gdd_irq, err);
+		goto out_err;
+	}
+
+	omap_ssi->port = devm_kzalloc(&ssi->device,
+		sizeof(struct omap_ssi_port *) * ssi->num_ports, GFP_KERNEL);
+	if (!omap_ssi->port) {
+		err = -ENOMEM;
+		goto out_err;
+	}
+
+	omap_ssi->fck = devm_clk_get(&ssi->device, "ssi_ssr_fck");
+	if (IS_ERR(omap_ssi->fck)) {
+		dev_err(&pd->dev, "Could not acquire clock \"ssi_ssr_fck\": %li\n",
+			PTR_ERR(omap_ssi->fck));
+		err = -ENODEV;
+		goto out_err;
+	}
+
+	/* TODO: find register, which can be used to detect context loss */
+	omap_ssi->get_loss = NULL;
+
+	omap_ssi->max_speed = UINT_MAX;
+	spin_lock_init(&omap_ssi->lock);
+	err = hsi_register_controller(ssi);
+
+	if (err < 0)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	ida_simple_remove(&platform_omap_ssi_ida, ssi->id);
+	return err;
+}
+
+static int __init ssi_hw_init(struct hsi_controller *ssi)
+{
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	unsigned int i;
+	u32 val;
+	int err;
+
+	err = pm_runtime_get_sync(ssi->device.parent);
+	if (err < 0) {
+		dev_err(&ssi->device, "runtime PM failed %d\n", err);
+		return err;
+	}
+	/* Reseting SSI controller */
+	writel_relaxed(SSI_SOFTRESET, omap_ssi->sys + SSI_SYSCONFIG_REG);
+	val = readl(omap_ssi->sys + SSI_SYSSTATUS_REG);
+	for (i = 0; ((i < 20) && !(val & SSI_RESETDONE)); i++) {
+		msleep(20);
+		val = readl(omap_ssi->sys + SSI_SYSSTATUS_REG);
+	}
+	if (!(val & SSI_RESETDONE)) {
+		dev_err(&ssi->device, "SSI HW reset failed\n");
+		pm_runtime_put_sync(ssi->device.parent);
+		return -EIO;
+	}
+	/* Reseting GDD */
+	writel_relaxed(SSI_SWRESET, omap_ssi->gdd + SSI_GDD_GRST_REG);
+	/* Get FCK rate in KHz */
+	omap_ssi->fck_rate = DIV_ROUND_CLOSEST(ssi_get_clk_rate(ssi), 1000);
+	dev_dbg(&ssi->device, "SSI fck rate %lu KHz\n", omap_ssi->fck_rate);
+	/* Set default PM settings */
+	val = SSI_AUTOIDLE | SSI_SIDLEMODE_SMART | SSI_MIDLEMODE_SMART;
+	writel_relaxed(val, omap_ssi->sys + SSI_SYSCONFIG_REG);
+	omap_ssi->sysconfig = val;
+	writel_relaxed(SSI_CLK_AUTOGATING_ON, omap_ssi->sys + SSI_GDD_GCR_REG);
+	omap_ssi->gdd_gcr = SSI_CLK_AUTOGATING_ON;
+	pm_runtime_put_sync(ssi->device.parent);
+
+	return 0;
+}
+
+static void ssi_remove_controller(struct hsi_controller *ssi)
+{
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	int id = ssi->id;
+	tasklet_kill(&omap_ssi->gdd_tasklet);
+	hsi_unregister_controller(ssi);
+	ida_simple_remove(&platform_omap_ssi_ida, id);
+}
+
+static inline int ssi_of_get_available_ports_count(const struct device_node *np)
+{
+	struct device_node *child;
+	int num = 0;
+
+	for_each_available_child_of_node(np, child)
+		if (of_device_is_compatible(child, "ti,omap3-ssi-port"))
+			num++;
+
+	return num;
+}
+
+static const struct of_device_id ssi_port_match[] = {
+	{ .compatible = "ti,omap3-ssi-port" },
+	{},
+};
+
+static int __init ssi_probe(struct platform_device *pd)
+{
+	struct device_node *np = pd->dev.of_node;
+	struct hsi_controller *ssi;
+	int err;
+	int num_ports;
+
+	if (!np) {
+		dev_err(&pd->dev, "missing device tree data\n");
+		return -EINVAL;
+	}
+
+	num_ports = ssi_of_get_available_ports_count(np);
+
+	ssi = hsi_alloc_controller(num_ports, GFP_KERNEL);
+	if (!ssi) {
+		dev_err(&pd->dev, "No memory for controller\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pd, ssi);
+
+	err = ssi_add_controller(ssi, pd);
+	if (err < 0)
+		goto out1;
+
+	pm_runtime_irq_safe(&pd->dev);
+	pm_runtime_enable(&pd->dev);
+
+	err = ssi_hw_init(ssi);
+	if (err < 0)
+		goto out2;
+#ifdef CONFIG_DEBUG_FS
+	err = ssi_debug_add_ctrl(ssi);
+	if (err < 0)
+		goto out2;
+#endif
+
+	err = of_platform_populate(pd->dev.of_node, NULL, ssi_port_match, &pd->dev);
+	if (err) {
+		dev_err(&pd->dev, "failed to create ssi controller ports (err=%d)\n",
+			err);
+		return -ENODEV;
+	}
+
+	dev_info(&pd->dev, "ssi controller %d initialized (%d ports)!\n",
+		ssi->id, num_ports);
+	return err;
+out2:
+	ssi_remove_controller(ssi);
+out1:
+	platform_set_drvdata(pd, NULL);
+	pm_runtime_disable(&pd->dev);
+
+	return err;
+}
+
+static int __exit ssi_remove_ports(struct device *dev, void *c)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	of_device_unregister(pdev);
+
+	return 0;
+}
+
+static int __exit ssi_remove(struct platform_device *pd)
+{
+	struct hsi_controller *ssi = platform_get_drvdata(pd);
+
+#ifdef CONFIG_DEBUG_FS
+	ssi_debug_remove_ctrl(ssi);
+#endif
+	ssi_remove_controller(ssi);
+	platform_set_drvdata(pd, NULL);
+
+	pm_runtime_disable(&pd->dev);
+
+	/* cleanup of of_platform_populate() call */
+	device_for_each_child(&pd->dev, NULL, ssi_remove_ports);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int omap_ssi_runtime_suspend(struct device *dev)
+{
+	struct hsi_controller *ssi = dev_get_drvdata(dev);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+	dev_dbg(dev, "runtime suspend!\n");
+
+	if (omap_ssi->get_loss)
+		omap_ssi->loss_count =
+				omap_ssi->get_loss(ssi->device.parent);
+
+	return 0;
+}
+
+static int omap_ssi_runtime_resume(struct device *dev)
+{
+	struct hsi_controller *ssi = dev_get_drvdata(dev);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+	dev_dbg(dev, "runtime resume!\n");
+
+	if ((omap_ssi->get_loss) && (omap_ssi->loss_count ==
+				omap_ssi->get_loss(ssi->device.parent)))
+		return 0;
+
+	writel_relaxed(omap_ssi->gdd_gcr, omap_ssi->gdd + SSI_GDD_GCR_REG);
+
+	return 0;
+}
+
+static const struct dev_pm_ops omap_ssi_pm_ops = {
+	SET_RUNTIME_PM_OPS(omap_ssi_runtime_suspend, omap_ssi_runtime_resume,
+		NULL)
+};
+
+#define DEV_PM_OPS     (&omap_ssi_pm_ops)
+#else
+#define DEV_PM_OPS     NULL
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id omap_ssi_of_match[] = {
+	{ .compatible = "ti,omap3-ssi", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, omap_ssi_of_match);
+#else
+#define omap_ssi_of_match NULL
+#endif
+
+static struct platform_driver ssi_pdriver = {
+	.remove	= __exit_p(ssi_remove),
+	.driver	= {
+		.name	= "omap_ssi",
+		.owner	= THIS_MODULE,
+		.pm     = DEV_PM_OPS,
+		.of_match_table = omap_ssi_of_match,
+	},
+};
+
+module_platform_driver_probe(ssi_pdriver, ssi_probe);
+
+MODULE_ALIAS("platform:omap_ssi");
+MODULE_AUTHOR("Carlos Chinea <carlos.chinea@nokia.com>");
+MODULE_AUTHOR("Sebastian Reichel <sre@debian.org>");
+MODULE_DESCRIPTION("Synchronous Serial Interface Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hsi/controllers/omap_ssi.h b/drivers/hsi/controllers/omap_ssi.h
new file mode 100644
index 0000000..9d05641
--- /dev/null
+++ b/drivers/hsi/controllers/omap_ssi.h
@@ -0,0 +1,166 @@
+/* OMAP SSI internal interface.
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ * Copyright (C) 2013 Sebastian Reichel
+ *
+ * Contact: Carlos Chinea <carlos.chinea@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __LINUX_HSI_OMAP_SSI_H__
+#define __LINUX_HSI_OMAP_SSI_H__
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/hsi/hsi.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#define SSI_MAX_CHANNELS	8
+#define SSI_MAX_GDD_LCH		8
+#define SSI_BYTES_TO_FRAMES(x) ((((x) - 1) >> 2) + 1)
+
+/**
+ * struct omap_ssm_ctx - OMAP synchronous serial module (TX/RX) context
+ * @mode: Bit transmission mode
+ * @channels: Number of channels
+ * @framesize: Frame size in bits
+ * @timeout: RX frame timeout
+ * @divisor: TX divider
+ * @arb_mode: Arbitration mode for TX frame (Round robin, priority)
+ */
+struct omap_ssm_ctx {
+	u32	mode;
+	u32	channels;
+	u32	frame_size;
+	union	{
+			u32	timeout; /* Rx Only */
+			struct	{
+					u32	arb_mode;
+					u32	divisor;
+			}; /* Tx only */
+	};
+};
+
+/**
+ * struct omap_ssi_port - OMAP SSI port data
+ * @dev: device associated to the port (HSI port)
+ * @pdev: platform device associated to the port
+ * @sst_dma: SSI transmitter physical base address
+ * @ssr_dma: SSI receiver physical base address
+ * @sst_base: SSI transmitter base address
+ * @ssr_base: SSI receiver base address
+ * @wk_lock: spin lock to serialize access to the wake lines
+ * @lock: Spin lock to serialize access to the SSI port
+ * @channels: Current number of channels configured (1,2,4 or 8)
+ * @txqueue: TX message queues
+ * @rxqueue: RX message queues
+ * @brkqueue: Queue of incoming HWBREAK requests (FRAME mode)
+ * @irq: IRQ number
+ * @wake_irq: IRQ number for incoming wake line (-1 if none)
+ * @wake_gpio: GPIO number for incoming wake line (-1 if none)
+ * @pio_tasklet: Bottom half for PIO transfers and events
+ * @wake_tasklet: Bottom half for incoming wake events
+ * @wkin_cken: Keep track of clock references due to the incoming wake line
+ * @wk_refcount: Reference count for output wake line
+ * @sys_mpu_enable: Context for the interrupt enable register for irq 0
+ * @sst: Context for the synchronous serial transmitter
+ * @ssr: Context for the synchronous serial receiver
+ */
+struct omap_ssi_port {
+	struct device		*dev;
+	struct device           *pdev;
+	dma_addr_t		sst_dma;
+	dma_addr_t		ssr_dma;
+	void __iomem		*sst_base;
+	void __iomem		*ssr_base;
+	spinlock_t		wk_lock;
+	spinlock_t		lock;
+	unsigned int		channels;
+	struct list_head	txqueue[SSI_MAX_CHANNELS];
+	struct list_head	rxqueue[SSI_MAX_CHANNELS];
+	struct list_head	brkqueue;
+	unsigned int		irq;
+	int			wake_irq;
+	int			wake_gpio;
+	struct tasklet_struct	pio_tasklet;
+	struct tasklet_struct	wake_tasklet;
+	bool			wktest:1; /* FIXME: HACK to be removed */
+	bool			wkin_cken:1; /* Workaround */
+	unsigned int		wk_refcount;
+	/* OMAP SSI port context */
+	u32			sys_mpu_enable; /* We use only one irq */
+	struct omap_ssm_ctx	sst;
+	struct omap_ssm_ctx	ssr;
+	u32			loss_count;
+	u32			port_id;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dir;
+#endif
+};
+
+/**
+ * struct gdd_trn - GDD transaction data
+ * @msg: Pointer to the HSI message being served
+ * @sg: Pointer to the current sg entry being served
+ */
+struct gdd_trn {
+	struct hsi_msg		*msg;
+	struct scatterlist	*sg;
+};
+
+/**
+ * struct omap_ssi_controller - OMAP SSI controller data
+ * @dev: device associated to the controller (HSI controller)
+ * @sys: SSI I/O base address
+ * @gdd: GDD I/O base address
+ * @fck: SSI functional clock
+ * @gdd_irq: IRQ line for GDD
+ * @gdd_tasklet: bottom half for DMA transfers
+ * @gdd_trn: Array of GDD transaction data for ongoing GDD transfers
+ * @lock: lock to serialize access to GDD
+ * @loss_count: To follow if we need to restore context or not
+ * @max_speed: Maximum TX speed (Kb/s) set by the clients.
+ * @sysconfig: SSI controller saved context
+ * @gdd_gcr: SSI GDD saved context
+ * @get_loss: Pointer to omap_pm_get_dev_context_loss_count, if any
+ * @port: Array of pointers of the ports of the controller
+ * @dir: Debugfs SSI root directory
+ */
+struct omap_ssi_controller {
+	struct device		*dev;
+	void __iomem		*sys;
+	void __iomem		*gdd;
+	struct clk		*fck;
+	unsigned int		gdd_irq;
+	struct tasklet_struct	gdd_tasklet;
+	struct gdd_trn		gdd_trn[SSI_MAX_GDD_LCH];
+	spinlock_t		lock;
+	unsigned long		fck_rate;
+	u32			loss_count;
+	u32			max_speed;
+	/* OMAP SSI Controller context */
+	u32			sysconfig;
+	u32			gdd_gcr;
+	int			(*get_loss)(struct device *dev);
+	struct omap_ssi_port	**port;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dir;
+#endif
+};
+
+#endif /* __LINUX_HSI_OMAP_SSI_H__ */
diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c
new file mode 100644
index 0000000..04115f6
--- /dev/null
+++ b/drivers/hsi/controllers/omap_ssi_port.c
@@ -0,0 +1,1401 @@
+/* OMAP SSI port driver.
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ * Copyright (C) 2014 Sebastian Reichel <sre@kernel.org>
+ *
+ * Contact: Carlos Chinea <carlos.chinea@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/of_gpio.h>
+#include <linux/debugfs.h>
+
+#include "omap_ssi_regs.h"
+#include "omap_ssi.h"
+
+static inline int hsi_dummy_msg(struct hsi_msg *msg __maybe_unused)
+{
+	return 0;
+}
+
+static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused)
+{
+	return 0;
+}
+
+static inline unsigned int ssi_wakein(struct hsi_port *port)
+{
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	return gpio_get_value(omap_port->wake_gpio);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void ssi_debug_remove_port(struct hsi_port *port)
+{
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+
+	debugfs_remove_recursive(omap_port->dir);
+}
+
+static int ssi_debug_port_show(struct seq_file *m, void *p __maybe_unused)
+{
+	struct hsi_port *port = m->private;
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	void __iomem	*base = omap_ssi->sys;
+	unsigned int ch;
+
+	pm_runtime_get_sync(omap_port->pdev);
+	if (omap_port->wake_irq > 0)
+		seq_printf(m, "CAWAKE\t\t: %d\n", ssi_wakein(port));
+	seq_printf(m, "WAKE\t\t: 0x%08x\n",
+				readl(base + SSI_WAKE_REG(port->num)));
+	seq_printf(m, "MPU_ENABLE_IRQ%d\t: 0x%08x\n", 0,
+			readl(base + SSI_MPU_ENABLE_REG(port->num, 0)));
+	seq_printf(m, "MPU_STATUS_IRQ%d\t: 0x%08x\n", 0,
+			readl(base + SSI_MPU_STATUS_REG(port->num, 0)));
+	/* SST */
+	base = omap_port->sst_base;
+	seq_puts(m, "\nSST\n===\n");
+	seq_printf(m, "ID SST\t\t: 0x%08x\n",
+				readl(base + SSI_SST_ID_REG));
+	seq_printf(m, "MODE\t\t: 0x%08x\n",
+				readl(base + SSI_SST_MODE_REG));
+	seq_printf(m, "FRAMESIZE\t: 0x%08x\n",
+				readl(base + SSI_SST_FRAMESIZE_REG));
+	seq_printf(m, "DIVISOR\t\t: 0x%08x\n",
+				readl(base + SSI_SST_DIVISOR_REG));
+	seq_printf(m, "CHANNELS\t: 0x%08x\n",
+				readl(base + SSI_SST_CHANNELS_REG));
+	seq_printf(m, "ARBMODE\t\t: 0x%08x\n",
+				readl(base + SSI_SST_ARBMODE_REG));
+	seq_printf(m, "TXSTATE\t\t: 0x%08x\n",
+				readl(base + SSI_SST_TXSTATE_REG));
+	seq_printf(m, "BUFSTATE\t: 0x%08x\n",
+				readl(base + SSI_SST_BUFSTATE_REG));
+	seq_printf(m, "BREAK\t\t: 0x%08x\n",
+				readl(base + SSI_SST_BREAK_REG));
+	for (ch = 0; ch < omap_port->channels; ch++) {
+		seq_printf(m, "BUFFER_CH%d\t: 0x%08x\n", ch,
+				readl(base + SSI_SST_BUFFER_CH_REG(ch)));
+	}
+	/* SSR */
+	base = omap_port->ssr_base;
+	seq_puts(m, "\nSSR\n===\n");
+	seq_printf(m, "ID SSR\t\t: 0x%08x\n",
+				readl(base + SSI_SSR_ID_REG));
+	seq_printf(m, "MODE\t\t: 0x%08x\n",
+				readl(base + SSI_SSR_MODE_REG));
+	seq_printf(m, "FRAMESIZE\t: 0x%08x\n",
+				readl(base + SSI_SSR_FRAMESIZE_REG));
+	seq_printf(m, "CHANNELS\t: 0x%08x\n",
+				readl(base + SSI_SSR_CHANNELS_REG));
+	seq_printf(m, "TIMEOUT\t\t: 0x%08x\n",
+				readl(base + SSI_SSR_TIMEOUT_REG));
+	seq_printf(m, "RXSTATE\t\t: 0x%08x\n",
+				readl(base + SSI_SSR_RXSTATE_REG));
+	seq_printf(m, "BUFSTATE\t: 0x%08x\n",
+				readl(base + SSI_SSR_BUFSTATE_REG));
+	seq_printf(m, "BREAK\t\t: 0x%08x\n",
+				readl(base + SSI_SSR_BREAK_REG));
+	seq_printf(m, "ERROR\t\t: 0x%08x\n",
+				readl(base + SSI_SSR_ERROR_REG));
+	seq_printf(m, "ERRORACK\t: 0x%08x\n",
+				readl(base + SSI_SSR_ERRORACK_REG));
+	for (ch = 0; ch < omap_port->channels; ch++) {
+		seq_printf(m, "BUFFER_CH%d\t: 0x%08x\n", ch,
+				readl(base + SSI_SSR_BUFFER_CH_REG(ch)));
+	}
+	pm_runtime_put_sync(omap_port->pdev);
+
+	return 0;
+}
+
+static int ssi_port_regs_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ssi_debug_port_show, inode->i_private);
+}
+
+static const struct file_operations ssi_port_regs_fops = {
+	.open		= ssi_port_regs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int ssi_div_get(void *data, u64 *val)
+{
+	struct hsi_port *port = data;
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+
+	pm_runtime_get_sync(omap_port->pdev);
+	*val = readl(omap_port->sst_base + SSI_SST_DIVISOR_REG);
+	pm_runtime_put_sync(omap_port->pdev);
+
+	return 0;
+}
+
+static int ssi_div_set(void *data, u64 val)
+{
+	struct hsi_port *port = data;
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+
+	if (val > 127)
+		return -EINVAL;
+
+	pm_runtime_get_sync(omap_port->pdev);
+	writel(val, omap_port->sst_base + SSI_SST_DIVISOR_REG);
+	omap_port->sst.divisor = val;
+	pm_runtime_put_sync(omap_port->pdev);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(ssi_sst_div_fops, ssi_div_get, ssi_div_set, "%llu\n");
+
+static int __init ssi_debug_add_port(struct omap_ssi_port *omap_port,
+							struct dentry *dir)
+{
+	struct hsi_port *port = to_hsi_port(omap_port->dev);
+
+	dir = debugfs_create_dir(dev_name(omap_port->dev), dir);
+	if (IS_ERR(dir))
+		return PTR_ERR(dir);
+	omap_port->dir = dir;
+	debugfs_create_file("regs", S_IRUGO, dir, port, &ssi_port_regs_fops);
+	dir = debugfs_create_dir("sst", dir);
+	if (IS_ERR(dir))
+		return PTR_ERR(dir);
+	debugfs_create_file("divisor", S_IRUGO | S_IWUSR, dir, port,
+							&ssi_sst_div_fops);
+
+	return 0;
+}
+#endif
+
+static int ssi_claim_lch(struct hsi_msg *msg)
+{
+
+	struct hsi_port *port = hsi_get_port(msg->cl);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	int lch;
+
+	for (lch = 0; lch < SSI_MAX_GDD_LCH; lch++)
+		if (!omap_ssi->gdd_trn[lch].msg) {
+			omap_ssi->gdd_trn[lch].msg = msg;
+			omap_ssi->gdd_trn[lch].sg = msg->sgt.sgl;
+			return lch;
+		}
+
+	return -EBUSY;
+}
+
+static int ssi_start_dma(struct hsi_msg *msg, int lch)
+{
+	struct hsi_port *port = hsi_get_port(msg->cl);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	void __iomem *gdd = omap_ssi->gdd;
+	int err;
+	u16 csdp;
+	u16 ccr;
+	u32 s_addr;
+	u32 d_addr;
+	u32 tmp;
+
+	if (msg->ttype == HSI_MSG_READ) {
+		err = dma_map_sg(&ssi->device, msg->sgt.sgl, msg->sgt.nents,
+							DMA_FROM_DEVICE);
+		if (err < 0) {
+			dev_dbg(&ssi->device, "DMA map SG failed !\n");
+			return err;
+		}
+		csdp = SSI_DST_BURST_4x32_BIT | SSI_DST_MEMORY_PORT |
+			SSI_SRC_SINGLE_ACCESS0 | SSI_SRC_PERIPHERAL_PORT |
+			SSI_DATA_TYPE_S32;
+		ccr = msg->channel + 0x10 + (port->num * 8); /* Sync */
+		ccr |= SSI_DST_AMODE_POSTINC | SSI_SRC_AMODE_CONST |
+			SSI_CCR_ENABLE;
+		s_addr = omap_port->ssr_dma +
+					SSI_SSR_BUFFER_CH_REG(msg->channel);
+		d_addr = sg_dma_address(msg->sgt.sgl);
+	} else {
+		err = dma_map_sg(&ssi->device, msg->sgt.sgl, msg->sgt.nents,
+							DMA_TO_DEVICE);
+		if (err < 0) {
+			dev_dbg(&ssi->device, "DMA map SG failed !\n");
+			return err;
+		}
+		csdp = SSI_SRC_BURST_4x32_BIT | SSI_SRC_MEMORY_PORT |
+			SSI_DST_SINGLE_ACCESS0 | SSI_DST_PERIPHERAL_PORT |
+			SSI_DATA_TYPE_S32;
+		ccr = (msg->channel + 1 + (port->num * 8)) & 0xf; /* Sync */
+		ccr |= SSI_SRC_AMODE_POSTINC | SSI_DST_AMODE_CONST |
+			SSI_CCR_ENABLE;
+		s_addr = sg_dma_address(msg->sgt.sgl);
+		d_addr = omap_port->sst_dma +
+					SSI_SST_BUFFER_CH_REG(msg->channel);
+	}
+	dev_dbg(&ssi->device, "lch %d cdsp %08x ccr %04x s_addr %08x d_addr %08x\n",
+		lch, csdp, ccr, s_addr, d_addr);
+
+	/* Hold clocks during the transfer */
+	pm_runtime_get_sync(omap_port->pdev);
+
+	writew_relaxed(csdp, gdd + SSI_GDD_CSDP_REG(lch));
+	writew_relaxed(SSI_BLOCK_IE | SSI_TOUT_IE, gdd + SSI_GDD_CICR_REG(lch));
+	writel_relaxed(d_addr, gdd + SSI_GDD_CDSA_REG(lch));
+	writel_relaxed(s_addr, gdd + SSI_GDD_CSSA_REG(lch));
+	writew_relaxed(SSI_BYTES_TO_FRAMES(msg->sgt.sgl->length),
+						gdd + SSI_GDD_CEN_REG(lch));
+
+	spin_lock_bh(&omap_ssi->lock);
+	tmp = readl(omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
+	tmp |= SSI_GDD_LCH(lch);
+	writel_relaxed(tmp, omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
+	spin_unlock_bh(&omap_ssi->lock);
+	writew(ccr, gdd + SSI_GDD_CCR_REG(lch));
+	msg->status = HSI_STATUS_PROCEEDING;
+
+	return 0;
+}
+
+static int ssi_start_pio(struct hsi_msg *msg)
+{
+	struct hsi_port *port = hsi_get_port(msg->cl);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	u32 val;
+
+	pm_runtime_get_sync(omap_port->pdev);
+	if (msg->ttype == HSI_MSG_WRITE) {
+		val = SSI_DATAACCEPT(msg->channel);
+		/* Hold clocks for pio writes */
+		pm_runtime_get_sync(omap_port->pdev);
+	} else {
+		val = SSI_DATAAVAILABLE(msg->channel) | SSI_ERROROCCURED;
+	}
+	dev_dbg(&port->device, "Single %s transfer\n",
+						msg->ttype ? "write" : "read");
+	val |= readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	writel(val, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	pm_runtime_put_sync(omap_port->pdev);
+	msg->actual_len = 0;
+	msg->status = HSI_STATUS_PROCEEDING;
+
+	return 0;
+}
+
+static int ssi_start_transfer(struct list_head *queue)
+{
+	struct hsi_msg *msg;
+	int lch = -1;
+
+	if (list_empty(queue))
+		return 0;
+	msg = list_first_entry(queue, struct hsi_msg, link);
+	if (msg->status != HSI_STATUS_QUEUED)
+		return 0;
+	if ((msg->sgt.nents) && (msg->sgt.sgl->length > sizeof(u32)))
+		lch = ssi_claim_lch(msg);
+	if (lch >= 0)
+		return ssi_start_dma(msg, lch);
+	else
+		return ssi_start_pio(msg);
+}
+
+static int ssi_async_break(struct hsi_msg *msg)
+{
+	struct hsi_port *port = hsi_get_port(msg->cl);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	int err = 0;
+	u32 tmp;
+
+	pm_runtime_get_sync(omap_port->pdev);
+	if (msg->ttype == HSI_MSG_WRITE) {
+		if (omap_port->sst.mode != SSI_MODE_FRAME) {
+			err = -EINVAL;
+			goto out;
+		}
+		writel(1, omap_port->sst_base + SSI_SST_BREAK_REG);
+		msg->status = HSI_STATUS_COMPLETED;
+		msg->complete(msg);
+	} else {
+		if (omap_port->ssr.mode != SSI_MODE_FRAME) {
+			err = -EINVAL;
+			goto out;
+		}
+		spin_lock_bh(&omap_port->lock);
+		tmp = readl(omap_ssi->sys +
+					SSI_MPU_ENABLE_REG(port->num, 0));
+		writel(tmp | SSI_BREAKDETECTED,
+			omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+		msg->status = HSI_STATUS_PROCEEDING;
+		list_add_tail(&msg->link, &omap_port->brkqueue);
+		spin_unlock_bh(&omap_port->lock);
+	}
+out:
+	pm_runtime_put_sync(omap_port->pdev);
+
+	return err;
+}
+
+static int ssi_async(struct hsi_msg *msg)
+{
+	struct hsi_port *port = hsi_get_port(msg->cl);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct list_head *queue;
+	int err = 0;
+
+	BUG_ON(!msg);
+
+	if (msg->sgt.nents > 1)
+		return -ENOSYS; /* TODO: Add sg support */
+
+	if (msg->break_frame)
+		return ssi_async_break(msg);
+
+	if (msg->ttype) {
+		BUG_ON(msg->channel >= omap_port->sst.channels);
+		queue = &omap_port->txqueue[msg->channel];
+	} else {
+		BUG_ON(msg->channel >= omap_port->ssr.channels);
+		queue = &omap_port->rxqueue[msg->channel];
+	}
+	msg->status = HSI_STATUS_QUEUED;
+	spin_lock_bh(&omap_port->lock);
+	list_add_tail(&msg->link, queue);
+	err = ssi_start_transfer(queue);
+	if (err < 0) {
+		list_del(&msg->link);
+		msg->status = HSI_STATUS_ERROR;
+	}
+	spin_unlock_bh(&omap_port->lock);
+	dev_dbg(&port->device, "msg status %d ttype %d ch %d\n",
+				msg->status, msg->ttype, msg->channel);
+
+	return err;
+}
+
+static u32 ssi_calculate_div(struct hsi_controller *ssi)
+{
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	u32 tx_fckrate = (u32) omap_ssi->fck_rate;
+
+	/* / 2 : SSI TX clock is always half of the SSI functional clock */
+	tx_fckrate >>= 1;
+	/* Round down when tx_fckrate % omap_ssi->max_speed == 0 */
+	tx_fckrate--;
+	dev_dbg(&ssi->device, "TX div %d for fck_rate %lu Khz speed %d Kb/s\n",
+			tx_fckrate / omap_ssi->max_speed, omap_ssi->fck_rate,
+							omap_ssi->max_speed);
+
+	return tx_fckrate / omap_ssi->max_speed;
+}
+
+static void ssi_flush_queue(struct list_head *queue, struct hsi_client *cl)
+{
+	struct list_head *node, *tmp;
+	struct hsi_msg *msg;
+
+	list_for_each_safe(node, tmp, queue) {
+		msg = list_entry(node, struct hsi_msg, link);
+		if ((cl) && (cl != msg->cl))
+			continue;
+		list_del(node);
+		pr_debug("flush queue: ch %d, msg %p len %d type %d ctxt %p\n",
+			msg->channel, msg, msg->sgt.sgl->length,
+					msg->ttype, msg->context);
+		if (msg->destructor)
+			msg->destructor(msg);
+		else
+			hsi_free_msg(msg);
+	}
+}
+
+static int ssi_setup(struct hsi_client *cl)
+{
+	struct hsi_port *port = to_hsi_port(cl->device.parent);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	void __iomem *sst = omap_port->sst_base;
+	void __iomem *ssr = omap_port->ssr_base;
+	u32 div;
+	u32 val;
+	int err = 0;
+
+	pm_runtime_get_sync(omap_port->pdev);
+	spin_lock_bh(&omap_port->lock);
+	if (cl->tx_cfg.speed)
+		omap_ssi->max_speed = cl->tx_cfg.speed;
+	div = ssi_calculate_div(ssi);
+	if (div > SSI_MAX_DIVISOR) {
+		dev_err(&cl->device, "Invalid TX speed %d Mb/s (div %d)\n",
+						cl->tx_cfg.speed, div);
+		err = -EINVAL;
+		goto out;
+	}
+	/* Set TX/RX module to sleep to stop TX/RX during cfg update */
+	writel_relaxed(SSI_MODE_SLEEP, sst + SSI_SST_MODE_REG);
+	writel_relaxed(SSI_MODE_SLEEP, ssr + SSI_SSR_MODE_REG);
+	/* Flush posted write */
+	val = readl(ssr + SSI_SSR_MODE_REG);
+	/* TX */
+	writel_relaxed(31, sst + SSI_SST_FRAMESIZE_REG);
+	writel_relaxed(div, sst + SSI_SST_DIVISOR_REG);
+	writel_relaxed(cl->tx_cfg.num_hw_channels, sst + SSI_SST_CHANNELS_REG);
+	writel_relaxed(cl->tx_cfg.arb_mode, sst + SSI_SST_ARBMODE_REG);
+	writel_relaxed(cl->tx_cfg.mode, sst + SSI_SST_MODE_REG);
+	/* RX */
+	writel_relaxed(31, ssr + SSI_SSR_FRAMESIZE_REG);
+	writel_relaxed(cl->rx_cfg.num_hw_channels, ssr + SSI_SSR_CHANNELS_REG);
+	writel_relaxed(0, ssr + SSI_SSR_TIMEOUT_REG);
+	/* Cleanup the break queue if we leave FRAME mode */
+	if ((omap_port->ssr.mode == SSI_MODE_FRAME) &&
+		(cl->rx_cfg.mode != SSI_MODE_FRAME))
+		ssi_flush_queue(&omap_port->brkqueue, cl);
+	writel_relaxed(cl->rx_cfg.mode, ssr + SSI_SSR_MODE_REG);
+	omap_port->channels = max(cl->rx_cfg.num_hw_channels, cl->tx_cfg.num_hw_channels);
+	/* Shadow registering for OFF mode */
+	/* SST */
+	omap_port->sst.divisor = div;
+	omap_port->sst.frame_size = 31;
+	omap_port->sst.channels = cl->tx_cfg.num_hw_channels;
+	omap_port->sst.arb_mode = cl->tx_cfg.arb_mode;
+	omap_port->sst.mode = cl->tx_cfg.mode;
+	/* SSR */
+	omap_port->ssr.frame_size = 31;
+	omap_port->ssr.timeout = 0;
+	omap_port->ssr.channels = cl->rx_cfg.num_hw_channels;
+	omap_port->ssr.mode = cl->rx_cfg.mode;
+out:
+	spin_unlock_bh(&omap_port->lock);
+	pm_runtime_put_sync(omap_port->pdev);
+
+	return err;
+}
+
+static int ssi_flush(struct hsi_client *cl)
+{
+	struct hsi_port *port = hsi_get_port(cl);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	struct hsi_msg *msg;
+	void __iomem *sst = omap_port->sst_base;
+	void __iomem *ssr = omap_port->ssr_base;
+	unsigned int i;
+	u32 err;
+
+	pm_runtime_get_sync(omap_port->pdev);
+	spin_lock_bh(&omap_port->lock);
+	/* Stop all DMA transfers */
+	for (i = 0; i < SSI_MAX_GDD_LCH; i++) {
+		msg = omap_ssi->gdd_trn[i].msg;
+		if (!msg || (port != hsi_get_port(msg->cl)))
+			continue;
+		writew_relaxed(0, omap_ssi->gdd + SSI_GDD_CCR_REG(i));
+		if (msg->ttype == HSI_MSG_READ)
+			pm_runtime_put_sync(omap_port->pdev);
+		omap_ssi->gdd_trn[i].msg = NULL;
+	}
+	/* Flush all SST buffers */
+	writel_relaxed(0, sst + SSI_SST_BUFSTATE_REG);
+	writel_relaxed(0, sst + SSI_SST_TXSTATE_REG);
+	/* Flush all SSR buffers */
+	writel_relaxed(0, ssr + SSI_SSR_RXSTATE_REG);
+	writel_relaxed(0, ssr + SSI_SSR_BUFSTATE_REG);
+	/* Flush all errors */
+	err = readl(ssr + SSI_SSR_ERROR_REG);
+	writel_relaxed(err, ssr + SSI_SSR_ERRORACK_REG);
+	/* Flush break */
+	writel_relaxed(0, ssr + SSI_SSR_BREAK_REG);
+	/* Clear interrupts */
+	writel_relaxed(0, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	writel_relaxed(0xffffff00,
+			omap_ssi->sys + SSI_MPU_STATUS_REG(port->num, 0));
+	writel_relaxed(0, omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
+	writel(0xff, omap_ssi->sys + SSI_GDD_MPU_IRQ_STATUS_REG);
+	/* Dequeue all pending requests */
+	for (i = 0; i < omap_port->channels; i++) {
+		/* Release write clocks */
+		if (!list_empty(&omap_port->txqueue[i]))
+			pm_runtime_put_sync(omap_port->pdev);
+		ssi_flush_queue(&omap_port->txqueue[i], NULL);
+		ssi_flush_queue(&omap_port->rxqueue[i], NULL);
+	}
+	ssi_flush_queue(&omap_port->brkqueue, NULL);
+	spin_unlock_bh(&omap_port->lock);
+	pm_runtime_put_sync(omap_port->pdev);
+
+	return 0;
+}
+
+static int ssi_start_tx(struct hsi_client *cl)
+{
+	struct hsi_port *port = hsi_get_port(cl);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+	dev_dbg(&port->device, "Wake out high %d\n", omap_port->wk_refcount);
+
+	spin_lock_bh(&omap_port->wk_lock);
+	if (omap_port->wk_refcount++) {
+		spin_unlock_bh(&omap_port->wk_lock);
+		return 0;
+	}
+	pm_runtime_get_sync(omap_port->pdev); /* Grab clocks */
+	writel(SSI_WAKE(0), omap_ssi->sys + SSI_SET_WAKE_REG(port->num));
+	spin_unlock_bh(&omap_port->wk_lock);
+
+	return 0;
+}
+
+static int ssi_stop_tx(struct hsi_client *cl)
+{
+	struct hsi_port *port = hsi_get_port(cl);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+	dev_dbg(&port->device, "Wake out low %d\n", omap_port->wk_refcount);
+
+	spin_lock_bh(&omap_port->wk_lock);
+	BUG_ON(!omap_port->wk_refcount);
+	if (--omap_port->wk_refcount) {
+		spin_unlock_bh(&omap_port->wk_lock);
+		return 0;
+	}
+	writel(SSI_WAKE(0),
+				omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num));
+	pm_runtime_put_sync(omap_port->pdev); /* Release clocks */
+	spin_unlock_bh(&omap_port->wk_lock);
+
+	return 0;
+}
+
+static void ssi_transfer(struct omap_ssi_port *omap_port,
+							struct list_head *queue)
+{
+	struct hsi_msg *msg;
+	int err = -1;
+
+	spin_lock_bh(&omap_port->lock);
+	while (err < 0) {
+		err = ssi_start_transfer(queue);
+		if (err < 0) {
+			msg = list_first_entry(queue, struct hsi_msg, link);
+			msg->status = HSI_STATUS_ERROR;
+			msg->actual_len = 0;
+			list_del(&msg->link);
+			spin_unlock_bh(&omap_port->lock);
+			msg->complete(msg);
+			spin_lock_bh(&omap_port->lock);
+		}
+	}
+	spin_unlock_bh(&omap_port->lock);
+}
+
+static void ssi_cleanup_queues(struct hsi_client *cl)
+{
+	struct hsi_port *port = hsi_get_port(cl);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	struct hsi_msg *msg;
+	unsigned int i;
+	u32 rxbufstate = 0;
+	u32 txbufstate = 0;
+	u32 status = SSI_ERROROCCURED;
+	u32 tmp;
+
+	ssi_flush_queue(&omap_port->brkqueue, cl);
+	if (list_empty(&omap_port->brkqueue))
+		status |= SSI_BREAKDETECTED;
+
+	for (i = 0; i < omap_port->channels; i++) {
+		if (list_empty(&omap_port->txqueue[i]))
+			continue;
+		msg = list_first_entry(&omap_port->txqueue[i], struct hsi_msg,
+									link);
+		if ((msg->cl == cl) && (msg->status == HSI_STATUS_PROCEEDING)) {
+			txbufstate |= (1 << i);
+			status |= SSI_DATAACCEPT(i);
+			/* Release the clocks writes, also GDD ones */
+			pm_runtime_put_sync(omap_port->pdev);
+		}
+		ssi_flush_queue(&omap_port->txqueue[i], cl);
+	}
+	for (i = 0; i < omap_port->channels; i++) {
+		if (list_empty(&omap_port->rxqueue[i]))
+			continue;
+		msg = list_first_entry(&omap_port->rxqueue[i], struct hsi_msg,
+									link);
+		if ((msg->cl == cl) && (msg->status == HSI_STATUS_PROCEEDING)) {
+			rxbufstate |= (1 << i);
+			status |= SSI_DATAAVAILABLE(i);
+		}
+		ssi_flush_queue(&omap_port->rxqueue[i], cl);
+		/* Check if we keep the error detection interrupt armed */
+		if (!list_empty(&omap_port->rxqueue[i]))
+			status &= ~SSI_ERROROCCURED;
+	}
+	/* Cleanup write buffers */
+	tmp = readl(omap_port->sst_base + SSI_SST_BUFSTATE_REG);
+	tmp &= ~txbufstate;
+	writel_relaxed(tmp, omap_port->sst_base + SSI_SST_BUFSTATE_REG);
+	/* Cleanup read buffers */
+	tmp = readl(omap_port->ssr_base + SSI_SSR_BUFSTATE_REG);
+	tmp &= ~rxbufstate;
+	writel_relaxed(tmp, omap_port->ssr_base + SSI_SSR_BUFSTATE_REG);
+	/* Disarm and ack pending interrupts */
+	tmp = readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	tmp &= ~status;
+	writel_relaxed(tmp, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	writel_relaxed(status, omap_ssi->sys +
+		SSI_MPU_STATUS_REG(port->num, 0));
+}
+
+static void ssi_cleanup_gdd(struct hsi_controller *ssi, struct hsi_client *cl)
+{
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	struct hsi_port *port = hsi_get_port(cl);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_msg *msg;
+	unsigned int i;
+	u32 val = 0;
+	u32 tmp;
+
+	for (i = 0; i < SSI_MAX_GDD_LCH; i++) {
+		msg = omap_ssi->gdd_trn[i].msg;
+		if ((!msg) || (msg->cl != cl))
+			continue;
+		writew_relaxed(0, omap_ssi->gdd + SSI_GDD_CCR_REG(i));
+		val |= (1 << i);
+		/*
+		 * Clock references for write will be handled in
+		 * ssi_cleanup_queues
+		 */
+		if (msg->ttype == HSI_MSG_READ)
+			pm_runtime_put_sync(omap_port->pdev);
+		omap_ssi->gdd_trn[i].msg = NULL;
+	}
+	tmp = readl_relaxed(omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
+	tmp &= ~val;
+	writel_relaxed(tmp, omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
+	writel(val, omap_ssi->sys + SSI_GDD_MPU_IRQ_STATUS_REG);
+}
+
+static int ssi_set_port_mode(struct omap_ssi_port *omap_port, u32 mode)
+{
+	writel(mode, omap_port->sst_base + SSI_SST_MODE_REG);
+	writel(mode, omap_port->ssr_base + SSI_SSR_MODE_REG);
+	/* OCP barrier */
+	mode = readl(omap_port->ssr_base + SSI_SSR_MODE_REG);
+
+	return 0;
+}
+
+static int ssi_release(struct hsi_client *cl)
+{
+	struct hsi_port *port = hsi_get_port(cl);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+
+	spin_lock_bh(&omap_port->lock);
+	pm_runtime_get_sync(omap_port->pdev);
+	/* Stop all the pending DMA requests for that client */
+	ssi_cleanup_gdd(ssi, cl);
+	/* Now cleanup all the queues */
+	ssi_cleanup_queues(cl);
+	pm_runtime_put_sync(omap_port->pdev);
+	/* If it is the last client of the port, do extra checks and cleanup */
+	if (port->claimed <= 1) {
+		/*
+		 * Drop the clock reference for the incoming wake line
+		 * if it is still kept high by the other side.
+		 */
+		if (omap_port->wkin_cken) {
+			pm_runtime_put_sync(omap_port->pdev);
+			omap_port->wkin_cken = 0;
+		}
+		pm_runtime_get_sync(omap_port->pdev);
+		/* Stop any SSI TX/RX without a client */
+		ssi_set_port_mode(omap_port, SSI_MODE_SLEEP);
+		omap_port->sst.mode = SSI_MODE_SLEEP;
+		omap_port->ssr.mode = SSI_MODE_SLEEP;
+		pm_runtime_put_sync(omap_port->pdev);
+		WARN_ON(omap_port->wk_refcount != 0);
+	}
+	spin_unlock_bh(&omap_port->lock);
+
+	return 0;
+}
+
+
+
+static void ssi_error(struct hsi_port *port)
+{
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	struct hsi_msg *msg;
+	unsigned int i;
+	u32 err;
+	u32 val;
+	u32 tmp;
+
+	/* ACK error */
+	err = readl(omap_port->ssr_base + SSI_SSR_ERROR_REG);
+	dev_err(&port->device, "SSI error: 0x%02x\n", err);
+	if (!err) {
+		dev_dbg(&port->device, "spurious SSI error ignored!\n");
+		return;
+	}
+	spin_lock(&omap_ssi->lock);
+	/* Cancel all GDD read transfers */
+	for (i = 0, val = 0; i < SSI_MAX_GDD_LCH; i++) {
+		msg = omap_ssi->gdd_trn[i].msg;
+		if ((msg) && (msg->ttype == HSI_MSG_READ)) {
+			writew_relaxed(0, omap_ssi->gdd + SSI_GDD_CCR_REG(i));
+			val |= (1 << i);
+			omap_ssi->gdd_trn[i].msg = NULL;
+		}
+	}
+	tmp = readl(omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
+	tmp &= ~val;
+	writel_relaxed(tmp, omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
+	spin_unlock(&omap_ssi->lock);
+	/* Cancel all PIO read transfers */
+	spin_lock(&omap_port->lock);
+	tmp = readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	tmp &= 0xfeff00ff; /* Disable error & all dataavailable interrupts */
+	writel_relaxed(tmp, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	/* ACK error */
+	writel_relaxed(err, omap_port->ssr_base + SSI_SSR_ERRORACK_REG);
+	writel_relaxed(SSI_ERROROCCURED,
+			omap_ssi->sys + SSI_MPU_STATUS_REG(port->num, 0));
+	/* Signal the error all current pending read requests */
+	for (i = 0; i < omap_port->channels; i++) {
+		if (list_empty(&omap_port->rxqueue[i]))
+			continue;
+		msg = list_first_entry(&omap_port->rxqueue[i], struct hsi_msg,
+									link);
+		list_del(&msg->link);
+		msg->status = HSI_STATUS_ERROR;
+		spin_unlock(&omap_port->lock);
+		msg->complete(msg);
+		/* Now restart queued reads if any */
+		ssi_transfer(omap_port, &omap_port->rxqueue[i]);
+		spin_lock(&omap_port->lock);
+	}
+	spin_unlock(&omap_port->lock);
+}
+
+static void ssi_break_complete(struct hsi_port *port)
+{
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	struct hsi_msg *msg;
+	struct hsi_msg *tmp;
+	u32 val;
+
+	dev_dbg(&port->device, "HWBREAK received\n");
+
+	spin_lock(&omap_port->lock);
+	val = readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	val &= ~SSI_BREAKDETECTED;
+	writel_relaxed(val, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	writel_relaxed(0, omap_port->ssr_base + SSI_SSR_BREAK_REG);
+	writel(SSI_BREAKDETECTED,
+			omap_ssi->sys + SSI_MPU_STATUS_REG(port->num, 0));
+	spin_unlock(&omap_port->lock);
+
+	list_for_each_entry_safe(msg, tmp, &omap_port->brkqueue, link) {
+		msg->status = HSI_STATUS_COMPLETED;
+		spin_lock(&omap_port->lock);
+		list_del(&msg->link);
+		spin_unlock(&omap_port->lock);
+		msg->complete(msg);
+	}
+
+}
+
+static void ssi_pio_complete(struct hsi_port *port, struct list_head *queue)
+{
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_msg *msg;
+	u32 *buf;
+	u32 reg;
+	u32 val;
+
+	spin_lock(&omap_port->lock);
+	msg = list_first_entry(queue, struct hsi_msg, link);
+	if ((!msg->sgt.nents) || (!msg->sgt.sgl->length)) {
+		msg->actual_len = 0;
+		msg->status = HSI_STATUS_PENDING;
+	}
+	if (msg->ttype == HSI_MSG_WRITE)
+		val = SSI_DATAACCEPT(msg->channel);
+	else
+		val = SSI_DATAAVAILABLE(msg->channel);
+	if (msg->status == HSI_STATUS_PROCEEDING) {
+		buf = sg_virt(msg->sgt.sgl) + msg->actual_len;
+		if (msg->ttype == HSI_MSG_WRITE)
+			writel(*buf, omap_port->sst_base +
+					SSI_SST_BUFFER_CH_REG(msg->channel));
+		 else
+			*buf = readl(omap_port->ssr_base +
+					SSI_SSR_BUFFER_CH_REG(msg->channel));
+		dev_dbg(&port->device, "ch %d ttype %d 0x%08x\n", msg->channel,
+							msg->ttype, *buf);
+		msg->actual_len += sizeof(*buf);
+		if (msg->actual_len >= msg->sgt.sgl->length)
+			msg->status = HSI_STATUS_COMPLETED;
+		/*
+		 * Wait for the last written frame to be really sent before
+		 * we call the complete callback
+		 */
+		if ((msg->status == HSI_STATUS_PROCEEDING) ||
+				((msg->status == HSI_STATUS_COMPLETED) &&
+					(msg->ttype == HSI_MSG_WRITE))) {
+			writel(val, omap_ssi->sys +
+					SSI_MPU_STATUS_REG(port->num, 0));
+			spin_unlock(&omap_port->lock);
+
+			return;
+		}
+
+	}
+	/* Transfer completed at this point */
+	reg = readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	if (msg->ttype == HSI_MSG_WRITE) {
+		/* Release clocks for write transfer */
+		pm_runtime_put_sync(omap_port->pdev);
+	}
+	reg &= ~val;
+	writel_relaxed(reg, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	writel_relaxed(val, omap_ssi->sys + SSI_MPU_STATUS_REG(port->num, 0));
+	list_del(&msg->link);
+	spin_unlock(&omap_port->lock);
+	msg->complete(msg);
+	ssi_transfer(omap_port, queue);
+}
+
+static void ssi_pio_tasklet(unsigned long ssi_port)
+{
+	struct hsi_port *port = (struct hsi_port *)ssi_port;
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	void __iomem *sys = omap_ssi->sys;
+	unsigned int ch;
+	u32 status_reg;
+
+	pm_runtime_get_sync(omap_port->pdev);
+	status_reg = readl(sys + SSI_MPU_STATUS_REG(port->num, 0));
+	status_reg &= readl(sys + SSI_MPU_ENABLE_REG(port->num, 0));
+
+	for (ch = 0; ch < omap_port->channels; ch++) {
+		if (status_reg & SSI_DATAACCEPT(ch))
+			ssi_pio_complete(port, &omap_port->txqueue[ch]);
+		if (status_reg & SSI_DATAAVAILABLE(ch))
+			ssi_pio_complete(port, &omap_port->rxqueue[ch]);
+	}
+	if (status_reg & SSI_BREAKDETECTED)
+		ssi_break_complete(port);
+	if (status_reg & SSI_ERROROCCURED)
+		ssi_error(port);
+
+	status_reg = readl(sys + SSI_MPU_STATUS_REG(port->num, 0));
+	status_reg &= readl(sys + SSI_MPU_ENABLE_REG(port->num, 0));
+	pm_runtime_put_sync(omap_port->pdev);
+
+	if (status_reg)
+		tasklet_hi_schedule(&omap_port->pio_tasklet);
+	else
+		enable_irq(omap_port->irq);
+}
+
+static irqreturn_t ssi_pio_isr(int irq, void *port)
+{
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+
+	tasklet_hi_schedule(&omap_port->pio_tasklet);
+	disable_irq_nosync(irq);
+
+	return IRQ_HANDLED;
+}
+
+static void ssi_wake_tasklet(unsigned long ssi_port)
+{
+	struct hsi_port *port = (struct hsi_port *)ssi_port;
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+	if (ssi_wakein(port)) {
+		/**
+		 * We can have a quick High-Low-High transition in the line.
+		 * In such a case if we have long interrupt latencies,
+		 * we can miss the low event or get twice a high event.
+		 * This workaround will avoid breaking the clock reference
+		 * count when such a situation ocurrs.
+		 */
+		spin_lock(&omap_port->lock);
+		if (!omap_port->wkin_cken) {
+			omap_port->wkin_cken = 1;
+			pm_runtime_get_sync(omap_port->pdev);
+		}
+		spin_unlock(&omap_port->lock);
+		dev_dbg(&ssi->device, "Wake in high\n");
+		if (omap_port->wktest) { /* FIXME: HACK ! To be removed */
+			writel(SSI_WAKE(0),
+				omap_ssi->sys + SSI_SET_WAKE_REG(port->num));
+		}
+		hsi_event(port, HSI_EVENT_START_RX);
+	} else {
+		dev_dbg(&ssi->device, "Wake in low\n");
+		if (omap_port->wktest) { /* FIXME: HACK ! To be removed */
+			writel(SSI_WAKE(0),
+				omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num));
+		}
+		hsi_event(port, HSI_EVENT_STOP_RX);
+		spin_lock(&omap_port->lock);
+		if (omap_port->wkin_cken) {
+			pm_runtime_put_sync(omap_port->pdev);
+			omap_port->wkin_cken = 0;
+		}
+		spin_unlock(&omap_port->lock);
+	}
+}
+
+static irqreturn_t ssi_wake_isr(int irq __maybe_unused, void *ssi_port)
+{
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(ssi_port);
+
+	tasklet_hi_schedule(&omap_port->wake_tasklet);
+
+	return IRQ_HANDLED;
+}
+
+static int __init ssi_port_irq(struct hsi_port *port,
+						struct platform_device *pd)
+{
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct resource *irq;
+	int err;
+
+	irq = platform_get_resource_byname(pd, IORESOURCE_IRQ, "mpu_irq0");
+	if (!irq) {
+		dev_err(&port->device, "Port IRQ resource missing\n");
+		return -ENXIO;
+	}
+	omap_port->irq = irq->start;
+	tasklet_init(&omap_port->pio_tasklet, ssi_pio_tasklet,
+							(unsigned long)port);
+	err = devm_request_irq(&port->device, omap_port->irq, ssi_pio_isr,
+						0, irq->name, port);
+	if (err < 0)
+		dev_err(&port->device, "Request IRQ %d failed (%d)\n",
+							omap_port->irq, err);
+	return err;
+}
+
+static int __init ssi_wake_irq(struct hsi_port *port,
+						struct platform_device *pd)
+{
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	int cawake_irq;
+	int err;
+
+	if (omap_port->wake_gpio == -1) {
+		omap_port->wake_irq = -1;
+		return 0;
+	}
+
+	cawake_irq = gpio_to_irq(omap_port->wake_gpio);
+
+	omap_port->wake_irq = cawake_irq;
+	tasklet_init(&omap_port->wake_tasklet, ssi_wake_tasklet,
+							(unsigned long)port);
+	err = devm_request_irq(&port->device, cawake_irq, ssi_wake_isr,
+		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+							"cawake", port);
+	if (err < 0)
+		dev_err(&port->device, "Request Wake in IRQ %d failed %d\n",
+						cawake_irq, err);
+	err = enable_irq_wake(cawake_irq);
+	if (err < 0)
+		dev_err(&port->device, "Enable wake on the wakeline in irq %d failed %d\n",
+			cawake_irq, err);
+
+	return err;
+}
+
+static void __init ssi_queues_init(struct omap_ssi_port *omap_port)
+{
+	unsigned int ch;
+
+	for (ch = 0; ch < SSI_MAX_CHANNELS; ch++) {
+		INIT_LIST_HEAD(&omap_port->txqueue[ch]);
+		INIT_LIST_HEAD(&omap_port->rxqueue[ch]);
+	}
+	INIT_LIST_HEAD(&omap_port->brkqueue);
+}
+
+static int __init ssi_port_get_iomem(struct platform_device *pd,
+		const char *name, void __iomem **pbase, dma_addr_t *phy)
+{
+	struct hsi_port *port = platform_get_drvdata(pd);
+	struct resource *mem;
+	struct resource *ioarea;
+	void __iomem *base;
+
+	mem = platform_get_resource_byname(pd, IORESOURCE_MEM, name);
+	if (!mem) {
+		dev_err(&pd->dev, "IO memory region missing (%s)\n", name);
+		return -ENXIO;
+	}
+	ioarea = devm_request_mem_region(&port->device, mem->start,
+					resource_size(mem), dev_name(&pd->dev));
+	if (!ioarea) {
+		dev_err(&pd->dev, "%s IO memory region request failed\n",
+								mem->name);
+		return -ENXIO;
+	}
+	base = devm_ioremap(&port->device, mem->start, resource_size(mem));
+	if (!base) {
+		dev_err(&pd->dev, "%s IO remap failed\n", mem->name);
+		return -ENXIO;
+	}
+	*pbase = base;
+
+	if (phy)
+		*phy = mem->start;
+
+	return 0;
+}
+
+static int __init ssi_port_probe(struct platform_device *pd)
+{
+	struct device_node *np = pd->dev.of_node;
+	struct hsi_port *port;
+	struct omap_ssi_port *omap_port;
+	struct hsi_controller *ssi = dev_get_drvdata(pd->dev.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	u32 cawake_gpio = 0;
+	u32 port_id;
+	int err;
+
+	dev_dbg(&pd->dev, "init ssi port...\n");
+
+	err = ref_module(THIS_MODULE, ssi->owner);
+	if (err) {
+		dev_err(&pd->dev, "could not increment parent module refcount (err=%d)\n",
+			err);
+		return -ENODEV;
+	}
+
+	if (!ssi->port || !omap_ssi->port) {
+		dev_err(&pd->dev, "ssi controller not initialized!\n");
+		err = -ENODEV;
+		goto error;
+	}
+
+	/* get id of first uninitialized port in controller */
+	for (port_id = 0; port_id < ssi->num_ports && omap_ssi->port[port_id];
+		port_id++)
+		;
+
+	if (port_id >= ssi->num_ports) {
+		dev_err(&pd->dev, "port id out of range!\n");
+		err = -ENODEV;
+		goto error;
+	}
+
+	port = ssi->port[port_id];
+
+	if (!np) {
+		dev_err(&pd->dev, "missing device tree data\n");
+		err = -EINVAL;
+		goto error;
+	}
+
+	cawake_gpio = of_get_named_gpio(np, "ti,ssi-cawake-gpio", 0);
+	if (cawake_gpio < 0) {
+		dev_err(&pd->dev, "DT data is missing cawake gpio (err=%d)\n",
+			cawake_gpio);
+		err = -ENODEV;
+		goto error;
+	}
+
+	err = devm_gpio_request_one(&port->device, cawake_gpio, GPIOF_DIR_IN,
+		"cawake");
+	if (err) {
+		dev_err(&pd->dev, "could not request cawake gpio (err=%d)!\n",
+			err);
+		err = -ENXIO;
+		goto error;
+	}
+
+	omap_port = devm_kzalloc(&port->device, sizeof(*omap_port), GFP_KERNEL);
+	if (!omap_port) {
+		err = -ENOMEM;
+		goto error;
+	}
+	omap_port->wake_gpio = cawake_gpio;
+	omap_port->pdev = &pd->dev;
+	omap_port->port_id = port_id;
+
+	/* initialize HSI port */
+	port->async	= ssi_async;
+	port->setup	= ssi_setup;
+	port->flush	= ssi_flush;
+	port->start_tx	= ssi_start_tx;
+	port->stop_tx	= ssi_stop_tx;
+	port->release	= ssi_release;
+	hsi_port_set_drvdata(port, omap_port);
+	omap_ssi->port[port_id] = omap_port;
+
+	platform_set_drvdata(pd, port);
+
+	err = ssi_port_get_iomem(pd, "tx", &omap_port->sst_base,
+		&omap_port->sst_dma);
+	if (err < 0)
+		goto error;
+	err = ssi_port_get_iomem(pd, "rx", &omap_port->ssr_base,
+		&omap_port->ssr_dma);
+	if (err < 0)
+		goto error;
+
+	err = ssi_port_irq(port, pd);
+	if (err < 0)
+		goto error;
+	err = ssi_wake_irq(port, pd);
+	if (err < 0)
+		goto error;
+
+	ssi_queues_init(omap_port);
+	spin_lock_init(&omap_port->lock);
+	spin_lock_init(&omap_port->wk_lock);
+	omap_port->dev = &port->device;
+
+	pm_runtime_irq_safe(omap_port->pdev);
+	pm_runtime_enable(omap_port->pdev);
+
+#ifdef CONFIG_DEBUG_FS
+	err = ssi_debug_add_port(omap_port, omap_ssi->dir);
+	if (err < 0) {
+		pm_runtime_disable(omap_port->pdev);
+		goto error;
+	}
+#endif
+
+	hsi_add_clients_from_dt(port, np);
+
+	dev_info(&pd->dev, "ssi port %u successfully initialized (cawake=%d)\n",
+		port_id, cawake_gpio);
+
+	return 0;
+
+error:
+	return err;
+}
+
+static int __exit ssi_port_remove(struct platform_device *pd)
+{
+	struct hsi_port *port = platform_get_drvdata(pd);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+#ifdef CONFIG_DEBUG_FS
+	ssi_debug_remove_port(port);
+#endif
+
+	hsi_port_unregister_clients(port);
+
+	tasklet_kill(&omap_port->wake_tasklet);
+	tasklet_kill(&omap_port->pio_tasklet);
+
+	port->async	= hsi_dummy_msg;
+	port->setup	= hsi_dummy_cl;
+	port->flush	= hsi_dummy_cl;
+	port->start_tx	= hsi_dummy_cl;
+	port->stop_tx	= hsi_dummy_cl;
+	port->release	= hsi_dummy_cl;
+
+	omap_ssi->port[omap_port->port_id] = NULL;
+	platform_set_drvdata(pd, NULL);
+	pm_runtime_disable(&pd->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int ssi_save_port_ctx(struct omap_ssi_port *omap_port)
+{
+	struct hsi_port *port = to_hsi_port(omap_port->dev);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+	omap_port->sys_mpu_enable = readl(omap_ssi->sys +
+					SSI_MPU_ENABLE_REG(port->num, 0));
+
+	return 0;
+}
+
+static int ssi_restore_port_ctx(struct omap_ssi_port *omap_port)
+{
+	struct hsi_port *port = to_hsi_port(omap_port->dev);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+	void __iomem	*base;
+
+	writel_relaxed(omap_port->sys_mpu_enable,
+			omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
+
+	/* SST context */
+	base = omap_port->sst_base;
+	writel_relaxed(omap_port->sst.frame_size, base + SSI_SST_FRAMESIZE_REG);
+	writel_relaxed(omap_port->sst.channels, base + SSI_SST_CHANNELS_REG);
+	writel_relaxed(omap_port->sst.arb_mode, base + SSI_SST_ARBMODE_REG);
+
+	/* SSR context */
+	base = omap_port->ssr_base;
+	writel_relaxed(omap_port->ssr.frame_size, base + SSI_SSR_FRAMESIZE_REG);
+	writel_relaxed(omap_port->ssr.channels, base + SSI_SSR_CHANNELS_REG);
+	writel_relaxed(omap_port->ssr.timeout, base + SSI_SSR_TIMEOUT_REG);
+
+	return 0;
+}
+
+static int ssi_restore_port_mode(struct omap_ssi_port *omap_port)
+{
+	u32 mode;
+
+	writel_relaxed(omap_port->sst.mode,
+				omap_port->sst_base + SSI_SST_MODE_REG);
+	writel_relaxed(omap_port->ssr.mode,
+				omap_port->ssr_base + SSI_SSR_MODE_REG);
+	/* OCP barrier */
+	mode = readl(omap_port->ssr_base + SSI_SSR_MODE_REG);
+
+	return 0;
+}
+
+static int ssi_restore_divisor(struct omap_ssi_port *omap_port)
+{
+	writel_relaxed(omap_port->sst.divisor,
+				omap_port->sst_base + SSI_SST_DIVISOR_REG);
+
+	return 0;
+}
+
+static int omap_ssi_port_runtime_suspend(struct device *dev)
+{
+	struct hsi_port *port = dev_get_drvdata(dev);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+	dev_dbg(dev, "port runtime suspend!\n");
+
+	ssi_set_port_mode(omap_port, SSI_MODE_SLEEP);
+	if (omap_ssi->get_loss)
+		omap_port->loss_count =
+				omap_ssi->get_loss(ssi->device.parent);
+	ssi_save_port_ctx(omap_port);
+
+	return 0;
+}
+
+static int omap_ssi_port_runtime_resume(struct device *dev)
+{
+	struct hsi_port *port = dev_get_drvdata(dev);
+	struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
+	struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+	dev_dbg(dev, "port runtime resume!\n");
+
+	if ((omap_ssi->get_loss) && (omap_port->loss_count ==
+				omap_ssi->get_loss(ssi->device.parent)))
+		goto mode; /* We always need to restore the mode & TX divisor */
+
+	ssi_restore_port_ctx(omap_port);
+
+mode:
+	ssi_restore_divisor(omap_port);
+	ssi_restore_port_mode(omap_port);
+
+	return 0;
+}
+
+static const struct dev_pm_ops omap_ssi_port_pm_ops = {
+	SET_RUNTIME_PM_OPS(omap_ssi_port_runtime_suspend,
+		omap_ssi_port_runtime_resume, NULL)
+};
+
+#define DEV_PM_OPS     (&omap_ssi_port_pm_ops)
+#else
+#define DEV_PM_OPS     NULL
+#endif
+
+
+#ifdef CONFIG_OF
+static const struct of_device_id omap_ssi_port_of_match[] = {
+	{ .compatible = "ti,omap3-ssi-port", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, omap_ssi_port_of_match);
+#else
+#define omap_ssi_port_of_match NULL
+#endif
+
+static struct platform_driver ssi_port_pdriver = {
+	.remove	= __exit_p(ssi_port_remove),
+	.driver	= {
+		.name	= "omap_ssi_port",
+		.owner	= THIS_MODULE,
+		.of_match_table = omap_ssi_port_of_match,
+		.pm	= DEV_PM_OPS,
+	},
+};
+
+module_platform_driver_probe(ssi_port_pdriver, ssi_port_probe);
+
+MODULE_ALIAS("platform:omap_ssi_port");
+MODULE_AUTHOR("Carlos Chinea <carlos.chinea@nokia.com>");
+MODULE_AUTHOR("Sebastian Reichel <sre@debian.org>");
+MODULE_DESCRIPTION("Synchronous Serial Interface Port Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hsi/controllers/omap_ssi_regs.h b/drivers/hsi/controllers/omap_ssi_regs.h
new file mode 100644
index 0000000..08f98dd
--- /dev/null
+++ b/drivers/hsi/controllers/omap_ssi_regs.h
@@ -0,0 +1,171 @@
+/* Hardware definitions for SSI.
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Carlos Chinea <carlos.chinea@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __OMAP_SSI_REGS_H__
+#define __OMAP_SSI_REGS_H__
+
+/*
+ * SSI SYS registers
+ */
+#define SSI_REVISION_REG    0
+#  define SSI_REV_MAJOR    0xf0
+#  define SSI_REV_MINOR    0xf
+#define SSI_SYSCONFIG_REG    0x10
+#  define SSI_AUTOIDLE    (1 << 0)
+#  define SSI_SOFTRESET    (1 << 1)
+#  define SSI_SIDLEMODE_FORCE  0
+#  define SSI_SIDLEMODE_NO    (1 << 3)
+#  define SSI_SIDLEMODE_SMART  (1 << 4)
+#  define SSI_SIDLEMODE_MASK  0x18
+#  define SSI_MIDLEMODE_FORCE  0
+#  define SSI_MIDLEMODE_NO    (1 << 12)
+#  define SSI_MIDLEMODE_SMART  (1 << 13)
+#  define SSI_MIDLEMODE_MASK  0x3000
+#define SSI_SYSSTATUS_REG    0x14
+#  define SSI_RESETDONE    1
+#define SSI_MPU_STATUS_REG(port, irq)  (0x808 + ((port) * 0x10) + ((irq) * 2))
+#define SSI_MPU_ENABLE_REG(port, irq)  (0x80c + ((port) * 0x10) + ((irq) * 8))
+#  define SSI_DATAACCEPT(channel)    (1 << (channel))
+#  define SSI_DATAAVAILABLE(channel)  (1 << ((channel) + 8))
+#  define SSI_DATAOVERRUN(channel)    (1 << ((channel) + 16))
+#  define SSI_ERROROCCURED      (1 << 24)
+#  define SSI_BREAKDETECTED    (1 << 25)
+#define SSI_GDD_MPU_IRQ_STATUS_REG  0x0800
+#define SSI_GDD_MPU_IRQ_ENABLE_REG  0x0804
+#  define SSI_GDD_LCH(channel)  (1 << (channel))
+#define SSI_WAKE_REG(port)    (0xc00 + ((port) * 0x10))
+#define SSI_CLEAR_WAKE_REG(port)  (0xc04 + ((port) * 0x10))
+#define SSI_SET_WAKE_REG(port)    (0xc08 + ((port) * 0x10))
+#  define SSI_WAKE(channel)  (1 << (channel))
+#  define SSI_WAKE_MASK    0xff
+
+/*
+ * SSI SST registers
+ */
+#define SSI_SST_ID_REG      0
+#define SSI_SST_MODE_REG    4
+#  define SSI_MODE_VAL_MASK  3
+#  define SSI_MODE_SLEEP    0
+#  define SSI_MODE_STREAM    1
+#  define SSI_MODE_FRAME    2
+#  define SSI_MODE_MULTIPOINTS  3
+#define SSI_SST_FRAMESIZE_REG    8
+#  define SSI_FRAMESIZE_DEFAULT  31
+#define SSI_SST_TXSTATE_REG    0xc
+#  define  SSI_TXSTATE_IDLE  0
+#define SSI_SST_BUFSTATE_REG    0x10
+#  define  SSI_FULL(channel)  (1 << (channel))
+#define SSI_SST_DIVISOR_REG    0x18
+#  define SSI_MAX_DIVISOR    127
+#define SSI_SST_BREAK_REG    0x20
+#define SSI_SST_CHANNELS_REG    0x24
+#  define SSI_CHANNELS_DEFAULT  4
+#define SSI_SST_ARBMODE_REG    0x28
+#  define SSI_ARBMODE_ROUNDROBIN  0
+#  define SSI_ARBMODE_PRIORITY  1
+#define SSI_SST_BUFFER_CH_REG(channel)  (0x80 + ((channel) * 4))
+#define SSI_SST_SWAPBUF_CH_REG(channel)  (0xc0 + ((channel) * 4))
+
+/*
+ * SSI SSR registers
+ */
+#define SSI_SSR_ID_REG      0
+#define SSI_SSR_MODE_REG    4
+#define SSI_SSR_FRAMESIZE_REG    8
+#define SSI_SSR_RXSTATE_REG    0xc
+#define SSI_SSR_BUFSTATE_REG    0x10
+#  define SSI_NOTEMPTY(channel)  (1 << (channel))
+#define SSI_SSR_BREAK_REG    0x1c
+#define SSI_SSR_ERROR_REG    0x20
+#define SSI_SSR_ERRORACK_REG    0x24
+#define SSI_SSR_OVERRUN_REG    0x2c
+#define SSI_SSR_OVERRUNACK_REG    0x30
+#define SSI_SSR_TIMEOUT_REG    0x34
+#  define SSI_TIMEOUT_DEFAULT  0
+#define SSI_SSR_CHANNELS_REG    0x28
+#define SSI_SSR_BUFFER_CH_REG(channel)  (0x80 + ((channel) * 4))
+#define SSI_SSR_SWAPBUF_CH_REG(channel)  (0xc0 + ((channel) * 4))
+
+/*
+ * SSI GDD registers
+ */
+#define SSI_GDD_HW_ID_REG    0
+#define SSI_GDD_PPORT_ID_REG    0x10
+#define SSI_GDD_MPORT_ID_REG    0x14
+#define SSI_GDD_PPORT_SR_REG    0x20
+#define SSI_GDD_MPORT_SR_REG    0x24
+#  define SSI_ACTIVE_LCH_NUM_MASK  0xff
+#define SSI_GDD_TEST_REG    0x40
+#  define SSI_TEST      1
+#define SSI_GDD_GCR_REG      0x100
+#  define  SSI_CLK_AUTOGATING_ON  (1 << 3)
+#  define  SSI_FREE    (1 << 2)
+#  define  SSI_SWITCH_OFF    (1 << 0)
+#define SSI_GDD_GRST_REG    0x200
+#  define SSI_SWRESET    1
+#define SSI_GDD_CSDP_REG(channel)  (0x800 + ((channel) * 0x40))
+#  define SSI_DST_BURST_EN_MASK  0xc000
+#  define SSI_DST_SINGLE_ACCESS0  0
+#  define SSI_DST_SINGLE_ACCESS  (1 << 14)
+#  define SSI_DST_BURST_4x32_BIT  (2 << 14)
+#  define SSI_DST_BURST_8x32_BIT  (3 << 14)
+#  define SSI_DST_MASK    0x1e00
+#  define SSI_DST_MEMORY_PORT  (8 << 9)
+#  define SSI_DST_PERIPHERAL_PORT  (9 << 9)
+#  define SSI_SRC_BURST_EN_MASK  0x180
+#  define SSI_SRC_SINGLE_ACCESS0  0
+#  define SSI_SRC_SINGLE_ACCESS  (1 << 7)
+#  define SSI_SRC_BURST_4x32_BIT  (2 << 7)
+#  define SSI_SRC_BURST_8x32_BIT  (3 << 7)
+#  define SSI_SRC_MASK    0x3c
+#  define SSI_SRC_MEMORY_PORT  (8 << 2)
+#  define SSI_SRC_PERIPHERAL_PORT  (9 << 2)
+#  define SSI_DATA_TYPE_MASK  3
+#  define SSI_DATA_TYPE_S32  2
+#define SSI_GDD_CCR_REG(channel)  (0x802 + ((channel) * 0x40))
+#  define SSI_DST_AMODE_MASK  (3 << 14)
+#  define SSI_DST_AMODE_CONST  0
+#  define SSI_DST_AMODE_POSTINC  (1 << 12)
+#  define SSI_SRC_AMODE_MASK  (3 << 12)
+#  define SSI_SRC_AMODE_CONST  0
+#  define SSI_SRC_AMODE_POSTINC  (1 << 12)
+#  define SSI_CCR_ENABLE    (1 << 7)
+#  define SSI_CCR_SYNC_MASK  0x1f
+#define SSI_GDD_CICR_REG(channel)  (0x804 + ((channel) * 0x40))
+#  define SSI_BLOCK_IE    (1 << 5)
+#  define SSI_HALF_IE    (1 << 2)
+#  define SSI_TOUT_IE    (1 << 0)
+#define SSI_GDD_CSR_REG(channel)  (0x806 + ((channel) * 0x40))
+#  define SSI_CSR_SYNC    (1 << 6)
+#  define SSI_CSR_BLOCK    (1 << 5)
+#  define SSI_CSR_HALF    (1 << 2)
+#  define SSI_CSR_TOUR    (1 << 0)
+#define SSI_GDD_CSSA_REG(channel)  (0x808 + ((channel) * 0x40))
+#define SSI_GDD_CDSA_REG(channel)  (0x80c + ((channel) * 0x40))
+#define SSI_GDD_CEN_REG(channel)  (0x810 + ((channel) * 0x40))
+#define SSI_GDD_CSAC_REG(channel)  (0x818 + ((channel) * 0x40))
+#define SSI_GDD_CDAC_REG(channel)  (0x81a + ((channel) * 0x40))
+#define SSI_GDD_CLNK_CTRL_REG(channel)  (0x828 + ((channel) * 0x40))
+#  define SSI_ENABLE_LNK    (1 << 15)
+#  define SSI_STOP_LNK    (1 << 14)
+#  define SSI_NEXT_CH_ID_MASK  0xf
+
+#endif /* __OMAP_SSI_REGS_H__ */
-- 
1.9.0


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

* [PATCHv3 09/14] Documentation: DT: omap-ssi binding documentation
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
                   ` (7 preceding siblings ...)
  2014-03-29  0:31 ` [PATCHv3 08/14] HSI: Introduce OMAP SSI driver Sebastian Reichel
@ 2014-03-29  0:31 ` Sebastian Reichel
  2014-04-19 19:32   ` Pavel Machek
  2014-04-21 16:43   ` Rob Herring
  2014-03-29  0:31 ` [PATCHv3 10/14] HSI: Introduce driver for SSI Protocol Sebastian Reichel
                   ` (5 subsequent siblings)
  14 siblings, 2 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

Create device tree binding documentation for
OMAP Synchronous Serial Interface (SSI) device.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 Documentation/devicetree/bindings/hsi/omap-ssi.txt | 85 ++++++++++++++++++++++
 1 file changed, 85 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hsi/omap-ssi.txt

diff --git a/Documentation/devicetree/bindings/hsi/omap-ssi.txt b/Documentation/devicetree/bindings/hsi/omap-ssi.txt
new file mode 100644
index 0000000..709419b
--- /dev/null
+++ b/Documentation/devicetree/bindings/hsi/omap-ssi.txt
@@ -0,0 +1,85 @@
+OMAP SSI controller bindings
+
+OMAP Synchronous Serial Interface (SSI) controller implements a legacy
+variant of MIPI's High Speed Synchronous Serial Interface (HSI).
+
+Required properties:
+- compatible:		Should include "ti,omap3-ssi".
+- reg-names:		Contains the values "sys" and "gdd".
+- reg:			Contains a register specifier for each entry in
+			reg-names.
+- interrupt-names:      Contains the value "gdd_mpu".
+- interrupts: 		Contains interrupt information for each entry in
+			interrupt-names.
+- ranges:		Represents the bus address mapping between the main
+			controller node and the child nodes below.
+- clocks:		Contains clock specifiers for each entry in
+                        clock-names.
+- clock-names:		Must include the following entries:
+  "ssi_ssr_fck": The OMAP clock of that name
+  "ssi_sst_fck": The OMAP clock of that name
+  "ssi_ick": The OMAP clock of that name
+- #address-cells:	Should be set to <1>
+- #size-cells:		Should be set to <1>
+
+Each port is represented as a sub-node of the ti,omap3-ssi device.
+
+Required Port sub-node properties:
+- compatible:		Should be set to the following value
+                        ti,omap3-ssi-port (applicable to OMAP34xx devices)
+- reg-names:		Contains the values "rx" and "tx".
+- reg:			Contains a register specifier for each entry in
+			reg-names.
+- interrupt-parent	Should be a phandle for the interrupt controller
+- interrupt-names:	Contains the values "mpu_irq0" and "mpu_irq1".
+- interrupts:		Contains interrupt information for each entry in
+			interrupt-names.
+- ti,ssi-cawake-gpio:	Defines which GPIO pin is used to signify CAWAKE
+			events for the port. This is an optional board-specific
+			property. If it's missing the port will not be
+			enabled.
+
+Example for Nokia N900:
+
+ssi-controller@48058000 {
+	compatible = "ti,omap3-ssi";
+
+	/* needed until hwmod is updated to use the compatible string */
+	ti,hwmods = "ssi";
+
+	reg = <0x48058000 0x1000>,
+	      <0x48059000 0x1000>;
+	reg-names = "sys",
+		    "gdd";
+
+	interrupts = <55>;
+	interrupt-names = "gdd_mpu";
+
+	clocks = <&ssi_ssr_fck>,
+		 <&ssi_sst_fck>,
+		 <&ssi_ick>;
+	clock-names = "ssi_ssr_fck",
+		      "ssi_sst_fck",
+		      "ssi_ick";
+
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+
+	ssi-port@0 {
+		compatible = "ti,omap3-ssi-port";
+
+		reg = <0x4805a000 0x800>,
+		      <0x4805a800 0x800>;
+		reg-names = "tx",
+			    "rx";
+
+		interrupt-parent = <&intc>;
+		interrupts = <51>,
+			     <52>;
+		interrupt-names = "mpu_irq0",
+				  "mpu_irq1";
+
+		ti,ssi-cawake-gpio = <&gpio5 23 GPIO_ACTIVE_HIGH>; /* 151 */
+	}
+}
-- 
1.9.0


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

* [PATCHv3 10/14] HSI: Introduce driver for SSI Protocol
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
                   ` (8 preceding siblings ...)
  2014-03-29  0:31 ` [PATCHv3 09/14] Documentation: DT: omap-ssi binding documentation Sebastian Reichel
@ 2014-03-29  0:31 ` Sebastian Reichel
  2014-04-19 19:49     ` Pavel Machek
  2014-03-29  0:31   ` Sebastian Reichel
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel, Carlos Chinea

This adds a driver for the SSI McSAAB protocol as used in
the Nokia N900.

Signed-off-by: Carlos Chinea <carlos.chinea@nokia.com>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 drivers/hsi/clients/Kconfig        |    8 +
 drivers/hsi/clients/Makefile       |    3 +-
 drivers/hsi/clients/ssi_protocol.c | 1188 ++++++++++++++++++++++++++++++++++++
 include/linux/hsi/ssi_protocol.h   |   42 ++
 4 files changed, 1240 insertions(+), 1 deletion(-)
 create mode 100644 drivers/hsi/clients/ssi_protocol.c
 create mode 100644 include/linux/hsi/ssi_protocol.h

diff --git a/drivers/hsi/clients/Kconfig b/drivers/hsi/clients/Kconfig
index 3bacd27..0c70861 100644
--- a/drivers/hsi/clients/Kconfig
+++ b/drivers/hsi/clients/Kconfig
@@ -4,6 +4,14 @@
 
 comment "HSI clients"
 
+config SSI_PROTOCOL
+	tristate "SSI protocol"
+	depends on HSI && OMAP_SSI && PHONET
+	help
+	If you say Y here, you will enable the SSI protocol aka McSAAB.
+
+	If unsure, say N.
+
 config HSI_CHAR
 	tristate "HSI/SSI character driver"
 	depends on HSI
diff --git a/drivers/hsi/clients/Makefile b/drivers/hsi/clients/Makefile
index 327c0e2..ccbf768 100644
--- a/drivers/hsi/clients/Makefile
+++ b/drivers/hsi/clients/Makefile
@@ -2,4 +2,5 @@
 # Makefile for HSI clients
 #
 
-obj-$(CONFIG_HSI_CHAR)	+= hsi_char.o
+obj-$(CONFIG_SSI_PROTOCOL)	+= ssi_protocol.o
+obj-$(CONFIG_HSI_CHAR)		+= hsi_char.o
diff --git a/drivers/hsi/clients/ssi_protocol.c b/drivers/hsi/clients/ssi_protocol.c
new file mode 100644
index 0000000..66a7737
--- /dev/null
+++ b/drivers/hsi/clients/ssi_protocol.c
@@ -0,0 +1,1188 @@
+/*
+ * ssi_protocol.c
+ *
+ * Implementation of the SSI McSAAB improved protocol.
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ * Copyright (C) 2013 Sebastian Reichel <sre@kernel.org>
+ *
+ * Contact: Carlos Chinea <carlos.chinea@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <asm/atomic.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <linux/if_phonet.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/notifier.h>
+#include <linux/scatterlist.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/hsi/hsi.h>
+#include <linux/hsi/ssi_protocol.h>
+
+void ssi_waketest(struct hsi_client *cl, unsigned int enable);
+
+#define SSIP_TXQUEUE_LEN	100
+#define SSIP_MAX_MTU		65535
+#define SSIP_DEFAULT_MTU	4000
+#define PN_MEDIA_SOS		21
+#define SSIP_MIN_PN_HDR		6	/* FIXME: Revisit */
+#define SSIP_WDTOUT		2000	/* FIXME: has to be 500 msecs */
+#define SSIP_KATOUT		15	/* 15 msecs */
+#define SSIP_MAX_CMDS		5 /* Number of pre-allocated commands buffers */
+#define SSIP_BYTES_TO_FRAMES(x) ((((x) - 1) >> 2) + 1)
+#define SSIP_CMT_LOADER_SYNC	0x11223344
+/*
+ * SSI protocol command definitions
+ */
+#define SSIP_COMMAND(data)	((data) >> 28)
+#define SSIP_PAYLOAD(data)	((data) & 0xfffffff)
+/* Commands */
+#define SSIP_SW_BREAK		0
+#define SSIP_BOOTINFO_REQ	1
+#define SSIP_BOOTINFO_RESP	2
+#define SSIP_WAKETEST_RESULT	3
+#define SSIP_START_TRANS	4
+#define SSIP_READY		5
+/* Payloads */
+#define SSIP_DATA_VERSION(data)	((data) & 0xff)
+#define SSIP_LOCAL_VERID	1
+#define SSIP_WAKETEST_OK	0
+#define SSIP_WAKETEST_FAILED	1
+#define SSIP_PDU_LENGTH(data)	(((data) >> 8) & 0xffff)
+#define SSIP_MSG_ID(data)	((data) & 0xff)
+/* Generic Command */
+#define SSIP_CMD(cmd, payload)	(((cmd) << 28) | ((payload) & 0xfffffff))
+/* Commands for the control channel */
+#define SSIP_BOOTINFO_REQ_CMD(ver) \
+		SSIP_CMD(SSIP_BOOTINFO_REQ, SSIP_DATA_VERSION(ver))
+#define SSIP_BOOTINFO_RESP_CMD(ver) \
+		SSIP_CMD(SSIP_BOOTINFO_RESP, SSIP_DATA_VERSION(ver))
+#define SSIP_START_TRANS_CMD(pdulen, id) \
+		SSIP_CMD(SSIP_START_TRANS, (((pdulen) << 8) | SSIP_MSG_ID(id)))
+#define SSIP_READY_CMD		SSIP_CMD(SSIP_READY, 0)
+#define SSIP_SWBREAK_CMD	SSIP_CMD(SSIP_SW_BREAK, 0)
+
+/* Main state machine states */
+enum {
+	INIT,
+	HANDSHAKE,
+	ACTIVE,
+};
+
+/* Send state machine states */
+enum {
+	SEND_IDLE,
+	WAIT4READY,
+	SEND_READY,
+	SENDING,
+	SENDING_SWBREAK,
+};
+
+/* Receive state machine states */
+enum {
+	RECV_IDLE,
+	RECV_READY,
+	RECEIVING,
+};
+
+/**
+ * struct ssi_protocol - SSI protocol (McSAAB) data
+ * @main_state: Main state machine
+ * @send_state: TX state machine
+ * @recv_state: RX state machine
+ * @waketest: Flag to follow wake line test
+ * @rxid: RX data id
+ * @txid: TX data id
+ * @txqueue_len: TX queue length
+ * @tx_wd: TX watchdog
+ * @rx_wd: RX watchdog
+ * @keep_alive: Workaround for SSI HW bug
+ * @lock: To serialize access to this struct
+ * @netdev: Phonet network device
+ * @txqueue: TX data queue
+ * @cmdqueue: Queue of free commands
+ * @cl: HSI client own reference
+ * @link: Link for ssip_list
+ * @tx_usecount: Refcount to keep track the slaves that use the wake line
+ * @channel_id_cmd: HSI channel id for command stream
+ * @channel_id_data: HSI channel id for data stream
+ */
+struct ssi_protocol {
+	unsigned int		main_state;
+	unsigned int		send_state;
+	unsigned int		recv_state;
+	unsigned int		waketest:1;
+	u8			rxid;
+	u8			txid;
+	unsigned int		txqueue_len;
+	struct timer_list	tx_wd;
+	struct timer_list	rx_wd;
+	struct timer_list	keep_alive; /* wake-up workaround */
+	spinlock_t		lock;
+	struct net_device	*netdev;
+	struct list_head	txqueue;
+	struct list_head	cmdqueue;
+	struct hsi_client	*cl;
+	struct list_head	link;
+	atomic_t		tx_usecnt;
+	int			channel_id_cmd;
+	int			channel_id_data;
+};
+
+/* List of ssi protocol instances */
+static LIST_HEAD(ssip_list);
+
+static void ssip_rxcmd_complete(struct hsi_msg *msg);
+
+static inline void ssip_set_cmd(struct hsi_msg *msg, u32 cmd)
+{
+	u32 *data;
+
+	data = sg_virt(msg->sgt.sgl);
+	*data = cmd;
+}
+
+static inline u32 ssip_get_cmd(struct hsi_msg *msg)
+{
+	u32 *data;
+
+	data = sg_virt(msg->sgt.sgl);
+
+	return *data;
+}
+
+static void ssip_skb_to_msg(struct sk_buff *skb, struct hsi_msg *msg)
+{
+	skb_frag_t *frag;
+	struct scatterlist *sg;
+	int i;
+
+	BUG_ON(msg->sgt.nents != (unsigned int)(skb_shinfo(skb)->nr_frags + 1));
+
+	sg = msg->sgt.sgl;
+	sg_set_buf(sg, skb->data, skb_headlen(skb));
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		sg = sg_next(sg);
+		BUG_ON(!sg);
+		frag = &skb_shinfo(skb)->frags[i];
+		sg_set_page(sg, frag->page.p, frag->size, frag->page_offset);
+	}
+}
+
+static void ssip_free_data(struct hsi_msg *msg)
+{
+	struct sk_buff *skb;
+
+	skb = msg->context;
+	pr_debug("free data: msg %p context %p skb %p\n", msg, msg->context,
+								skb);
+	msg->destructor = NULL;
+	dev_kfree_skb(skb);
+	hsi_free_msg(msg);
+}
+
+static struct hsi_msg *ssip_alloc_data(struct ssi_protocol *ssi,
+					struct sk_buff *skb, gfp_t flags)
+{
+	struct hsi_msg *msg;
+
+	msg = hsi_alloc_msg(skb_shinfo(skb)->nr_frags + 1, flags);
+	if (!msg)
+		return NULL;
+	ssip_skb_to_msg(skb, msg);
+	msg->destructor = ssip_free_data;
+	msg->channel = ssi->channel_id_data;
+	msg->context = skb;
+
+	return msg;
+}
+
+static inline void ssip_release_cmd(struct hsi_msg *msg)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(msg->cl);
+
+	dev_dbg(&msg->cl->device, "Release cmd 0x%08x\n", ssip_get_cmd(msg));
+	spin_lock_bh(&ssi->lock);
+	list_add_tail(&msg->link, &ssi->cmdqueue);
+	spin_unlock_bh(&ssi->lock);
+}
+
+static struct hsi_msg *ssip_claim_cmd(struct ssi_protocol *ssi)
+{
+	struct hsi_msg *msg;
+
+	BUG_ON(list_empty(&ssi->cmdqueue));
+
+	spin_lock_bh(&ssi->lock);
+	msg = list_first_entry(&ssi->cmdqueue, struct hsi_msg, link);
+	list_del(&msg->link);
+	spin_unlock_bh(&ssi->lock);
+	msg->destructor = ssip_release_cmd;
+
+	return msg;
+}
+
+static void ssip_free_cmds(struct ssi_protocol *ssi)
+{
+	struct hsi_msg *msg, *tmp;
+
+	list_for_each_entry_safe(msg, tmp, &ssi->cmdqueue, link) {
+		list_del(&msg->link);
+		msg->destructor = NULL;
+		kfree(sg_virt(msg->sgt.sgl));
+		hsi_free_msg(msg);
+	}
+}
+
+static int ssip_alloc_cmds(struct ssi_protocol *ssi)
+{
+	struct hsi_msg *msg;
+	u32 *buf;
+	unsigned int i;
+
+	for (i = 0; i < SSIP_MAX_CMDS; i++) {
+		msg = hsi_alloc_msg(1, GFP_KERNEL);
+		if (!msg)
+			goto out;
+		buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+		if (!buf) {
+			hsi_free_msg(msg);
+			goto out;
+		}
+		sg_init_one(msg->sgt.sgl, buf, sizeof(*buf));
+		msg->channel = ssi->channel_id_cmd;
+		list_add_tail(&msg->link, &ssi->cmdqueue);
+	}
+
+	return 0;
+out:
+	ssip_free_cmds(ssi);
+
+	return -ENOMEM;
+}
+
+static void ssip_set_rxstate(struct ssi_protocol *ssi, unsigned int state)
+{
+	ssi->recv_state = state;
+	switch (state) {
+	case RECV_IDLE:
+		del_timer(&ssi->rx_wd);
+		if (ssi->send_state == SEND_IDLE)
+			del_timer(&ssi->keep_alive);
+		break;
+	case RECV_READY:
+		/* CMT speech workaround */
+		if (atomic_read(&ssi->tx_usecnt))
+			break;
+		/* Otherwise fall through */
+	case RECEIVING:
+		mod_timer(&ssi->keep_alive, jiffies +
+						msecs_to_jiffies(SSIP_KATOUT));
+		mod_timer(&ssi->rx_wd, jiffies + msecs_to_jiffies(SSIP_WDTOUT));
+		break;
+	default:
+		break;
+	}
+}
+
+static void ssip_set_txstate(struct ssi_protocol *ssi, unsigned int state)
+{
+	ssi->send_state = state;
+	switch (state) {
+	case SEND_IDLE:
+	case SEND_READY:
+		del_timer(&ssi->tx_wd);
+		if (ssi->recv_state == RECV_IDLE)
+			del_timer(&ssi->keep_alive);
+		break;
+	case WAIT4READY:
+	case SENDING:
+	case SENDING_SWBREAK:
+		mod_timer(&ssi->keep_alive,
+				jiffies + msecs_to_jiffies(SSIP_KATOUT));
+		mod_timer(&ssi->tx_wd, jiffies + msecs_to_jiffies(SSIP_WDTOUT));
+		break;
+	default:
+		break;
+	}
+}
+
+struct hsi_client *ssip_slave_get_master(struct hsi_client *slave)
+{
+	struct hsi_client *master = ERR_PTR(-ENODEV);
+	struct ssi_protocol *ssi;
+
+	list_for_each_entry(ssi, &ssip_list, link)
+		if (slave->device.parent == ssi->cl->device.parent) {
+			master = ssi->cl;
+			break;
+		}
+
+	return master;
+}
+EXPORT_SYMBOL_GPL(ssip_slave_get_master);
+
+int ssip_slave_start_tx(struct hsi_client *master)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(master);
+
+	dev_dbg(&master->device, "start TX %d\n", atomic_read(&ssi->tx_usecnt));
+	spin_lock_bh(&ssi->lock);
+	if (ssi->send_state == SEND_IDLE) {
+		ssip_set_txstate(ssi, WAIT4READY);
+		hsi_start_tx(master);
+	}
+	spin_unlock_bh(&ssi->lock);
+	atomic_inc(&ssi->tx_usecnt);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ssip_slave_start_tx);
+
+int ssip_slave_stop_tx(struct hsi_client *master)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(master);
+
+	WARN_ON_ONCE(atomic_read(&ssi->tx_usecnt) == 0);
+
+	if (atomic_dec_and_test(&ssi->tx_usecnt)) {
+		spin_lock_bh(&ssi->lock);
+		if ((ssi->send_state == SEND_READY) ||
+			(ssi->send_state == WAIT4READY)) {
+			ssip_set_txstate(ssi, SEND_IDLE);
+			hsi_stop_tx(master);
+		}
+		spin_unlock_bh(&ssi->lock);
+	}
+	dev_dbg(&master->device, "stop TX %d\n", atomic_read(&ssi->tx_usecnt));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ssip_slave_stop_tx);
+
+int ssip_slave_running(struct hsi_client *master)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(master);
+	return netif_running(ssi->netdev);
+}
+EXPORT_SYMBOL_GPL(ssip_slave_running);
+
+static void ssip_reset(struct hsi_client *cl)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	struct list_head *head, *tmp;
+	struct hsi_msg *msg;
+
+	if (netif_running(ssi->netdev))
+		netif_carrier_off(ssi->netdev);
+	hsi_flush(cl);
+	spin_lock_bh(&ssi->lock);
+	if (ssi->send_state != SEND_IDLE)
+		hsi_stop_tx(cl);
+	if (ssi->waketest)
+		ssi_waketest(cl, 0);
+	del_timer(&ssi->rx_wd);
+	del_timer(&ssi->tx_wd);
+	del_timer(&ssi->keep_alive);
+	ssi->main_state = 0;
+	ssi->send_state = 0;
+	ssi->recv_state = 0;
+	ssi->waketest = 0;
+	ssi->rxid = 0;
+	ssi->txid = 0;
+	list_for_each_safe(head, tmp, &ssi->txqueue) {
+		msg = list_entry(head, struct hsi_msg, link);
+		dev_dbg(&cl->device, "Pending TX data\n");
+		list_del(head);
+		ssip_free_data(msg);
+	}
+	ssi->txqueue_len = 0;
+	spin_unlock_bh(&ssi->lock);
+}
+
+static void ssip_dump_state(struct hsi_client *cl)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	struct hsi_msg *msg;
+
+	spin_lock_bh(&ssi->lock);
+	dev_err(&cl->device, "Main state: %d\n", ssi->main_state);
+	dev_err(&cl->device, "Recv state: %d\n", ssi->recv_state);
+	dev_err(&cl->device, "Send state: %d\n", ssi->send_state);
+	dev_err(&cl->device, "CMT %s\n", (ssi->main_state == ACTIVE) ?
+							"Online" : "Offline");
+	dev_err(&cl->device, "Wake test %d\n", ssi->waketest);
+	dev_err(&cl->device, "Data RX id: %d\n", ssi->rxid);
+	dev_err(&cl->device, "Data TX id: %d\n", ssi->txid);
+
+	list_for_each_entry(msg, &ssi->txqueue, link)
+		dev_err(&cl->device, "pending TX data (%p)\n", msg);
+	spin_unlock_bh(&ssi->lock);
+}
+
+static void ssip_error(struct hsi_client *cl)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	struct hsi_msg *msg;
+
+	ssip_dump_state(cl);
+	ssip_reset(cl);
+	msg = ssip_claim_cmd(ssi);
+	msg->complete = ssip_rxcmd_complete;
+	hsi_async_read(cl, msg);
+}
+
+static void ssip_keep_alive(unsigned long data)
+{
+	struct hsi_client *cl = (struct hsi_client *)data;
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+
+	dev_dbg(&cl->device, "Keep alive kick in: m(%d) r(%d) s(%d)\n",
+		ssi->main_state, ssi->recv_state, ssi->send_state);
+
+	spin_lock(&ssi->lock);
+	if (ssi->recv_state == RECV_IDLE)
+		switch (ssi->send_state) {
+		case SEND_READY:
+			if (atomic_read(&ssi->tx_usecnt) == 0)
+				break;
+			/*
+			 * Fall through. Workaround for cmt-speech
+			 * in that case we relay on audio timers.
+			 */
+		case SEND_IDLE:
+			spin_unlock(&ssi->lock);
+			return;
+		}
+	mod_timer(&ssi->keep_alive, jiffies + msecs_to_jiffies(SSIP_KATOUT));
+	spin_unlock(&ssi->lock);
+}
+
+static void ssip_wd(unsigned long data)
+{
+	struct hsi_client *cl = (struct hsi_client *)data;
+
+	dev_err(&cl->device, "Watchdog trigerred\n");
+	ssip_error(cl);
+}
+
+static void ssip_send_bootinfo_req_cmd(struct hsi_client *cl)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	struct hsi_msg *msg;
+
+	dev_dbg(&cl->device, "Issuing BOOT INFO REQ command\n");
+	msg = ssip_claim_cmd(ssi);
+	ssip_set_cmd(msg, SSIP_BOOTINFO_REQ_CMD(SSIP_LOCAL_VERID));
+	msg->complete = ssip_release_cmd;
+	hsi_async_write(cl, msg);
+	dev_dbg(&cl->device, "Issuing RX command\n");
+	msg = ssip_claim_cmd(ssi);
+	msg->complete = ssip_rxcmd_complete;
+	hsi_async_read(cl, msg);
+}
+
+static void ssip_start_rx(struct hsi_client *cl)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	struct hsi_msg *msg;
+
+	dev_dbg(&cl->device, "RX start M(%d) R(%d)\n", ssi->main_state,
+						ssi->recv_state);
+	spin_lock(&ssi->lock);
+	/*
+	 * We can have two UP events in a row due to a short low
+	 * high transition. Therefore we need to ignore the sencond UP event.
+	 */
+	if ((ssi->main_state != ACTIVE) || (ssi->recv_state == RECV_READY)) {
+		if(ssi->main_state == INIT)
+		{
+			ssi->main_state = HANDSHAKE;
+			spin_unlock(&ssi->lock);
+			ssip_send_bootinfo_req_cmd(cl);
+		}
+		else
+			spin_unlock(&ssi->lock);
+		return;
+	}
+	ssip_set_rxstate(ssi, RECV_READY);
+	spin_unlock(&ssi->lock);
+
+	msg = ssip_claim_cmd(ssi);
+	ssip_set_cmd(msg, SSIP_READY_CMD);
+	msg->complete = ssip_release_cmd;
+	dev_dbg(&cl->device, "Send READY\n");
+	hsi_async_write(cl, msg);
+}
+
+static void ssip_stop_rx(struct hsi_client *cl)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+
+	dev_dbg(&cl->device, "RX stop M(%d)\n", ssi->main_state);
+	spin_lock(&ssi->lock);
+	if (likely(ssi->main_state == ACTIVE))
+		ssip_set_rxstate(ssi, RECV_IDLE);
+	spin_unlock(&ssi->lock);
+}
+
+static void ssip_free_strans(struct hsi_msg *msg)
+{
+	ssip_free_data(msg->context);
+	ssip_release_cmd(msg);
+}
+
+static void ssip_strans_complete(struct hsi_msg *msg)
+{
+	struct hsi_client *cl = msg->cl;
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	struct hsi_msg *data;
+
+	data = msg->context;
+	ssip_release_cmd(msg);
+	spin_lock(&ssi->lock);
+	ssip_set_txstate(ssi, SENDING);
+	spin_unlock(&ssi->lock);
+	hsi_async_write(cl, data);
+}
+
+static int ssip_xmit(struct hsi_client *cl)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	struct hsi_msg *msg, *dmsg;
+	struct sk_buff *skb;
+
+	spin_lock_bh(&ssi->lock);
+	if (list_empty(&ssi->txqueue)) {
+		spin_unlock_bh(&ssi->lock);
+		return 0;
+	}
+	dmsg = list_first_entry(&ssi->txqueue, struct hsi_msg, link);
+	list_del(&dmsg->link);
+	ssi->txqueue_len--;
+	spin_unlock_bh(&ssi->lock);
+
+	msg = ssip_claim_cmd(ssi);
+	skb = dmsg->context;
+	msg->context = dmsg;
+	msg->complete = ssip_strans_complete;
+	msg->destructor = ssip_free_strans;
+
+	spin_lock_bh(&ssi->lock);
+	ssip_set_cmd(msg, SSIP_START_TRANS_CMD(SSIP_BYTES_TO_FRAMES(skb->len),
+								ssi->txid));
+	ssi->txid++;
+	ssip_set_txstate(ssi, SENDING);
+	spin_unlock_bh(&ssi->lock);
+
+	dev_dbg(&cl->device, "Send STRANS (%d frames)\n",
+						SSIP_BYTES_TO_FRAMES(skb->len));
+
+	return hsi_async_write(cl, msg);
+}
+
+/* In soft IRQ context */
+static void ssip_pn_rx(struct sk_buff *skb)
+{
+	struct net_device *dev = skb->dev;
+
+	if (unlikely(!netif_running(dev))) {
+		dev_dbg(&dev->dev, "Drop RX packet\n");
+		dev->stats.rx_dropped++;
+		dev_kfree_skb(skb);
+		return;
+	}
+	if (unlikely(!pskb_may_pull(skb, SSIP_MIN_PN_HDR))) {
+		dev_dbg(&dev->dev, "Error drop RX packet\n");
+		dev->stats.rx_errors++;
+		dev->stats.rx_length_errors++;
+		dev_kfree_skb(skb);
+		return;
+	}
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += skb->len;
+#ifdef __LITTLE_ENDIAN
+	((u16 *)skb->data)[2] = swab16(((u16 *)skb->data)[2]);
+	dev_dbg(&dev->dev, "RX length fixed (%04x -> %u)\n",
+			((u16 *)skb->data)[2], ntohs(((u16 *)skb->data)[2]));
+#endif
+	skb->protocol = htons(ETH_P_PHONET);
+	skb_reset_mac_header(skb);
+	__skb_pull(skb, 1);
+	netif_rx(skb);
+}
+
+static void ssip_rx_data_complete(struct hsi_msg *msg)
+{
+	struct hsi_client *cl = msg->cl;
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	struct sk_buff *skb;
+
+	if (msg->status == HSI_STATUS_ERROR) {
+		dev_err(&cl->device, "RX data error\n");
+		ssip_free_data(msg);
+		ssip_error(cl);
+		return;
+	}
+	del_timer(&ssi->rx_wd); /* FIXME: Revisit */
+	skb = msg->context;
+	ssip_pn_rx(skb);
+	hsi_free_msg(msg);
+}
+
+static void ssip_rx_bootinforeq(struct hsi_client *cl, u32 cmd)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	struct hsi_msg *msg;
+
+	/* Workaroud: Ignore CMT Loader message leftover */
+	if (cmd == SSIP_CMT_LOADER_SYNC)
+		return;
+
+	switch (ssi->main_state) {
+	case ACTIVE:
+		dev_err(&cl->device, "Boot info req on active state\n");
+		ssip_error(cl);
+		/* Fall through */
+	case INIT:
+		spin_lock(&ssi->lock);
+		ssi->main_state = HANDSHAKE;
+		if (!ssi->waketest) {
+			ssi->waketest = 1;
+			ssi_waketest(cl, 1); /* FIXME: To be removed */
+		}
+		/* Start boot handshake watchdog */
+		mod_timer(&ssi->tx_wd, jiffies + msecs_to_jiffies(SSIP_WDTOUT));
+		spin_unlock(&ssi->lock);
+		dev_dbg(&cl->device, "Send BOOTINFO_RESP\n");
+		if (SSIP_DATA_VERSION(cmd) != SSIP_LOCAL_VERID)
+			dev_warn(&cl->device, "boot info req verid mismatch\n");
+		msg = ssip_claim_cmd(ssi);
+		ssip_set_cmd(msg, SSIP_BOOTINFO_RESP_CMD(SSIP_LOCAL_VERID));
+		msg->complete = ssip_release_cmd;
+		hsi_async_write(cl, msg);
+		break;
+	case HANDSHAKE:
+		/* Ignore */
+		break;
+	default:
+		dev_dbg(&cl->device, "Wrong state M(%d)\n", ssi->main_state);
+		break;
+	}
+}
+
+static void ssip_rx_bootinforesp(struct hsi_client *cl, u32 cmd)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+
+	if (SSIP_DATA_VERSION(cmd) != SSIP_LOCAL_VERID)
+		dev_warn(&cl->device, "boot info resp verid mismatch\n");
+
+	spin_lock(&ssi->lock);
+	if (ssi->main_state != ACTIVE)
+		/* Use tx_wd as a boot watchdog in non ACTIVE state */
+		mod_timer(&ssi->tx_wd, jiffies + msecs_to_jiffies(SSIP_WDTOUT));
+	else
+		dev_dbg(&cl->device, "boot info resp ignored M(%d)\n",
+							ssi->main_state);
+	spin_unlock(&ssi->lock);
+}
+
+static void ssip_rx_waketest(struct hsi_client *cl, u32 cmd)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	unsigned int wkres = SSIP_PAYLOAD(cmd);
+
+	spin_lock(&ssi->lock);
+	if (ssi->main_state != HANDSHAKE) {
+		dev_dbg(&cl->device, "wake lines test ignored M(%d)\n",
+							ssi->main_state);
+		spin_unlock(&ssi->lock);
+		return;
+	}
+	if (ssi->waketest) {
+		ssi->waketest = 0;
+		ssi_waketest(cl, 0); /* FIXME: To be removed */
+	}
+	ssi->main_state = ACTIVE;
+	del_timer(&ssi->tx_wd); /* Stop boot handshake timer */
+	spin_unlock(&ssi->lock);
+
+	dev_notice(&cl->device, "WAKELINES TEST %s\n",
+				wkres & SSIP_WAKETEST_FAILED ? "FAILED" : "OK");
+	if (wkres & SSIP_WAKETEST_FAILED) {
+		ssip_error(cl);
+		return;
+	}
+	dev_dbg(&cl->device, "CMT is ONLINE\n");
+	netif_wake_queue(ssi->netdev);
+	netif_carrier_on(ssi->netdev);
+}
+
+static void ssip_rx_ready(struct hsi_client *cl)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+
+	spin_lock(&ssi->lock);
+	if (unlikely(ssi->main_state != ACTIVE)) {
+		dev_dbg(&cl->device, "READY on wrong state: S(%d) M(%d)\n",
+					ssi->send_state, ssi->main_state);
+		spin_unlock(&ssi->lock);
+		return;
+	}
+	if (ssi->send_state != WAIT4READY) {
+		dev_dbg(&cl->device, "Ignore spurious READY command\n");
+		spin_unlock(&ssi->lock);
+		return;
+	}
+	ssip_set_txstate(ssi, SEND_READY);
+	spin_unlock(&ssi->lock);
+	ssip_xmit(cl);
+}
+
+static void ssip_rx_strans(struct hsi_client *cl, u32 cmd)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	struct sk_buff *skb;
+	struct hsi_msg *msg;
+	int len = SSIP_PDU_LENGTH(cmd);
+
+	dev_dbg(&cl->device, "RX strans: %d frames\n", len);
+	spin_lock(&ssi->lock);
+	if (unlikely(ssi->main_state != ACTIVE)) {
+		dev_err(&cl->device, "START TRANS wrong state: S(%d) M(%d)\n",
+					ssi->send_state, ssi->main_state);
+		spin_unlock(&ssi->lock);
+		return;
+	}
+	ssip_set_rxstate(ssi, RECEIVING);
+	if (unlikely(SSIP_MSG_ID(cmd) != ssi->rxid)) {
+		dev_err(&cl->device, "START TRANS id %d expeceted %d\n",
+					SSIP_MSG_ID(cmd), ssi->rxid);
+		spin_unlock(&ssi->lock);
+		goto out1;
+	}
+	ssi->rxid++;
+	spin_unlock(&ssi->lock);
+	skb = netdev_alloc_skb(ssi->netdev, len * 4);
+	if (unlikely(!skb)) {
+		dev_err(&cl->device, "No memory for rx skb\n");
+		goto out1;
+	}
+	skb->dev = ssi->netdev;
+	skb_put(skb, len * 4);
+	msg = ssip_alloc_data(ssi, skb, GFP_ATOMIC);
+	if (unlikely(!msg)) {
+		dev_err(&cl->device, "No memory for RX data msg\n");
+		goto out2;
+	}
+	msg->complete = ssip_rx_data_complete;
+	hsi_async_read(cl, msg);
+
+	return;
+out2:
+	dev_kfree_skb(skb);
+out1:
+	ssip_error(cl);
+}
+
+static void ssip_rxcmd_complete(struct hsi_msg *msg)
+{
+	struct hsi_client *cl = msg->cl;
+	u32 cmd = ssip_get_cmd(msg);
+	unsigned int cmdid = SSIP_COMMAND(cmd);
+
+	if (msg->status == HSI_STATUS_ERROR) {
+		dev_err(&cl->device, "RX error detected\n");
+		ssip_release_cmd(msg);
+		ssip_error(cl);
+		return;
+	}
+	hsi_async_read(cl, msg);
+	dev_dbg(&cl->device, "RX cmd: 0x%08x\n", cmd);
+	switch (cmdid) {
+	case SSIP_SW_BREAK:
+		/* Ignored */
+		break;
+	case SSIP_BOOTINFO_REQ:
+		ssip_rx_bootinforeq(cl, cmd);
+		break;
+	case SSIP_BOOTINFO_RESP:
+		ssip_rx_bootinforesp(cl, cmd);
+		break;
+	case SSIP_WAKETEST_RESULT:
+		ssip_rx_waketest(cl, cmd);
+		break;
+	case SSIP_START_TRANS:
+		ssip_rx_strans(cl, cmd);
+		break;
+	case SSIP_READY:
+		ssip_rx_ready(cl);
+		break;
+	default:
+		dev_warn(&cl->device, "command 0x%08x not supported\n", cmd);
+		break;
+	}
+}
+
+static void ssip_swbreak_complete(struct hsi_msg *msg)
+{
+	struct hsi_client *cl = msg->cl;
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+
+	ssip_release_cmd(msg);
+	spin_lock(&ssi->lock);
+	if (list_empty(&ssi->txqueue)) {
+		if (atomic_read(&ssi->tx_usecnt)) {
+			ssip_set_txstate(ssi, SEND_READY);
+		} else {
+			ssip_set_txstate(ssi, SEND_IDLE);
+			hsi_stop_tx(cl);
+		}
+		spin_unlock(&ssi->lock);
+	} else {
+		spin_unlock(&ssi->lock);
+		ssip_xmit(cl);
+	}
+	netif_wake_queue(ssi->netdev);
+}
+
+static void ssip_tx_data_complete(struct hsi_msg *msg)
+{
+	struct hsi_client *cl = msg->cl;
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	struct hsi_msg *cmsg;
+
+	if (msg->status == HSI_STATUS_ERROR) {
+		dev_err(&cl->device, "TX data error\n");
+		ssip_error(cl);
+		goto out;
+	}
+	spin_lock(&ssi->lock);
+	if (list_empty(&ssi->txqueue)) {
+		ssip_set_txstate(ssi, SENDING_SWBREAK);
+		spin_unlock(&ssi->lock);
+		cmsg = ssip_claim_cmd(ssi);
+		ssip_set_cmd(cmsg, SSIP_SWBREAK_CMD);
+		cmsg->complete = ssip_swbreak_complete;
+		dev_dbg(&cl->device, "Send SWBREAK\n");
+		hsi_async_write(cl, cmsg);
+	} else {
+		spin_unlock(&ssi->lock);
+		ssip_xmit(cl);
+	}
+out:
+	ssip_free_data(msg);
+}
+
+void ssip_port_event(struct hsi_client *cl, unsigned long event)
+{
+	switch (event) {
+	case HSI_EVENT_START_RX:
+		ssip_start_rx(cl);
+		break;
+	case HSI_EVENT_STOP_RX:
+		ssip_stop_rx(cl);
+		break;
+	default:
+		return;
+	}
+}
+
+static int ssip_pn_open(struct net_device *dev)
+{
+	struct hsi_client *cl = to_hsi_client(dev->dev.parent);
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	int err;
+
+	err = hsi_claim_port(cl, 1);
+	if (err < 0) {
+		dev_err(&cl->device, "SSI port already claimed\n");
+		return err;
+	}
+	err = hsi_register_port_event(cl, ssip_port_event);
+	if (err < 0) {
+		dev_err(&cl->device, "Register HSI port event failed (%d)\n", err);
+		return err;
+	}
+	dev_dbg(&cl->device, "Configuring SSI port\n");
+	hsi_setup(cl);
+	spin_lock_bh(&ssi->lock);
+	if (!ssi->waketest) {
+		ssi->waketest = 1;
+		ssi_waketest(cl, 1); /* FIXME: To be removed */
+	}
+	ssi->main_state = INIT;
+	spin_unlock_bh(&ssi->lock);
+
+	return 0;
+}
+
+static int ssip_pn_stop(struct net_device *dev)
+{
+	struct hsi_client *cl = to_hsi_client(dev->dev.parent);
+
+	ssip_reset(cl);
+	hsi_unregister_port_event(cl);
+	hsi_release_port(cl);
+
+	return 0;
+}
+
+static int ssip_pn_set_mtu(struct net_device *dev, int new_mtu)
+{
+	if (new_mtu > SSIP_MAX_MTU || new_mtu < PHONET_MIN_MTU)
+		return -EINVAL;
+	dev->mtu = new_mtu;
+
+	return 0;
+}
+
+static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct hsi_client *cl = to_hsi_client(dev->dev.parent);
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+	struct hsi_msg *msg;
+
+	if ((skb->protocol != htons(ETH_P_PHONET)) ||
+					(skb->len < SSIP_MIN_PN_HDR))
+		goto drop;
+	/* Pad to 32-bits - FIXME: Revisit*/
+	if ((skb->len & 3) && skb_pad(skb, 4 - (skb->len & 3)))
+		goto drop;
+
+	/*
+	 * Modem sends Phonet messages over SSI with its own endianess...
+	 * Assume that modem has the same endianess as we do.
+	 */
+	if (skb_cow_head(skb, 0))
+		goto drop;
+#ifdef __LITTLE_ENDIAN
+	((u16 *)skb->data)[2] = swab16(((u16 *)skb->data)[2]);
+#endif
+	msg = ssip_alloc_data(ssi, skb, GFP_ATOMIC);
+	if (!msg) {
+		dev_dbg(&cl->device, "Dropping tx data: No memory\n");
+		goto drop;
+	}
+	msg->complete = ssip_tx_data_complete;
+
+	spin_lock_bh(&ssi->lock);
+	if (unlikely(ssi->main_state != ACTIVE)) {
+		spin_unlock_bh(&ssi->lock);
+		dev_dbg(&cl->device, "Dropping tx data: CMT is OFFLINE\n");
+		goto drop2;
+	}
+	list_add_tail(&msg->link, &ssi->txqueue);
+	ssi->txqueue_len++;
+	if (dev->tx_queue_len < ssi->txqueue_len) {
+		dev_info(&cl->device, "TX queue full %d\n", ssi->txqueue_len);
+		netif_stop_queue(dev);
+	}
+	if (ssi->send_state == SEND_IDLE) {
+		ssip_set_txstate(ssi, WAIT4READY);
+		spin_unlock_bh(&ssi->lock);
+		dev_dbg(&cl->device, "Start TX qlen %d\n", ssi->txqueue_len);
+		hsi_start_tx(cl);
+	} else if (ssi->send_state == SEND_READY) {
+		/* Needed for cmt-speech workaround */
+		dev_dbg(&cl->device, "Start TX on SEND READY qlen %d\n",
+							ssi->txqueue_len);
+		spin_unlock_bh(&ssi->lock);
+		ssip_xmit(cl);
+	} else {
+		spin_unlock_bh(&ssi->lock);
+	}
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
+
+	return 0;
+drop2:
+	hsi_free_msg(msg);
+drop:
+	dev->stats.tx_dropped++;
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+/* CMT reset event handler */
+void ssip_reset_event(struct hsi_client *master)
+{
+	struct ssi_protocol *ssi = hsi_client_drvdata(master);
+	dev_err(&ssi->cl->device, "CMT reset detected!\n");
+	ssip_error(ssi->cl);
+}
+
+static const struct net_device_ops ssip_pn_ops = {
+	.ndo_open	= ssip_pn_open,
+	.ndo_stop	= ssip_pn_stop,
+	.ndo_start_xmit	= ssip_pn_xmit,
+	.ndo_change_mtu	= ssip_pn_set_mtu,
+};
+
+static void ssip_pn_setup(struct net_device *dev)
+{
+	dev->features		= 0;
+	dev->netdev_ops		= &ssip_pn_ops;
+	dev->type		= ARPHRD_PHONET;
+	dev->flags		= IFF_POINTOPOINT | IFF_NOARP;
+	dev->mtu		= SSIP_DEFAULT_MTU;
+	dev->hard_header_len	= 1;
+	dev->dev_addr[0]	= PN_MEDIA_SOS;
+	dev->addr_len		= 1;
+	dev->tx_queue_len	= SSIP_TXQUEUE_LEN;
+
+	dev->destructor		= free_netdev;
+	dev->header_ops		= &phonet_header_ops;
+}
+
+static int ssi_protocol_probe(struct device *dev)
+{
+	static const char ifname[] = "phonet%d";
+	struct hsi_client *cl = to_hsi_client(dev);
+	struct ssi_protocol *ssi;
+	int err;
+
+	ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
+	if (!ssi) {
+		dev_err(dev, "No memory for ssi protocol\n");
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&ssi->lock);
+	init_timer_deferrable(&ssi->rx_wd);
+	init_timer_deferrable(&ssi->tx_wd);
+	init_timer(&ssi->keep_alive);
+	ssi->rx_wd.data = (unsigned long)cl;
+	ssi->rx_wd.function = ssip_wd;
+	ssi->tx_wd.data = (unsigned long)cl;
+	ssi->tx_wd.function = ssip_wd;
+	ssi->keep_alive.data = (unsigned long)cl;
+	ssi->keep_alive.function = ssip_keep_alive;
+	INIT_LIST_HEAD(&ssi->txqueue);
+	INIT_LIST_HEAD(&ssi->cmdqueue);
+	atomic_set(&ssi->tx_usecnt, 0);
+	hsi_client_set_drvdata(cl, ssi);
+	ssi->cl = cl;
+
+	ssi->channel_id_cmd = hsi_get_channel_id_by_name(cl, "mcsaab-control");
+	if (ssi->channel_id_cmd < 0) {
+		err = ssi->channel_id_cmd;
+		dev_err(dev, "Could not get cmd channel (%d)\n", err);
+		goto out;
+	}
+
+	ssi->channel_id_data = hsi_get_channel_id_by_name(cl, "mcsaab-data");
+	if (ssi->channel_id_data < 0) {
+		err = ssi->channel_id_data;
+		dev_err(dev, "Could not get data channel (%d)\n", err);
+		goto out;
+	}
+
+	err = ssip_alloc_cmds(ssi);
+	if (err < 0) {
+		dev_err(dev, "No memory for commands\n");
+		goto out;
+	}
+
+	ssi->netdev = alloc_netdev(0, ifname, ssip_pn_setup);
+	if (!ssi->netdev) {
+		dev_err(dev, "No memory for netdev\n");
+		err = -ENOMEM;
+		goto out1;
+	}
+
+	SET_NETDEV_DEV(ssi->netdev, dev);
+	netif_carrier_off(ssi->netdev);
+	err = register_netdev(ssi->netdev);
+	if (err < 0) {
+		dev_err(dev, "Register netdev failed (%d)\n", err);
+		goto out2;
+	}
+
+	list_add(&ssi->link, &ssip_list);
+
+	dev_dbg(dev, "channel configuration: cmd=%d, data=%d\n",
+		ssi->channel_id_cmd, ssi->channel_id_data);
+
+	return 0;
+out2:
+	free_netdev(ssi->netdev);
+out1:
+	ssip_free_cmds(ssi);
+out:
+	kfree(ssi);
+
+	return err;
+}
+
+static int ssi_protocol_remove(struct device *dev)
+{
+	struct hsi_client *cl = to_hsi_client(dev);
+	struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+
+	list_del(&ssi->link);
+	unregister_netdev(ssi->netdev);
+	ssip_free_cmds(ssi);
+	hsi_client_set_drvdata(cl, NULL);
+	kfree(ssi);
+
+	return 0;
+}
+
+static struct hsi_client_driver ssip_driver = {
+	.driver = {
+		.name	= "ssi-protocol",
+		.owner	= THIS_MODULE,
+		.probe	= ssi_protocol_probe,
+		.remove	= ssi_protocol_remove,
+	},
+};
+
+static int __init ssip_init(void)
+{
+	pr_info("SSI protocol aka McSAAB added\n");
+
+	return hsi_register_client_driver(&ssip_driver);
+}
+module_init(ssip_init);
+
+static void __exit ssip_exit(void)
+{
+	hsi_unregister_client_driver(&ssip_driver);
+	pr_info("SSI protocol driver removed\n");
+}
+module_exit(ssip_exit);
+
+MODULE_ALIAS("hsi:ssi_protocol");
+MODULE_AUTHOR("Carlos Chinea <carlos.chinea@nokia.com>,"
+		"Remi Denis-Courmont <remi.denis-courmont@nokia.com>");
+MODULE_DESCRIPTION("SSI protocol improved aka McSAAB");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/hsi/ssi_protocol.h b/include/linux/hsi/ssi_protocol.h
new file mode 100644
index 0000000..1433651
--- /dev/null
+++ b/include/linux/hsi/ssi_protocol.h
@@ -0,0 +1,42 @@
+/*
+ * ssip_slave.h
+ *
+ * SSIP slave support header file
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Carlos Chinea <carlos.chinea@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __LINUX_SSIP_SLAVE_H__
+#define __LINUX_SSIP_SLAVE_H__
+
+#include <linux/hsi/hsi.h>
+
+static inline void ssip_slave_put_master(struct hsi_client *master)
+{
+}
+
+struct hsi_client *ssip_slave_get_master(struct hsi_client *slave);
+int ssip_slave_start_tx(struct hsi_client *master);
+int ssip_slave_stop_tx(struct hsi_client *master);
+void ssip_reset_event(struct hsi_client *master);
+
+int ssip_slave_running(struct hsi_client *master);
+
+#endif /* __LINUX_SSIP_SLAVE_H__ */
+
-- 
1.9.0


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

* [PATCHv3 11/14] HSI: Introduce Nokia N900 modem driver
@ 2014-03-29  0:31   ` Sebastian Reichel
  0 siblings, 0 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

The Nokia N900's modem is connected via Synchronous Serial Interface (SSI),
which is a legacy version of MIPI's High-speed Synchronous Serial Interface
(HSI).

The handles the GPIOs for enabling and resetting the modem and instanciates
ssi-protocol for data exchange. It does not yet support exchanging voice data
with the modem.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 .../devicetree/bindings/hsi/nokia-modem.txt        |  58 +++++
 drivers/hsi/clients/Kconfig                        |   9 +
 drivers/hsi/clients/Makefile                       |   1 +
 drivers/hsi/clients/nokia-modem.c                  | 272 +++++++++++++++++++++
 4 files changed, 340 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hsi/nokia-modem.txt
 create mode 100644 drivers/hsi/clients/nokia-modem.c

diff --git a/Documentation/devicetree/bindings/hsi/nokia-modem.txt b/Documentation/devicetree/bindings/hsi/nokia-modem.txt
new file mode 100644
index 0000000..a8b8b6b
--- /dev/null
+++ b/Documentation/devicetree/bindings/hsi/nokia-modem.txt
@@ -0,0 +1,58 @@
+Nokia modem client bindings
+
+The Nokia modem HSI client follows the common HSI
+client binding and inherits all required properties.
+The following additional properties are needed by
+the Nokia modem HSI client:
+
+Required properties:
+- compatible:		Should be one of
+      "nokia,n900-modem"
+- reg-names:		Should contain the following strings
+      "mcsaab-control"
+      "speech-control"
+      "speech-data"
+      "mcsaab-data"
+- gpios:		Should provide a GPIO handler for each GPIO listed in
+                        gpio-names
+- gpio-names:		Should contain the following strings
+      "cmt_apeslpx"
+      "cmt_rst_rq"
+      "cmt_en"
+      "cmt_rst"
+      "cmt_bsi"
+- interrupts:		Should be IRQ handle for modem's reset indication
+
+Example:
+
+&ssi_port {
+	modem: hsi-client {
+		compatible = "nokia,n900-modem";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&modem_pins>;
+
+		reg = <0>, <1>, <2>, <3>;
+		reg-names = "mcsaab-control",
+			    "speech-control",
+			    "speech-data",
+			    "mcsaab-data";
+		hsi-speed-kbps = <55000>;
+		hsi-mode = "frame";
+		hsi-flow = "synchronized";
+		hsi-arb-mode = "round-robin";
+
+		interrupts-extended = <&gpio3 8 IRQ_TYPE_EDGE_FALLING>; /* 72 */
+
+		gpios = <&gpio3  6 GPIO_ACTIVE_HIGH>, /* 70 */
+			<&gpio3  9 GPIO_ACTIVE_HIGH>, /* 73 */
+			<&gpio3 10 GPIO_ACTIVE_HIGH>, /* 74 */
+			<&gpio3 11 GPIO_ACTIVE_HIGH>, /* 75 */
+			<&gpio5 29 GPIO_ACTIVE_HIGH>; /* 157 */
+		gpio-names = "cmt_apeslpx",
+			     "cmt_rst_rq",
+			     "cmt_en",
+			     "cmt_rst",
+			     "cmt_bsi";
+	};
+};
diff --git a/drivers/hsi/clients/Kconfig b/drivers/hsi/clients/Kconfig
index 0c70861..6ce1ea2 100644
--- a/drivers/hsi/clients/Kconfig
+++ b/drivers/hsi/clients/Kconfig
@@ -4,6 +4,15 @@
 
 comment "HSI clients"
 
+config NOKIA_MODEM
+	tristate "Nokia Modem"
+	depends on SSI_PROTOCOL
+	help
+	Say Y here if you want to add support for the modem on Nokia
+	N900 (Nokia RX-51) hardware.
+
+	If unsure, say N.
+
 config SSI_PROTOCOL
 	tristate "SSI protocol"
 	depends on HSI && OMAP_SSI && PHONET
diff --git a/drivers/hsi/clients/Makefile b/drivers/hsi/clients/Makefile
index ccbf768..4d5bc0e 100644
--- a/drivers/hsi/clients/Makefile
+++ b/drivers/hsi/clients/Makefile
@@ -2,5 +2,6 @@
 # Makefile for HSI clients
 #
 
+obj-$(CONFIG_NOKIA_MODEM)	+= nokia-modem.o
 obj-$(CONFIG_SSI_PROTOCOL)	+= ssi_protocol.o
 obj-$(CONFIG_HSI_CHAR)		+= hsi_char.o
diff --git a/drivers/hsi/clients/nokia-modem.c b/drivers/hsi/clients/nokia-modem.c
new file mode 100644
index 0000000..f12ec76
--- /dev/null
+++ b/drivers/hsi/clients/nokia-modem.c
@@ -0,0 +1,272 @@
+/*
+ * nokia-modem.c
+ *
+ * HSI client driver for Nokia N900 modem.
+ *
+ * Copyright (C) 2014 Sebastian Reichel <sre@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/hsi/hsi.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/hsi/ssi_protocol.h>
+
+struct nokia_modem_gpio {
+	struct gpio_desc	*gpio;
+	const char		*name;
+};
+
+struct nokia_modem_device {
+	struct tasklet_struct	nokia_modem_rst_ind_tasklet;
+	int			nokia_modem_rst_ind_irq;
+	struct device		*device;
+	struct nokia_modem_gpio	*gpios;
+	int			gpio_amount;
+	struct hsi_client	*ssi_protocol;
+};
+
+static void do_nokia_modem_rst_ind_tasklet(unsigned long data)
+{
+	struct nokia_modem_device *modem = (struct nokia_modem_device *)data;
+
+	if (!modem)
+		return;
+
+	dev_info(modem->device, "*** CMT rst line change detected ***\n");
+
+	if (modem->ssi_protocol)
+		ssip_reset_event(modem->ssi_protocol);
+}
+
+static irqreturn_t nokia_modem_rst_ind_isr(int irq, void *data)
+{
+	struct nokia_modem_device *modem = (struct nokia_modem_device *)data;
+
+	tasklet_schedule(&modem->nokia_modem_rst_ind_tasklet);
+
+	return IRQ_HANDLED;
+}
+
+static void nokia_modem_gpio_unexport(struct device *dev)
+{
+	struct nokia_modem_device *modem = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < modem->gpio_amount; i++) {
+		sysfs_remove_link(&dev->kobj, modem->gpios[i].name);
+		gpiod_unexport(modem->gpios[i].gpio);
+	}
+}
+
+static int nokia_modem_gpio_probe(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct nokia_modem_device *modem = dev_get_drvdata(dev);
+	int gpio_count, gpio_name_count, i, err;
+
+	gpio_count = of_gpio_count(np);
+	gpio_name_count = of_property_count_strings(np, "gpio-names");
+
+	if(gpio_count != gpio_name_count) {
+		dev_err(dev, "number of gpios does not equal number of gpio names\n");
+		return -EINVAL;
+	}
+
+	modem->gpios = devm_kzalloc(dev, gpio_count*sizeof(struct nokia_modem_gpio),
+								GFP_KERNEL);
+	if (modem->gpios == NULL) {
+		dev_err(dev, "Could not allocate memory for gpios\n");
+		return -ENOMEM;
+	}
+
+	modem->gpio_amount = gpio_count;
+
+	for (i = 0; i < gpio_count; i++) {
+		modem->gpios[i].gpio = devm_gpiod_get_index(dev, NULL, i);
+		if (IS_ERR(modem->gpios[i].gpio)) {
+			dev_err(dev, "Could not get gpio %d\n", i);
+			return PTR_ERR(modem->gpios[i].gpio);
+		}
+
+		err = of_property_read_string_index(np, "gpio-names", i,
+							&(modem->gpios[i].name));
+		if (err) {
+			dev_err(dev, "Could not get gpio name %d\n", i);
+			return err;
+		}
+
+		err = gpiod_direction_output(modem->gpios[i].gpio, 0);
+		if (err)
+			return err;
+
+		err = gpiod_export(modem->gpios[i].gpio, 0);
+		if (err)
+			return err;
+
+		err = gpiod_export_link(dev, modem->gpios[i].name,
+							modem->gpios[i].gpio);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int nokia_modem_probe(struct device *dev)
+{
+	struct device_node *np;
+	struct nokia_modem_device *modem;
+	struct hsi_client *cl = to_hsi_client(dev);
+	struct hsi_port *port = hsi_get_port(cl);
+	int irq, pflags, err;
+	struct hsi_board_info ssip;
+
+	np = dev->of_node;
+	if (!np) {
+		dev_err(dev, "device tree node not found\n");
+		return -ENXIO;
+	}
+
+	modem = devm_kzalloc(dev, sizeof(*modem), GFP_KERNEL);
+	if (!modem) {
+		dev_err(dev, "Could not allocate memory for nokia_modem_device\n");
+		return -ENOMEM;
+	}
+	dev_set_drvdata(dev, modem);
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (irq < 0) {
+		dev_err(dev, "Invalid nokia_modem_rst_ind interrupt: %d\n", irq);
+		return irq;
+	}
+	modem->nokia_modem_rst_ind_irq = irq;
+	pflags = irq_get_trigger_type(irq);
+
+	tasklet_init(&modem->nokia_modem_rst_ind_tasklet,
+			do_nokia_modem_rst_ind_tasklet, (unsigned long)modem);
+	err = devm_request_irq(dev, irq, nokia_modem_rst_ind_isr,
+				IRQF_DISABLED | pflags, "modem_rst_ind", modem);
+	if (err < 0) {
+		dev_err(dev, "Request modem_rst_ind irq(%d) failed (flags %d)\n",
+								irq, pflags);
+		return err;
+	}
+	enable_irq_wake(irq);
+
+	err = nokia_modem_gpio_probe(dev);
+	if (err < 0) {
+		dev_err(dev, "Could not probe GPIOs\n");
+		goto error1;
+	}
+
+	ssip.name = "ssi-protocol";
+	ssip.tx_cfg = cl->tx_cfg;
+	ssip.rx_cfg = cl->rx_cfg;
+	ssip.platform_data = NULL;
+	ssip.archdata = NULL;
+
+	modem->ssi_protocol = hsi_new_client(port, &ssip);
+	if (modem->ssi_protocol == NULL) {
+		dev_err(dev, "Could not register ssi-protocol device\n");
+		goto error2;
+	}
+
+	err = device_attach(&modem->ssi_protocol->device);
+	if (err == 0) {
+		dev_err(dev, "Missing ssi-protocol driver\n");
+		err = -EPROBE_DEFER;
+		goto error3;
+	} else if (err < 0) {
+		dev_err(dev, "Could not load ssi-protocol driver (%d)\n", err);
+		goto error3;
+	}
+
+	/* TODO: register cmt-speech hsi client */
+
+	dev_info(dev, "Registered Nokia HSI modem\n");
+
+	return 0;
+
+error3:
+	hsi_remove_client(&modem->ssi_protocol->device, NULL);
+error2:
+	nokia_modem_gpio_unexport(dev);
+error1:
+	disable_irq_wake(modem->nokia_modem_rst_ind_irq);
+	tasklet_kill(&modem->nokia_modem_rst_ind_tasklet);
+
+	return err;
+}
+
+static int nokia_modem_remove(struct device *dev)
+{
+	struct nokia_modem_device *modem = dev_get_drvdata(dev);
+
+	if (!modem)
+		return 0;
+
+	if (modem->ssi_protocol) {
+		hsi_remove_client(&modem->ssi_protocol->device, NULL);
+		modem->ssi_protocol = NULL;
+	}
+
+	nokia_modem_gpio_unexport(dev);
+	dev_set_drvdata(dev, NULL);
+	disable_irq_wake(modem->nokia_modem_rst_ind_irq);
+	tasklet_kill(&modem->nokia_modem_rst_ind_tasklet);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id nokia_modem_of_match[] = {
+       { .compatible = "nokia,n900-modem", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, nokia_modem_of_match);
+#endif
+
+static struct hsi_client_driver nokia_modem_driver = {
+	.driver = {
+		.name	= "nokia-modem",
+		.owner	= THIS_MODULE,
+		.probe	= nokia_modem_probe,
+		.remove	= nokia_modem_remove,
+		.of_match_table = of_match_ptr(nokia_modem_of_match),
+	},
+};
+
+static int __init nokia_modem_init(void)
+{
+	return hsi_register_client_driver(&nokia_modem_driver);
+}
+module_init(nokia_modem_init);
+
+static void __exit nokia_modem_exit(void)
+{
+	hsi_unregister_client_driver(&nokia_modem_driver);
+}
+module_exit(nokia_modem_exit);
+
+MODULE_ALIAS("hsi:nokia-modem");
+MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
+MODULE_DESCRIPTION("HSI driver module for Nokia N900 Modem");
+MODULE_LICENSE("GPL");
-- 
1.9.0


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

* [PATCHv3 11/14] HSI: Introduce Nokia N900 modem driver
@ 2014-03-29  0:31   ` Sebastian Reichel
  0 siblings, 0 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

The Nokia N900's modem is connected via Synchronous Serial Interface (SSI),
which is a legacy version of MIPI's High-speed Synchronous Serial Interface
(HSI).

The handles the GPIOs for enabling and resetting the modem and instanciates
ssi-protocol for data exchange. It does not yet support exchanging voice data
with the modem.

Signed-off-by: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
 .../devicetree/bindings/hsi/nokia-modem.txt        |  58 +++++
 drivers/hsi/clients/Kconfig                        |   9 +
 drivers/hsi/clients/Makefile                       |   1 +
 drivers/hsi/clients/nokia-modem.c                  | 272 +++++++++++++++++++++
 4 files changed, 340 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hsi/nokia-modem.txt
 create mode 100644 drivers/hsi/clients/nokia-modem.c

diff --git a/Documentation/devicetree/bindings/hsi/nokia-modem.txt b/Documentation/devicetree/bindings/hsi/nokia-modem.txt
new file mode 100644
index 0000000..a8b8b6b
--- /dev/null
+++ b/Documentation/devicetree/bindings/hsi/nokia-modem.txt
@@ -0,0 +1,58 @@
+Nokia modem client bindings
+
+The Nokia modem HSI client follows the common HSI
+client binding and inherits all required properties.
+The following additional properties are needed by
+the Nokia modem HSI client:
+
+Required properties:
+- compatible:		Should be one of
+      "nokia,n900-modem"
+- reg-names:		Should contain the following strings
+      "mcsaab-control"
+      "speech-control"
+      "speech-data"
+      "mcsaab-data"
+- gpios:		Should provide a GPIO handler for each GPIO listed in
+                        gpio-names
+- gpio-names:		Should contain the following strings
+      "cmt_apeslpx"
+      "cmt_rst_rq"
+      "cmt_en"
+      "cmt_rst"
+      "cmt_bsi"
+- interrupts:		Should be IRQ handle for modem's reset indication
+
+Example:
+
+&ssi_port {
+	modem: hsi-client {
+		compatible = "nokia,n900-modem";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&modem_pins>;
+
+		reg = <0>, <1>, <2>, <3>;
+		reg-names = "mcsaab-control",
+			    "speech-control",
+			    "speech-data",
+			    "mcsaab-data";
+		hsi-speed-kbps = <55000>;
+		hsi-mode = "frame";
+		hsi-flow = "synchronized";
+		hsi-arb-mode = "round-robin";
+
+		interrupts-extended = <&gpio3 8 IRQ_TYPE_EDGE_FALLING>; /* 72 */
+
+		gpios = <&gpio3  6 GPIO_ACTIVE_HIGH>, /* 70 */
+			<&gpio3  9 GPIO_ACTIVE_HIGH>, /* 73 */
+			<&gpio3 10 GPIO_ACTIVE_HIGH>, /* 74 */
+			<&gpio3 11 GPIO_ACTIVE_HIGH>, /* 75 */
+			<&gpio5 29 GPIO_ACTIVE_HIGH>; /* 157 */
+		gpio-names = "cmt_apeslpx",
+			     "cmt_rst_rq",
+			     "cmt_en",
+			     "cmt_rst",
+			     "cmt_bsi";
+	};
+};
diff --git a/drivers/hsi/clients/Kconfig b/drivers/hsi/clients/Kconfig
index 0c70861..6ce1ea2 100644
--- a/drivers/hsi/clients/Kconfig
+++ b/drivers/hsi/clients/Kconfig
@@ -4,6 +4,15 @@
 
 comment "HSI clients"
 
+config NOKIA_MODEM
+	tristate "Nokia Modem"
+	depends on SSI_PROTOCOL
+	help
+	Say Y here if you want to add support for the modem on Nokia
+	N900 (Nokia RX-51) hardware.
+
+	If unsure, say N.
+
 config SSI_PROTOCOL
 	tristate "SSI protocol"
 	depends on HSI && OMAP_SSI && PHONET
diff --git a/drivers/hsi/clients/Makefile b/drivers/hsi/clients/Makefile
index ccbf768..4d5bc0e 100644
--- a/drivers/hsi/clients/Makefile
+++ b/drivers/hsi/clients/Makefile
@@ -2,5 +2,6 @@
 # Makefile for HSI clients
 #
 
+obj-$(CONFIG_NOKIA_MODEM)	+= nokia-modem.o
 obj-$(CONFIG_SSI_PROTOCOL)	+= ssi_protocol.o
 obj-$(CONFIG_HSI_CHAR)		+= hsi_char.o
diff --git a/drivers/hsi/clients/nokia-modem.c b/drivers/hsi/clients/nokia-modem.c
new file mode 100644
index 0000000..f12ec76
--- /dev/null
+++ b/drivers/hsi/clients/nokia-modem.c
@@ -0,0 +1,272 @@
+/*
+ * nokia-modem.c
+ *
+ * HSI client driver for Nokia N900 modem.
+ *
+ * Copyright (C) 2014 Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/hsi/hsi.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/hsi/ssi_protocol.h>
+
+struct nokia_modem_gpio {
+	struct gpio_desc	*gpio;
+	const char		*name;
+};
+
+struct nokia_modem_device {
+	struct tasklet_struct	nokia_modem_rst_ind_tasklet;
+	int			nokia_modem_rst_ind_irq;
+	struct device		*device;
+	struct nokia_modem_gpio	*gpios;
+	int			gpio_amount;
+	struct hsi_client	*ssi_protocol;
+};
+
+static void do_nokia_modem_rst_ind_tasklet(unsigned long data)
+{
+	struct nokia_modem_device *modem = (struct nokia_modem_device *)data;
+
+	if (!modem)
+		return;
+
+	dev_info(modem->device, "*** CMT rst line change detected ***\n");
+
+	if (modem->ssi_protocol)
+		ssip_reset_event(modem->ssi_protocol);
+}
+
+static irqreturn_t nokia_modem_rst_ind_isr(int irq, void *data)
+{
+	struct nokia_modem_device *modem = (struct nokia_modem_device *)data;
+
+	tasklet_schedule(&modem->nokia_modem_rst_ind_tasklet);
+
+	return IRQ_HANDLED;
+}
+
+static void nokia_modem_gpio_unexport(struct device *dev)
+{
+	struct nokia_modem_device *modem = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < modem->gpio_amount; i++) {
+		sysfs_remove_link(&dev->kobj, modem->gpios[i].name);
+		gpiod_unexport(modem->gpios[i].gpio);
+	}
+}
+
+static int nokia_modem_gpio_probe(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct nokia_modem_device *modem = dev_get_drvdata(dev);
+	int gpio_count, gpio_name_count, i, err;
+
+	gpio_count = of_gpio_count(np);
+	gpio_name_count = of_property_count_strings(np, "gpio-names");
+
+	if(gpio_count != gpio_name_count) {
+		dev_err(dev, "number of gpios does not equal number of gpio names\n");
+		return -EINVAL;
+	}
+
+	modem->gpios = devm_kzalloc(dev, gpio_count*sizeof(struct nokia_modem_gpio),
+								GFP_KERNEL);
+	if (modem->gpios == NULL) {
+		dev_err(dev, "Could not allocate memory for gpios\n");
+		return -ENOMEM;
+	}
+
+	modem->gpio_amount = gpio_count;
+
+	for (i = 0; i < gpio_count; i++) {
+		modem->gpios[i].gpio = devm_gpiod_get_index(dev, NULL, i);
+		if (IS_ERR(modem->gpios[i].gpio)) {
+			dev_err(dev, "Could not get gpio %d\n", i);
+			return PTR_ERR(modem->gpios[i].gpio);
+		}
+
+		err = of_property_read_string_index(np, "gpio-names", i,
+							&(modem->gpios[i].name));
+		if (err) {
+			dev_err(dev, "Could not get gpio name %d\n", i);
+			return err;
+		}
+
+		err = gpiod_direction_output(modem->gpios[i].gpio, 0);
+		if (err)
+			return err;
+
+		err = gpiod_export(modem->gpios[i].gpio, 0);
+		if (err)
+			return err;
+
+		err = gpiod_export_link(dev, modem->gpios[i].name,
+							modem->gpios[i].gpio);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int nokia_modem_probe(struct device *dev)
+{
+	struct device_node *np;
+	struct nokia_modem_device *modem;
+	struct hsi_client *cl = to_hsi_client(dev);
+	struct hsi_port *port = hsi_get_port(cl);
+	int irq, pflags, err;
+	struct hsi_board_info ssip;
+
+	np = dev->of_node;
+	if (!np) {
+		dev_err(dev, "device tree node not found\n");
+		return -ENXIO;
+	}
+
+	modem = devm_kzalloc(dev, sizeof(*modem), GFP_KERNEL);
+	if (!modem) {
+		dev_err(dev, "Could not allocate memory for nokia_modem_device\n");
+		return -ENOMEM;
+	}
+	dev_set_drvdata(dev, modem);
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (irq < 0) {
+		dev_err(dev, "Invalid nokia_modem_rst_ind interrupt: %d\n", irq);
+		return irq;
+	}
+	modem->nokia_modem_rst_ind_irq = irq;
+	pflags = irq_get_trigger_type(irq);
+
+	tasklet_init(&modem->nokia_modem_rst_ind_tasklet,
+			do_nokia_modem_rst_ind_tasklet, (unsigned long)modem);
+	err = devm_request_irq(dev, irq, nokia_modem_rst_ind_isr,
+				IRQF_DISABLED | pflags, "modem_rst_ind", modem);
+	if (err < 0) {
+		dev_err(dev, "Request modem_rst_ind irq(%d) failed (flags %d)\n",
+								irq, pflags);
+		return err;
+	}
+	enable_irq_wake(irq);
+
+	err = nokia_modem_gpio_probe(dev);
+	if (err < 0) {
+		dev_err(dev, "Could not probe GPIOs\n");
+		goto error1;
+	}
+
+	ssip.name = "ssi-protocol";
+	ssip.tx_cfg = cl->tx_cfg;
+	ssip.rx_cfg = cl->rx_cfg;
+	ssip.platform_data = NULL;
+	ssip.archdata = NULL;
+
+	modem->ssi_protocol = hsi_new_client(port, &ssip);
+	if (modem->ssi_protocol == NULL) {
+		dev_err(dev, "Could not register ssi-protocol device\n");
+		goto error2;
+	}
+
+	err = device_attach(&modem->ssi_protocol->device);
+	if (err == 0) {
+		dev_err(dev, "Missing ssi-protocol driver\n");
+		err = -EPROBE_DEFER;
+		goto error3;
+	} else if (err < 0) {
+		dev_err(dev, "Could not load ssi-protocol driver (%d)\n", err);
+		goto error3;
+	}
+
+	/* TODO: register cmt-speech hsi client */
+
+	dev_info(dev, "Registered Nokia HSI modem\n");
+
+	return 0;
+
+error3:
+	hsi_remove_client(&modem->ssi_protocol->device, NULL);
+error2:
+	nokia_modem_gpio_unexport(dev);
+error1:
+	disable_irq_wake(modem->nokia_modem_rst_ind_irq);
+	tasklet_kill(&modem->nokia_modem_rst_ind_tasklet);
+
+	return err;
+}
+
+static int nokia_modem_remove(struct device *dev)
+{
+	struct nokia_modem_device *modem = dev_get_drvdata(dev);
+
+	if (!modem)
+		return 0;
+
+	if (modem->ssi_protocol) {
+		hsi_remove_client(&modem->ssi_protocol->device, NULL);
+		modem->ssi_protocol = NULL;
+	}
+
+	nokia_modem_gpio_unexport(dev);
+	dev_set_drvdata(dev, NULL);
+	disable_irq_wake(modem->nokia_modem_rst_ind_irq);
+	tasklet_kill(&modem->nokia_modem_rst_ind_tasklet);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id nokia_modem_of_match[] = {
+       { .compatible = "nokia,n900-modem", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, nokia_modem_of_match);
+#endif
+
+static struct hsi_client_driver nokia_modem_driver = {
+	.driver = {
+		.name	= "nokia-modem",
+		.owner	= THIS_MODULE,
+		.probe	= nokia_modem_probe,
+		.remove	= nokia_modem_remove,
+		.of_match_table = of_match_ptr(nokia_modem_of_match),
+	},
+};
+
+static int __init nokia_modem_init(void)
+{
+	return hsi_register_client_driver(&nokia_modem_driver);
+}
+module_init(nokia_modem_init);
+
+static void __exit nokia_modem_exit(void)
+{
+	hsi_unregister_client_driver(&nokia_modem_driver);
+}
+module_exit(nokia_modem_exit);
+
+MODULE_ALIAS("hsi:nokia-modem");
+MODULE_AUTHOR("Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>");
+MODULE_DESCRIPTION("HSI driver module for Nokia N900 Modem");
+MODULE_LICENSE("GPL");
-- 
1.9.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCHv3 12/14] ARM: dts: omap3 clocks: simplify ssi aliases
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
                   ` (10 preceding siblings ...)
  2014-03-29  0:31   ` Sebastian Reichel
@ 2014-03-29  0:31 ` Sebastian Reichel
  2014-04-19 20:26   ` Pavel Machek
  2014-03-29  0:31 ` [PATCHv3 13/14] DTS: ARM: OMAP3-N900: Add SSI support Sebastian Reichel
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

From: Sebastian Reichel <sre@debian.org>

update aliases for the ssi clocks ssi_ssr_fck, ssi_sst_fck and ssi_ick
to make them consistent for omap34xx and omap36xx. This makes it
possible to reference the clocks from generic omap3 dts files.

Signed-off-by: Sebastian Reichel <sre@debian.org>
Acked-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/boot/dts/omap3430es1-clocks.dtsi              | 10 +++++-----
 arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi | 10 +++++-----
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/arch/arm/boot/dts/omap3430es1-clocks.dtsi b/arch/arm/boot/dts/omap3430es1-clocks.dtsi
index 02f6c7f..6f31954 100644
--- a/arch/arm/boot/dts/omap3430es1-clocks.dtsi
+++ b/arch/arm/boot/dts/omap3430es1-clocks.dtsi
@@ -82,16 +82,16 @@
 		ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
 	};
 
-	ssi_ssr_fck_3430es1: ssi_ssr_fck_3430es1 {
+	ssi_ssr_fck: ssi_ssr_fck_3430es1 {
 		#clock-cells = <0>;
 		compatible = "ti,composite-clock";
 		clocks = <&ssi_ssr_gate_fck_3430es1>, <&ssi_ssr_div_fck_3430es1>;
 	};
 
-	ssi_sst_fck_3430es1: ssi_sst_fck_3430es1 {
+	ssi_sst_fck: ssi_sst_fck_3430es1 {
 		#clock-cells = <0>;
 		compatible = "fixed-factor-clock";
-		clocks = <&ssi_ssr_fck_3430es1>;
+		clocks = <&ssi_ssr_fck>;
 		clock-mult = <1>;
 		clock-div = <2>;
 	};
@@ -120,7 +120,7 @@
 		clock-div = <1>;
 	};
 
-	ssi_ick_3430es1: ssi_ick_3430es1 {
+	ssi_ick: ssi_ick_3430es1 {
 		#clock-cells = <0>;
 		compatible = "ti,omap3-no-wait-interface-clock";
 		clocks = <&ssi_l4_ick>;
@@ -203,6 +203,6 @@
 			 <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>,
 			 <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>,
 			 <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>,
-			 <&fshostusb_fck>, <&fac_ick>, <&ssi_ick_3430es1>;
+			 <&fshostusb_fck>, <&fac_ick>, <&ssi_ick>;
 	};
 };
diff --git a/arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi b/arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi
index 8ed475d..877318c 100644
--- a/arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi
+++ b/arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi
@@ -25,16 +25,16 @@
 		ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
 	};
 
-	ssi_ssr_fck_3430es2: ssi_ssr_fck_3430es2 {
+	ssi_ssr_fck: ssi_ssr_fck_3430es2 {
 		#clock-cells = <0>;
 		compatible = "ti,composite-clock";
 		clocks = <&ssi_ssr_gate_fck_3430es2>, <&ssi_ssr_div_fck_3430es2>;
 	};
 
-	ssi_sst_fck_3430es2: ssi_sst_fck_3430es2 {
+	ssi_sst_fck: ssi_sst_fck_3430es2 {
 		#clock-cells = <0>;
 		compatible = "fixed-factor-clock";
-		clocks = <&ssi_ssr_fck_3430es2>;
+		clocks = <&ssi_ssr_fck>;
 		clock-mult = <1>;
 		clock-div = <2>;
 	};
@@ -55,7 +55,7 @@
 		clock-div = <1>;
 	};
 
-	ssi_ick_3430es2: ssi_ick_3430es2 {
+	ssi_ick: ssi_ick_3430es2 {
 		#clock-cells = <0>;
 		compatible = "ti,omap3-ssi-interface-clock";
 		clocks = <&ssi_l4_ick>;
@@ -193,6 +193,6 @@
 			 <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>,
 			 <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>,
 			 <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>,
-			 <&ssi_ick_3430es2>;
+			 <&ssi_ick>;
 	};
 };
-- 
1.9.0


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

* [PATCHv3 13/14] DTS: ARM: OMAP3-N900: Add SSI support
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
                   ` (11 preceding siblings ...)
  2014-03-29  0:31 ` [PATCHv3 12/14] ARM: dts: omap3 clocks: simplify ssi aliases Sebastian Reichel
@ 2014-03-29  0:31 ` Sebastian Reichel
  2014-04-19 20:28   ` Pavel Machek
  2014-03-29  0:31 ` [PATCHv3 14/14] DTS: ARM: OMAP3-N900: Add modem support Sebastian Reichel
  2014-05-05 19:31 ` [PATCHv3 00/14] OMAP SSI driver / N900 " Tony Lindgren
  14 siblings, 1 reply; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

Add SSI device tree data for OMAP3 and Nokia N900.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 arch/arm/boot/dts/omap3-n900.dts | 24 ++++++++++++++++++
 arch/arm/boot/dts/omap3.dtsi     | 55 ++++++++++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/omap34xx.dtsi  | 11 ++++++++
 arch/arm/boot/dts/omap36xx.dtsi  | 11 ++++++++
 4 files changed, 101 insertions(+)

diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index 0bf40c9..5bccd8c 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -145,6 +145,19 @@
 			0x0d4 (PIN_OUTPUT | MUX_MODE4)		/* RX51_LCD_RESET_GPIO */
 		>;
 	};
+
+	ssi_pins: pinmux_ssi {
+		pinctrl-single,pins = <
+			0x150 (PIN_INPUT_PULLUP | MUX_MODE1)	/* ssi1_rdy_tx */
+			0x14e (PIN_OUTPUT | MUX_MODE1)		/* ssi1_flag_tx */
+			0x152 (PIN_INPUT | WAKEUP_EN | MUX_MODE4) /* ssi1_wake_tx (cawake) */
+			0x14c (PIN_OUTPUT | MUX_MODE1)		/* ssi1_dat_tx */
+			0x154 (PIN_INPUT | MUX_MODE1)		/* ssi1_dat_rx */
+			0x156 (PIN_INPUT | MUX_MODE1)		/* ssi1_flag_rx */
+			0x158 (PIN_OUTPUT | MUX_MODE1)		/* ssi1_rdy_rx */
+			0x15a (PIN_OUTPUT | MUX_MODE1)		/* ssi1_wake */
+		>;
+	};
 };
 
 &i2c1 {
@@ -490,6 +503,17 @@
 	power = <50>;
 };
 
+&ssi_port1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&ssi_pins>;
+
+	ti,ssi-cawake-gpio = <&gpio5 23 GPIO_ACTIVE_HIGH>; /* 151 */
+};
+
+&ssi_port2 {
+	status = "disabled";
+};
+
 &uart1 {
 	status = "disabled";
 };
diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi
index a5fc83b..cb00ce6 100644
--- a/arch/arm/boot/dts/omap3.dtsi
+++ b/arch/arm/boot/dts/omap3.dtsi
@@ -669,6 +669,61 @@
 			num-eps = <16>;
 			ram-bits = <12>;
 		};
+
+		ssi: ssi-controller@48058000 {
+			compatible = "ti,omap3-ssi";
+			ti,hwmods = "ssi";
+
+			status = "disabled";
+
+			reg = <0x48058000 0x1000>,
+			      <0x48059000 0x1000>;
+			reg-names = "sys",
+				    "gdd";
+
+			interrupts = <71>;
+			interrupt-names = "gdd_mpu";
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			ssi_port1: ssi-port@0 {
+				compatible = "ti,omap3-ssi-port";
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				reg = <0x4805a000 0x800>,
+				      <0x4805a800 0x800>;
+				reg-names = "tx",
+					    "rx";
+
+				interrupt-parent = <&intc>;
+				interrupts = <67>,
+					     <68>;
+				interrupt-names = "mpu_irq0",
+						  "mpu_irq1";
+			};
+
+			ssi_port2: ssi-port@1 {
+				compatible = "ti,omap3-ssi-port";
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				reg = <0x4805b000 0x800>,
+				      <0x4805b800 0x800>;
+				reg-names = "tx",
+					    "rx";
+
+				interrupt-parent = <&intc>;
+				interrupts = <69>,
+					     <70>;
+				interrupt-names = "mpu_irq0",
+						  "mpu_irq1";
+			};
+		};
 	};
 };
 
diff --git a/arch/arm/boot/dts/omap34xx.dtsi b/arch/arm/boot/dts/omap34xx.dtsi
index 2e92360..3819c1e 100644
--- a/arch/arm/boot/dts/omap34xx.dtsi
+++ b/arch/arm/boot/dts/omap34xx.dtsi
@@ -40,6 +40,17 @@
 	};
 };
 
+&ssi {
+	status = "ok";
+
+	clocks = <&ssi_ssr_fck>,
+		 <&ssi_sst_fck>,
+		 <&ssi_ick>;
+	clock-names = "ssi_ssr_fck",
+		      "ssi_sst_fck",
+		      "ssi_ick";
+};
+
 /include/ "omap34xx-omap36xx-clocks.dtsi"
 /include/ "omap36xx-omap3430es2plus-clocks.dtsi"
 /include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi"
diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi
index 7e8dee9..a634961 100644
--- a/arch/arm/boot/dts/omap36xx.dtsi
+++ b/arch/arm/boot/dts/omap36xx.dtsi
@@ -52,6 +52,17 @@
 	};
 };
 
+&ssi {
+	status = "ok";
+
+	clocks = <&ssi_ssr_fck>,
+		 <&ssi_sst_fck>,
+		 <&ssi_ick>;
+	clock-names = "ssi_ssr_fck",
+		      "ssi_sst_fck",
+		      "ssi_ick";
+};
+
 /include/ "omap36xx-clocks.dtsi"
 /include/ "omap34xx-omap36xx-clocks.dtsi"
 /include/ "omap36xx-omap3430es2plus-clocks.dtsi"
-- 
1.9.0


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

* [PATCHv3 14/14] DTS: ARM: OMAP3-N900: Add modem support
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
                   ` (12 preceding siblings ...)
  2014-03-29  0:31 ` [PATCHv3 13/14] DTS: ARM: OMAP3-N900: Add SSI support Sebastian Reichel
@ 2014-03-29  0:31 ` Sebastian Reichel
  2014-04-19 20:28   ` Pavel Machek
  2014-05-05 19:31 ` [PATCHv3 00/14] OMAP SSI driver / N900 " Tony Lindgren
  14 siblings, 1 reply; 54+ messages in thread
From: Sebastian Reichel @ 2014-03-29  0:31 UTC (permalink / raw)
  To: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta, Carlos Chinea
  Cc: Tony Lindgren, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

Add modem device tree data to Nokia N900's DTS file.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 arch/arm/boot/dts/omap3-n900.dts | 41 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index 5bccd8c..6655790 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -158,6 +158,17 @@
 			0x15a (PIN_OUTPUT | MUX_MODE1)		/* ssi1_wake */
 		>;
 	};
+
+	modem_pins: pinmux_modem {
+		pinctrl-single,pins = <
+			0x0ac (PIN_OUTPUT | MUX_MODE4)		/* gpio 70 => cmt_apeslpx */
+			0x0b0 (PIN_INPUT | WAKEUP_EN | MUX_MODE4) /* gpio 72 => ape_rst_rq */
+			0x0b2 (PIN_OUTPUT | MUX_MODE4)		/* gpio 73 => cmt_rst_rq */
+			0x0b4 (PIN_OUTPUT | MUX_MODE4)		/* gpio 74 => cmt_en */
+			0x0b6 (PIN_OUTPUT | MUX_MODE4)		/* gpio 75 => cmt_rst */
+			0x15e (PIN_OUTPUT | MUX_MODE4)		/* gpio 157 => cmt_bsi */
+		>;
+	};
 };
 
 &i2c1 {
@@ -508,6 +519,36 @@
 	pinctrl-0 = <&ssi_pins>;
 
 	ti,ssi-cawake-gpio = <&gpio5 23 GPIO_ACTIVE_HIGH>; /* 151 */
+
+	modem: hsi-client {
+		compatible = "nokia,n900-modem";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&modem_pins>;
+
+		reg = <0>, <1>, <2>, <3>;
+		reg-names = "mcsaab-control",
+			    "speech-control",
+			    "speech-data",
+			    "mcsaab-data";
+		hsi-speed-kbps = <55000>;
+		hsi-mode = "frame";
+		hsi-flow = "synchronized";
+		hsi-arb-mode = "round-robin";
+
+		interrupts-extended = <&gpio3 8 IRQ_TYPE_EDGE_FALLING>; /* 72 */
+
+		gpios = <&gpio3  6 GPIO_ACTIVE_HIGH>, /* 70 */
+			<&gpio3  9 GPIO_ACTIVE_HIGH>, /* 73 */
+			<&gpio3 10 GPIO_ACTIVE_HIGH>, /* 74 */
+			<&gpio3 11 GPIO_ACTIVE_HIGH>, /* 75 */
+			<&gpio5 29 GPIO_ACTIVE_HIGH>; /* 157 */
+		gpio-names = "cmt_apeslpx",
+			     "cmt_rst_rq",
+			     "cmt_en",
+			     "cmt_rst",
+			     "cmt_bsi";
+	};
 };
 
 &ssi_port2 {
-- 
1.9.0


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

* Re: [PATCHv3 01/14] Documentation: HSI: Add some general description for the HSI subsystem
@ 2014-04-19 19:05     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:05 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:37, Sebastian Reichel wrote:
> Add a document, which gives a rough introduction about what HSI
> is and how its handled by the Linux kernel.
> 
> Signed-off-by: Sebastian Reichel <sre@kernel.org>

Reviewed-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 01/14] Documentation: HSI: Add some general description for the HSI subsystem
@ 2014-04-19 19:05     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:05 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:37, Sebastian Reichel wrote:
> Add a document, which gives a rough introduction about what HSI
> is and how its handled by the Linux kernel.
> 
> Signed-off-by: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

Reviewed-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCHv3 02/14] MAINTAINERS: update HSI entry
  2014-03-29  0:31 ` [PATCHv3 02/14] MAINTAINERS: update HSI entry Sebastian Reichel
@ 2014-04-19 19:06   ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:06 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:38, Sebastian Reichel wrote:
> Add git tree for hsi subsystem, update Sebastian Reichel's e-mail
> address and add Documentation/hsi.txt as maintained file.
> 
> Signed-off-by: Sebastian Reichel <sre@kernel.org>

Reviewed-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 03/14] HSI: hsi-char: fix driver for multiport scenarios
  2014-03-29  0:31 ` [PATCHv3 03/14] HSI: hsi-char: fix driver for multiport scenarios Sebastian Reichel
@ 2014-04-19 19:06   ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:06 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:39, Sebastian Reichel wrote:
> Fix return code check of alloc_chrdev_region, which
> returns 0 on success.
> 
> Signed-off-by: Sebastian Reichel <sre@kernel.org>

Reviewed-by: Pavel Machek <pavel@ucw.cz>


-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 04/14] HSI: method to unregister clients from an hsi port
@ 2014-04-19 19:07     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:07 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:40, Sebastian Reichel wrote:
> This exports a method to unregister all clients from
> an hsi port.
> 
> Signed-off-by: Sebastian Reichel <sre@kernel.org>

Reviewed-by: Pavel Machek <pavel@ucw.cz>


-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 04/14] HSI: method to unregister clients from an hsi port
@ 2014-04-19 19:07     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:07 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:40, Sebastian Reichel wrote:
> This exports a method to unregister all clients from
> an hsi port.
> 
> Signed-off-by: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

Reviewed-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>


-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCHv3 05/14] HSI: Add channel resource support to HSI clients
@ 2014-04-19 19:11     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:11 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

Hi!

> Make HSI channel ids platform data, which can be provided
> by platform data.
>

>  static void hsi_client_release(struct device *dev)
>  {
> -	kfree(to_hsi_client(dev));
> +	struct hsi_client *cl = to_hsi_client(dev);
> +
> +	if (cl->tx_cfg.channels)
> +		kfree(cl->tx_cfg.channels);
> +	if (cl->rx_cfg.channels && cl->rx_cfg.channels != cl->tx_cfg.channels)
> +		kfree(cl->rx_cfg.channels);
> +
> +	kfree(cl);

Can cl->rx_cfg.channels == cl->tx_cfg.channels happen? That seems like
quite a hack :-(.
								Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 05/14] HSI: Add channel resource support to HSI clients
@ 2014-04-19 19:11     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:11 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

Hi!

> Make HSI channel ids platform data, which can be provided
> by platform data.
>

>  static void hsi_client_release(struct device *dev)
>  {
> -	kfree(to_hsi_client(dev));
> +	struct hsi_client *cl = to_hsi_client(dev);
> +
> +	if (cl->tx_cfg.channels)
> +		kfree(cl->tx_cfg.channels);
> +	if (cl->rx_cfg.channels && cl->rx_cfg.channels != cl->tx_cfg.channels)
> +		kfree(cl->rx_cfg.channels);
> +
> +	kfree(cl);

Can cl->rx_cfg.channels == cl->tx_cfg.channels happen? That seems like
quite a hack :-(.
								Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCHv3 06/14] HSI: export method to (un)register clients
@ 2014-04-19 19:13     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:13 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:42, Sebastian Reichel wrote:
> Expose method for registering and unregistering HSI clients, so that
> client drivers can register other client drivers.
> 
> This is useful for HSI drivers, which want to use the functionality
> of other HSI drivers. For example the N900 modem driver can load HSI
> drivers for mcsaab protocol and speech protocol.
> 
> Signed-off-by: Sebastian Reichel <sre@kernel.org>

Reviewed-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 06/14] HSI: export method to (un)register clients
@ 2014-04-19 19:13     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:13 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:42, Sebastian Reichel wrote:
> Expose method for registering and unregistering HSI clients, so that
> client drivers can register other client drivers.
> 
> This is useful for HSI drivers, which want to use the functionality
> of other HSI drivers. For example the N900 modem driver can load HSI
> drivers for mcsaab protocol and speech protocol.
> 
> Signed-off-by: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

Reviewed-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices
@ 2014-04-19 19:16     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:16 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:43, Sebastian Reichel wrote:
> Implement and document generic DT bindings for HSI clients.
> 
> Signed-off-by: Sebastian Reichel <sre@kernel.org>

Reviewed-by: Pavel Machek <pavel@ucw.cz>

> diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
> index 07e1639..5973906 100644
> --- a/drivers/hsi/hsi.c
> +++ b/drivers/hsi/hsi.c
> @@ -26,8 +26,14 @@
>  #include <linux/slab.h>
>  #include <linux/string.h>
>  #include <linux/notifier.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
>  #include "hsi_core.h"


> +	err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
> +	if (err) {
> +		err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
> +						 &cl->rx_cfg.mode);
> +		if (err)
> +			goto err;
> +
> +		err = hsi_of_property_parse_mode(client, "hsi-tx-mode",
> +						 &cl->tx_cfg.mode);
> +		if (err)
> +			goto err;

Will this need some #ifdef CONFIG_OF? 

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices
@ 2014-04-19 19:16     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:16 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:43, Sebastian Reichel wrote:
> Implement and document generic DT bindings for HSI clients.
> 
> Signed-off-by: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

Reviewed-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>

> diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
> index 07e1639..5973906 100644
> --- a/drivers/hsi/hsi.c
> +++ b/drivers/hsi/hsi.c
> @@ -26,8 +26,14 @@
>  #include <linux/slab.h>
>  #include <linux/string.h>
>  #include <linux/notifier.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
>  #include "hsi_core.h"


> +	err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
> +	if (err) {
> +		err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
> +						 &cl->rx_cfg.mode);
> +		if (err)
> +			goto err;
> +
> +		err = hsi_of_property_parse_mode(client, "hsi-tx-mode",
> +						 &cl->tx_cfg.mode);
> +		if (err)
> +			goto err;

Will this need some #ifdef CONFIG_OF? 

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCHv3 08/14] HSI: Introduce OMAP SSI driver
@ 2014-04-19 19:30     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:30 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Carlos Chinea

Hi!

> Add OMAP SSI driver to the HSI subsystem.
> 
> The Synchronous Serial Interface (SSI) is a legacy version
> of HSI. As in the case of HSI, it is mainly used to connect
> Application engines (APE) with cellular modem engines (CMT)
> in cellular handsets.
> 
> It provides a multichannel, full-duplex, multi-core communication
> with no reference clock. The OMAP SSI block is capable of reaching
> speeds of 110 Mbit/s.
> 
> Signed-off-by: Carlos Chinea <carlos.chinea@nokia.com>
> Signed-off-by: Sebastian Reichel <sre@kernel.org>

> +	bool			wktest:1; /* FIXME: HACK to be removed */
> +	bool			wkin_cken:1; /* Workaround */

There is more thanone FIXME in the code. It may be better to fix after
merge...


> +DEFINE_SIMPLE_ATTRIBUTE(ssi_sst_div_fops, ssi_div_get, ssi_div_set, "%llu\n");
> +
> +static int __init ssi_debug_add_port(struct omap_ssi_port *omap_port,
> +							struct dentry *dir)
> +{

A little strange indentation. Is it intentional?

> +	if (IS_ERR(dir))
> +		return PTR_ERR(dir);
> +	debugfs_create_file("divisor", S_IRUGO | S_IWUSR, dir, port,
> +							&ssi_sst_div_fops);

Here, too.

> +	dev_dbg(&ssi->device, "TX div %d for fck_rate %lu Khz speed %d Kb/s\n",
> +			tx_fckrate / omap_ssi->max_speed, omap_ssi->fck_rate,
> +							omap_ssi->max_speed);

...and here.

> +	if (--omap_port->wk_refcount) {
> +		spin_unlock_bh(&omap_port->wk_lock);
> +		return 0;
> +	}
> +	writel(SSI_WAKE(0),
> +				omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num));

...and here. Should be on one line, AFAICT.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 08/14] HSI: Introduce OMAP SSI driver
@ 2014-04-19 19:30     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:30 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Carlos Chinea

Hi!

> Add OMAP SSI driver to the HSI subsystem.
> 
> The Synchronous Serial Interface (SSI) is a legacy version
> of HSI. As in the case of HSI, it is mainly used to connect
> Application engines (APE) with cellular modem engines (CMT)
> in cellular handsets.
> 
> It provides a multichannel, full-duplex, multi-core communication
> with no reference clock. The OMAP SSI block is capable of reaching
> speeds of 110 Mbit/s.
> 
> Signed-off-by: Carlos Chinea <carlos.chinea-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

> +	bool			wktest:1; /* FIXME: HACK to be removed */
> +	bool			wkin_cken:1; /* Workaround */

There is more thanone FIXME in the code. It may be better to fix after
merge...


> +DEFINE_SIMPLE_ATTRIBUTE(ssi_sst_div_fops, ssi_div_get, ssi_div_set, "%llu\n");
> +
> +static int __init ssi_debug_add_port(struct omap_ssi_port *omap_port,
> +							struct dentry *dir)
> +{

A little strange indentation. Is it intentional?

> +	if (IS_ERR(dir))
> +		return PTR_ERR(dir);
> +	debugfs_create_file("divisor", S_IRUGO | S_IWUSR, dir, port,
> +							&ssi_sst_div_fops);

Here, too.

> +	dev_dbg(&ssi->device, "TX div %d for fck_rate %lu Khz speed %d Kb/s\n",
> +			tx_fckrate / omap_ssi->max_speed, omap_ssi->fck_rate,
> +							omap_ssi->max_speed);

...and here.

> +	if (--omap_port->wk_refcount) {
> +		spin_unlock_bh(&omap_port->wk_lock);
> +		return 0;
> +	}
> +	writel(SSI_WAKE(0),
> +				omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num));

...and here. Should be on one line, AFAICT.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCHv3 09/14] Documentation: DT: omap-ssi binding documentation
  2014-03-29  0:31 ` [PATCHv3 09/14] Documentation: DT: omap-ssi binding documentation Sebastian Reichel
@ 2014-04-19 19:32   ` Pavel Machek
  2014-04-21 16:43   ` Rob Herring
  1 sibling, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:32 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:45, Sebastian Reichel wrote:
> Create device tree binding documentation for
> OMAP Synchronous Serial Interface (SSI) device.
> 
> Signed-off-by: Sebastian Reichel <sre@kernel.org>

Reviewed-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 10/14] HSI: Introduce driver for SSI Protocol
@ 2014-04-19 19:49     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:49 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Carlos Chinea

Hi!

> This adds a driver for the SSI McSAAB protocol as used in
> the Nokia N900.
> 
> Signed-off-by: Carlos Chinea <carlos.chinea@nokia.com>
> Signed-off-by: Sebastian Reichel <sre@kernel.org>

> +#define SSIP_MIN_PN_HDR		6	/* FIXME: Revisit */
> +#define SSIP_WDTOUT		2000	/* FIXME: has to be 500 msecs> */

Can they be fixed now, or do they have to wait?


> +#ifdef __LITTLE_ENDIAN
> +	((u16 *)skb->data)[2] = swab16(((u16 *)skb->data)[2]);
> +	dev_dbg(&dev->dev, "RX length fixed (%04x -> %u)\n",
> +			((u16 *)skb->data)[2], ntohs(((u16 *)skb->data)[2]));
> +#endif

Uh. Can this be replaced by
    ((u16 *)skb->data)[2] = htons(((u16 *)skb->data)[2]);

(without the ifdef?)

> +	/*
> +	 * Modem sends Phonet messages over SSI with its own endianess...
> +	 * Assume that modem has the same endianess as we do.
> +	 */
> +	if (skb_cow_head(skb, 0))
> +		goto drop;
> +#ifdef __LITTLE_ENDIAN
> +	((u16 *)skb->data)[2] = swab16(((u16 *)skb->data)[2]);
> +#endif

Here, too?

But it looks like the comment does not match the code, because we
swap.

Best regards,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 10/14] HSI: Introduce driver for SSI Protocol
@ 2014-04-19 19:49     ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 19:49 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Carlos Chinea

Hi!

> This adds a driver for the SSI McSAAB protocol as used in
> the Nokia N900.
> 
> Signed-off-by: Carlos Chinea <carlos.chinea-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

> +#define SSIP_MIN_PN_HDR		6	/* FIXME: Revisit */
> +#define SSIP_WDTOUT		2000	/* FIXME: has to be 500 msecs> */

Can they be fixed now, or do they have to wait?


> +#ifdef __LITTLE_ENDIAN
> +	((u16 *)skb->data)[2] = swab16(((u16 *)skb->data)[2]);
> +	dev_dbg(&dev->dev, "RX length fixed (%04x -> %u)\n",
> +			((u16 *)skb->data)[2], ntohs(((u16 *)skb->data)[2]));
> +#endif

Uh. Can this be replaced by
    ((u16 *)skb->data)[2] = htons(((u16 *)skb->data)[2]);

(without the ifdef?)

> +	/*
> +	 * Modem sends Phonet messages over SSI with its own endianess...
> +	 * Assume that modem has the same endianess as we do.
> +	 */
> +	if (skb_cow_head(skb, 0))
> +		goto drop;
> +#ifdef __LITTLE_ENDIAN
> +	((u16 *)skb->data)[2] = swab16(((u16 *)skb->data)[2]);
> +#endif

Here, too?

But it looks like the comment does not match the code, because we
swap.

Best regards,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCHv3 11/14] HSI: Introduce Nokia N900 modem driver
  2014-03-29  0:31   ` Sebastian Reichel
  (?)
@ 2014-04-19 20:25   ` Pavel Machek
  -1 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 20:25 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:47, Sebastian Reichel wrote:
> The Nokia N900's modem is connected via Synchronous Serial Interface (SSI),
> which is a legacy version of MIPI's High-speed Synchronous Serial Interface
> (HSI).
> 
> The handles the GPIOs for enabling and resetting the modem and instanciates
> ssi-protocol for data exchange. It does not yet support exchanging voice data
> with the modem.
> 
> Signed-off-by: Sebastian Reichel <sre@kernel.org>

Reviewed-by: Pavel Machek <pavel@ucw.cz>

> +static void do_nokia_modem_rst_ind_tasklet(unsigned long data)
> +{
> +	struct nokia_modem_device *modem = (struct nokia_modem_device *)data;
> +
> +	if (!modem)
> +		return;
> +
> +	dev_info(modem->device, "*** CMT rst line change detected ***\n");

Maybe slightly less stars would work?


> +static int nokia_modem_gpio_probe(struct device *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct nokia_modem_device *modem = dev_get_drvdata(dev);
> +	int gpio_count, gpio_name_count, i, err;
> +
> +	gpio_count = of_gpio_count(np);
> +	gpio_name_count = of_property_count_strings(np, "gpio-names");
> +
> +	if(gpio_count != gpio_name_count) {

"if (".

> +	modem->ssi_protocol = hsi_new_client(port, &ssip);
> +	if (modem->ssi_protocol == NULL) {

...if (! ...)

> +		dev_err(dev, "Could not register ssi-protocol device\n");
> +		goto error2;
> +	}
> +
> +	err = device_attach(&modem->ssi_protocol->device);
> +	if (err == 0) {

if (!...)

									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 12/14] ARM: dts: omap3 clocks: simplify ssi aliases
  2014-03-29  0:31 ` [PATCHv3 12/14] ARM: dts: omap3 clocks: simplify ssi aliases Sebastian Reichel
@ 2014-04-19 20:26   ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 20:26 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Sebastian Reichel

On Sat 2014-03-29 01:31:48, Sebastian Reichel wrote:
> From: Sebastian Reichel <sre@debian.org>
> 
> update aliases for the ssi clocks ssi_ssr_fck, ssi_sst_fck and ssi_ick
> to make them consistent for omap34xx and omap36xx. This makes it
> possible to reference the clocks from generic omap3 dts files.
> 
> Signed-off-by: Sebastian Reichel <sre@debian.org>
> Acked-by: Tero Kristo <t-kristo@ti.com>

Reviewed-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 13/14] DTS: ARM: OMAP3-N900: Add SSI support
  2014-03-29  0:31 ` [PATCHv3 13/14] DTS: ARM: OMAP3-N900: Add SSI support Sebastian Reichel
@ 2014-04-19 20:28   ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 20:28 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:49, Sebastian Reichel wrote:
> Add SSI device tree data for OMAP3 and Nokia N900.
> 
> Signed-off-by: Sebastian Reichel <sre@kernel.org>

Reviewed-by: Pavel Machek <pavel@ucw.cz>


-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 14/14] DTS: ARM: OMAP3-N900: Add modem support
  2014-03-29  0:31 ` [PATCHv3 14/14] DTS: ARM: OMAP3-N900: Add modem support Sebastian Reichel
@ 2014-04-19 20:28   ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-19 20:28 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Sat 2014-03-29 01:31:50, Sebastian Reichel wrote:
> Add modem device tree data to Nokia N900's DTS file.
> 
> Signed-off-by: Sebastian Reichel <sre@kernel.org>

Reviewed-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 09/14] Documentation: DT: omap-ssi binding documentation
  2014-03-29  0:31 ` [PATCHv3 09/14] Documentation: DT: omap-ssi binding documentation Sebastian Reichel
  2014-04-19 19:32   ` Pavel Machek
@ 2014-04-21 16:43   ` Rob Herring
  2014-04-25 18:38     ` Sebastian Reichel
  1 sibling, 1 reply; 54+ messages in thread
From: Rob Herring @ 2014-04-21 16:43 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Fri, Mar 28, 2014 at 7:31 PM, Sebastian Reichel <sre@kernel.org> wrote:
> Create device tree binding documentation for
> OMAP Synchronous Serial Interface (SSI) device.
>
> Signed-off-by: Sebastian Reichel <sre@kernel.org>
> ---
>  Documentation/devicetree/bindings/hsi/omap-ssi.txt | 85 ++++++++++++++++++++++
>  1 file changed, 85 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/hsi/omap-ssi.txt
>
> diff --git a/Documentation/devicetree/bindings/hsi/omap-ssi.txt b/Documentation/devicetree/bindings/hsi/omap-ssi.txt
> new file mode 100644
> index 0000000..709419b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hsi/omap-ssi.txt
> @@ -0,0 +1,85 @@
> +OMAP SSI controller bindings
> +
> +OMAP Synchronous Serial Interface (SSI) controller implements a legacy
> +variant of MIPI's High Speed Synchronous Serial Interface (HSI).
> +
> +Required properties:
> +- compatible:          Should include "ti,omap3-ssi".
> +- reg-names:           Contains the values "sys" and "gdd".
> +- reg:                 Contains a register specifier for each entry in
> +                       reg-names.

You need to define the order here unless you have a strong argument
why you can't.

> +- interrupt-names:      Contains the value "gdd_mpu".
> +- interrupts:          Contains interrupt information for each entry in
> +                       interrupt-names.
> +- ranges:              Represents the bus address mapping between the main
> +                       controller node and the child nodes below.
> +- clocks:              Contains clock specifiers for each entry in
> +                        clock-names.
> +- clock-names:         Must include the following entries:
> +  "ssi_ssr_fck": The OMAP clock of that name
> +  "ssi_sst_fck": The OMAP clock of that name
> +  "ssi_ick": The OMAP clock of that name
> +- #address-cells:      Should be set to <1>
> +- #size-cells:         Should be set to <1>
> +
> +Each port is represented as a sub-node of the ti,omap3-ssi device.
> +
> +Required Port sub-node properties:
> +- compatible:          Should be set to the following value
> +                        ti,omap3-ssi-port (applicable to OMAP34xx devices)
> +- reg-names:           Contains the values "rx" and "tx".
> +- reg:                 Contains a register specifier for each entry in
> +                       reg-names.

You need to define the order here unless you have a strong argument
why you can't.

> +- interrupt-parent     Should be a phandle for the interrupt controller
> +- interrupt-names:     Contains the values "mpu_irq0" and "mpu_irq1".

Those names aren't exactly useful.

> +- interrupts:          Contains interrupt information for each entry in
> +                       interrupt-names.

You need to define the order here unless you have a strong argument
why you can't.

> +- ti,ssi-cawake-gpio:  Defines which GPIO pin is used to signify CAWAKE
> +                       events for the port. This is an optional board-specific
> +                       property. If it's missing the port will not be
> +                       enabled.
> +
> +Example for Nokia N900:
> +
> +ssi-controller@48058000 {
> +       compatible = "ti,omap3-ssi";
> +
> +       /* needed until hwmod is updated to use the compatible string */
> +       ti,hwmods = "ssi";
> +
> +       reg = <0x48058000 0x1000>,
> +             <0x48059000 0x1000>;
> +       reg-names = "sys",
> +                   "gdd";
> +
> +       interrupts = <55>;
> +       interrupt-names = "gdd_mpu";
> +
> +       clocks = <&ssi_ssr_fck>,
> +                <&ssi_sst_fck>,
> +                <&ssi_ick>;
> +       clock-names = "ssi_ssr_fck",
> +                     "ssi_sst_fck",
> +                     "ssi_ick";
> +
> +       #address-cells = <1>;
> +       #size-cells = <1>;
> +       ranges;
> +
> +       ssi-port@0 {

Does this h/w really have more than 1 port?

This should really be "ssi-port@4805a800" Or you need to fill in
ranges to have a local offset.

> +               compatible = "ti,omap3-ssi-port";
> +
> +               reg = <0x4805a000 0x800>,
> +                     <0x4805a800 0x800>;
> +               reg-names = "tx",
> +                           "rx";
> +
> +               interrupt-parent = <&intc>;
> +               interrupts = <51>,
> +                            <52>;
> +               interrupt-names = "mpu_irq0",
> +                                 "mpu_irq1";
> +
> +               ti,ssi-cawake-gpio = <&gpio5 23 GPIO_ACTIVE_HIGH>; /* 151 */
> +       }
> +}
> --
> 1.9.0
>

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

* Re: [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices
  2014-03-29  0:31 ` [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices Sebastian Reichel
  2014-04-19 19:16     ` Pavel Machek
@ 2014-04-21 16:52   ` Rob Herring
  2014-04-25 18:32     ` Sebastian Reichel
  1 sibling, 1 reply; 54+ messages in thread
From: Rob Herring @ 2014-04-21 16:52 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Tony Lindgren, Rob Herring, Pawel Moll,
	Mark Rutland, Kumar Gala, devicetree, linux-kernel, linux-omap,
	Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Fri, Mar 28, 2014 at 7:31 PM, Sebastian Reichel <sre@kernel.org> wrote:
> Implement and document generic DT bindings for HSI clients.
>
> Signed-off-by: Sebastian Reichel <sre@kernel.org>

Seems pretty reasonable although I know little about HSI.

> ---
>  .../devicetree/bindings/hsi/client-devices.txt     |  44 +++++
>  drivers/hsi/hsi.c                                  | 197 ++++++++++++++++++++-
>  include/linux/hsi/hsi.h                            |   2 +
>  3 files changed, 241 insertions(+), 2 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/hsi/client-devices.txt
>
> diff --git a/Documentation/devicetree/bindings/hsi/client-devices.txt b/Documentation/devicetree/bindings/hsi/client-devices.txt
> new file mode 100644
> index 0000000..7504cb1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hsi/client-devices.txt
> @@ -0,0 +1,44 @@
> +Each HSI port is supposed to have one child node, which
> +symbols the remote device connected to the HSI port. The
> +following properties are standardized for HSI clients:
> +
> +Required HSI configuration properties:
> +
> +- reg:                 A list of channel ids
> +
> +- hsi-rx-mode:         Receiver Bit transmission mode ("stream" or "frame")
> +- hsi-tx-mode:         Transmitter Bit transmission mode ("stream" or "frame")
> +- hsi-mode:            May be used instead hsi-rx-mode and hsi-tx-mode if
> +                       the transmission mode is the same for receiver and
> +                       transmitter
> +- hsi-speed-kbps:      Max bit transmission speed in kbit/s
> +- hsi-flow:            RX flow type ("synchronized" or "pipeline")
> +- hsi-arb-mode:                Arbitration mode for TX frame ("round-robin", "priority")
> +
> +Optional HSI configuration properties:
> +
> +- reg-names:           A list with one name per channel specified in the
> +                       reg property
> +
> +
> +Device Tree node example for an HSI client:
> +
> +hsi-controller {
> +       hsi-port {
> +               modem: hsi-client {
> +                       compatible = "nokia,n900-modem";

Is there only 1 version of HSI? If not, then perhaps you need to know
what version a client is.

> +
> +                       reg = <0>, <1>, <2>, <3>;

Where do these numbers get defined? Are they always 0-N?

I don't see much advantage to using reg. Perhaps something like
hsi-channel-ids would be better.

Rob

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

* Re: [PATCHv3 05/14] HSI: Add channel resource support to HSI clients
  2014-04-19 19:11     ` Pavel Machek
  (?)
@ 2014-04-25 17:32     ` Sebastian Reichel
  -1 siblings, 0 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-04-25 17:32 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Tony Lindgren,
	Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala, devicetree,
	linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

[-- Attachment #1: Type: text/plain, Size: 740 bytes --]

On Sat, Apr 19, 2014 at 09:11:26PM +0200, Pavel Machek wrote:
> Hi!
> 
> > Make HSI channel ids platform data, which can be provided
> > by platform data.
> >
> 
> >  static void hsi_client_release(struct device *dev)
> >  {
> > -	kfree(to_hsi_client(dev));
> > +	struct hsi_client *cl = to_hsi_client(dev);
> > +
> > +	if (cl->tx_cfg.channels)
> > +		kfree(cl->tx_cfg.channels);
> > +	if (cl->rx_cfg.channels && cl->rx_cfg.channels != cl->tx_cfg.channels)
> > +		kfree(cl->rx_cfg.channels);
> > +
> > +	kfree(cl);
> 
> Can cl->rx_cfg.channels == cl->tx_cfg.channels happen? That seems
> like quite a hack :-(.

Yes it could happen. I have updated this for PATCHv4 (so that it can
no longer happen).

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices
  2014-04-19 19:16     ` Pavel Machek
  (?)
@ 2014-04-25 18:25     ` Sebastian Reichel
  2014-04-25 20:59         ` Sebastian Reichel
  -1 siblings, 1 reply; 54+ messages in thread
From: Sebastian Reichel @ 2014-04-25 18:25 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Tony Lindgren,
	Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala, devicetree,
	linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

[-- Attachment #1: Type: text/plain, Size: 1280 bytes --]

On Sat, Apr 19, 2014 at 09:16:12PM +0200, Pavel Machek wrote:
> On Sat 2014-03-29 01:31:43, Sebastian Reichel wrote:
> > Implement and document generic DT bindings for HSI clients.
> > 
> > Signed-off-by: Sebastian Reichel <sre@kernel.org>
> 
> Reviewed-by: Pavel Machek <pavel@ucw.cz>
> 
> > diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
> > index 07e1639..5973906 100644
> > --- a/drivers/hsi/hsi.c
> > +++ b/drivers/hsi/hsi.c
> > @@ -26,8 +26,14 @@
> >  #include <linux/slab.h>
> >  #include <linux/string.h>
> >  #include <linux/notifier.h>
> > +#include <linux/of.h>
> > +#include <linux/of_device.h>
> >  #include "hsi_core.h"
> 
> 
> > +	err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
> > +	if (err) {
> > +		err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
> > +						 &cl->rx_cfg.mode);
> > +		if (err)
> > +			goto err;
> > +
> > +		err = hsi_of_property_parse_mode(client, "hsi-tx-mode",
> > +						 &cl->tx_cfg.mode);
> > +		if (err)
> > +			goto err;
> 
> Will this need some #ifdef CONFIG_OF?

It would only be needed to reduce the amount of kernel code for
disabled Device Tree. I don't think its worth it, since there is no
platform in the mainline kernel, which uses HSI without DT.

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices
  2014-04-21 16:52   ` Rob Herring
@ 2014-04-25 18:32     ` Sebastian Reichel
  0 siblings, 0 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-04-25 18:32 UTC (permalink / raw)
  To: Rob Herring
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Tony Lindgren,
	Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala, devicetree,
	linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

[-- Attachment #1: Type: text/plain, Size: 3125 bytes --]

On Mon, Apr 21, 2014 at 11:52:11AM -0500, Rob Herring wrote:
> On Fri, Mar 28, 2014 at 7:31 PM, Sebastian Reichel <sre@kernel.org> wrote:
> > Implement and document generic DT bindings for HSI clients.
> >
> > Signed-off-by: Sebastian Reichel <sre@kernel.org>
> 
> Seems pretty reasonable although I know little about HSI.

ok.

> > ---
> >  .../devicetree/bindings/hsi/client-devices.txt     |  44 +++++
> >  drivers/hsi/hsi.c                                  | 197 ++++++++++++++++++++-
> >  include/linux/hsi/hsi.h                            |   2 +
> >  3 files changed, 241 insertions(+), 2 deletions(-)
> >  create mode 100644 Documentation/devicetree/bindings/hsi/client-devices.txt
> >
> > diff --git a/Documentation/devicetree/bindings/hsi/client-devices.txt b/Documentation/devicetree/bindings/hsi/client-devices.txt
> > new file mode 100644
> > index 0000000..7504cb1
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/hsi/client-devices.txt
> > @@ -0,0 +1,44 @@
> > +Each HSI port is supposed to have one child node, which
> > +symbols the remote device connected to the HSI port. The
> > +following properties are standardized for HSI clients:
> > +
> > +Required HSI configuration properties:
> > +
> > +- reg:                 A list of channel ids
> > +
> > +- hsi-rx-mode:         Receiver Bit transmission mode ("stream" or "frame")
> > +- hsi-tx-mode:         Transmitter Bit transmission mode ("stream" or "frame")
> > +- hsi-mode:            May be used instead hsi-rx-mode and hsi-tx-mode if
> > +                       the transmission mode is the same for receiver and
> > +                       transmitter
> > +- hsi-speed-kbps:      Max bit transmission speed in kbit/s
> > +- hsi-flow:            RX flow type ("synchronized" or "pipeline")
> > +- hsi-arb-mode:                Arbitration mode for TX frame ("round-robin", "priority")
> > +
> > +Optional HSI configuration properties:
> > +
> > +- reg-names:           A list with one name per channel specified in the
> > +                       reg property
> > +
> > +
> > +Device Tree node example for an HSI client:
> > +
> > +hsi-controller {
> > +       hsi-port {
> > +               modem: hsi-client {
> > +                       compatible = "nokia,n900-modem";
> 
> Is there only 1 version of HSI? If not, then perhaps you need to
> know what version a client is.

There is HSI (High-speed Synchronous Serial Interface) and a legacy
variant from Texas Instruments called SSI (Synchronous Serial Interface).
The main difference is the speed and I don't think the difference
must be encoded in the Device Tree.

> > +                       reg = <0>, <1>, <2>, <3>;
> 
> Where do these numbers get defined?

HSI provides multiple serial connections and this describes which
channels are used for the remote device.

>Are they always 0-N?

From what I understand they don't have to.

> I don't see much advantage to using reg. Perhaps something like
> hsi-channel-ids would be better.

I will change it to hsi-channel-ids for PATCHv4.

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCHv3 08/14] HSI: Introduce OMAP SSI driver
  2014-04-19 19:30     ` Pavel Machek
  (?)
@ 2014-04-25 18:36     ` Sebastian Reichel
  -1 siblings, 0 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-04-25 18:36 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Tony Lindgren,
	Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala, devicetree,
	linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Carlos Chinea

[-- Attachment #1: Type: text/plain, Size: 1430 bytes --]

On Sat, Apr 19, 2014 at 09:30:51PM +0200, Pavel Machek wrote:
> > Add OMAP SSI driver to the HSI subsystem.
> > 
> > The Synchronous Serial Interface (SSI) is a legacy version
> > of HSI. As in the case of HSI, it is mainly used to connect
> > Application engines (APE) with cellular modem engines (CMT)
> > in cellular handsets.
> > 
> > It provides a multichannel, full-duplex, multi-core communication
> > with no reference clock. The OMAP SSI block is capable of reaching
> > speeds of 110 Mbit/s.
> > 
> > Signed-off-by: Carlos Chinea <carlos.chinea@nokia.com>
> > Signed-off-by: Sebastian Reichel <sre@kernel.org>
> 
> > +	bool			wktest:1; /* FIXME: HACK to be removed */
> > +	bool			wkin_cken:1; /* Workaround */
> 
> There is more thanone FIXME in the code. It may be better to fix after
> merge...

I would prefer to keep them in there and have a look after the
merge. Most FIXMEs in the code are for the wakeline test and some
concern the timings. Since the current code works I would prefer
to add it to the mainline kernel and tackle this afterwards.

> > +DEFINE_SIMPLE_ATTRIBUTE(ssi_sst_div_fops, ssi_div_get, ssi_div_set, "%llu\n");
> > +
> > +static int __init ssi_debug_add_port(struct omap_ssi_port *omap_port,
> > +							struct dentry *dir)
> > +{
> 
> A little strange indentation. Is it intentional?
>
> [...] (more ugly indentation cases)

Fixed in v4.

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCHv3 09/14] Documentation: DT: omap-ssi binding documentation
  2014-04-21 16:43   ` Rob Herring
@ 2014-04-25 18:38     ` Sebastian Reichel
  0 siblings, 0 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-04-25 18:38 UTC (permalink / raw)
  To: Rob Herring
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Tony Lindgren,
	Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala, devicetree,
	linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

[-- Attachment #1: Type: text/plain, Size: 4511 bytes --]

Hi,

On Mon, Apr 21, 2014 at 11:43:47AM -0500, Rob Herring wrote:
> On Fri, Mar 28, 2014 at 7:31 PM, Sebastian Reichel <sre@kernel.org> wrote:
> > Create device tree binding documentation for
> > OMAP Synchronous Serial Interface (SSI) device.
> >
> > Signed-off-by: Sebastian Reichel <sre@kernel.org>
> > ---
> >  Documentation/devicetree/bindings/hsi/omap-ssi.txt | 85 ++++++++++++++++++++++
> >  1 file changed, 85 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/hsi/omap-ssi.txt
> >
> > diff --git a/Documentation/devicetree/bindings/hsi/omap-ssi.txt b/Documentation/devicetree/bindings/hsi/omap-ssi.txt
> > new file mode 100644
> > index 0000000..709419b
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/hsi/omap-ssi.txt
> > @@ -0,0 +1,85 @@
> > +OMAP SSI controller bindings
> > +
> > +OMAP Synchronous Serial Interface (SSI) controller implements a legacy
> > +variant of MIPI's High Speed Synchronous Serial Interface (HSI).
> > +
> > +Required properties:
> > +- compatible:          Should include "ti,omap3-ssi".
> > +- reg-names:           Contains the values "sys" and "gdd".
> > +- reg:                 Contains a register specifier for each entry in
> > +                       reg-names.
> 
> You need to define the order here unless you have a strong
> argument why you can't.

ok.

> > +- interrupt-names:      Contains the value "gdd_mpu".
> > +- interrupts:          Contains interrupt information for each entry in
> > +                       interrupt-names.
> > +- ranges:              Represents the bus address mapping between the main
> > +                       controller node and the child nodes below.
> > +- clocks:              Contains clock specifiers for each entry in
> > +                        clock-names.
> > +- clock-names:         Must include the following entries:
> > +  "ssi_ssr_fck": The OMAP clock of that name
> > +  "ssi_sst_fck": The OMAP clock of that name
> > +  "ssi_ick": The OMAP clock of that name
> > +- #address-cells:      Should be set to <1>
> > +- #size-cells:         Should be set to <1>
> > +
> > +Each port is represented as a sub-node of the ti,omap3-ssi device.
> > +
> > +Required Port sub-node properties:
> > +- compatible:          Should be set to the following value
> > +                        ti,omap3-ssi-port (applicable to OMAP34xx devices)
> > +- reg-names:           Contains the values "rx" and "tx".
> > +- reg:                 Contains a register specifier for each entry in
> > +                       reg-names.
> 
> You need to define the order here unless you have a strong argument
> why you can't.

ok.

> > +- interrupt-parent     Should be a phandle for the interrupt controller
> > +- interrupt-names:     Contains the values "mpu_irq0" and "mpu_irq1".
> 
> Those names aren't exactly useful.

I removed interrupt-names in PATCHv4.

> > +- interrupts:          Contains interrupt information for each entry in
> > +                       interrupt-names.
> 
> You need to define the order here unless you have a strong argument
> why you can't.

ok.

> > +- ti,ssi-cawake-gpio:  Defines which GPIO pin is used to signify CAWAKE
> > +                       events for the port. This is an optional board-specific
> > +                       property. If it's missing the port will not be
> > +                       enabled.
> > +
> > +Example for Nokia N900:
> > +
> > +ssi-controller@48058000 {
> > +       compatible = "ti,omap3-ssi";
> > +
> > +       /* needed until hwmod is updated to use the compatible string */
> > +       ti,hwmods = "ssi";
> > +
> > +       reg = <0x48058000 0x1000>,
> > +             <0x48059000 0x1000>;
> > +       reg-names = "sys",
> > +                   "gdd";
> > +
> > +       interrupts = <55>;
> > +       interrupt-names = "gdd_mpu";
> > +
> > +       clocks = <&ssi_ssr_fck>,
> > +                <&ssi_sst_fck>,
> > +                <&ssi_ick>;
> > +       clock-names = "ssi_ssr_fck",
> > +                     "ssi_sst_fck",
> > +                     "ssi_ick";
> > +
> > +       #address-cells = <1>;
> > +       #size-cells = <1>;
> > +       ranges;
> > +
> > +       ssi-port@0 {
> 
> Does this h/w really have more than 1 port?

Yes. I added this to the example in PATCHv4.

> This should really be "ssi-port@4805a800" Or you need to fill in
> ranges to have a local offset.

ok.

>> [...]

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCHv3 10/14] HSI: Introduce driver for SSI Protocol
@ 2014-04-25 18:49       ` Sebastian Reichel
  0 siblings, 0 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-04-25 18:49 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Tony Lindgren,
	Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala, devicetree,
	linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Carlos Chinea

[-- Attachment #1: Type: text/plain, Size: 1598 bytes --]

On Sat, Apr 19, 2014 at 09:49:36PM +0200, Pavel Machek wrote:
> Hi!
> 
> > This adds a driver for the SSI McSAAB protocol as used in
> > the Nokia N900.
> > 
> > Signed-off-by: Carlos Chinea <carlos.chinea@nokia.com>
> > Signed-off-by: Sebastian Reichel <sre@kernel.org>
> 
> > +#define SSIP_MIN_PN_HDR		6	/* FIXME: Revisit */
> > +#define SSIP_WDTOUT		2000	/* FIXME: has to be 500 msecs> */
> 
> Can they be fixed now, or do they have to wait?

I would prefer to wait. The timing above works and having it in the
git history doesn't hurt.

> > +#ifdef __LITTLE_ENDIAN
> > +	((u16 *)skb->data)[2] = swab16(((u16 *)skb->data)[2]);
> > +	dev_dbg(&dev->dev, "RX length fixed (%04x -> %u)\n",
> > +			((u16 *)skb->data)[2], ntohs(((u16 *)skb->data)[2]));
> > +#endif
> 
> Uh. Can this be replaced by
>     ((u16 *)skb->data)[2] = htons(((u16 *)skb->data)[2]);
> 
> (without the ifdef?)

Yes.

> > +	/*
> > +	 * Modem sends Phonet messages over SSI with its own endianess...
> > +	 * Assume that modem has the same endianess as we do.
> > +	 */
> > +	if (skb_cow_head(skb, 0))
> > +		goto drop;
> > +#ifdef __LITTLE_ENDIAN
> > +	((u16 *)skb->data)[2] = swab16(((u16 *)skb->data)[2]);
> > +#endif
> 
> Here, too?

Fixed in PATCHv4.

> But it looks like the comment does not match the code, because we
> swap.

The swap only converts the package length field from/to network byte
order. I think the comment still applies for the other actual message.

I added a comment for the length field and kept the other comment as
is for PATCHv4.

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCHv3 10/14] HSI: Introduce driver for SSI Protocol
@ 2014-04-25 18:49       ` Sebastian Reichel
  0 siblings, 0 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-04-25 18:49 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Tony Lindgren,
	Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen, Carlos Chinea

[-- Attachment #1: Type: text/plain, Size: 1657 bytes --]

On Sat, Apr 19, 2014 at 09:49:36PM +0200, Pavel Machek wrote:
> Hi!
> 
> > This adds a driver for the SSI McSAAB protocol as used in
> > the Nokia N900.
> > 
> > Signed-off-by: Carlos Chinea <carlos.chinea-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
> > Signed-off-by: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> 
> > +#define SSIP_MIN_PN_HDR		6	/* FIXME: Revisit */
> > +#define SSIP_WDTOUT		2000	/* FIXME: has to be 500 msecs> */
> 
> Can they be fixed now, or do they have to wait?

I would prefer to wait. The timing above works and having it in the
git history doesn't hurt.

> > +#ifdef __LITTLE_ENDIAN
> > +	((u16 *)skb->data)[2] = swab16(((u16 *)skb->data)[2]);
> > +	dev_dbg(&dev->dev, "RX length fixed (%04x -> %u)\n",
> > +			((u16 *)skb->data)[2], ntohs(((u16 *)skb->data)[2]));
> > +#endif
> 
> Uh. Can this be replaced by
>     ((u16 *)skb->data)[2] = htons(((u16 *)skb->data)[2]);
> 
> (without the ifdef?)

Yes.

> > +	/*
> > +	 * Modem sends Phonet messages over SSI with its own endianess...
> > +	 * Assume that modem has the same endianess as we do.
> > +	 */
> > +	if (skb_cow_head(skb, 0))
> > +		goto drop;
> > +#ifdef __LITTLE_ENDIAN
> > +	((u16 *)skb->data)[2] = swab16(((u16 *)skb->data)[2]);
> > +#endif
> 
> Here, too?

Fixed in PATCHv4.

> But it looks like the comment does not match the code, because we
> swap.

The swap only converts the package length field from/to network byte
order. I think the comment still applies for the other actual message.

I added a comment for the length field and kept the other comment as
is for PATCHv4.

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices
@ 2014-04-25 20:59         ` Sebastian Reichel
  0 siblings, 0 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-04-25 20:59 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Tony Lindgren,
	Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala, devicetree,
	linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

[-- Attachment #1: Type: text/plain, Size: 1611 bytes --]

On Fri, Apr 25, 2014 at 08:25:36PM +0200, Sebastian Reichel wrote:
> On Sat, Apr 19, 2014 at 09:16:12PM +0200, Pavel Machek wrote:
> > On Sat 2014-03-29 01:31:43, Sebastian Reichel wrote:
> > > Implement and document generic DT bindings for HSI clients.
> > > 
> > > Signed-off-by: Sebastian Reichel <sre@kernel.org>
> > 
> > Reviewed-by: Pavel Machek <pavel@ucw.cz>
> > 
> > > diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
> > > index 07e1639..5973906 100644
> > > --- a/drivers/hsi/hsi.c
> > > +++ b/drivers/hsi/hsi.c
> > > @@ -26,8 +26,14 @@
> > >  #include <linux/slab.h>
> > >  #include <linux/string.h>
> > >  #include <linux/notifier.h>
> > > +#include <linux/of.h>
> > > +#include <linux/of_device.h>
> > >  #include "hsi_core.h"
> > 
> > 
> > > +	err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
> > > +	if (err) {
> > > +		err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
> > > +						 &cl->rx_cfg.mode);
> > > +		if (err)
> > > +			goto err;
> > > +
> > > +		err = hsi_of_property_parse_mode(client, "hsi-tx-mode",
> > > +						 &cl->tx_cfg.mode);
> > > +		if (err)
> > > +			goto err;
> > 
> > Will this need some #ifdef CONFIG_OF?
> 
> It would only be needed to reduce the amount of kernel code for
> disabled Device Tree. I don't think its worth it, since there is no
> platform in the mainline kernel, which uses HSI without DT.

mh actually it is needed, since there is no stub provided for
of_modalias_node in non DT mode (there are stubs for all other
of_* methods used). I will include the ifdef in PATCHv5.

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices
@ 2014-04-25 20:59         ` Sebastian Reichel
  0 siblings, 0 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-04-25 20:59 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Tony Lindgren,
	Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

[-- Attachment #1: Type: text/plain, Size: 1662 bytes --]

On Fri, Apr 25, 2014 at 08:25:36PM +0200, Sebastian Reichel wrote:
> On Sat, Apr 19, 2014 at 09:16:12PM +0200, Pavel Machek wrote:
> > On Sat 2014-03-29 01:31:43, Sebastian Reichel wrote:
> > > Implement and document generic DT bindings for HSI clients.
> > > 
> > > Signed-off-by: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> > 
> > Reviewed-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
> > 
> > > diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
> > > index 07e1639..5973906 100644
> > > --- a/drivers/hsi/hsi.c
> > > +++ b/drivers/hsi/hsi.c
> > > @@ -26,8 +26,14 @@
> > >  #include <linux/slab.h>
> > >  #include <linux/string.h>
> > >  #include <linux/notifier.h>
> > > +#include <linux/of.h>
> > > +#include <linux/of_device.h>
> > >  #include "hsi_core.h"
> > 
> > 
> > > +	err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
> > > +	if (err) {
> > > +		err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
> > > +						 &cl->rx_cfg.mode);
> > > +		if (err)
> > > +			goto err;
> > > +
> > > +		err = hsi_of_property_parse_mode(client, "hsi-tx-mode",
> > > +						 &cl->tx_cfg.mode);
> > > +		if (err)
> > > +			goto err;
> > 
> > Will this need some #ifdef CONFIG_OF?
> 
> It would only be needed to reduce the amount of kernel code for
> disabled Device Tree. I don't think its worth it, since there is no
> platform in the mainline kernel, which uses HSI without DT.

mh actually it is needed, since there is no stub provided for
of_modalias_node in non DT mode (there are stubs for all other
of_* methods used). I will include the ifdef in PATCHv5.

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices
@ 2014-04-27 10:57           ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-27 10:57 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Tony Lindgren,
	Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala, devicetree,
	linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Fri 2014-04-25 22:59:27, Sebastian Reichel wrote:
> On Fri, Apr 25, 2014 at 08:25:36PM +0200, Sebastian Reichel wrote:
> > On Sat, Apr 19, 2014 at 09:16:12PM +0200, Pavel Machek wrote:
> > > On Sat 2014-03-29 01:31:43, Sebastian Reichel wrote:
> > > > Implement and document generic DT bindings for HSI clients.
> > > > 
> > > > Signed-off-by: Sebastian Reichel <sre@kernel.org>
> > > 
> > > Reviewed-by: Pavel Machek <pavel@ucw.cz>
> > > 
> > > > diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
> > > > index 07e1639..5973906 100644
> > > > --- a/drivers/hsi/hsi.c
> > > > +++ b/drivers/hsi/hsi.c
> > > > @@ -26,8 +26,14 @@
> > > >  #include <linux/slab.h>
> > > >  #include <linux/string.h>
> > > >  #include <linux/notifier.h>
> > > > +#include <linux/of.h>
> > > > +#include <linux/of_device.h>
> > > >  #include "hsi_core.h"
> > > 
> > > 
> > > > +	err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
> > > > +	if (err) {
> > > > +		err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
> > > > +						 &cl->rx_cfg.mode);
> > > > +		if (err)
> > > > +			goto err;
> > > > +
> > > > +		err = hsi_of_property_parse_mode(client, "hsi-tx-mode",
> > > > +						 &cl->tx_cfg.mode);
> > > > +		if (err)
> > > > +			goto err;
> > > 
> > > Will this need some #ifdef CONFIG_OF?
> > 
> > It would only be needed to reduce the amount of kernel code for
> > disabled Device Tree. I don't think its worth it, since there is no
> > platform in the mainline kernel, which uses HSI without DT.
> 
> mh actually it is needed, since there is no stub provided for
> of_modalias_node in non DT mode (there are stubs for all other
> of_* methods used). I will include the ifdef in PATCHv5.

Alternatively, you can make driver depend on DT...

Thanks,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices
@ 2014-04-27 10:57           ` Pavel Machek
  0 siblings, 0 replies; 54+ messages in thread
From: Pavel Machek @ 2014-04-27 10:57 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Tony Lindgren,
	Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

On Fri 2014-04-25 22:59:27, Sebastian Reichel wrote:
> On Fri, Apr 25, 2014 at 08:25:36PM +0200, Sebastian Reichel wrote:
> > On Sat, Apr 19, 2014 at 09:16:12PM +0200, Pavel Machek wrote:
> > > On Sat 2014-03-29 01:31:43, Sebastian Reichel wrote:
> > > > Implement and document generic DT bindings for HSI clients.
> > > > 
> > > > Signed-off-by: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> > > 
> > > Reviewed-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
> > > 
> > > > diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
> > > > index 07e1639..5973906 100644
> > > > --- a/drivers/hsi/hsi.c
> > > > +++ b/drivers/hsi/hsi.c
> > > > @@ -26,8 +26,14 @@
> > > >  #include <linux/slab.h>
> > > >  #include <linux/string.h>
> > > >  #include <linux/notifier.h>
> > > > +#include <linux/of.h>
> > > > +#include <linux/of_device.h>
> > > >  #include "hsi_core.h"
> > > 
> > > 
> > > > +	err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
> > > > +	if (err) {
> > > > +		err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
> > > > +						 &cl->rx_cfg.mode);
> > > > +		if (err)
> > > > +			goto err;
> > > > +
> > > > +		err = hsi_of_property_parse_mode(client, "hsi-tx-mode",
> > > > +						 &cl->tx_cfg.mode);
> > > > +		if (err)
> > > > +			goto err;
> > > 
> > > Will this need some #ifdef CONFIG_OF?
> > 
> > It would only be needed to reduce the amount of kernel code for
> > disabled Device Tree. I don't think its worth it, since there is no
> > platform in the mainline kernel, which uses HSI without DT.
> 
> mh actually it is needed, since there is no stub provided for
> of_modalias_node in non DT mode (there are stubs for all other
> of_* methods used). I will include the ifdef in PATCHv5.

Alternatively, you can make driver depend on DT...

Thanks,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices
@ 2014-04-27 11:33             ` Sebastian Reichel
  0 siblings, 0 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-04-27 11:33 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Tony Lindgren,
	Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala, devicetree,
	linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

[-- Attachment #1: Type: text/plain, Size: 2135 bytes --]

On Sun, Apr 27, 2014 at 12:57:55PM +0200, Pavel Machek wrote:
> On Fri 2014-04-25 22:59:27, Sebastian Reichel wrote:
> > On Fri, Apr 25, 2014 at 08:25:36PM +0200, Sebastian Reichel wrote:
> > > On Sat, Apr 19, 2014 at 09:16:12PM +0200, Pavel Machek wrote:
> > > > On Sat 2014-03-29 01:31:43, Sebastian Reichel wrote:
> > > > > Implement and document generic DT bindings for HSI clients.
> > > > > 
> > > > > Signed-off-by: Sebastian Reichel <sre@kernel.org>
> > > > 
> > > > Reviewed-by: Pavel Machek <pavel@ucw.cz>
> > > > 
> > > > > diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
> > > > > index 07e1639..5973906 100644
> > > > > --- a/drivers/hsi/hsi.c
> > > > > +++ b/drivers/hsi/hsi.c
> > > > > @@ -26,8 +26,14 @@
> > > > >  #include <linux/slab.h>
> > > > >  #include <linux/string.h>
> > > > >  #include <linux/notifier.h>
> > > > > +#include <linux/of.h>
> > > > > +#include <linux/of_device.h>
> > > > >  #include "hsi_core.h"
> > > > 
> > > > 
> > > > > +	err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
> > > > > +	if (err) {
> > > > > +		err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
> > > > > +						 &cl->rx_cfg.mode);
> > > > > +		if (err)
> > > > > +			goto err;
> > > > > +
> > > > > +		err = hsi_of_property_parse_mode(client, "hsi-tx-mode",
> > > > > +						 &cl->tx_cfg.mode);
> > > > > +		if (err)
> > > > > +			goto err;
> > > > 
> > > > Will this need some #ifdef CONFIG_OF?
> > > 
> > > It would only be needed to reduce the amount of kernel code for
> > > disabled Device Tree. I don't think its worth it, since there is no
> > > platform in the mainline kernel, which uses HSI without DT.
> > 
> > mh actually it is needed, since there is no stub provided for
> > of_modalias_node in non DT mode (there are stubs for all other
> > of_* methods used). I will include the ifdef in PATCHv5.
> 
> Alternatively, you can make driver depend on DT...

I would be ok with making individual HSI client or controller
drivers dependent on DT, but I don't think its a good idea to make
the whole HSI framework dependent on DT.

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices
@ 2014-04-27 11:33             ` Sebastian Reichel
  0 siblings, 0 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-04-27 11:33 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Tony Lindgren,
	Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

[-- Attachment #1: Type: text/plain, Size: 2186 bytes --]

On Sun, Apr 27, 2014 at 12:57:55PM +0200, Pavel Machek wrote:
> On Fri 2014-04-25 22:59:27, Sebastian Reichel wrote:
> > On Fri, Apr 25, 2014 at 08:25:36PM +0200, Sebastian Reichel wrote:
> > > On Sat, Apr 19, 2014 at 09:16:12PM +0200, Pavel Machek wrote:
> > > > On Sat 2014-03-29 01:31:43, Sebastian Reichel wrote:
> > > > > Implement and document generic DT bindings for HSI clients.
> > > > > 
> > > > > Signed-off-by: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> > > > 
> > > > Reviewed-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
> > > > 
> > > > > diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
> > > > > index 07e1639..5973906 100644
> > > > > --- a/drivers/hsi/hsi.c
> > > > > +++ b/drivers/hsi/hsi.c
> > > > > @@ -26,8 +26,14 @@
> > > > >  #include <linux/slab.h>
> > > > >  #include <linux/string.h>
> > > > >  #include <linux/notifier.h>
> > > > > +#include <linux/of.h>
> > > > > +#include <linux/of_device.h>
> > > > >  #include "hsi_core.h"
> > > > 
> > > > 
> > > > > +	err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
> > > > > +	if (err) {
> > > > > +		err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
> > > > > +						 &cl->rx_cfg.mode);
> > > > > +		if (err)
> > > > > +			goto err;
> > > > > +
> > > > > +		err = hsi_of_property_parse_mode(client, "hsi-tx-mode",
> > > > > +						 &cl->tx_cfg.mode);
> > > > > +		if (err)
> > > > > +			goto err;
> > > > 
> > > > Will this need some #ifdef CONFIG_OF?
> > > 
> > > It would only be needed to reduce the amount of kernel code for
> > > disabled Device Tree. I don't think its worth it, since there is no
> > > platform in the mainline kernel, which uses HSI without DT.
> > 
> > mh actually it is needed, since there is no stub provided for
> > of_modalias_node in non DT mode (there are stubs for all other
> > of_* methods used). I will include the ifdef in PATCHv5.
> 
> Alternatively, you can make driver depend on DT...

I would be ok with making individual HSI client or controller
drivers dependent on DT, but I don't think its a good idea to make
the whole HSI framework dependent on DT.

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCHv3 00/14] OMAP SSI driver / N900 modem support
  2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
                   ` (13 preceding siblings ...)
  2014-03-29  0:31 ` [PATCHv3 14/14] DTS: ARM: OMAP3-N900: Add modem support Sebastian Reichel
@ 2014-05-05 19:31 ` Tony Lindgren
  2014-05-05 22:41   ` Sebastian Reichel
  14 siblings, 1 reply; 54+ messages in thread
From: Tony Lindgren @ 2014-05-05 19:31 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
	Carlos Chinea, Rob Herring, Pawel Moll, Mark Rutland, Kumar Gala,
	devicetree, linux-kernel, linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

* Sebastian Reichel <sre@kernel.org> [140328 17:36]:
> Please send feedback (e.g. Tested-By or Reviewed-By :)), so that I can
> send a pull request for 3.16. You can either apply this patchset or
> use the n900-modem-support branch available on [1].

Sebastian, can you please do a separate pull request for the .dts
changes for me once the driver changes are pulled? Otherwise we
will be creating pointless merge conflicts.

Regards,

Tony

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

* Re: [PATCHv3 00/14] OMAP SSI driver / N900 modem support
  2014-05-05 19:31 ` [PATCHv3 00/14] OMAP SSI driver / N900 " Tony Lindgren
@ 2014-05-05 22:41   ` Sebastian Reichel
  0 siblings, 0 replies; 54+ messages in thread
From: Sebastian Reichel @ 2014-05-05 22:41 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: Linus Walleij, Shubhrajyoti Datta, Carlos Chinea, Rob Herring,
	Pawel Moll, Mark Rutland, Kumar Gala, devicetree, linux-kernel,
	linux-omap, Pali Rohár,
	Ивайло
	Димитров,
	Joni Lapilainen, Aaro Koskinen

[-- Attachment #1: Type: text/plain, Size: 828 bytes --]

On Mon, May 05, 2014 at 12:31:30PM -0700, Tony Lindgren wrote:
> * Sebastian Reichel <sre@kernel.org> [140328 17:36]:
> > Please send feedback (e.g. Tested-By or Reviewed-By :)), so that I can
> > send a pull request for 3.16. You can either apply this patchset or
> > use the n900-modem-support branch available on [1].
> 
> Sebastian, can you please do a separate pull request for the .dts
> changes for me once the driver changes are pulled? Otherwise we
> will be creating pointless merge conflicts.

That was my intention from the beginning. I only added those patches
here to make reviewing the other patches easier.

I'm still missing a reviewed by for the most important patches (ssi
driver, modem protocol driver), though. Can somebody at least test
the patches and provide a Tested-By?

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

end of thread, other threads:[~2014-05-05 22:41 UTC | newest]

Thread overview: 54+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-29  0:31 [PATCHv3 00/14] OMAP SSI driver / N900 modem support Sebastian Reichel
2014-03-29  0:31 ` [PATCHv3 01/14] Documentation: HSI: Add some general description for the HSI subsystem Sebastian Reichel
2014-04-19 19:05   ` Pavel Machek
2014-04-19 19:05     ` Pavel Machek
2014-03-29  0:31 ` [PATCHv3 02/14] MAINTAINERS: update HSI entry Sebastian Reichel
2014-04-19 19:06   ` Pavel Machek
2014-03-29  0:31 ` [PATCHv3 03/14] HSI: hsi-char: fix driver for multiport scenarios Sebastian Reichel
2014-04-19 19:06   ` Pavel Machek
2014-03-29  0:31 ` [PATCHv3 04/14] HSI: method to unregister clients from an hsi port Sebastian Reichel
2014-04-19 19:07   ` Pavel Machek
2014-04-19 19:07     ` Pavel Machek
2014-03-29  0:31 ` [PATCHv3 05/14] HSI: Add channel resource support to HSI clients Sebastian Reichel
2014-04-19 19:11   ` Pavel Machek
2014-04-19 19:11     ` Pavel Machek
2014-04-25 17:32     ` Sebastian Reichel
2014-03-29  0:31 ` [PATCHv3 06/14] HSI: export method to (un)register clients Sebastian Reichel
2014-04-19 19:13   ` Pavel Machek
2014-04-19 19:13     ` Pavel Machek
2014-03-29  0:31 ` [PATCHv3 07/14] HSI: Add common DT binding for HSI client devices Sebastian Reichel
2014-04-19 19:16   ` Pavel Machek
2014-04-19 19:16     ` Pavel Machek
2014-04-25 18:25     ` Sebastian Reichel
2014-04-25 20:59       ` Sebastian Reichel
2014-04-25 20:59         ` Sebastian Reichel
2014-04-27 10:57         ` Pavel Machek
2014-04-27 10:57           ` Pavel Machek
2014-04-27 11:33           ` Sebastian Reichel
2014-04-27 11:33             ` Sebastian Reichel
2014-04-21 16:52   ` Rob Herring
2014-04-25 18:32     ` Sebastian Reichel
2014-03-29  0:31 ` [PATCHv3 08/14] HSI: Introduce OMAP SSI driver Sebastian Reichel
2014-04-19 19:30   ` Pavel Machek
2014-04-19 19:30     ` Pavel Machek
2014-04-25 18:36     ` Sebastian Reichel
2014-03-29  0:31 ` [PATCHv3 09/14] Documentation: DT: omap-ssi binding documentation Sebastian Reichel
2014-04-19 19:32   ` Pavel Machek
2014-04-21 16:43   ` Rob Herring
2014-04-25 18:38     ` Sebastian Reichel
2014-03-29  0:31 ` [PATCHv3 10/14] HSI: Introduce driver for SSI Protocol Sebastian Reichel
2014-04-19 19:49   ` Pavel Machek
2014-04-19 19:49     ` Pavel Machek
2014-04-25 18:49     ` Sebastian Reichel
2014-04-25 18:49       ` Sebastian Reichel
2014-03-29  0:31 ` [PATCHv3 11/14] HSI: Introduce Nokia N900 modem driver Sebastian Reichel
2014-03-29  0:31   ` Sebastian Reichel
2014-04-19 20:25   ` Pavel Machek
2014-03-29  0:31 ` [PATCHv3 12/14] ARM: dts: omap3 clocks: simplify ssi aliases Sebastian Reichel
2014-04-19 20:26   ` Pavel Machek
2014-03-29  0:31 ` [PATCHv3 13/14] DTS: ARM: OMAP3-N900: Add SSI support Sebastian Reichel
2014-04-19 20:28   ` Pavel Machek
2014-03-29  0:31 ` [PATCHv3 14/14] DTS: ARM: OMAP3-N900: Add modem support Sebastian Reichel
2014-04-19 20:28   ` Pavel Machek
2014-05-05 19:31 ` [PATCHv3 00/14] OMAP SSI driver / N900 " Tony Lindgren
2014-05-05 22:41   ` Sebastian Reichel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.