Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a088cf16 authored by Sebastian Reichel's avatar Sebastian Reichel
Browse files

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
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -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;
+45 −1
Original line number Diff line number Diff line
@@ -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);
+20 −4
Original line number Diff line number Diff line
@@ -67,17 +67,31 @@ enum {
	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
 * @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;
	struct hsi_channel	*channels;
	unsigned int		num_channels;
	unsigned int		num_hw_channels;
	unsigned int		speed;
	union {
		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_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