xref: /linux/drivers/spi/spi-ljca.c (revision caee8e38da67a8991a60f1f67e6820a0063278c4)
1*caee8e38SWentong Wu // SPDX-License-Identifier: GPL-2.0-only
2*caee8e38SWentong Wu /*
3*caee8e38SWentong Wu  * Intel La Jolla Cove Adapter USB-SPI driver
4*caee8e38SWentong Wu  *
5*caee8e38SWentong Wu  * Copyright (c) 2023, Intel Corporation.
6*caee8e38SWentong Wu  */
7*caee8e38SWentong Wu 
8*caee8e38SWentong Wu #include <linux/auxiliary_bus.h>
9*caee8e38SWentong Wu #include <linux/bitfield.h>
10*caee8e38SWentong Wu #include <linux/bits.h>
11*caee8e38SWentong Wu #include <linux/dev_printk.h>
12*caee8e38SWentong Wu #include <linux/module.h>
13*caee8e38SWentong Wu #include <linux/spi/spi.h>
14*caee8e38SWentong Wu #include <linux/usb/ljca.h>
15*caee8e38SWentong Wu 
16*caee8e38SWentong Wu #define LJCA_SPI_BUS_MAX_HZ		48000000
17*caee8e38SWentong Wu 
18*caee8e38SWentong Wu #define LJCA_SPI_BUF_SIZE		60u
19*caee8e38SWentong Wu #define LJCA_SPI_MAX_XFER_SIZE		\
20*caee8e38SWentong Wu 	(LJCA_SPI_BUF_SIZE - sizeof(struct ljca_spi_xfer_packet))
21*caee8e38SWentong Wu 
22*caee8e38SWentong Wu #define LJCA_SPI_CLK_MODE_POLARITY	BIT(0)
23*caee8e38SWentong Wu #define LJCA_SPI_CLK_MODE_PHASE		BIT(1)
24*caee8e38SWentong Wu 
25*caee8e38SWentong Wu #define LJCA_SPI_XFER_INDICATOR_ID	GENMASK(5, 0)
26*caee8e38SWentong Wu #define LJCA_SPI_XFER_INDICATOR_CMPL	BIT(6)
27*caee8e38SWentong Wu #define LJCA_SPI_XFER_INDICATOR_INDEX	BIT(7)
28*caee8e38SWentong Wu 
29*caee8e38SWentong Wu /* SPI commands */
30*caee8e38SWentong Wu enum ljca_spi_cmd {
31*caee8e38SWentong Wu 	LJCA_SPI_INIT = 1,
32*caee8e38SWentong Wu 	LJCA_SPI_READ,
33*caee8e38SWentong Wu 	LJCA_SPI_WRITE,
34*caee8e38SWentong Wu 	LJCA_SPI_WRITEREAD,
35*caee8e38SWentong Wu 	LJCA_SPI_DEINIT,
36*caee8e38SWentong Wu };
37*caee8e38SWentong Wu 
38*caee8e38SWentong Wu enum {
39*caee8e38SWentong Wu 	LJCA_SPI_BUS_SPEED_24M,
40*caee8e38SWentong Wu 	LJCA_SPI_BUS_SPEED_12M,
41*caee8e38SWentong Wu 	LJCA_SPI_BUS_SPEED_8M,
42*caee8e38SWentong Wu 	LJCA_SPI_BUS_SPEED_6M,
43*caee8e38SWentong Wu 	LJCA_SPI_BUS_SPEED_4_8M, /*4.8MHz*/
44*caee8e38SWentong Wu 	LJCA_SPI_BUS_SPEED_MIN = LJCA_SPI_BUS_SPEED_4_8M,
45*caee8e38SWentong Wu };
46*caee8e38SWentong Wu 
47*caee8e38SWentong Wu enum {
48*caee8e38SWentong Wu 	LJCA_SPI_CLOCK_LOW_POLARITY,
49*caee8e38SWentong Wu 	LJCA_SPI_CLOCK_HIGH_POLARITY,
50*caee8e38SWentong Wu };
51*caee8e38SWentong Wu 
52*caee8e38SWentong Wu enum {
53*caee8e38SWentong Wu 	LJCA_SPI_CLOCK_FIRST_PHASE,
54*caee8e38SWentong Wu 	LJCA_SPI_CLOCK_SECOND_PHASE,
55*caee8e38SWentong Wu };
56*caee8e38SWentong Wu 
57*caee8e38SWentong Wu struct ljca_spi_init_packet {
58*caee8e38SWentong Wu 	u8 index;
59*caee8e38SWentong Wu 	u8 speed;
60*caee8e38SWentong Wu 	u8 mode;
61*caee8e38SWentong Wu } __packed;
62*caee8e38SWentong Wu 
63*caee8e38SWentong Wu struct ljca_spi_xfer_packet {
64*caee8e38SWentong Wu 	u8 indicator;
65*caee8e38SWentong Wu 	u8 len;
66*caee8e38SWentong Wu 	u8 data[] __counted_by(len);
67*caee8e38SWentong Wu } __packed;
68*caee8e38SWentong Wu 
69*caee8e38SWentong Wu struct ljca_spi_dev {
70*caee8e38SWentong Wu 	struct ljca_client *ljca;
71*caee8e38SWentong Wu 	struct spi_controller *controller;
72*caee8e38SWentong Wu 	struct ljca_spi_info *spi_info;
73*caee8e38SWentong Wu 	u8 speed;
74*caee8e38SWentong Wu 	u8 mode;
75*caee8e38SWentong Wu 
76*caee8e38SWentong Wu 	u8 obuf[LJCA_SPI_BUF_SIZE];
77*caee8e38SWentong Wu 	u8 ibuf[LJCA_SPI_BUF_SIZE];
78*caee8e38SWentong Wu };
79*caee8e38SWentong Wu 
80*caee8e38SWentong Wu static int ljca_spi_read_write(struct ljca_spi_dev *ljca_spi, const u8 *w_data,
81*caee8e38SWentong Wu 			       u8 *r_data, int len, int id, int complete,
82*caee8e38SWentong Wu 			       int cmd)
83*caee8e38SWentong Wu {
84*caee8e38SWentong Wu 	struct ljca_spi_xfer_packet *w_packet =
85*caee8e38SWentong Wu 			(struct ljca_spi_xfer_packet *)ljca_spi->obuf;
86*caee8e38SWentong Wu 	struct ljca_spi_xfer_packet *r_packet =
87*caee8e38SWentong Wu 			(struct ljca_spi_xfer_packet *)ljca_spi->ibuf;
88*caee8e38SWentong Wu 	int ret;
89*caee8e38SWentong Wu 
90*caee8e38SWentong Wu 	w_packet->indicator = FIELD_PREP(LJCA_SPI_XFER_INDICATOR_ID, id) |
91*caee8e38SWentong Wu 			      FIELD_PREP(LJCA_SPI_XFER_INDICATOR_CMPL, complete) |
92*caee8e38SWentong Wu 			      FIELD_PREP(LJCA_SPI_XFER_INDICATOR_INDEX,
93*caee8e38SWentong Wu 					 ljca_spi->spi_info->id);
94*caee8e38SWentong Wu 
95*caee8e38SWentong Wu 	if (cmd == LJCA_SPI_READ) {
96*caee8e38SWentong Wu 		w_packet->len = sizeof(u16);
97*caee8e38SWentong Wu 		*(__le16 *)&w_packet->data[0] = cpu_to_le16(len);
98*caee8e38SWentong Wu 	} else {
99*caee8e38SWentong Wu 		w_packet->len = len;
100*caee8e38SWentong Wu 		memcpy(w_packet->data, w_data, len);
101*caee8e38SWentong Wu 	}
102*caee8e38SWentong Wu 
103*caee8e38SWentong Wu 	ret = ljca_transfer(ljca_spi->ljca, cmd, (u8 *)w_packet,
104*caee8e38SWentong Wu 			    struct_size(w_packet, data, w_packet->len),
105*caee8e38SWentong Wu 			    (u8 *)r_packet, LJCA_SPI_BUF_SIZE);
106*caee8e38SWentong Wu 	if (ret < 0)
107*caee8e38SWentong Wu 		return ret;
108*caee8e38SWentong Wu 	else if (ret < sizeof(*r_packet) || r_packet->len <= 0)
109*caee8e38SWentong Wu 		return -EIO;
110*caee8e38SWentong Wu 
111*caee8e38SWentong Wu 	if (r_data)
112*caee8e38SWentong Wu 		memcpy(r_data, r_packet->data, r_packet->len);
113*caee8e38SWentong Wu 
114*caee8e38SWentong Wu 	return 0;
115*caee8e38SWentong Wu }
116*caee8e38SWentong Wu 
117*caee8e38SWentong Wu static int ljca_spi_init(struct ljca_spi_dev *ljca_spi, u8 div, u8 mode)
118*caee8e38SWentong Wu {
119*caee8e38SWentong Wu 	struct ljca_spi_init_packet w_packet = {};
120*caee8e38SWentong Wu 	int ret;
121*caee8e38SWentong Wu 
122*caee8e38SWentong Wu 	if (ljca_spi->mode == mode && ljca_spi->speed == div)
123*caee8e38SWentong Wu 		return 0;
124*caee8e38SWentong Wu 
125*caee8e38SWentong Wu 	w_packet.index = ljca_spi->spi_info->id;
126*caee8e38SWentong Wu 	w_packet.speed = div;
127*caee8e38SWentong Wu 	w_packet.mode = FIELD_PREP(LJCA_SPI_CLK_MODE_POLARITY,
128*caee8e38SWentong Wu 				   (mode & SPI_CPOL) ? LJCA_SPI_CLOCK_HIGH_POLARITY :
129*caee8e38SWentong Wu 						       LJCA_SPI_CLOCK_LOW_POLARITY) |
130*caee8e38SWentong Wu 			FIELD_PREP(LJCA_SPI_CLK_MODE_PHASE,
131*caee8e38SWentong Wu 				   (mode & SPI_CPHA) ? LJCA_SPI_CLOCK_SECOND_PHASE :
132*caee8e38SWentong Wu 						       LJCA_SPI_CLOCK_FIRST_PHASE);
133*caee8e38SWentong Wu 
134*caee8e38SWentong Wu 	ret = ljca_transfer(ljca_spi->ljca, LJCA_SPI_INIT, (u8 *)&w_packet,
135*caee8e38SWentong Wu 			    sizeof(w_packet), NULL, 0);
136*caee8e38SWentong Wu 	if (ret < 0)
137*caee8e38SWentong Wu 		return ret;
138*caee8e38SWentong Wu 
139*caee8e38SWentong Wu 	ljca_spi->mode = mode;
140*caee8e38SWentong Wu 	ljca_spi->speed = div;
141*caee8e38SWentong Wu 
142*caee8e38SWentong Wu 	return 0;
143*caee8e38SWentong Wu }
144*caee8e38SWentong Wu 
145*caee8e38SWentong Wu static int ljca_spi_deinit(struct ljca_spi_dev *ljca_spi)
146*caee8e38SWentong Wu {
147*caee8e38SWentong Wu 	struct ljca_spi_init_packet w_packet = {};
148*caee8e38SWentong Wu 	int ret;
149*caee8e38SWentong Wu 
150*caee8e38SWentong Wu 	w_packet.index = ljca_spi->spi_info->id;
151*caee8e38SWentong Wu 
152*caee8e38SWentong Wu 	ret = ljca_transfer(ljca_spi->ljca, LJCA_SPI_DEINIT, (u8 *)&w_packet,
153*caee8e38SWentong Wu 			    sizeof(w_packet), NULL, 0);
154*caee8e38SWentong Wu 
155*caee8e38SWentong Wu 	return ret < 0 ? ret : 0;
156*caee8e38SWentong Wu }
157*caee8e38SWentong Wu 
158*caee8e38SWentong Wu static inline int ljca_spi_transfer(struct ljca_spi_dev *ljca_spi,
159*caee8e38SWentong Wu 				    const u8 *tx_data, u8 *rx_data, u16 len)
160*caee8e38SWentong Wu {
161*caee8e38SWentong Wu 	int complete, cur_len;
162*caee8e38SWentong Wu 	int remaining = len;
163*caee8e38SWentong Wu 	int cmd, ret, i;
164*caee8e38SWentong Wu 	int offset = 0;
165*caee8e38SWentong Wu 
166*caee8e38SWentong Wu 	if (tx_data && rx_data)
167*caee8e38SWentong Wu 		cmd = LJCA_SPI_WRITEREAD;
168*caee8e38SWentong Wu 	else if (tx_data)
169*caee8e38SWentong Wu 		cmd = LJCA_SPI_WRITE;
170*caee8e38SWentong Wu 	else if (rx_data)
171*caee8e38SWentong Wu 		cmd = LJCA_SPI_READ;
172*caee8e38SWentong Wu 	else
173*caee8e38SWentong Wu 		return -EINVAL;
174*caee8e38SWentong Wu 
175*caee8e38SWentong Wu 	for (i = 0; remaining > 0; i++) {
176*caee8e38SWentong Wu 		cur_len = min_t(unsigned int, remaining, LJCA_SPI_MAX_XFER_SIZE);
177*caee8e38SWentong Wu 		complete = (cur_len == remaining);
178*caee8e38SWentong Wu 
179*caee8e38SWentong Wu 		ret = ljca_spi_read_write(ljca_spi,
180*caee8e38SWentong Wu 					  tx_data ? tx_data + offset : NULL,
181*caee8e38SWentong Wu 					  rx_data ? rx_data + offset : NULL,
182*caee8e38SWentong Wu 					  cur_len, i, complete, cmd);
183*caee8e38SWentong Wu 		if (ret)
184*caee8e38SWentong Wu 			return ret;
185*caee8e38SWentong Wu 
186*caee8e38SWentong Wu 		offset += cur_len;
187*caee8e38SWentong Wu 		remaining -= cur_len;
188*caee8e38SWentong Wu 	}
189*caee8e38SWentong Wu 
190*caee8e38SWentong Wu 	return 0;
191*caee8e38SWentong Wu }
192*caee8e38SWentong Wu 
193*caee8e38SWentong Wu static int ljca_spi_transfer_one(struct spi_controller *controller,
194*caee8e38SWentong Wu 				 struct spi_device *spi,
195*caee8e38SWentong Wu 				 struct spi_transfer *xfer)
196*caee8e38SWentong Wu {
197*caee8e38SWentong Wu 	u8 div = DIV_ROUND_UP(controller->max_speed_hz, xfer->speed_hz) / 2 - 1;
198*caee8e38SWentong Wu 	struct ljca_spi_dev *ljca_spi = spi_controller_get_devdata(controller);
199*caee8e38SWentong Wu 	int ret;
200*caee8e38SWentong Wu 
201*caee8e38SWentong Wu 	div = min_t(u8, LJCA_SPI_BUS_SPEED_MIN, div);
202*caee8e38SWentong Wu 
203*caee8e38SWentong Wu 	ret = ljca_spi_init(ljca_spi, div, spi->mode);
204*caee8e38SWentong Wu 	if (ret) {
205*caee8e38SWentong Wu 		dev_err(&ljca_spi->ljca->auxdev.dev,
206*caee8e38SWentong Wu 			"cannot initialize transfer ret %d\n", ret);
207*caee8e38SWentong Wu 		return ret;
208*caee8e38SWentong Wu 	}
209*caee8e38SWentong Wu 
210*caee8e38SWentong Wu 	ret = ljca_spi_transfer(ljca_spi, xfer->tx_buf, xfer->rx_buf, xfer->len);
211*caee8e38SWentong Wu 	if (ret)
212*caee8e38SWentong Wu 		dev_err(&ljca_spi->ljca->auxdev.dev,
213*caee8e38SWentong Wu 			"transfer failed len: %d\n", xfer->len);
214*caee8e38SWentong Wu 
215*caee8e38SWentong Wu 	return ret;
216*caee8e38SWentong Wu }
217*caee8e38SWentong Wu 
218*caee8e38SWentong Wu static int ljca_spi_probe(struct auxiliary_device *auxdev,
219*caee8e38SWentong Wu 			  const struct auxiliary_device_id *aux_dev_id)
220*caee8e38SWentong Wu {
221*caee8e38SWentong Wu 	struct ljca_client *ljca = auxiliary_dev_to_ljca_client(auxdev);
222*caee8e38SWentong Wu 	struct spi_controller *controller;
223*caee8e38SWentong Wu 	struct ljca_spi_dev *ljca_spi;
224*caee8e38SWentong Wu 	int ret;
225*caee8e38SWentong Wu 
226*caee8e38SWentong Wu 	controller = devm_spi_alloc_master(&auxdev->dev, sizeof(*ljca_spi));
227*caee8e38SWentong Wu 	if (!controller)
228*caee8e38SWentong Wu 		return -ENOMEM;
229*caee8e38SWentong Wu 
230*caee8e38SWentong Wu 	ljca_spi = spi_controller_get_devdata(controller);
231*caee8e38SWentong Wu 	ljca_spi->ljca = ljca;
232*caee8e38SWentong Wu 	ljca_spi->spi_info = dev_get_platdata(&auxdev->dev);
233*caee8e38SWentong Wu 	ljca_spi->controller = controller;
234*caee8e38SWentong Wu 
235*caee8e38SWentong Wu 	controller->bus_num = -1;
236*caee8e38SWentong Wu 	controller->mode_bits = SPI_CPHA | SPI_CPOL;
237*caee8e38SWentong Wu 	controller->transfer_one = ljca_spi_transfer_one;
238*caee8e38SWentong Wu 	controller->auto_runtime_pm = false;
239*caee8e38SWentong Wu 	controller->max_speed_hz = LJCA_SPI_BUS_MAX_HZ;
240*caee8e38SWentong Wu 
241*caee8e38SWentong Wu 	device_set_node(&ljca_spi->controller->dev, dev_fwnode(&auxdev->dev));
242*caee8e38SWentong Wu 	auxiliary_set_drvdata(auxdev, controller);
243*caee8e38SWentong Wu 
244*caee8e38SWentong Wu 	ret = spi_register_controller(controller);
245*caee8e38SWentong Wu 	if (ret)
246*caee8e38SWentong Wu 		dev_err(&auxdev->dev, "Failed to register controller\n");
247*caee8e38SWentong Wu 
248*caee8e38SWentong Wu 	return ret;
249*caee8e38SWentong Wu }
250*caee8e38SWentong Wu 
251*caee8e38SWentong Wu static void ljca_spi_dev_remove(struct auxiliary_device *auxdev)
252*caee8e38SWentong Wu {
253*caee8e38SWentong Wu 	struct spi_controller *controller = auxiliary_get_drvdata(auxdev);
254*caee8e38SWentong Wu 	struct ljca_spi_dev *ljca_spi = spi_controller_get_devdata(controller);
255*caee8e38SWentong Wu 
256*caee8e38SWentong Wu 	spi_unregister_controller(controller);
257*caee8e38SWentong Wu 	ljca_spi_deinit(ljca_spi);
258*caee8e38SWentong Wu }
259*caee8e38SWentong Wu 
260*caee8e38SWentong Wu static int ljca_spi_dev_suspend(struct device *dev)
261*caee8e38SWentong Wu {
262*caee8e38SWentong Wu 	struct spi_controller *controller = dev_get_drvdata(dev);
263*caee8e38SWentong Wu 
264*caee8e38SWentong Wu 	return spi_controller_suspend(controller);
265*caee8e38SWentong Wu }
266*caee8e38SWentong Wu 
267*caee8e38SWentong Wu static int ljca_spi_dev_resume(struct device *dev)
268*caee8e38SWentong Wu {
269*caee8e38SWentong Wu 	struct spi_controller *controller = dev_get_drvdata(dev);
270*caee8e38SWentong Wu 
271*caee8e38SWentong Wu 	return spi_controller_resume(controller);
272*caee8e38SWentong Wu }
273*caee8e38SWentong Wu 
274*caee8e38SWentong Wu static const struct dev_pm_ops ljca_spi_pm = {
275*caee8e38SWentong Wu 	SYSTEM_SLEEP_PM_OPS(ljca_spi_dev_suspend, ljca_spi_dev_resume)
276*caee8e38SWentong Wu };
277*caee8e38SWentong Wu 
278*caee8e38SWentong Wu static const struct auxiliary_device_id ljca_spi_id_table[] = {
279*caee8e38SWentong Wu 	{ "usb_ljca.ljca-spi", 0 },
280*caee8e38SWentong Wu 	{ /* sentinel */ }
281*caee8e38SWentong Wu };
282*caee8e38SWentong Wu MODULE_DEVICE_TABLE(auxiliary, ljca_spi_id_table);
283*caee8e38SWentong Wu 
284*caee8e38SWentong Wu static struct auxiliary_driver ljca_spi_driver = {
285*caee8e38SWentong Wu 	.driver.pm	= &ljca_spi_pm,
286*caee8e38SWentong Wu 	.probe		= ljca_spi_probe,
287*caee8e38SWentong Wu 	.remove		= ljca_spi_dev_remove,
288*caee8e38SWentong Wu 	.id_table	= ljca_spi_id_table,
289*caee8e38SWentong Wu };
290*caee8e38SWentong Wu module_auxiliary_driver(ljca_spi_driver);
291*caee8e38SWentong Wu 
292*caee8e38SWentong Wu MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>");
293*caee8e38SWentong Wu MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>");
294*caee8e38SWentong Wu MODULE_AUTHOR("Lixu Zhang <lixu.zhang@intel.com>");
295*caee8e38SWentong Wu MODULE_DESCRIPTION("Intel La Jolla Cove Adapter USB-SPI driver");
296*caee8e38SWentong Wu MODULE_LICENSE("GPL");
297*caee8e38SWentong Wu MODULE_IMPORT_NS(LJCA);
298