Commit a088cf16 authored by Sebastian Reichel's avatar Sebastian Reichel

HSI: Add channel resource support to HSI clients

Make HSI channel ids platform data, which can be provided
by platform data.
Signed-off-by: default avatarSebastian Reichel <sre@kernel.org>
Tested-By: default avatarIvaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
parent a0bf37ed
...@@ -367,7 +367,7 @@ static int hsc_rx_set(struct hsi_client *cl, struct hsc_rx_config *rxc) ...@@ -367,7 +367,7 @@ static int hsc_rx_set(struct hsi_client *cl, struct hsc_rx_config *rxc)
return -EINVAL; return -EINVAL;
tmp = cl->rx_cfg; tmp = cl->rx_cfg;
cl->rx_cfg.mode = rxc->mode; 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; cl->rx_cfg.flow = rxc->flow;
ret = hsi_setup(cl); ret = hsi_setup(cl);
if (ret < 0) { if (ret < 0) {
...@@ -383,7 +383,7 @@ static int hsc_rx_set(struct hsi_client *cl, struct hsc_rx_config *rxc) ...@@ -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) static inline void hsc_rx_get(struct hsi_client *cl, struct hsc_rx_config *rxc)
{ {
rxc->mode = cl->rx_cfg.mode; 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; rxc->flow = cl->rx_cfg.flow;
} }
...@@ -402,7 +402,7 @@ static int hsc_tx_set(struct hsi_client *cl, struct hsc_tx_config *txc) ...@@ -402,7 +402,7 @@ static int hsc_tx_set(struct hsi_client *cl, struct hsc_tx_config *txc)
return -EINVAL; return -EINVAL;
tmp = cl->tx_cfg; tmp = cl->tx_cfg;
cl->tx_cfg.mode = txc->mode; 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.speed = txc->speed;
cl->tx_cfg.arb_mode = txc->arb_mode; cl->tx_cfg.arb_mode = txc->arb_mode;
ret = hsi_setup(cl); ret = hsi_setup(cl);
...@@ -417,7 +417,7 @@ static int hsc_tx_set(struct hsi_client *cl, struct hsc_tx_config *txc) ...@@ -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) static inline void hsc_tx_get(struct hsi_client *cl, struct hsc_tx_config *txc)
{ {
txc->mode = cl->tx_cfg.mode; 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->speed = cl->tx_cfg.speed;
txc->arb_mode = cl->tx_cfg.arb_mode; 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, ...@@ -435,7 +435,7 @@ static ssize_t hsc_read(struct file *file, char __user *buf, size_t len,
return -EINVAL; return -EINVAL;
if (len > max_data_size) if (len > max_data_size)
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; return -ECHRNG;
if (test_and_set_bit(HSC_CH_READ, &channel->flags)) if (test_and_set_bit(HSC_CH_READ, &channel->flags))
return -EBUSY; return -EBUSY;
...@@ -492,7 +492,7 @@ static ssize_t hsc_write(struct file *file, const char __user *buf, size_t len, ...@@ -492,7 +492,7 @@ static ssize_t hsc_write(struct file *file, const char __user *buf, size_t len,
return -EINVAL; return -EINVAL;
if (len > max_data_size) if (len > max_data_size)
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; return -ECHRNG;
if (test_and_set_bit(HSC_CH_WRITE, &channel->flags)) if (test_and_set_bit(HSC_CH_WRITE, &channel->flags))
return -EBUSY; return -EBUSY;
......
...@@ -62,18 +62,36 @@ static struct bus_type hsi_bus_type = { ...@@ -62,18 +62,36 @@ static struct bus_type hsi_bus_type = {
static void hsi_client_release(struct device *dev) 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) static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info)
{ {
struct hsi_client *cl; struct hsi_client *cl;
size_t size;
cl = kzalloc(sizeof(*cl), GFP_KERNEL); cl = kzalloc(sizeof(*cl), GFP_KERNEL);
if (!cl) if (!cl)
return; return;
cl->tx_cfg = info->tx_cfg; 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; 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.bus = &hsi_bus_type;
cl->device.parent = &port->device; cl->device.parent = &port->device;
cl->device.release = hsi_client_release; cl->device.release = hsi_client_release;
...@@ -502,6 +520,32 @@ int hsi_event(struct hsi_port *port, unsigned long event) ...@@ -502,6 +520,32 @@ int hsi_event(struct hsi_port *port, unsigned long event)
} }
EXPORT_SYMBOL_GPL(hsi_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) static int __init hsi_init(void)
{ {
return bus_register(&hsi_bus_type); return bus_register(&hsi_bus_type);
......
...@@ -67,18 +67,32 @@ enum { ...@@ -67,18 +67,32 @@ enum {
HSI_EVENT_STOP_RX, HSI_EVENT_STOP_RX,
}; };
/**
* 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 * struct hsi_config - Configuration for RX/TX HSI modules
* @mode: Bit transmission mode (STREAM or FRAME) * @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) * @speed: Max bit transmission speed (Kbit/s)
* @flow: RX flow type (SYNCHRONIZED or PIPELINE) * @flow: RX flow type (SYNCHRONIZED or PIPELINE)
* @arb_mode: Arbitration mode for TX frame (Round robin, priority) * @arb_mode: Arbitration mode for TX frame (Round robin, priority)
*/ */
struct hsi_config { struct hsi_config {
unsigned int mode; unsigned int mode;
unsigned int channels; struct hsi_channel *channels;
unsigned int speed; unsigned int num_channels;
unsigned int num_hw_channels;
unsigned int speed;
union { union {
unsigned int flow; /* RX only */ unsigned int flow; /* RX only */
unsigned int arb_mode; /* TX only */ unsigned int arb_mode; /* TX only */
...@@ -306,6 +320,8 @@ static inline struct hsi_port *hsi_find_port_num(struct hsi_controller *hsi, ...@@ -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_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 * hsi_id - Get HSI controller ID associated to a client
* @cl: Pointer to a HSI client * @cl: Pointer to a HSI client
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment