xref: /OK3568_Linux_fs/kernel/drivers/input/touchscreen/cyttsp5/cyttsp5_spi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * cyttsp5_spi.c
3  * Parade TrueTouch(TM) Standard Product V5 SPI Module.
4  * For use with Parade touchscreen controllers.
5  * Supported parts include:
6  * CYTMA5XX
7  * CYTMA448
8  * CYTMA445A
9  * CYTT21XXX
10  * CYTT31XXX
11  *
12  * Copyright (C) 2015 Parade Technologies
13  * Copyright (C) 2012-2015 Cypress Semiconductor
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * version 2, and only version 2, as published by the
18  * Free Software Foundation.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
26  *
27  */
28 
29 #include "cyttsp5_regs.h"
30 
31 #include <linux/spi/spi.h>
32 #include <linux/version.h>
33 
34 #define CY_SPI_WR_OP		0x00 /* r/~w */
35 #define CY_SPI_RD_OP		0x01
36 #define CY_SPI_BITS_PER_WORD	8
37 #define CY_SPI_SYNC_ACK         0x62
38 
39 #define CY_SPI_CMD_BYTES	0
40 #define CY_SPI_DATA_SIZE	(2 * 256)
41 #define CY_SPI_DATA_BUF_SIZE	(CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
42 
cyttsp5_spi_add_rw_msg(struct spi_message * msg,struct spi_transfer * xfer,u8 * w_header,u8 * r_header,u8 op)43 static void cyttsp5_spi_add_rw_msg(struct spi_message *msg,
44 		struct spi_transfer *xfer, u8 *w_header, u8 *r_header, u8 op)
45 {
46 	xfer->tx_buf = w_header;
47 	xfer->rx_buf = r_header;
48 	w_header[0] = op;
49 	xfer->len = 1;
50 	spi_message_add_tail(xfer, msg);
51 }
52 
cyttsp5_spi_xfer(struct device * dev,u8 op,u8 * buf,int length)53 static int cyttsp5_spi_xfer(struct device *dev, u8 op, u8 *buf, int length)
54 {
55 	struct spi_device *spi = to_spi_device(dev);
56 	struct spi_message msg;
57 	struct spi_transfer xfer[2];
58 	u8 w_header[2];
59 	u8 r_header[2];
60 	int rc;
61 
62 	memset(xfer, 0, sizeof(xfer));
63 
64 	spi_message_init(&msg);
65 	cyttsp5_spi_add_rw_msg(&msg, &xfer[0], w_header, r_header, op);
66 
67 	switch (op) {
68 	case CY_SPI_RD_OP:
69 		xfer[1].rx_buf = buf;
70 		xfer[1].len = length;
71 		spi_message_add_tail(&xfer[1], &msg);
72 		break;
73 	case CY_SPI_WR_OP:
74 		xfer[1].tx_buf = buf;
75 		xfer[1].len = length;
76 		spi_message_add_tail(&xfer[1], &msg);
77 		break;
78 	default:
79 		rc = -EIO;
80 		goto exit;
81 	}
82 
83 	rc = spi_sync(spi, &msg);
84 exit:
85 	if (rc < 0)
86 		parade_debug(dev, DEBUG_LEVEL_2, "%s: spi_sync() error %d\n",
87 			__func__, rc);
88 
89 	if (r_header[0] != CY_SPI_SYNC_ACK)
90 		return -EIO;
91 
92 	return rc;
93 }
94 
cyttsp5_spi_read_default(struct device * dev,void * buf,int size)95 static int cyttsp5_spi_read_default(struct device *dev, void *buf, int size)
96 {
97 	if (!buf || !size)
98 		return 0;
99 
100 	return cyttsp5_spi_xfer(dev, CY_SPI_RD_OP, buf, size);
101 }
102 
cyttsp5_spi_read_default_nosize(struct device * dev,u8 * buf,u32 max)103 static int cyttsp5_spi_read_default_nosize(struct device *dev, u8 *buf, u32 max)
104 {
105 	u32 size;
106 	int rc;
107 
108 	if (!buf)
109 		return 0;
110 
111 	rc = cyttsp5_spi_xfer(dev, CY_SPI_RD_OP, buf, 2);
112 	if (rc < 0)
113 		return rc;
114 
115 	size = get_unaligned_le16(&buf[0]);
116 	if (!size)
117 		return rc;
118 
119 	if (size > max)
120 		return -EINVAL;
121 
122 	return cyttsp5_spi_read_default(dev, buf, size);
123 }
124 
cyttsp5_spi_write_read_specific(struct device * dev,u8 write_len,u8 * write_buf,u8 * read_buf)125 static int cyttsp5_spi_write_read_specific(struct device *dev, u8 write_len,
126 		u8 *write_buf, u8 *read_buf)
127 {
128 	int rc;
129 
130 	rc = cyttsp5_spi_xfer(dev, CY_SPI_WR_OP, write_buf, write_len);
131 	if (rc < 0)
132 		return rc;
133 
134 	if (read_buf)
135 		rc = cyttsp5_spi_read_default_nosize(dev, read_buf,
136 				CY_SPI_DATA_SIZE);
137 
138 	return rc;
139 }
140 
141 static struct cyttsp5_bus_ops cyttsp5_spi_bus_ops = {
142 	.bustype = BUS_SPI,
143 	.read_default = cyttsp5_spi_read_default,
144 	.read_default_nosize = cyttsp5_spi_read_default_nosize,
145 	.write_read_specific = cyttsp5_spi_write_read_specific,
146 };
147 
148 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
149 static const struct of_device_id cyttsp5_spi_of_match[] = {
150 	{ .compatible = "cy,cyttsp5_spi_adapter", },
151 	{ }
152 };
153 MODULE_DEVICE_TABLE(of, cyttsp5_spi_of_match);
154 #endif
155 
cyttsp5_spi_probe(struct spi_device * spi)156 static int cyttsp5_spi_probe(struct spi_device *spi)
157 {
158 	struct device *dev = &spi->dev;
159 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
160 	const struct of_device_id *match;
161 #endif
162 	int rc;
163 
164 	/* Set up SPI*/
165 	spi->bits_per_word = CY_SPI_BITS_PER_WORD;
166 	spi->mode = SPI_MODE_0;
167 	rc = spi_setup(spi);
168 	if (rc < 0) {
169 		dev_err(dev, "%s: SPI setup error %d\n", __func__, rc);
170 		return rc;
171 	}
172 
173 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
174 	match = of_match_device(of_match_ptr(cyttsp5_spi_of_match), dev);
175 	if (match) {
176 		rc = cyttsp5_devtree_create_and_get_pdata(dev);
177 		if (rc < 0)
178 			return rc;
179 	}
180 #endif
181 
182 	rc = cyttsp5_probe(&cyttsp5_spi_bus_ops, &spi->dev, spi->irq,
183 			  CY_SPI_DATA_BUF_SIZE);
184 
185 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
186 	if (rc && match)
187 		cyttsp5_devtree_clean_pdata(dev);
188 #endif
189 
190 	return rc;
191 }
192 
cyttsp5_spi_remove(struct spi_device * spi)193 static int cyttsp5_spi_remove(struct spi_device *spi)
194 {
195 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
196 	struct device *dev = &spi->dev;
197 	const struct of_device_id *match;
198 #endif
199 	struct cyttsp5_core_data *cd = dev_get_drvdata(&spi->dev);
200 
201 	cyttsp5_release(cd);
202 
203 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
204 	match = of_match_device(of_match_ptr(cyttsp5_spi_of_match), dev);
205 	if (match)
206 		cyttsp5_devtree_clean_pdata(dev);
207 #endif
208 
209 	return 0;
210 }
211 
212 static const struct spi_device_id cyttsp5_spi_id[] = {
213 	{ CYTTSP5_SPI_NAME, 0 },
214 	{ }
215 };
216 MODULE_DEVICE_TABLE(spi, cyttsp5_spi_id);
217 
218 static struct spi_driver cyttsp5_spi_driver = {
219 	.driver = {
220 		.name = CYTTSP5_SPI_NAME,
221 		.bus = &spi_bus_type,
222 		.owner = THIS_MODULE,
223 		.pm = &cyttsp5_pm_ops,
224 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
225 		.of_match_table = cyttsp5_spi_of_match,
226 #endif
227 	},
228 	.probe = cyttsp5_spi_probe,
229 	.remove = (cyttsp5_spi_remove),
230 	.id_table = cyttsp5_spi_id,
231 };
232 
233 #if (KERNEL_VERSION(3, 3, 0) <= LINUX_VERSION_CODE)
234 module_spi_driver(cyttsp5_spi_driver);
235 #else
cyttsp5_spi_init(void)236 static int __init cyttsp5_spi_init(void)
237 {
238 	int err = spi_register_driver(&cyttsp5_spi_driver);
239 
240 	pr_info("%s: Parade TTSP SPI Driver (Built %s) rc=%d\n",
241 		 __func__, CY_DRIVER_VERSION, err);
242 	return err;
243 }
244 module_init(cyttsp5_spi_init);
245 
cyttsp5_spi_exit(void)246 static void __exit cyttsp5_spi_exit(void)
247 {
248 	spi_unregister_driver(&cyttsp5_spi_driver);
249 }
250 module_exit(cyttsp5_spi_exit);
251 #endif
252 
253 MODULE_LICENSE("GPL");
254 MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product SPI Driver");
255 MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");
256