From patchwork Sun Feb 23 23:49:56 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sebastian Reichel X-Patchwork-Id: 3705491 Return-Path: X-Original-To: patchwork-linux-omap@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 40A0D9F35F for ; Sun, 23 Feb 2014 23:52:29 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2252B201DD for ; Sun, 23 Feb 2014 23:52:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 1A778200F4 for ; Sun, 23 Feb 2014 23:52:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752379AbaBWXub (ORCPT ); Sun, 23 Feb 2014 18:50:31 -0500 Received: from ring0.de ([5.45.105.125]:59869 "EHLO smtp.ring0.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751392AbaBWXu3 (ORCPT ); Sun, 23 Feb 2014 18:50:29 -0500 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 From: Sebastian Reichel To: Sebastian Reichel , Linus Walleij , Shubhrajyoti Datta , Carlos Chinea Cc: Tony Lindgren , Grant Likely , Rob Herring , Pawel Moll , Mark Rutland , Stephen Warren , Ian Campbell , Rob Landley , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org, =?UTF-8?q?Pali=20Roh=C3=A1r?= , =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=B9=D0=BB=D0=BE=20=D0=94=D0=B8=D0=BC=D0=B8=D1=82=D1=80=D0=BE=D0=B2?= , Joni Lapilainen , Aaro Koskinen , Sebastian Reichel Subject: [PATCHv1 1/6] HSI: add Device Tree support for HSI clients Date: Mon, 24 Feb 2014 00:49:56 +0100 Message-Id: <1393199401-27197-2-git-send-email-sre@debian.org> X-Mailer: git-send-email 1.8.5.3 In-Reply-To: <1393199401-27197-1-git-send-email-sre@debian.org> References: <1393199401-27197-1-git-send-email-sre@debian.org> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add new method hsi_add_clients_from_dt, which can be used to initialize HSI clients from a device tree node. The patch also documents the DT binding for trivial HSI clients. Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/hsi/trivial-devices.txt | 36 +++++++++++ drivers/hsi/hsi.c | 70 +++++++++++++++++++++- include/dt-bindings/hsi/hsi.h | 17 ++++++ include/linux/hsi/hsi.h | 2 + 4 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/hsi/trivial-devices.txt create mode 100644 include/dt-bindings/hsi/hsi.h diff --git a/Documentation/devicetree/bindings/hsi/trivial-devices.txt b/Documentation/devicetree/bindings/hsi/trivial-devices.txt new file mode 100644 index 0000000..1ace14a --- /dev/null +++ b/Documentation/devicetree/bindings/hsi/trivial-devices.txt @@ -0,0 +1,36 @@ +This is a list of trivial hsi client devices that have simple +device tree bindings, consisting only of a compatible field +and the optional hsi configuration. + +If a device needs more specific bindings, such as properties to +describe some aspect of it, there needs to be a specific binding +document for it just like any other devices. + +Optional HSI configuration properties: + +- hsi,mode Bit transmission mode (STREAM or FRAME) + The first value is used for RX and the second one for + TX configuration. If only one value is provided it will + be used for RX and TX. + The assignments may be found in header file + . +- hsi,channels Number of channels to use [1..16] + The first value is used for RX and the second one for + TX configuration. If only one value is provided it will + be used for RX and TX. +- hsi,speed Max bit transmission speed (Kbit/s) + The first value is used for RX and the second one for + TX configuration. If only one value is provided it will + be used for RX and TX. +- hsi,flow RX flow type (SYNCHRONIZED or PIPELINE) + The assignments may be found in header file + . +- hsi,arb_mode Arbitration mode for TX frame (Round robin, priority) + The assignments may be found in header file + . + +This is the list of trivial client devices: + +Compatible Description +========== ============= +hsi-char HSI character device diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c index 749f7b5..8bbc0f1 100644 --- a/drivers/hsi/hsi.c +++ b/drivers/hsi/hsi.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include "hsi_core.h" static ssize_t modalias_show(struct device *dev, @@ -50,7 +52,10 @@ 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 (dev->of_node != NULL) + return of_driver_match_device(dev, driver); + else + return strcmp(dev_name(dev), driver->name) == 0; } static struct bus_type hsi_bus_type = { @@ -75,6 +80,7 @@ static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info) cl->tx_cfg = info->tx_cfg; cl->rx_cfg = info->rx_cfg; cl->device.bus = &hsi_bus_type; + cl->device.parent = &port->device; cl->device.release = hsi_client_release; dev_set_name(&cl->device, "%s", info->name); @@ -101,6 +107,68 @@ static void hsi_scan_board_info(struct hsi_controller *hsi) } } +static void hsi_of_get_client_cfg_property(struct device_node *client, + char *name, unsigned int *rx, unsigned int *tx) +{ + int err; + + err = of_property_read_u32_index(client, name, 0, rx); + if (err) + *rx = 0; + + err = of_property_read_u32_index(client, name, 1, tx); + if (err) + *tx = *rx; +} + +static void hsi_add_client_from_dt(struct hsi_port *port, + struct device_node *client) +{ + struct hsi_client *cl; + const char *name; + int err; + + cl = kzalloc(sizeof(*cl), GFP_KERNEL); + if (!cl) + return; + + err = of_property_read_string(client, "compatible", &name); + if (!err) { + dev_set_name(&cl->device, "%s", name); + } else { + kfree(cl); + return; + } + + hsi_of_get_client_cfg_property(client, "hsi,mode", &cl->rx_cfg.mode, + &cl->tx_cfg.mode); + hsi_of_get_client_cfg_property(client, "hsi,speed", &cl->rx_cfg.speed, + &cl->tx_cfg.speed); + hsi_of_get_client_cfg_property(client, "hsi,channels", + &cl->rx_cfg.channels, &cl->tx_cfg.channels); + of_property_read_u32(client, "hsi,flow", &cl->rx_cfg.flow); + of_property_read_u32(client, "hsi,arb_mode", &cl->tx_cfg.arb_mode); + + 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); + } +} + +void hsi_add_clients_from_dt(struct hsi_port *port, struct device_node *clients) +{ + struct device_node *child; + + for_each_available_child_of_node(clients, child) + hsi_add_client_from_dt(port, child); +} +EXPORT_SYMBOL_GPL(hsi_add_clients_from_dt); + static int hsi_remove_client(struct device *dev, void *data __maybe_unused) { device_unregister(dev); diff --git a/include/dt-bindings/hsi/hsi.h b/include/dt-bindings/hsi/hsi.h new file mode 100644 index 0000000..2d6b181 --- /dev/null +++ b/include/dt-bindings/hsi/hsi.h @@ -0,0 +1,17 @@ +/* + * This header provides constants for hsi client bindings. + */ + +#ifndef _DT_BINDINGS_HSI_H +#define _DT_BINDINGS_HSI_H + +#define HSI_MODE_STREAM 1 +#define HSI_MODE_FRAME 2 + +#define HSI_FLOW_SYNC 0 +#define HSI_FLOW_PIPE 1 + +#define HSI_ARB_RR 0 +#define HSI_ARB_PRIO 1 + +#endif /* _DT_BINDINGS_HSI_H */ diff --git a/include/linux/hsi/hsi.h b/include/linux/hsi/hsi.h index 0dca785..fb07339 100644 --- a/include/linux/hsi/hsi.h +++ b/include/linux/hsi/hsi.h @@ -282,6 +282,8 @@ 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_add_clients_from_dt(struct hsi_port *port, + struct device_node *clients); static inline void hsi_controller_set_drvdata(struct hsi_controller *hsi, void *data)