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

Commit ffdd7f4c authored by Srivatsa Vaddagiri's avatar Srivatsa Vaddagiri Committed by Gerrit - the friendly Code Review server
Browse files

Merge "can: Merge rh850.c from 3.18" into dev/msm-4.4-8996au

parents a674e321 dd9b7cf9
Loading
Loading
Loading
Loading
+135 −46
Original line number Original line Diff line number Diff line
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * it under the terms of the GNU General Public License version 2 and
@@ -36,6 +36,9 @@
#define RX_ASSEMBLY_BUFFER_SIZE	128
#define RX_ASSEMBLY_BUFFER_SIZE	128
#define RH850_CLOCK	16000000
#define RH850_CLOCK	16000000
#define RH850_MAX_CHANNELS	4
#define RH850_MAX_CHANNELS	4
#define DRIVER_MODE_RAW_FRAMES 0
#define DRIVER_MODE_PROPERTIES 1
#define DRIVER_MODE_AMB 2


struct rh850_can {
struct rh850_can {
	struct net_device	*netdev[RH850_MAX_CHANNELS];
	struct net_device	*netdev[RH850_MAX_CHANNELS];
@@ -54,6 +57,7 @@ struct rh850_can {
	struct completion response_completion;
	struct completion response_completion;
	int wait_cmd;
	int wait_cmd;
	int cmd_result;
	int cmd_result;
	int driver_mode;
};
};


struct rh850_netdev_privdata {
struct rh850_netdev_privdata {
@@ -94,6 +98,8 @@ struct spi_miso { /* TLV for MISO line */
#define CMD_CAN_DATA_BUFF_REMOVE	0X88
#define CMD_CAN_DATA_BUFF_REMOVE	0X88
#define CMD_CAN_RELEASE_BUFFER	0x89
#define CMD_CAN_RELEASE_BUFFER	0x89
#define CMD_CAN_DATA_BUFF_REMOVE_ALL	0x8A
#define CMD_CAN_DATA_BUFF_REMOVE_ALL	0x8A
#define CMD_PROPERTY_WRITE	0x8B
#define CMD_PROPERTY_READ	0x8C


#define CMD_GET_FW_BR_VERSION		0x95
#define CMD_GET_FW_BR_VERSION		0x95
#define CMD_BEGIN_FIRMWARE_UPGRADE	0x96
#define CMD_BEGIN_FIRMWARE_UPGRADE	0x96
@@ -166,6 +172,22 @@ struct can_config_bit_timing {
	u32 sjw;
	u32 sjw;
} __packed;
} __packed;


struct vehicle_property {
	int id;
	u64 ts;
	int zone;
	int val_type;
	u32 data_len;
	union {
		u8 bval;
		int val;
		int val_arr[4];
		float f_value;
		float float_arr[4];
		u8 str[36];
	};
} __packed;

/* IOCTL messages */
/* IOCTL messages */
struct rh850_release_can_buffer {
struct rh850_release_can_buffer {
	u8 enable;
	u8 enable;
@@ -209,6 +231,18 @@ static struct can_bittiming_const rh850_bittiming_const = {
	.brp_inc = 1,
	.brp_inc = 1,
};
};


static struct can_bittiming_const rh850_data_bittiming_const = {
	.name = "rh850",
	.tseg1_min = 1,
	.tseg1_max = 16,
	.tseg2_min = 1,
	.tseg2_max = 16,
	.sjw_max = 4,
	.brp_min = 1,
	.brp_max = 70,
	.brp_inc = 1,
};

static int rh850_rx_message(struct rh850_can *priv_data);
static int rh850_rx_message(struct rh850_can *priv_data);


static irqreturn_t rh850_irq(int irq, void *priv)
static irqreturn_t rh850_irq(int irq, void *priv)
@@ -236,7 +270,7 @@ static void rh850_receive_frame(struct rh850_can *priv_data,
	}
	}
	netdev = priv_data->netdev[frame->can_if];
	netdev = priv_data->netdev[frame->can_if];
	skb = alloc_can_skb(netdev, &cf);
	skb = alloc_can_skb(netdev, &cf);
	if (skb == NULL) {
	if (!skb) {
		LOGDE("skb alloc failed. frame->can_if %d\n", frame->can_if);
		LOGDE("skb alloc failed. frame->can_if %d\n", frame->can_if);
		return;
		return;
	}
	}
@@ -262,6 +296,47 @@ static void rh850_receive_frame(struct rh850_can *priv_data,
	netdev->stats.rx_packets++;
	netdev->stats.rx_packets++;
}
}


static void rh850_receive_property(struct rh850_can *priv_data,
				   struct vehicle_property *property)
{
	struct canfd_frame *cfd;
	u8 *p;
	struct sk_buff *skb;
	struct skb_shared_hwtstamps *skt;
	struct timeval tv;
	static u64 nanosec;
	struct net_device *netdev;
	int i;

