From: Sebastian Reichel <sre@kernel.org>
To: Sebastian Reichel <sre@kernel.org>,
Linus Walleij <linus.walleij@linaro.org>,
Shubhrajyoti Datta <omaplinuxkernel@gmail.com>,
Carlos Chinea <cch.devel@gmail.com>
Cc: "Tony Lindgren" <tony@atomide.com>,
"Rob Herring" <robh+dt@kernel.org>,
"Pawel Moll" <pawel.moll@arm.com>,
"Mark Rutland" <mark.rutland@arm.com>,
"Kumar Gala" <galak@codeaurora.org>,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-omap@vger.kernel.org, "Pali Rohár" <pali.rohar@gmail.com>,
"Ивайло Димитров" <freemangordon@abv.bg>,
"Joni Lapilainen" <joni.lapilainen@gmail.com>,
"Aaro Koskinen" <aaro.koskinen@iki.fi>,
"Pavel Machek" <pavel@ucw.cz>
Subject: [PATCHv5 04/10] HSI: Add common DT binding for HSI client devices
Date: Sat, 10 May 2014 18:37:44 +0200 [thread overview]
Message-ID: <1399739870-13526-5-git-send-email-sre@kernel.org> (raw)
In-Reply-To: <1399739870-13526-1-git-send-email-sre@kernel.org>
Implement and document generic DT bindings for HSI clients.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
Reviewed-by: Pavel Machek <pavel@ucw.cz>
Tested-By: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
---
.../devicetree/bindings/hsi/client-devices.txt | 44 +++++
drivers/hsi/hsi.c | 208 ++++++++++++++++++++-
include/linux/hsi/hsi.h | 11 ++
3 files changed, 261 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..104c9a3
--- /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:
+
+- hsi-channel-ids: 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:
+
+- hsi-channel-names: A list with one name per channel specified in the
+ hsi-channel-ids property
+
+
+Device Tree node example for an HSI client:
+
+hsi-controller {
+ hsi-port {
+ modem: hsi-client {
+ compatible = "nokia,n900-modem";
+
+ hsi-channel-ids = <0>, <1>, <2>, <3>;
+ hsi-channel-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 834a2d6..fe93712 100644
--- a/drivers/hsi/hsi.c
+++ b/drivers/hsi/hsi.c
@@ -26,6 +26,8 @@
#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 ssize_t modalias_show(struct device *dev,
@@ -50,7 +52,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 = {
@@ -123,6 +131,202 @@ static void hsi_scan_board_info(struct hsi_controller *hsi)
}
}
+#ifdef CONFIG_OF
+static struct hsi_board_info hsi_char_dev_info = {
+ .name = "hsi_char",
+};
+
+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 channel;
+ 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, "hsi-channel-ids", &length);
+ if (!prop) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ cells = length / sizeof(u32);
+
+ cl->rx_cfg.num_channels = cells;
+ cl->tx_cfg.num_channels = cells;
+
+ cl->rx_cfg.channels = kzalloc(cells * sizeof(channel), GFP_KERNEL);
+ if (!cl->rx_cfg.channels) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ cl->tx_cfg.channels = kzalloc(cells * sizeof(channel), GFP_KERNEL);
+ if (!cl->tx_cfg.channels) {
+ err = -ENOMEM;
+ goto err2;
+ }
+
+ max_chan = 0;
+ for (i = 0; i < cells; i++) {
+ err = of_property_read_u32_index(client, "hsi-channel-ids", i,
+ &channel.id);
+ if (err)
+ goto err3;
+
+ err = of_property_read_string_index(client, "hsi-channel-names",
+ i, &channel.name);
+ if (err)
+ channel.name = NULL;
+
+ if (channel.id > max_chan)
+ max_chan = channel.id;
+
+ cl->rx_cfg.channels[i] = channel;
+ cl->tx_cfg.channels[i] = channel;
+ }
+
+ 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 err3;
+ }
+
+ return;
+
+err3:
+ kfree(cl->tx_cfg.channels);
+err2:
+ kfree(cl->rx_cfg.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);
+#endif
+
int hsi_remove_client(struct device *dev, void *data __maybe_unused)
{
device_unregister(dev);
@@ -505,7 +709,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 e20a399..3ec0630 100644
--- a/include/linux/hsi/hsi.h
+++ b/include/linux/hsi/hsi.h
@@ -301,6 +301,17 @@ struct hsi_client *hsi_new_client(struct hsi_port *port,
int hsi_remove_client(struct device *dev, void *data);
void hsi_port_unregister_clients(struct hsi_port *port);
+#ifdef CONFIG_OF
+void hsi_add_clients_from_dt(struct hsi_port *port,
+ struct device_node *clients);
+#else
+static inline void hsi_add_clients_from_dt(struct hsi_port *port,
+ struct device_node *clients)
+{
+ return;
+}
+#endif
+
static inline void hsi_controller_set_drvdata(struct hsi_controller *hsi,
void *data)
{
--
2.0.0.rc0
next prev parent reply other threads:[~2014-05-10 16:38 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-05-10 16:37 [PATCHv5 00/10] OMAP SSI driver / N900 modem support Sebastian Reichel
2014-05-10 16:37 ` [PATCHv5 01/10] HSI: method to unregister clients from an hsi port Sebastian Reichel
2014-05-10 16:37 ` [PATCHv5 02/10] HSI: Add channel resource support to HSI clients Sebastian Reichel
2014-05-10 16:37 ` [PATCHv5 03/10] HSI: export method to (un)register clients Sebastian Reichel
2014-05-10 16:37 ` Sebastian Reichel [this message]
2014-05-10 16:37 ` [PATCHv5 05/10] HSI: Introduce OMAP SSI driver Sebastian Reichel
2014-05-10 16:37 ` [PATCHv5 06/10] Documentation: DT: omap-ssi binding documentation Sebastian Reichel
2014-05-10 16:37 ` [PATCHv5 07/10] HSI: Introduce driver for SSI Protocol Sebastian Reichel
2014-05-10 16:37 ` [PATCHv5 08/10] HSI: Introduce Nokia N900 modem driver Sebastian Reichel
2014-05-10 16:37 ` [PATCHv5 09/10] DTS: ARM: OMAP3-N900: Add SSI support Sebastian Reichel
2014-05-14 21:55 ` Tony Lindgren
2014-05-20 0:35 ` Tony Lindgren
2014-05-21 18:25 ` Sebastian Reichel
2014-05-21 18:43 ` Tony Lindgren
2014-05-21 19:45 ` Tony Lindgren
2014-05-21 21:50 ` Sebastian Reichel
2014-05-21 22:08 ` Tony Lindgren
2014-05-22 0:05 ` Sebastian Reichel
[not found] ` <20140522000558.GC29118-SfvFxonMDyemK9LvCR3Hrw@public.gmane.org>
2014-05-27 20:35 ` Tony Lindgren
2014-05-27 20:35 ` Tony Lindgren
2014-05-27 20:47 ` Sebastian Reichel
[not found] ` <20140521184319.GL17417-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
2014-05-21 20:09 ` Sebastian Reichel
2014-05-21 20:09 ` Sebastian Reichel
2014-05-21 21:09 ` Tony Lindgren
2014-05-10 16:37 ` [PATCHv5 10/10] DTS: ARM: OMAP3-N900: Add modem support Sebastian Reichel
2014-05-14 21:55 ` Tony Lindgren
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1399739870-13526-5-git-send-email-sre@kernel.org \
--to=sre@kernel.org \
--cc=aaro.koskinen@iki.fi \
--cc=cch.devel@gmail.com \
--cc=devicetree@vger.kernel.org \
--cc=freemangordon@abv.bg \
--cc=galak@codeaurora.org \
--cc=joni.lapilainen@gmail.com \
--cc=linus.walleij@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-omap@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=omaplinuxkernel@gmail.com \
--cc=pali.rohar@gmail.com \
--cc=pavel@ucw.cz \
--cc=pawel.moll@arm.com \
--cc=robh+dt@kernel.org \
--cc=tony@atomide.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.