diff options
| -rw-r--r-- | drivers/hsi/clients/hsi_char.c | 12 | ||||
| -rw-r--r-- | drivers/hsi/hsi.c | 46 | ||||
| -rw-r--r-- | 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 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) | |||
| 383 | static inline void hsc_rx_get(struct hsi_client *cl, struct hsc_rx_config *rxc) | 383 | static 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) | |||
| 417 | static inline void hsc_tx_get(struct hsi_client *cl, struct hsc_tx_config *txc) | 417 | static 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 | ||
| 63 | static void hsi_client_release(struct device *dev) | 63 | static 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 | ||
| 68 | static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info) | 72 | static 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 | } |
| 503 | EXPORT_SYMBOL_GPL(hsi_event); | 521 | EXPORT_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 | */ | ||
| 534 | int 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 | } | ||
| 547 | EXPORT_SYMBOL_GPL(hsi_get_channel_id_by_name); | ||
| 548 | |||
| 505 | static int __init hsi_init(void) | 549 | static 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 | */ | ||
| 75 | struct 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 | */ |
| 78 | struct hsi_config { | 90 | struct 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 | */ |
| 307 | int hsi_async(struct hsi_client *cl, struct hsi_msg *msg); | 321 | int hsi_async(struct hsi_client *cl, struct hsi_msg *msg); |
| 308 | 322 | ||
| 323 | int 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 |
