mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-07 15:18:15 +00:00
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>
This commit is contained in:
parent
a0bf37edb4
commit
a088cf161c
3 changed files with 71 additions and 11 deletions
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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 = {
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
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,17 +67,31 @@ 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 num_channels;
|
||||||
|
unsigned int num_hw_channels;
|
||||||
unsigned int speed;
|
unsigned int speed;
|
||||||
union {
|
union {
|
||||||
unsigned int flow; /* RX only */
|
unsigned int flow; /* RX 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_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
|
||||||
|
|
Loading…
Add table
Reference in a new issue