aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Reichel <sre@kernel.org>2014-03-28 17:48:23 -0400
committerSebastian Reichel <sre@kernel.org>2014-05-15 18:54:36 -0400
commita088cf161cc87b39e83c7c53b9f239773422d212 (patch)
treea58304be6d5e9fd06e2739c1485a87a0824db0e6
parenta0bf37edb4d34c21bdaa19a1624378924b917491 (diff)
HSI: Add channel resource support to HSI clients
Make HSI channel ids platform data, which can be provided by platform data. Signed-off-by: Sebastian Reichel <sre@kernel.org> Tested-By: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
-rw-r--r--drivers/hsi/clients/hsi_char.c12
-rw-r--r--drivers/hsi/hsi.c46
-rw-r--r--include/linux/hsi/hsi.h24
3 files changed, 71 insertions, 11 deletions
diff --git a/drivers/hsi/clients/hsi_char.c b/drivers/hsi/clients/hsi_char.c
index 30733209fde2..57f70c28fa38 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)
367 return -EINVAL; 367 return -EINVAL;
368 tmp = cl->rx_cfg; 368 tmp = cl->rx_cfg;
369 cl->rx_cfg.mode = rxc->mode; 369 cl->rx_cfg.mode = rxc->mode;
370 cl->rx_cfg.channels = rxc->channels; 370 cl->rx_cfg.num_hw_channels = rxc->channels;
371 cl->rx_cfg.flow = rxc->flow; 371 cl->rx_cfg.flow = rxc->flow;
372 ret = hsi_setup(cl); 372 ret = hsi_setup(cl);
373 if (ret < 0) { 373 if (ret < 0) {
@@ -383,7 +383,7 @@ static int hsc_rx_set(struct hsi_client *cl, struct hsc_rx_config *rxc)
383static inline void hsc_rx_get(struct hsi_client *cl, struct hsc_rx_config *rxc) 383static inline void hsc_rx_get(struct hsi_client *cl, struct hsc_rx_config *rxc)
384{ 384{
385 rxc->mode = cl->rx_cfg.mode; 385 rxc->mode = cl->rx_cfg.mode;
386 rxc->channels = cl->rx_cfg.channels; 386 rxc->channels = cl->rx_cfg.num_hw_channels;
387 rxc->flow = cl->rx_cfg.flow; 387 rxc->flow = cl->rx_cfg.flow;
388} 388}
389 389
@@ -402,7 +402,7 @@ static int hsc_tx_set(struct hsi_client *cl, struct hsc_tx_config *txc)
402 return -EINVAL; 402 return -EINVAL;
403 tmp = cl->tx_cfg; 403 tmp = cl->tx_cfg;
404 cl->tx_cfg.mode = txc->mode; 404 cl->tx_cfg.mode = txc->mode;
405 cl->tx_cfg.channels = txc->channels; 405 cl->tx_cfg.num_hw_channels = txc->channels;
406 cl->tx_cfg.speed = txc->speed; 406 cl->tx_cfg.speed = txc->speed;
407 cl->tx_cfg.arb_mode = txc->arb_mode; 407 cl->tx_cfg.arb_mode = txc->arb_mode;
408 ret = hsi_setup(cl); 408 ret = hsi_setup(cl);
@@ -417,7 +417,7 @@ static int hsc_tx_set(struct hsi_client *cl, struct hsc_tx_config *txc)
417static inline void hsc_tx_get(struct hsi_client *cl, struct hsc_tx_config *txc) 417static inline void hsc_tx_get(struct hsi_client *cl, struct hsc_tx_config *txc)
418{ 418{
419 txc->mode = cl->tx_cfg.mode; 419 txc->mode = cl->tx_cfg.mode;
420 txc->channels = cl->tx_cfg.channels; 420 txc->channels = cl->tx_cfg.num_hw_channels;
421 txc->speed = cl->tx_cfg.speed; 421 txc->speed = cl->tx_cfg.speed;
422 txc->arb_mode = cl->tx_cfg.arb_mode; 422 txc->arb_mode = cl->tx_cfg.arb_mode;
423} 423}
@@ -435,7 +435,7 @@ static ssize_t hsc_read(struct file *file, char __user *buf, size_t len,
435 return -EINVAL; 435 return -EINVAL;
436 if (len > max_data_size) 436 if (len > max_data_size)
437 len = max_data_size; 437 len = max_data_size;
438 if (channel->ch >= channel->cl->rx_cfg.channels) 438 if (channel->ch >= channel->cl->rx_cfg.num_hw_channels)
439 return -ECHRNG; 439 return -ECHRNG;
440 if (test_and_set_bit(HSC_CH_READ, &channel->flags)) 440 if (test_and_set_bit(HSC_CH_READ, &channel->flags))
441 return -EBUSY; 441 return -EBUSY;
@@ -492,7 +492,7 @@ static ssize_t hsc_write(struct file *file, const char __user *buf, size_t len,
492 return -EINVAL; 492 return -EINVAL;
493 if (len > max_data_size) 493 if (len > max_data_size)
494 len = max_data_size; 494 len = max_data_size;
495 if (channel->ch >= channel->cl->tx_cfg.channels) 495 if (channel->ch >= channel->cl->tx_cfg.num_hw_channels)
496 return -ECHRNG; 496 return -ECHRNG;
497 if (test_and_set_bit(HSC_CH_WRITE, &channel->flags)) 497 if (test_and_set_bit(HSC_CH_WRITE, &channel->flags))
498 return -EBUSY; 498 return -EBUSY;
diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
index e96a9874b1a4..de2ad8f20d55 100644
--- a/drivers/hsi/hsi.c
+++ b/drivers/hsi/hsi.c
@@ -62,18 +62,36 @@ static struct bus_type hsi_bus_type = {
62 62
63static void hsi_client_release(struct device *dev) 63static void hsi_client_release(struct device *dev)
64{ 64{
65 kfree(to_hsi_client(dev)); 65 struct hsi_client *cl = to_hsi_client(dev);
66
67 kfree(cl->tx_cfg.channels);
68 kfree(cl->rx_cfg.channels);
69 kfree(cl);
66} 70}
67 71
68static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info) 72static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info)
69{ 73{
70 struct hsi_client *cl; 74 struct hsi_client *cl;
75 size_t size;
71 76
72 cl = kzalloc(sizeof(*cl), GFP_KERNEL); 77 cl = kzalloc(sizeof(*cl), GFP_KERNEL);
73 if (!cl) 78 if (!cl)
74 return; 79 return;
80
75 cl->tx_cfg = info->tx_cfg; 81 cl->tx_cfg = info->tx_cfg;
82 if (cl->tx_cfg.channels) {
83 size = cl->tx_cfg.num_channels * sizeof(*cl->tx_cfg.channels);
84 cl->tx_cfg.channels = kzalloc(size , GFP_KERNEL);
85 memcpy(cl->tx_cfg.channels, info->tx_cfg.channels, size);
86 }
87
76 cl->rx_cfg = info->rx_cfg; 88 cl->rx_cfg = info->rx_cfg;
89 if (cl->rx_cfg.channels) {
90 size = cl->rx_cfg.num_channels * sizeof(*cl->rx_cfg.channels);
91 cl->rx_cfg.channels = kzalloc(size , GFP_KERNEL);
92 memcpy(cl->rx_cfg.channels, info->rx_cfg.channels, size);
93 }
94
77 cl->device.bus = &hsi_bus_type; 95 cl->device.bus = &hsi_bus_type;
78 cl->device.parent = &port->device; 96 cl->device.parent = &port->device;
79 cl->device.release = hsi_client_release; 97 cl->device.release = hsi_client_release;
@@ -502,6 +520,32 @@ int hsi_event(struct hsi_port *port, unsigned long event)
502} 520}
503EXPORT_SYMBOL_GPL(hsi_event); 521EXPORT_SYMBOL_GPL(hsi_event);
504 522
523/**
524 * hsi_get_channel_id_by_name - acquire channel id by channel name
525 * @cl: HSI client, which uses the channel
526 * @name: name the channel is known under
527 *
528 * Clients can call this function to get the hsi channel ids similar to
529 * requesting IRQs or GPIOs by name. This function assumes the same
530 * channel configuration is used for RX and TX.
531 *
532 * Returns -errno on error or channel id on success.
533 */
534int hsi_get_channel_id_by_name(struct hsi_client *cl, char *name)
535{
536 int i;
537
538 if (!cl->rx_cfg.channels)
539 return -ENOENT;
540
541 for (i = 0; i < cl->rx_cfg.num_channels; i++)
542 if (!strcmp(cl->rx_cfg.channels[i].name, name))
543 return cl->rx_cfg.channels[i].id;
544
545 return -ENXIO;
546}
547EXPORT_SYMBOL_GPL(hsi_get_channel_id_by_name);
548
505static int __init hsi_init(void) 549static int __init hsi_init(void)
506{ 550{
507 return bus_register(&hsi_bus_type); 551 return bus_register(&hsi_bus_type);
diff --git a/include/linux/hsi/hsi.h b/include/linux/hsi/hsi.h
index 5a9f1210ed22..e3cff94bef04 100644
--- a/include/linux/hsi/hsi.h
+++ b/include/linux/hsi/hsi.h
@@ -68,17 +68,31 @@ enum {
68}; 68};
69 69
70/** 70/**
71 * struct hsi_channel - channel resource used by the hsi clients
72 * @id: Channel number
73 * @name: Channel name
74 */
75struct hsi_channel {
76 unsigned int id;
77 const char *name;
78};
79
80/**
71 * struct hsi_config - Configuration for RX/TX HSI modules 81 * struct hsi_config - Configuration for RX/TX HSI modules
72 * @mode: Bit transmission mode (STREAM or FRAME) 82 * @mode: Bit transmission mode (STREAM or FRAME)
73 * @channels: Number of channels to use [1..16] 83 * @channels: Channel resources used by the client
84 * @num_channels: Number of channel resources
85 * @num_hw_channels: Number of channels the transceiver is configured for [1..16]
74 * @speed: Max bit transmission speed (Kbit/s) 86 * @speed: Max bit transmission speed (Kbit/s)
75 * @flow: RX flow type (SYNCHRONIZED or PIPELINE) 87 * @flow: RX flow type (SYNCHRONIZED or PIPELINE)
76 * @arb_mode: Arbitration mode for TX frame (Round robin, priority) 88 * @arb_mode: Arbitration mode for TX frame (Round robin, priority)
77 */ 89 */
78struct hsi_config { 90struct hsi_config {
79 unsigned int mode; 91 unsigned int mode;
80 unsigned int channels; 92 struct hsi_channel *channels;
81 unsigned int speed; 93 unsigned int num_channels;
94 unsigned int num_hw_channels;
95 unsigned int speed;
82 union { 96 union {
83 unsigned int flow; /* RX only */ 97 unsigned int flow; /* RX only */
84 unsigned int arb_mode; /* TX only */ 98 unsigned int arb_mode; /* TX only */
@@ -306,6 +320,8 @@ static inline struct hsi_port *hsi_find_port_num(struct hsi_controller *hsi,
306 */ 320 */
307int hsi_async(struct hsi_client *cl, struct hsi_msg *msg); 321int hsi_async(struct hsi_client *cl, struct hsi_msg *msg);
308 322
323int hsi_get_channel_id_by_name(struct hsi_client *cl, char *name);
324
309/** 325/**
310 * hsi_id - Get HSI controller ID associated to a client 326 * hsi_id - Get HSI controller ID associated to a client
311 * @cl: Pointer to a HSI client 327 * @cl: Pointer to a HSI client