1/*
2 * SPI driver for the CPLD chip on the Mikrotik RB4xx boards
3 *
4 * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
5 *
6 * This file was based on the patches for Linux 2.6.27.39 published by
7 * MikroTik for their RouterBoard 4xx series devices.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published
11 * by the Free Software Foundation.
12 */
13
14#include <linux/types.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/init.h>
18#include <linux/module.h>
19#include <linux/device.h>
20#include <linux/bitops.h>
21#include <linux/spi/spi.h>
22#include <linux/gpio.h>
23#include <linux/slab.h>
24
25#include <asm/mach-ath79/rb4xx_cpld.h>
26
27#define DRV_NAME	"spi-rb4xx-cpld"
28#define DRV_DESC	"RB4xx CPLD driver"
29#define DRV_VERSION	"0.1.0"
30
31#define CPLD_CMD_WRITE_NAND	0x08 /* send cmd, n x send data, send indle */
32#define CPLD_CMD_WRITE_CFG	0x09 /* send cmd, n x send cfg */
33#define CPLD_CMD_READ_NAND	0x0a /* send cmd, send idle, n x read data */
34#define CPLD_CMD_READ_FAST	0x0b /* send cmd, 4 x idle, n x read data */
35#define CPLD_CMD_LED5_ON	0x0c /* send cmd */
36#define CPLD_CMD_LED5_OFF	0x0d /* send cmd */
37
38struct rb4xx_cpld {
39	struct spi_device	*spi;
40	struct mutex		lock;
41	struct gpio_chip	chip;
42	unsigned int		config;
43};
44
45static struct rb4xx_cpld *rb4xx_cpld;
46
47static inline struct rb4xx_cpld *gpio_to_cpld(struct gpio_chip *chip)
48{
49	return container_of(chip, struct rb4xx_cpld, chip);
50}
51
52static int rb4xx_cpld_write_cmd(struct rb4xx_cpld *cpld, unsigned char cmd)
53{
54	struct spi_transfer t[1];
55	struct spi_message m;
56	unsigned char tx_buf[1];
57	int err;
58
59	spi_message_init(&m);
60	memset(&t, 0, sizeof(t));
61
62	t[0].tx_buf = tx_buf;
63	t[0].len = sizeof(tx_buf);
64	spi_message_add_tail(&t[0], &m);
65
66	tx_buf[0] = cmd;
67
68	err = spi_sync(cpld->spi, &m);
69	return err;
70}
71
72static int rb4xx_cpld_write_cfg(struct rb4xx_cpld *cpld, unsigned char config)
73{
74	struct spi_transfer t[1];
75	struct spi_message m;
76	unsigned char cmd[2];
77	int err;
78
79	spi_message_init(&m);
80	memset(&t, 0, sizeof(t));
81
82	t[0].tx_buf = cmd;
83	t[0].len = sizeof(cmd);
84	spi_message_add_tail(&t[0], &m);
85
86	cmd[0] = CPLD_CMD_WRITE_CFG;
87	cmd[1] = config;
88
89	err = spi_sync(cpld->spi, &m);
90	return err;
91}
92
93static int __rb4xx_cpld_change_cfg(struct rb4xx_cpld *cpld, unsigned mask,
94				   unsigned value)
95{
96	unsigned int config;
97	int err;
98
99	config = cpld->config & ~mask;
100	config |= value;
101
102	if ((cpld->config ^ config) & 0xff) {
103		err = rb4xx_cpld_write_cfg(cpld, config);
104		if (err)
105			return err;
106	}
107
108	if ((cpld->config ^ config) & CPLD_CFG_nLED5) {
109		err = rb4xx_cpld_write_cmd(cpld, (value) ? CPLD_CMD_LED5_ON :
110							   CPLD_CMD_LED5_OFF);
111		if (err)
112			return err;
113	}
114
115	cpld->config = config;
116	return 0;
117}
118
119int rb4xx_cpld_change_cfg(unsigned mask, unsigned value)
120{
121	int ret;
122
123	if (rb4xx_cpld == NULL)
124		return -ENODEV;
125
126	mutex_lock(&rb4xx_cpld->lock);
127	ret = __rb4xx_cpld_change_cfg(rb4xx_cpld, mask, value);
128	mutex_unlock(&rb4xx_cpld->lock);
129
130	return ret;
131}
132EXPORT_SYMBOL_GPL(rb4xx_cpld_change_cfg);
133
134int rb4xx_cpld_read_from(unsigned addr, unsigned char *rx_buf,
135			 const unsigned char *verify_buf, unsigned count)
136{
137	const unsigned char cmd[5] = {
138		CPLD_CMD_READ_FAST,
139		(addr >> 16) & 0xff,
140		(addr >> 8) & 0xff,
141		 addr & 0xff,
142		 0
143	};
144	struct spi_transfer t[2] = {
145		{
146			.tx_buf = &cmd,
147			.len = 5,
148		},
149		{
150			.tx_buf = verify_buf,
151			.rx_buf = rx_buf,
152			.len = count,
153			.verify = (verify_buf != NULL),
154		},
155	};
156	struct spi_message m;
157
158	if (rb4xx_cpld == NULL)
159		return -ENODEV;
160
161	spi_message_init(&m);
162	m.fast_read = 1;
163	spi_message_add_tail(&t[0], &m);
164	spi_message_add_tail(&t[1], &m);
165	return spi_sync(rb4xx_cpld->spi, &m);
166}
167EXPORT_SYMBOL_GPL(rb4xx_cpld_read_from);
168
169#if 0
170int rb4xx_cpld_read(unsigned char *buf, unsigned char *verify_buf,
171		    unsigned count)
172{
173	struct spi_transfer t[2];
174	struct spi_message m;
175	unsigned char cmd[2];
176
177	if (rb4xx_cpld == NULL)
178		return -ENODEV;
179
180	spi_message_init(&m);
181	memset(&t, 0, sizeof(t));
182
183	/* send command */
184	t[0].tx_buf = cmd;
185	t[0].len = sizeof(cmd);
186	spi_message_add_tail(&t[0], &m);
187
188	cmd[0] = CPLD_CMD_READ_NAND;
189	cmd[1] = 0;
190
191	/* read data */
192	t[1].rx_buf = buf;
193	t[1].len = count;
194	spi_message_add_tail(&t[1], &m);
195
196	return spi_sync(rb4xx_cpld->spi, &m);
197}
198#else
199int rb4xx_cpld_read(unsigned char *rx_buf, const unsigned char *verify_buf,
200		    unsigned count)
201{
202	static const unsigned char cmd[2] = { CPLD_CMD_READ_NAND, 0 };
203	struct spi_transfer t[2] = {
204		{
205			.tx_buf = &cmd,
206			.len = 2,
207		}, {
208			.tx_buf = verify_buf,
209			.rx_buf = rx_buf,
210			.len = count,
211			.verify = (verify_buf != NULL),
212		},
213	};
214	struct spi_message m;
215
216	if (rb4xx_cpld == NULL)
217		return -ENODEV;
218
219	spi_message_init(&m);
220	spi_message_add_tail(&t[0], &m);
221	spi_message_add_tail(&t[1], &m);
222	return spi_sync(rb4xx_cpld->spi, &m);
223}
224#endif
225EXPORT_SYMBOL_GPL(rb4xx_cpld_read);
226
227int rb4xx_cpld_write(const unsigned char *buf, unsigned count)
228{
229#if 0
230	struct spi_transfer t[3];
231	struct spi_message m;
232	unsigned char cmd[1];
233
234	if (rb4xx_cpld == NULL)
235		return -ENODEV;
236
237	memset(&t, 0, sizeof(t));
238	spi_message_init(&m);
239
240	/* send command */
241	t[0].tx_buf = cmd;
242	t[0].len = sizeof(cmd);
243	spi_message_add_tail(&t[0], &m);
244
245	cmd[0] = CPLD_CMD_WRITE_NAND;
246
247	/* write data */
248	t[1].tx_buf = buf;
249	t[1].len = count;
250	spi_message_add_tail(&t[1], &m);
251
252	/* send idle */
253	t[2].len = 1;
254	spi_message_add_tail(&t[2], &m);
255
256	return spi_sync(rb4xx_cpld->spi, &m);
257#else
258	static const unsigned char cmd = CPLD_CMD_WRITE_NAND;
259	struct spi_transfer t[3] = {
260		{
261			.tx_buf = &cmd,
262			.len = 1,
263		}, {
264			.tx_buf = buf,
265			.len = count,
266			.fast_write = 1,
267		}, {
268			.len = 1,
269			.fast_write = 1,
270		},
271	};
272	struct spi_message m;
273
274	if (rb4xx_cpld == NULL)
275		return -ENODEV;
276
277	spi_message_init(&m);
278	spi_message_add_tail(&t[0], &m);
279	spi_message_add_tail(&t[1], &m);
280	spi_message_add_tail(&t[2], &m);
281	return spi_sync(rb4xx_cpld->spi, &m);
282#endif
283}
284EXPORT_SYMBOL_GPL(rb4xx_cpld_write);
285
286static int rb4xx_cpld_gpio_get(struct gpio_chip *chip, unsigned offset)
287{
288	struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
289	int ret;
290
291	mutex_lock(&cpld->lock);
292	ret = (cpld->config >> offset) & 1;
293	mutex_unlock(&cpld->lock);
294
295	return ret;
296}
297
298static void rb4xx_cpld_gpio_set(struct gpio_chip *chip, unsigned offset,
299				int value)
300{
301	struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
302
303	mutex_lock(&cpld->lock);
304	__rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset);
305	mutex_unlock(&cpld->lock);
306}
307
308static int rb4xx_cpld_gpio_direction_input(struct gpio_chip *chip,
309					   unsigned offset)
310{
311	return -EOPNOTSUPP;
312}
313
314static int rb4xx_cpld_gpio_direction_output(struct gpio_chip *chip,
315					    unsigned offset,
316					    int value)
317{
318	struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
319	int ret;
320
321	mutex_lock(&cpld->lock);
322	ret = __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset);
323	mutex_unlock(&cpld->lock);
324
325	return ret;
326}
327
328static int rb4xx_cpld_gpio_init(struct rb4xx_cpld *cpld, unsigned int base)
329{
330	int err;
331
332	/* init config */
333	cpld->config = CPLD_CFG_nLED1 | CPLD_CFG_nLED2 | CPLD_CFG_nLED3 |
334		       CPLD_CFG_nLED4 | CPLD_CFG_nCE;
335	rb4xx_cpld_write_cfg(cpld, cpld->config);
336
337	/* setup GPIO chip */
338	cpld->chip.label = DRV_NAME;
339
340	cpld->chip.get = rb4xx_cpld_gpio_get;
341	cpld->chip.set = rb4xx_cpld_gpio_set;
342	cpld->chip.direction_input = rb4xx_cpld_gpio_direction_input;
343	cpld->chip.direction_output = rb4xx_cpld_gpio_direction_output;
344
345	cpld->chip.base = base;
346	cpld->chip.ngpio = CPLD_NUM_GPIOS;
347	cpld->chip.can_sleep = 1;
348	cpld->chip.dev = &cpld->spi->dev;
349	cpld->chip.owner = THIS_MODULE;
350
351	err = gpiochip_add(&cpld->chip);
352	if (err)
353		dev_err(&cpld->spi->dev, "adding GPIO chip failed, err=%d\n",
354			err);
355
356	return err;
357}
358
359static int rb4xx_cpld_probe(struct spi_device *spi)
360{
361	struct rb4xx_cpld *cpld;
362	struct rb4xx_cpld_platform_data *pdata;
363	int err;
364
365	pdata = spi->dev.platform_data;
366	if (!pdata) {
367		dev_dbg(&spi->dev, "no platform data\n");
368		return -EINVAL;
369	}
370
371	cpld = kzalloc(sizeof(*cpld), GFP_KERNEL);
372	if (!cpld) {
373		dev_err(&spi->dev, "no memory for private data\n");
374		return -ENOMEM;
375	}
376
377	mutex_init(&cpld->lock);
378	cpld->spi = spi_dev_get(spi);
379	dev_set_drvdata(&spi->dev, cpld);
380
381	spi->mode = SPI_MODE_0;
382	spi->bits_per_word = 8;
383	err = spi_setup(spi);
384	if (err) {
385		dev_err(&spi->dev, "spi_setup failed, err=%d\n", err);
386		goto err_drvdata;
387	}
388
389	err = rb4xx_cpld_gpio_init(cpld, pdata->gpio_base);
390	if (err)
391		goto err_drvdata;
392
393	rb4xx_cpld = cpld;
394
395	return 0;
396
397err_drvdata:
398	dev_set_drvdata(&spi->dev, NULL);
399	kfree(cpld);
400
401	return err;
402}
403
404static int rb4xx_cpld_remove(struct spi_device *spi)
405{
406	struct rb4xx_cpld *cpld;
407
408	rb4xx_cpld = NULL;
409	cpld = dev_get_drvdata(&spi->dev);
410	dev_set_drvdata(&spi->dev, NULL);
411	kfree(cpld);
412
413	return 0;
414}
415
416static struct spi_driver rb4xx_cpld_driver = {
417	.driver = {
418		.name		= DRV_NAME,
419		.bus		= &spi_bus_type,
420		.owner		= THIS_MODULE,
421	},
422	.probe		= rb4xx_cpld_probe,
423	.remove		= rb4xx_cpld_remove,
424};
425
426static int __init rb4xx_cpld_init(void)
427{
428	return spi_register_driver(&rb4xx_cpld_driver);
429}
430module_init(rb4xx_cpld_init);
431
432static void __exit rb4xx_cpld_exit(void)
433{
434	spi_unregister_driver(&rb4xx_cpld_driver);
435}
436module_exit(rb4xx_cpld_exit);
437
438MODULE_DESCRIPTION(DRV_DESC);
439MODULE_VERSION(DRV_VERSION);
440MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
441MODULE_LICENSE("GPL v2");
442