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

Signed-off-by: Sebastian Reichel <s...@kernel.org>
Tested-By: Ivaylo Dimitrov <ivo.g.dimitrov...@gmail.com>
---
 drivers/hsi/clients/hsi_char.c | 12 +++++------
 drivers/hsi/hsi.c              | 46 +++++++++++++++++++++++++++++++++++++++++-
 include/linux/hsi/hsi.h        | 24 ++++++++++++++++++----
 3 files changed, 71 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..de2ad8f 100644
--- a/drivers/hsi/hsi.c
+++ b/drivers/hsi/hsi.c
@@ -62,18 +62,36 @@ 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);
+
+       kfree(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 +520,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 5a9f121..e3cff94 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
-- 
2.0.0.rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to