	/* can0 as the channel with properties */
	netdev = priv_data->netdev[0];
	skb = alloc_canfd_skb(netdev, &cfd);
	if (!skb) {
		LOGDE("skb alloc failed. frame->can_if %d\n", 0);
		return;
	}

	LOGDI("rcv property:0x%x data:%2x %2x %2x %2x",
	      property->id, property->str[0], property->str[1],
	      property->str[2], property->str[3]);
	cfd->can_id = 0x00;
	cfd->len = sizeof(struct vehicle_property);

	p = (u8 *)property;
	for (i = 0; i < cfd->len; i++)
		cfd->data[i] = p[i];

	nanosec = le64_to_cpu(property->ts);
	tv.tv_sec = (int)(nanosec / 1000000000);
	tv.tv_usec = (int)(nanosec - (u64)tv.tv_sec * 1000000000) / 1000;
	skt = skb_hwtstamps(skb);
	skt->hwtstamp = timeval_to_ktime(tv);
	LOGDI("  hwtstamp %lld\n", ktime_to_ms(skt->hwtstamp));
	skb->tstamp = timeval_to_ktime(tv);
	netif_rx(skb);
	netdev->stats.rx_packets++;
}

static int rh850_process_response(struct rh850_can *priv_data,
static int rh850_process_response(struct rh850_can *priv_data,
				  struct spi_miso *resp, int length)
				  struct spi_miso *resp, int length)
{
{
@@ -280,6 +355,19 @@ static int rh850_process_response(struct rh850_can *priv_data,
		} else {
		} else {
			rh850_receive_frame(priv_data, frame);
			rh850_receive_frame(priv_data, frame);
		}
		}
	} else if (resp->cmd == CMD_PROPERTY_READ) {
		struct vehicle_property *property =
				(struct vehicle_property *)&resp->data;
		if (resp->len > length) {
			LOGDE("Error. This should never happen\n");
			LOGDE("process_response: Saving %d bytes\n",
			      length);
			memcpy(priv_data->assembly_buffer, (char *)resp,
			       length);
			priv_data->assembly_buffer_size = length;
		} else {
			rh850_receive_property(priv_data, property);
		}
	} else if (resp->cmd  == CMD_GET_FW_VERSION) {
	} else if (resp->cmd  == CMD_GET_FW_VERSION) {
		struct can_fw_resp *fw_resp = (struct can_fw_resp *)resp->data;
		struct can_fw_resp *fw_resp = (struct can_fw_resp *)resp->data;
		dev_info(&priv_data->spidev->dev, "fw %d.%d",
		dev_info(&priv_data->spidev->dev, "fw %d.%d",
@@ -332,7 +420,8 @@ static int rh850_process_rx(struct rh850_can *priv_data, char *rx_buf)
			       rx_buf, 2);
			       rx_buf, 2);
			data = priv_data->assembly_buffer;
			data = priv_data->assembly_buffer;
			resp = (struct spi_miso *)data;
			resp = (struct spi_miso *)data;
			length = resp->len - priv_data->assembly_buffer_size;
			length = resp->len + sizeof(*resp)
					- priv_data->assembly_buffer_size;
			if (length > 0)
			if (length > 0)
				memcpy(priv_data->assembly_buffer +
				memcpy(priv_data->assembly_buffer +
				       priv_data->assembly_buffer_size,
				       priv_data->assembly_buffer_size,
@@ -353,7 +442,7 @@ static int rh850_process_rx(struct rh850_can *priv_data, char *rx_buf)
		      length_processed, length_left, priv_data->xfer_length);
		      length_processed, length_left, priv_data->xfer_length);
		length_processed += length;
		length_processed += length;
		if (length_left >= sizeof(*resp) &&
		if (length_left >= sizeof(*resp) &&
		    resp->len <= length_left) {
		    resp->len + sizeof(*resp) <= length_left) {
			struct spi_miso *resp =
			struct spi_miso *resp =
					(struct spi_miso *)data;
					(struct spi_miso *)data;
			ret = rh850_process_response(priv_data, resp,
			ret = rh850_process_response(priv_data, resp,
@@ -444,30 +533,6 @@ static int rh850_query_firmware_version(struct rh850_can *priv_data)
	return ret;
	return ret;
}
}


static int rh850_query_firmware_br_version(struct rh850_can *priv_data)
{
	char *tx_buf, *rx_buf;
	int ret;
	struct spi_mosi *req;

	mutex_lock(&priv_data->spi_lock);
	tx_buf = priv_data->tx_buf;
	rx_buf = priv_data->rx_buf;
	memset(tx_buf, 0, XFER_BUFFER_SIZE);
	memset(rx_buf, 0, XFER_BUFFER_SIZE);
	priv_data->xfer_length = XFER_BUFFER_SIZE;

	req = (struct spi_mosi *)tx_buf;
	req->cmd = CMD_GET_FW_BR_VERSION;
	req->len = 0;
	req->seq = atomic_inc_return(&priv_data->msg_seq);

	ret = rh850_do_spi_transaction(priv_data);
	mutex_unlock(&priv_data->spi_lock);

	return ret;
}

static int rh850_set_bitrate(struct net_device *netdev)
static int rh850_set_bitrate(struct net_device *netdev)
{
{
	char *tx_buf, *rx_buf;
	char *tx_buf, *rx_buf;
@@ -515,7 +580,7 @@ static int rh850_set_bitrate(struct net_device *netdev)
}
}


static int rh850_can_write(struct rh850_can *priv_data,
static int rh850_can_write(struct rh850_can *priv_data,
			   int can_channel, struct can_frame *cf)
			   int can_channel, struct canfd_frame *cf)
{
{
	char *tx_buf, *rx_buf;
	char *tx_buf, *rx_buf;
	int ret, i;
	int ret, i;
@@ -536,6 +601,7 @@ static int rh850_can_write(struct rh850_can *priv_data,
	priv_data->xfer_length = XFER_BUFFER_SIZE;
	priv_data->xfer_length = XFER_BUFFER_SIZE;


	req = (struct spi_mosi *)tx_buf;
	req = (struct spi_mosi *)tx_buf;
	if (priv_data->driver_mode == DRIVER_MODE_RAW_FRAMES) {
		req->cmd = CMD_CAN_SEND_FRAME;
		req->cmd = CMD_CAN_SEND_FRAME;
		req->len = sizeof(struct can_write_req) + 8;
		req->len = sizeof(struct can_write_req) + 8;
		req->seq = atomic_inc_return(&priv_data->msg_seq);
		req->seq = atomic_inc_return(&priv_data->msg_seq);
@@ -543,9 +609,21 @@ static int rh850_can_write(struct rh850_can *priv_data,
		req_d = (struct can_write_req *)req->data;
		req_d = (struct can_write_req *)req->data;
		req_d->can_if = can_channel;
		req_d->can_if = can_channel;
		req_d->mid = cf->can_id;
		req_d->mid = cf->can_id;
	req_d->dlc = cf->can_dlc;
		req_d->dlc = cf->len;
	for (i = 0; i < cf->can_dlc; i++)

		for (i = 0; i < cf->len; i++)
			req_d->data[i] = cf->data[i];
			req_d->data[i] = cf->data[i];
	} else if (priv_data->driver_mode == DRIVER_MODE_PROPERTIES ||
		   priv_data->driver_mode == DRIVER_MODE_AMB) {
		req->cmd = CMD_PROPERTY_WRITE;
		req->len = sizeof(struct vehicle_property);
		req->seq = atomic_inc_return(&priv_data->msg_seq);
		for (i = 0; i < cf->len; i++)
			req->data[i] = cf->data[i];
	} else {
		LOGDE("rh850_can_write: wrong driver mode %i",
		      priv_data->driver_mode);
	}


	ret = rh850_do_spi_transaction(priv_data);
	ret = rh850_do_spi_transaction(priv_data);
	netdev = priv_data->netdev[can_channel];
	netdev = priv_data->netdev[can_channel];
@@ -581,7 +659,7 @@ static int rh850_netdev_close(struct net_device *netdev)
static void rh850_send_can_frame(struct work_struct *ws)
static void rh850_send_can_frame(struct work_struct *ws)
{
{
	struct rh850_tx_work *tx_work;
	struct rh850_tx_work *tx_work;
	struct can_frame *cf;
	struct canfd_frame *cf;
	struct rh850_can *priv_data;
	struct rh850_can *priv_data;
	struct net_device *netdev;
	struct net_device *netdev;
	struct rh850_netdev_privdata *netdev_priv_data;
	struct rh850_netdev_privdata *netdev_priv_data;
@@ -595,7 +673,7 @@ static void rh850_send_can_frame(struct work_struct *ws)
	LOGDI("send_can_frame ws %p\n", ws);
	LOGDI("send_can_frame ws %p\n", ws);
	LOGDI("send_can_frame tx %p\n", tx_work);
	LOGDI("send_can_frame tx %p\n", tx_work);


	cf = (struct can_frame *)tx_work->skb->data;
	cf = (struct canfd_frame *)tx_work->skb->data;
	rh850_can_write(priv_data, can_channel, cf);
	rh850_can_write(priv_data, can_channel, cf);


	dev_kfree_skb(tx_work->skb);
	dev_kfree_skb(tx_work->skb);
@@ -632,6 +710,7 @@ static int rh850_send_release_can_buffer_cmd(struct net_device *netdev)
	struct spi_mosi *req;
	struct spi_mosi *req;
	struct rh850_can *priv_data;
	struct rh850_can *priv_data;
	struct rh850_netdev_privdata *netdev_priv_data;
	struct rh850_netdev_privdata *netdev_priv_data;
	int *mode;


	netdev_priv_data = netdev_priv(netdev);
	netdev_priv_data = netdev_priv(netdev);
	priv_data = netdev_priv_data->rh850_can;
	priv_data = netdev_priv_data->rh850_can;
@@ -644,8 +723,10 @@ static int rh850_send_release_can_buffer_cmd(struct net_device *netdev)


	req = (struct spi_mosi *)tx_buf;
	req = (struct spi_mosi *)tx_buf;
	req->cmd = CMD_CAN_RELEASE_BUFFER;
	req->cmd = CMD_CAN_RELEASE_BUFFER;
	req->len = 0;
	req->len = sizeof(int);
	req->seq = atomic_inc_return(&priv_data->msg_seq);
	req->seq = atomic_inc_return(&priv_data->msg_seq);
	mode = (int *)req->data;
	*mode = priv_data->driver_mode;


	ret = rh850_do_spi_transaction(priv_data);
	ret = rh850_do_spi_transaction(priv_data);
	mutex_unlock(&priv_data->spi_lock);
	mutex_unlock(&priv_data->spi_lock);
@@ -845,8 +926,7 @@ static int rh850_do_blocking_ioctl(struct net_device *netdev,
		len = ioctl_data->len;
		len = ioctl_data->len;
		data = ioctl_data->data;
		data = ioctl_data->data;
	}
	}
	LOGDI("rh850_do_blocking_ioctl len and data %d %x\n",
	LOGDI("rh850_do_blocking_ioctl len %d\n", len);
	      len, (void *)data);
	mutex_lock(&priv_data->spi_lock);
	mutex_lock(&priv_data->spi_lock);


	priv_data->wait_cmd = spi_cmd;
	priv_data->wait_cmd = spi_cmd;
@@ -870,6 +950,7 @@ static int rh850_netdev_do_ioctl(struct net_device *netdev,
{
{
	struct rh850_can *priv_data;
	struct rh850_can *priv_data;
	struct rh850_netdev_privdata *netdev_priv_data;
	struct rh850_netdev_privdata *netdev_priv_data;
	int *mode;
	int ret = -EINVAL;
	int ret = -EINVAL;


	netdev_priv_data = netdev_priv(netdev);
	netdev_priv_data = netdev_priv(netdev);
@@ -878,6 +959,11 @@ static int rh850_netdev_do_ioctl(struct net_device *netdev,


	switch (cmd) {
	switch (cmd) {
	case IOCTL_RELEASE_CAN_BUFFER:
	case IOCTL_RELEASE_CAN_BUFFER:
		if (ifr->ifr_data > (void *)0x100) {
			mode = ifr->ifr_data;
			priv_data->driver_mode = *mode;
		}
		LOGDE("rh850_driver_mode  %d\n", priv_data->driver_mode);
		rh850_send_release_can_buffer_cmd(netdev);
		rh850_send_release_can_buffer_cmd(netdev);
		ret = 0;
		ret = 0;
		break;
		break;
@@ -943,8 +1029,11 @@ static int rh850_create_netdev(struct spi_device *spi,
	netdev->netdev_ops = &rh850_netdev_ops;
	netdev->netdev_ops = &rh850_netdev_ops;
	SET_NETDEV_DEV(netdev, &spi->dev);
	SET_NETDEV_DEV(netdev, &spi->dev);
	netdev_priv_data->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
	netdev_priv_data->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
						   CAN_CTRLMODE_LISTENONLY;
						   CAN_CTRLMODE_LISTENONLY |
						   CAN_CTRLMODE_FD;
	netdev_priv_data->can.bittiming_const = &rh850_bittiming_const;
	netdev_priv_data->can.bittiming_const = &rh850_bittiming_const;
	netdev_priv_data->can.data_bittiming_const =
			&rh850_data_bittiming_const;
	netdev_priv_data->can.clock.freq = RH850_CLOCK;
	netdev_priv_data->can.clock.freq = RH850_CLOCK;
	netdev_priv_data->can.do_set_bittiming = rh850_set_bitrate;
	netdev_priv_data->can.do_set_bittiming = rh850_set_bitrate;


@@ -988,6 +1077,7 @@ static struct rh850_can *rh850_create_priv_data(struct spi_device *spi)
		goto cleanup_privdata;
		goto cleanup_privdata;
	}
	}
	priv_data->xfer_length = 0;
	priv_data->xfer_length = 0;
	priv_data->driver_mode = DRIVER_MODE_RAW_FRAMES;


	mutex_init(&priv_data->spi_lock);
	mutex_init(&priv_data->spi_lock);
	atomic_set(&priv_data->msg_seq, 0);
	atomic_set(&priv_data->msg_seq, 0);
@@ -1052,7 +1142,6 @@ static int rh850_probe(struct spi_device *spi)
	dev_info(dev, "Request irq %d ret %d\n", spi->irq, err);
	dev_info(dev, "Request irq %d ret %d\n", spi->irq, err);


	rh850_query_firmware_version(priv_data);
	rh850_query_firmware_version(priv_data);
	rh850_query_firmware_br_version(priv_data);
	return 0;
	return 0;


unregister_candev:
unregister_candev: