aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRodolfo Giometti <giometti@linux.it>2008-11-12 16:27:12 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-11-12 20:17:18 -0500
commit4e17e1db96474af5620e3259754df4cb1c46521c (patch)
treecc662ebf5158b407495a4939b0ea3d16b93a1b7e
parente0a29382c6f51c278a7e9a788917ff9182f3dba6 (diff)
Add c2 port support
C2port implements a two wire serial communication protocol (bit banging) designed to enable in-system programming, debugging, and boundary-scan testing on low pin-count Silicon Labs devices. Currently this code supports only flash programming through sysfs interface but extensions shoud be easy to add. Signed-off-by: Rodolfo Giometti <giometti@linux.it> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/ABI/testing/sysfs-c2port88
-rw-r--r--Documentation/c2port.txt90
-rw-r--r--drivers/misc/Kconfig2
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/c2port/Kconfig24
-rw-r--r--drivers/misc/c2port/Makefile1
-rw-r--r--drivers/misc/c2port/core.c1002
-rw-r--r--include/linux/c2port.h65
8 files changed, 1273 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-c2port b/Documentation/ABI/testing/sysfs-c2port
new file mode 100644
index 00000000000..716cffc457e
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-c2port
@@ -0,0 +1,88 @@
1What: /sys/class/c2port/
2Date: October 2008
3Contact: Rodolfo Giometti <giometti@linux.it>
4Description:
5 The /sys/class/c2port/ directory will contain files and
6 directories that will provide a unified interface to
7 the C2 port interface.
8
9What: /sys/class/c2port/c2portX
10Date: October 2008
11Contact: Rodolfo Giometti <giometti@linux.it>
12Description:
13 The /sys/class/c2port/c2portX/ directory is related to X-th
14 C2 port into the system. Each directory will contain files to
15 manage and control its C2 port.
16
17What: /sys/class/c2port/c2portX/access
18Date: October 2008
19Contact: Rodolfo Giometti <giometti@linux.it>
20Description:
21 The /sys/class/c2port/c2portX/access file enable the access
22 to the C2 port from the system. No commands can be sent
23 till this entry is set to 0.
24
25What: /sys/class/c2port/c2portX/dev_id
26Date: October 2008
27Contact: Rodolfo Giometti <giometti@linux.it>
28Description:
29 The /sys/class/c2port/c2portX/dev_id file show the device ID
30 of the connected micro.
31
32What: /sys/class/c2port/c2portX/flash_access
33Date: October 2008
34Contact: Rodolfo Giometti <giometti@linux.it>
35Description:
36 The /sys/class/c2port/c2portX/flash_access file enable the
37 access to the on-board flash of the connected micro.
38 No commands can be sent till this entry is set to 0.
39
40What: /sys/class/c2port/c2portX/flash_block_size
41Date: October 2008
42Contact: Rodolfo Giometti <giometti@linux.it>
43Description:
44 The /sys/class/c2port/c2portX/flash_block_size file show
45 the on-board flash block size of the connected micro.
46
47What: /sys/class/c2port/c2portX/flash_blocks_num
48Date: October 2008
49Contact: Rodolfo Giometti <giometti@linux.it>
50Description:
51 The /sys/class/c2port/c2portX/flash_blocks_num file show
52 the on-board flash blocks number of the connected micro.
53
54What: /sys/class/c2port/c2portX/flash_data
55Date: October 2008
56Contact: Rodolfo Giometti <giometti@linux.it>
57Description:
58 The /sys/class/c2port/c2portX/flash_data file export
59 the content of the on-board flash of the connected micro.
60
61What: /sys/class/c2port/c2portX/flash_erase
62Date: October 2008
63Contact: Rodolfo Giometti <giometti@linux.it>
64Description:
65 The /sys/class/c2port/c2portX/flash_erase file execute
66 the "erase" command on the on-board flash of the connected
67 micro.
68
69What: /sys/class/c2port/c2portX/flash_erase
70Date: October 2008
71Contact: Rodolfo Giometti <giometti@linux.it>
72Description:
73 The /sys/class/c2port/c2portX/flash_erase file show the
74 on-board flash size of the connected micro.
75
76What: /sys/class/c2port/c2portX/reset
77Date: October 2008
78Contact: Rodolfo Giometti <giometti@linux.it>
79Description:
80 The /sys/class/c2port/c2portX/reset file execute a "reset"
81 command on the connected micro.
82
83What: /sys/class/c2port/c2portX/rev_id
84Date: October 2008
85Contact: Rodolfo Giometti <giometti@linux.it>
86Description:
87 The /sys/class/c2port/c2portX/rev_id file show the revision ID
88 of the connected micro.
diff --git a/Documentation/c2port.txt b/Documentation/c2port.txt
new file mode 100644
index 00000000000..d9bf93ea439
--- /dev/null
+++ b/Documentation/c2port.txt
@@ -0,0 +1,90 @@
1 C2 port support
2 ---------------
3
4(C) Copyright 2007 Rodolfo Giometti <giometti@enneenne.com>
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16
17
18Overview
19--------
20
21This driver implements the support for Linux of Silicon Labs (Silabs)
22C2 Interface used for in-system programming of micro controllers.
23
24By using this driver you can reprogram the in-system flash without EC2
25or EC3 debug adapter. This solution is also useful in those systems
26where the micro controller is connected via special GPIOs pins.
27
28References
29----------
30
31The C2 Interface main references are at (http://www.silabs.com)
32Silicon Laboratories site], see:
33
34- AN127: FLASH Programming via the C2 Interface at
35http://www.silabs.com/public/documents/tpub_doc/anote/Microcontrollers/Small_Form_Factor/en/an127.pdf, and
36
37- C2 Specification at
38http://www.silabs.com/public/documents/tpub_doc/spec/Microcontrollers/en/C2spec.pdf,
39
40however it implements a two wire serial communication protocol (bit
41banging) designed to enable in-system programming, debugging, and
42boundary-scan testing on low pin-count Silicon Labs devices. Currently
43this code supports only flash programming but extensions are easy to
44add.
45
46Using the driver
47----------------
48
49Once the driver is loaded you can use sysfs support to get C2port's
50info or read/write in-system flash.
51
52# ls /sys/class/c2port/c2port0/
53access flash_block_size flash_erase rev_id
54dev_id flash_blocks_num flash_size subsystem/
55flash_access flash_data reset uevent
56
57Initially the C2port access is disabled since you hardware may have
58such lines multiplexed with other devices so, to get access to the
59C2port, you need the command:
60
61# echo 1 > /sys/class/c2port/c2port0/access
62
63after that you should read the device ID and revision ID of the
64connected micro controller:
65
66# cat /sys/class/c2port/c2port0/dev_id
678
68# cat /sys/class/c2port/c2port0/rev_id
691
70
71However, for security reasons, the in-system flash access in not
72enabled yet, to do so you need the command:
73
74# echo 1 > /sys/class/c2port/c2port0/flash_access
75
76After that you can read the whole flash:
77
78# cat /sys/class/c2port/c2port0/flash_data > image
79
80erase it:
81
82# echo 1 > /sys/class/c2port/c2port0/flash_erase
83
84and write it:
85
86# cat image > /sys/class/c2port/c2port0/flash_data
87
88after writing you have to reset the device to execute the new code:
89
90# echo 1 > /sys/class/c2port/c2port0/reset
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index dcac7ca7693..fee7304102a 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -498,4 +498,6 @@ config SGI_GRU_DEBUG
498 This option enables addition debugging code for the SGI GRU driver. If 498 This option enables addition debugging code for the SGI GRU driver. If
499 you are unsure, say N. 499 you are unsure, say N.
500 500
501source "drivers/misc/c2port/Kconfig"
502
501endif # MISC_DEVICES 503endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index bb14633d136..817f7f5ab3b 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -32,3 +32,4 @@ obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
32obj-$(CONFIG_SGI_XP) += sgi-xp/ 32obj-$(CONFIG_SGI_XP) += sgi-xp/
33obj-$(CONFIG_SGI_GRU) += sgi-gru/ 33obj-$(CONFIG_SGI_GRU) += sgi-gru/
34obj-$(CONFIG_HP_ILO) += hpilo.o 34obj-$(CONFIG_HP_ILO) += hpilo.o
35obj-$(CONFIG_C2PORT) += c2port/
diff --git a/drivers/misc/c2port/Kconfig b/drivers/misc/c2port/Kconfig
new file mode 100644
index 00000000000..f1bad2b4032
--- /dev/null
+++ b/drivers/misc/c2port/Kconfig
@@ -0,0 +1,24 @@
1#
2# C2 port devices
3#
4
5menuconfig C2PORT
6 tristate "Silicon Labs C2 port support (EXPERIMENTAL)"
7 depends on EXPERIMENTAL
8 default no
9 help
10 This option enables support for Silicon Labs C2 port used to
11 program Silicon micro controller chips (and other 8051 compatible).
12
13 If your board have no such micro controllers you don't need this
14 interface at all.
15
16 To compile this driver as a module, choose M here: the module will
17 be called c2port_core. Note that you also need a client module
18 usually called c2port-*.
19
20 If you are not sure, say N here.
21
22if C2PORT
23
24endif # C2PORT
diff --git a/drivers/misc/c2port/Makefile b/drivers/misc/c2port/Makefile
new file mode 100644
index 00000000000..3c610a2ba5e
--- /dev/null
+++ b/drivers/misc/c2port/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_C2PORT) += core.o
diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c
new file mode 100644
index 00000000000..976b35d1d03
--- /dev/null
+++ b/drivers/misc/c2port/core.c
@@ -0,0 +1,1002 @@
1/*
2 * Silicon Labs C2 port core Linux support
3 *
4 * Copyright (c) 2007 Rodolfo Giometti <giometti@linux.it>
5 * Copyright (c) 2007 Eurotech S.p.A. <info@eurotech.it>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation
10 */
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/device.h>
15#include <linux/errno.h>
16#include <linux/err.h>
17#include <linux/kernel.h>
18#include <linux/ctype.h>
19#include <linux/delay.h>
20#include <linux/idr.h>
21
22#include <linux/c2port.h>
23
24#define DRIVER_NAME "c2port"
25#define DRIVER_VERSION "0.51.0"
26
27static DEFINE_SPINLOCK(c2port_idr_lock);
28static DEFINE_IDR(c2port_idr);
29
30/*
31 * Local variables
32 */
33
34static struct class *c2port_class;
35
36/*
37 * C2 registers & commands defines
38 */
39
40/* C2 registers */
41#define C2PORT_DEVICEID 0x00
42#define C2PORT_REVID 0x01
43#define C2PORT_FPCTL 0x02
44#define C2PORT_FPDAT 0xB4
45
46/* C2 interface commands */
47#define C2PORT_GET_VERSION 0x01
48#define C2PORT_DEVICE_ERASE 0x03
49#define C2PORT_BLOCK_READ 0x06
50#define C2PORT_BLOCK_WRITE 0x07
51#define C2PORT_PAGE_ERASE 0x08
52
53/* C2 status return codes */
54#define C2PORT_INVALID_COMMAND 0x00
55#define C2PORT_COMMAND_FAILED 0x02
56#define C2PORT_COMMAND_OK 0x0d
57
58/*
59 * C2 port low level signal managements
60 */
61
62static void c2port_reset(struct c2port_device *dev)
63{
64 struct c2port_ops *ops = dev->ops;
65
66 /* To reset the device we have to keep clock line low for at least
67 * 20us.
68 */
69 local_irq_disable();
70 ops->c2ck_set(dev, 0);
71 udelay(25);
72 ops->c2ck_set(dev, 1);
73 local_irq_enable();
74
75 udelay(1);
76}
77
78static void c2port_strobe_ck(struct c2port_device *dev)
79{
80 struct c2port_ops *ops = dev->ops;
81
82 /* During hi-low-hi transition we disable local IRQs to avoid
83 * interructions since C2 port specification says that it must be
84 * shorter than 5us, otherwise the microcontroller may consider
85 * it as a reset signal!
86 */
87 local_irq_disable();
88 ops->c2ck_set(dev, 0);
89 udelay(1);
90 ops->c2ck_set(dev, 1);
91 local_irq_enable();
92
93 udelay(1);
94}
95
96/*
97 * C2 port basic functions
98 */
99
100static void c2port_write_ar(struct c2port_device *dev, u8 addr)
101{
102 struct c2port_ops *ops = dev->ops;
103 int i;
104
105 /* START field */
106 c2port_strobe_ck(dev);
107
108 /* INS field (11b, LSB first) */
109 ops->c2d_dir(dev, 0);
110 ops->c2d_set(dev, 1);
111 c2port_strobe_ck(dev);
112 ops->c2d_set(dev, 1);
113 c2port_strobe_ck(dev);
114
115 /* ADDRESS field */
116 for (i = 0; i < 8; i++) {
117 ops->c2d_set(dev, addr & 0x01);
118 c2port_strobe_ck(dev);
119
120 addr >>= 1;
121 }
122
123 /* STOP field */
124 ops->c2d_dir(dev, 1);
125 c2port_strobe_ck(dev);
126}
127
128static int c2port_read_ar(struct c2port_device *dev, u8 *addr)
129{
130 struct c2port_ops *ops = dev->ops;
131 int i;
132
133 /* START field */
134 c2port_strobe_ck(dev);
135
136 /* INS field (10b, LSB first) */
137 ops->c2d_dir(dev, 0);
138 ops->c2d_set(dev, 0);
139 c2port_strobe_ck(dev);
140 ops->c2d_set(dev, 1);
141 c2port_strobe_ck(dev);
142
143 /* ADDRESS field */
144 ops->c2d_dir(dev, 1);
145 *addr = 0;
146 for (i = 0; i < 8; i++) {
147 *addr >>= 1; /* shift in 8-bit ADDRESS field LSB first */
148
149 c2port_strobe_ck(dev);
150 if (ops->c2d_get(dev))
151 *addr |= 0x80;
152 }
153
154 /* STOP field */
155 c2port_strobe_ck(dev);
156
157 return 0;
158}
159
160static int c2port_write_dr(struct c2port_device *dev, u8 data)
161{
162 struct c2port_ops *ops = dev->ops;
163 int timeout, i;
164
165 /* START field */
166 c2port_strobe_ck(dev);
167
168 /* INS field (01b, LSB first) */
169 ops->c2d_dir(dev, 0);
170 ops->c2d_set(dev, 1);
171 c2port_strobe_ck(dev);
172 ops->c2d_set(dev, 0);
173 c2port_strobe_ck(dev);
174
175 /* LENGTH field (00b, LSB first -> 1 byte) */
176 ops->c2d_set(dev, 0);
177 c2port_strobe_ck(dev);
178 ops->c2d_set(dev, 0);
179 c2port_strobe_ck(dev);
180
181 /* DATA field */
182 for (i = 0; i < 8; i++) {
183 ops->c2d_set(dev, data & 0x01);
184 c2port_strobe_ck(dev);
185
186 data >>= 1;
187 }
188
189 /* WAIT field */
190 ops->c2d_dir(dev, 1);
191 timeout = 20;
192 do {
193 c2port_strobe_ck(dev);
194 if (ops->c2d_get(dev))
195 break;
196
197 udelay(1);
198 } while (--timeout > 0);
199 if (timeout == 0)
200 return -EIO;
201
202 /* STOP field */
203 c2port_strobe_ck(dev);
204
205 return 0;
206}
207
208static int c2port_read_dr(struct c2port_device *dev, u8 *data)
209{
210 struct c2port_ops *ops = dev->ops;
211 int timeout, i;
212
213 /* START field */
214 c2port_strobe_ck(dev);
215
216 /* INS field (00b, LSB first) */
217 ops->c2d_dir(dev, 0);
218 ops->c2d_set(dev, 0);
219 c2port_strobe_ck(dev);
220 ops->c2d_set(dev, 0);
221 c2port_strobe_ck(dev);
222
223 /* LENGTH field (00b, LSB first -> 1 byte) */
224 ops->c2d_set(dev, 0);
225 c2port_strobe_ck(dev);
226 ops->c2d_set(dev, 0);
227 c2port_strobe_ck(dev);
228
229 /* WAIT field */
230 ops->c2d_dir(dev, 1);
231 timeout = 20;
232 do {
233 c2port_strobe_ck(dev);
234 if (ops->c2d_get(dev))
235 break;
236
237 udelay(1);
238 } while (--timeout > 0);
239 if (timeout == 0)
240 return -EIO;
241
242 /* DATA field */
243 *data = 0;
244 for (i = 0; i < 8; i++) {
245 *data >>= 1; /* shift in 8-bit DATA field LSB first */
246
247 c2port_strobe_ck(dev);
248 if (ops->c2d_get(dev))
249 *data |= 0x80;
250 }
251
252 /* STOP field */
253 c2port_strobe_ck(dev);
254
255 return 0;
256}
257
258static int c2port_poll_in_busy(struct c2port_device *dev)
259{
260 u8 addr;
261 int ret, timeout = 20;
262
263 do {
264 ret = (c2port_read_ar(dev, &addr));
265 if (ret < 0)
266 return -EIO;
267
268 if (!(addr & 0x02))
269 break;
270
271 udelay(1);
272 } while (--timeout > 0);
273 if (timeout == 0)
274 return -EIO;
275
276 return 0;
277}
278
279static int c2port_poll_out_ready(struct c2port_device *dev)
280{
281 u8 addr;
282 int ret, timeout = 10000; /* erase flash needs long time... */
283
284 do {
285 ret = (c2port_read_ar(dev, &addr));
286 if (ret < 0)
287 return -EIO;
288
289 if (addr & 0x01)
290 break;
291
292 udelay(1);
293 } while (--timeout > 0);
294 if (timeout == 0)
295 return -EIO;
296
297 return 0;
298}
299
300/*
301 * sysfs methods
302 */
303
304static ssize_t c2port_show_name(struct device *dev,
305 struct device_attribute *attr, char *buf)
306{
307 struct c2port_device *c2dev = dev_get_drvdata(dev);
308
309 return sprintf(buf, "%s\n", c2dev->name);
310}
311
312static ssize_t c2port_show_flash_blocks_num(struct device *dev,
313 struct device_attribute *attr, char *buf)
314{
315 struct c2port_device *c2dev = dev_get_drvdata(dev);
316 struct c2port_ops *ops = c2dev->ops;
317
318 return sprintf(buf, "%d\n", ops->blocks_num);
319}
320
321static ssize_t c2port_show_flash_block_size(struct device *dev,
322 struct device_attribute *attr, char *buf)
323{
324 struct c2port_device *c2dev = dev_get_drvdata(dev);
325 struct c2port_ops *ops = c2dev->ops;
326
327 return sprintf(buf, "%d\n", ops->block_size);
328}
329
330static ssize_t c2port_show_flash_size(struct device *dev,
331 struct device_attribute *attr, char *buf)
332{
333 struct c2port_device *c2dev = dev_get_drvdata(dev);
334 struct c2port_ops *ops = c2dev->ops;
335
336 return sprintf(buf, "%d\n", ops->blocks_num * ops->block_size);
337}
338
339static ssize_t c2port_show_access(struct device *dev,
340 struct device_attribute *attr, char *buf)
341{
342 struct c2port_device *c2dev = dev_get_drvdata(dev);
343
344 return sprintf(buf, "%d\n", c2dev->access);
345}
346
347static ssize_t c2port_store_access(struct device *dev,
348 struct device_attribute *attr,
349 const char *buf, size_t count)
350{
351 struct c2port_device *c2dev = dev_get_drvdata(dev);
352 struct c2port_ops *ops = c2dev->ops;
353 int status, ret;
354
355 ret = sscanf(buf, "%d", &status);
356 if (ret != 1)
357 return -EINVAL;
358
359 mutex_lock(&c2dev->mutex);
360
361 c2dev->access = !!status;
362
363 /* If access is "on" clock should be HIGH _before_ setting the line
364 * as output and data line should be set as INPUT anyway */
365 if (c2dev->access)
366 ops->c2ck_set(c2dev, 1);
367 ops->access(c2dev, c2dev->access);
368 if (c2dev->access)
369 ops->c2d_dir(c2dev, 1);
370
371 mutex_unlock(&c2dev->mutex);
372
373 return count;
374}
375
376static ssize_t c2port_store_reset(struct device *dev,
377 struct device_attribute *attr,
378 const char *buf, size_t count)
379{
380 struct c2port_device *c2dev = dev_get_drvdata(dev);
381
382 /* Check the device access status */
383 if (!c2dev->access)
384 return -EBUSY;
385
386 mutex_lock(&c2dev->mutex);
387
388 c2port_reset(c2dev);
389 c2dev->flash_access = 0;
390
391 mutex_unlock(&c2dev->mutex);
392
393 return count;
394}
395
396static ssize_t __c2port_show_dev_id(struct c2port_device *dev, char *buf)
397{
398 u8 data;
399 int ret;
400
401 /* Select DEVICEID register for C2 data register accesses */
402 c2port_write_ar(dev, C2PORT_DEVICEID);
403
404 /* Read and return the device ID register */
405 ret = c2port_read_dr(dev, &data);
406 if (ret < 0)
407 return ret;
408
409 return sprintf(buf, "%d\n", data);
410}
411
412static ssize_t c2port_show_dev_id(struct device *dev,
413 struct device_attribute *attr, char *buf)
414{
415 struct c2port_device *c2dev = dev_get_drvdata(dev);
416 ssize_t ret;
417
418 /* Check the device access status */
419 if (!c2dev->access)
420 return -EBUSY;
421
422 mutex_lock(&c2dev->mutex);
423 ret = __c2port_show_dev_id(c2dev, buf);
424 mutex_unlock(&c2dev->mutex);
425
426 if (ret < 0)
427 dev_err(dev, "cannot read from %s\n", c2dev->name);
428
429 return ret;
430}
431
432static ssize_t __c2port_show_rev_id(struct c2port_device *dev, char *buf)
433{
434 u8 data;
435 int ret;
436
437 /* Select REVID register for C2 data register accesses */
438 c2port_write_ar(dev, C2PORT_REVID);
439
440 /* Read and return the revision ID register */
441 ret = c2port_read_dr(dev, &data);
442 if (ret < 0)
443 return ret;
444
445 return sprintf(buf, "%d\n", data);
446}
447
448static ssize_t c2port_show_rev_id(struct device *dev,
449 struct device_attribute *attr, char *buf)
450{
451 struct c2port_device *c2dev = dev_get_drvdata(dev);
452 ssize_t ret;
453
454 /* Check the device access status */
455 if (!c2dev->access)
456 return -EBUSY;
457
458 mutex_lock(&c2dev->mutex);
459 ret = __c2port_show_rev_id(c2dev, buf);
460 mutex_unlock(&c2dev->mutex);
461
462 if (ret < 0)
463 dev_err(c2dev->dev, "cannot read from %s\n", c2dev->name);
464
465 return ret;
466}
467
468static ssize_t c2port_show_flash_access(struct device *dev,
469 struct device_attribute *attr, char *buf)
470{
471 struct c2port_device *c2dev = dev_get_drvdata(dev);
472
473 return sprintf(buf, "%d\n", c2dev->flash_access);
474}
475
476static ssize_t __c2port_store_flash_access(struct c2port_device *dev,
477 int status)
478{
479 int ret;
480
481 /* Check the device access status */
482 if (!dev->access)
483 return -EBUSY;
484
485 dev->flash_access = !!status;
486
487 /* If flash_access is off we have nothing to do... */
488 if (dev->flash_access == 0)
489 return 0;
490
491 /* Target the C2 flash programming control register for C2 data
492 * register access */
493 c2port_write_ar(dev, C2PORT_FPCTL);
494
495 /* Write the first keycode to enable C2 Flash programming */
496 ret = c2port_write_dr(dev, 0x02);
497 if (ret < 0)
498 return ret;
499
500 /* Write the second keycode to enable C2 Flash programming */
501 ret = c2port_write_dr(dev, 0x01);
502 if (ret < 0)
503 return ret;
504
505 /* Delay for at least 20ms to ensure the target is ready for
506 * C2 flash programming */
507 mdelay(25);
508
509 return 0;
510}
511
512static ssize_t c2port_store_flash_access(struct device *dev,
513 struct device_attribute *attr,
514 const char *buf, size_t count)
515{
516 struct c2port_device *c2dev = dev_get_drvdata(dev);
517 int status;
518 ssize_t ret;
519
520 ret = sscanf(buf, "%d", &status);
521 if (ret != 1)
522 return -EINVAL;
523
524 mutex_lock(&c2dev->mutex);
525 ret = __c2port_store_flash_access(c2dev, status);
526 mutex_unlock(&c2dev->mutex);
527
528 if (ret < 0) {
529 dev_err(c2dev->dev, "cannot enable %s flash programming\n",
530 c2dev->name);
531 return ret;
532 }
533
534 return count;
535}
536
537static ssize_t __c2port_write_flash_erase(struct c2port_device *dev)
538{
539 u8 status;
540 int ret;
541
542 /* Target the C2 flash programming data register for C2 data register
543 * access.
544 */
545 c2port_write_ar(dev, C2PORT_FPDAT);
546
547 /* Send device erase command */
548 c2port_write_dr(dev, C2PORT_DEVICE_ERASE);
549
550 /* Wait for input acknowledge */
551 ret = c2port_poll_in_busy(dev);
552 if (ret < 0)
553 return ret;
554
555 /* Should check status before starting FLASH access sequence */
556
557 /* Wait for status information */
558 ret = c2port_poll_out_ready(dev);
559 if (ret < 0)
560 return ret;
561
562 /* Read flash programming interface status */
563 ret = c2port_read_dr(dev, &status);
564 if (ret < 0)
565 return ret;
566 if (status != C2PORT_COMMAND_OK)
567 return -EBUSY;
568
569 /* Send a three-byte arming sequence to enable the device erase.
570 * If the sequence is not received correctly, the command will be
571 * ignored.
572 * Sequence is: 0xde, 0xad, 0xa5.
573 */
574 c2port_write_dr(dev, 0xde);
575 ret = c2port_poll_in_busy(dev);
576 if (ret < 0)
577 return ret;
578 c2port_write_dr(dev, 0xad);
579 ret = c2port_poll_in_busy(dev);
580 if (ret < 0)
581 return ret;
582 c2port_write_dr(dev, 0xa5);
583 ret = c2port_poll_in_busy(dev);
584 if (ret < 0)
585 return ret;
586
587 ret = c2port_poll_out_ready(dev);
588 if (ret < 0)
589 return ret;
590
591 return 0;
592}
593
594static ssize_t c2port_store_flash_erase(struct device *dev,
595 struct device_attribute *attr,
596 const char *buf, size_t count)
597{
598 struct c2port_device *c2dev = dev_get_drvdata(dev);
599 int ret;
600
601 /* Check the device and flash access status */
602 if (!c2dev->access || !c2dev->flash_access)
603 return -EBUSY;
604
605 mutex_lock(&c2dev->mutex);
606 ret = __c2port_write_flash_erase(c2dev);
607 mutex_unlock(&c2dev->mutex);
608
609 if (ret < 0) {
610 dev_err(c2dev->dev, "cannot erase %s flash\n", c2dev->name);
611 return ret;
612 }
613
614 return count;
615}
616
617static ssize_t __c2port_read_flash_data(struct c2port_device *dev,
618 char *buffer, loff_t offset, size_t count)
619{
620 struct c2port_ops *ops = dev->ops;
621 u8 status, nread = 128;
622 int i, ret;
623
624 /* Check for flash end */
625 if (offset >= ops->block_size * ops->blocks_num)
626 return 0;
627
628 if (ops->block_size * ops->blocks_num - offset < nread)
629 nread = ops->block_size * ops->blocks_num - offset;
630 if (count < nread)
631 nread = count;
632 if (nread == 0)
633 return nread;
634
635 /* Target the C2 flash programming data register for C2 data register
636 * access */
637 c2port_write_ar(dev, C2PORT_FPDAT);
638
639 /* Send flash block read command */
640 c2port_write_dr(dev, C2PORT_BLOCK_READ);
641
642 /* Wait for input acknowledge */
643 ret = c2port_poll_in_busy(dev);
644 if (ret < 0)
645 return ret;
646
647 /* Should check status before starting FLASH access sequence */
648
649 /* Wait for status information */
650 ret = c2port_poll_out_ready(dev);
651 if (ret < 0)
652 return ret;
653
654 /* Read flash programming interface status */
655 ret = c2port_read_dr(dev, &status);
656 if (ret < 0)
657 return ret;
658 if (status != C2PORT_COMMAND_OK)
659 return -EBUSY;
660
661 /* Send address high byte */
662 c2port_write_dr(dev, offset >> 8);
663 ret = c2port_poll_in_busy(dev);
664 if (ret < 0)
665 return ret;
666
667 /* Send address low byte */
668 c2port_write_dr(dev, offset & 0x00ff);
669 ret = c2port_poll_in_busy(dev);
670 if (ret < 0)
671 return ret;
672
673 /* Send address block size */
674 c2port_write_dr(dev, nread);
675 ret = c2port_poll_in_busy(dev);
676 if (ret < 0)
677 return ret;
678
679 /* Should check status before reading FLASH block */
680
681 /* Wait for status information */
682 ret = c2port_poll_out_ready(dev);
683 if (ret < 0)
684 return ret;
685
686 /* Read flash programming interface status */
687 ret = c2port_read_dr(dev, &status);
688 if (ret < 0)
689 return ret;
690 if (status != C2PORT_COMMAND_OK)
691 return -EBUSY;
692
693 /* Read flash block */
694 for (i = 0; i < nread; i++) {
695 ret = c2port_poll_out_ready(dev);
696 if (ret < 0)
697 return ret;
698
699 ret = c2port_read_dr(dev, buffer+i);
700 if (ret < 0)
701 return ret;
702 }
703
704 return nread;
705}
706
707static ssize_t c2port_read_flash_data(struct kobject *kobj,
708 struct bin_attribute *attr,
709 char *buffer, loff_t offset, size_t count)
710{
711 struct c2port_device *c2dev =
712 dev_get_drvdata(container_of(kobj,
713 struct device, kobj));
714 ssize_t ret;
715
716 /* Check the device and flash access status */
717 if (!c2dev->access || !c2dev->flash_access)
718 return -EBUSY;
719
720 mutex_lock(&c2dev->mutex);
721 ret = __c2port_read_flash_data(c2dev, buffer, offset, count);
722 mutex_unlock(&c2dev->mutex);
723
724 if (ret < 0)
725 dev_err(c2dev->dev, "cannot read %s flash\n", c2dev->name);
726
727 return ret;
728}
729
730static ssize_t __c2port_write_flash_data(struct c2port_device *dev,
731 char *buffer, loff_t offset, size_t count)
732{
733 struct c2port_ops *ops = dev->ops;
734 u8 status, nwrite = 128;
735 int i, ret;
736
737 if (nwrite > count)
738 nwrite = count;
739 if (ops->block_size * ops->blocks_num - offset < nwrite)
740 nwrite = ops->block_size * ops->blocks_num - offset;
741
742 /* Check for flash end */
743 if (offset >= ops->block_size * ops->blocks_num)
744 return -EINVAL;
745
746 /* Target the C2 flash programming data register for C2 data register
747 * access */
748 c2port_write_ar(dev, C2PORT_FPDAT);
749
750 /* Send flash block write command */
751 c2port_write_dr(dev, C2PORT_BLOCK_WRITE);
752
753 /* Wait for input acknowledge */
754 ret = c2port_poll_in_busy(dev);
755 if (ret < 0)
756 return ret;
757
758 /* Should check status before starting FLASH access sequence */
759
760 /* Wait for status information */
761 ret = c2port_poll_out_ready(dev);
762 if (ret < 0)
763 return ret;
764
765 /* Read flash programming interface status */
766 ret = c2port_read_dr(dev, &status);
767 if (ret < 0)
768 return ret;
769 if (status != C2PORT_COMMAND_OK)
770 return -EBUSY;
771
772 /* Send address high byte */
773 c2port_write_dr(dev, offset >> 8);
774 ret = c2port_poll_in_busy(dev);
775 if (ret < 0)
776 return ret;
777
778 /* Send address low byte */
779 c2port_write_dr(dev, offset & 0x00ff);
780 ret = c2port_poll_in_busy(dev);
781 if (ret < 0)
782 return ret;
783
784 /* Send address block size */
785 c2port_write_dr(dev, nwrite);
786 ret = c2port_poll_in_busy(dev);
787 if (ret < 0)
788 return ret;
789
790 /* Should check status before writing FLASH block */
791
792 /* Wait for status information */
793 ret = c2port_poll_out_ready(dev);
794 if (ret < 0)
795 return ret;
796
797 /* Read flash programming interface status */
798 ret = c2port_read_dr(dev, &status);
799 if (ret < 0)
800 return ret;
801 if (status != C2PORT_COMMAND_OK)
802 return -EBUSY;
803
804 /* Write flash block */
805 for (i = 0; i < nwrite; i++) {
806 ret = c2port_write_dr(dev, *(buffer+i));
807 if (ret < 0)
808 return ret;
809
810 ret = c2port_poll_in_busy(dev);
811 if (ret < 0)
812 return ret;
813
814 }
815
816 /* Wait for last flash write to complete */
817 ret = c2port_poll_out_ready(dev);
818 if (ret < 0)
819 return ret;
820
821 return nwrite;
822}
823
824static ssize_t c2port_write_flash_data(struct kobject *kobj,
825 struct bin_attribute *attr,
826 char *buffer, loff_t offset, size_t count)
827{
828 struct c2port_device *c2dev =
829 dev_get_drvdata(container_of(kobj,
830 struct device, kobj));
831 int ret;
832
833 /* Check the device access status */
834 if (!c2dev->access || !c2dev->flash_access)
835 return -EBUSY;
836
837 mutex_lock(&c2dev->mutex);
838 ret = __c2port_write_flash_data(c2dev, buffer, offset, count);
839 mutex_unlock(&c2dev->mutex);
840
841 if (ret < 0)
842 dev_err(c2dev->dev, "cannot write %s flash\n", c2dev->name);
843
844 return ret;
845}
846
847/*
848 * Class attributes
849 */
850
851static struct device_attribute c2port_attrs[] = {
852 __ATTR(name, 0444, c2port_show_name, NULL),
853 __ATTR(flash_blocks_num, 0444, c2port_show_flash_blocks_num, NULL),
854 __ATTR(flash_block_size, 0444, c2port_show_flash_block_size, NULL),
855 __ATTR(flash_size, 0444, c2port_show_flash_size, NULL),
856 __ATTR(access, 0644, c2port_show_access, c2port_store_access),
857 __ATTR(reset, 0200, NULL, c2port_store_reset),
858 __ATTR(dev_id, 0444, c2port_show_dev_id, NULL),
859 __ATTR(rev_id, 0444, c2port_show_rev_id, NULL),
860
861 __ATTR(flash_access, 0644, c2port_show_flash_access,
862 c2port_store_flash_access),
863 __ATTR(flash_erase, 0200, NULL, c2port_store_flash_erase),
864 __ATTR_NULL,
865};
866
867static struct bin_attribute c2port_bin_attrs = {
868 .attr = {
869 .name = "flash_data",
870 .mode = 0644
871 },
872 .read = c2port_read_flash_data,
873 .write = c2port_write_flash_data,
874 /* .size is computed at run-time */
875};
876
877/*
878 * Exported functions
879 */
880
881struct c2port_device *c2port_device_register(char *name,
882 struct c2port_ops *ops, void *devdata)
883{
884 struct c2port_device *c2dev;
885 int id, ret;
886
887 if (unlikely(!ops) || unlikely(!ops->access) || \
888 unlikely(!ops->c2d_dir) || unlikely(!ops->c2ck_set) || \
889 unlikely(!ops->c2d_get) || unlikely(!ops->c2d_set))
890 return ERR_PTR(-EINVAL);
891
892 c2dev = kmalloc(sizeof(struct c2port_device), GFP_KERNEL);
893 if (unlikely(!c2dev))
894 return ERR_PTR(-ENOMEM);
895
896 ret = idr_pre_get(&c2port_idr, GFP_KERNEL);
897 if (!ret) {
898 ret = -ENOMEM;
899 goto error_idr_get_new;
900 }
901
902 spin_lock_irq(&c2port_idr_lock);
903 ret = idr_get_new(&c2port_idr, c2dev, &id);
904 spin_unlock_irq(&c2port_idr_lock);
905
906 if (ret < 0)
907 goto error_idr_get_new;
908 c2dev->id = id;
909
910 c2dev->dev = device_create(c2port_class, NULL, 0, c2dev,
911 "c2port%d", id);
912 if (unlikely(!c2dev->dev)) {
913 ret = -ENOMEM;
914 goto error_device_create;
915 }
916 dev_set_drvdata(c2dev->dev, c2dev);
917
918 strncpy(c2dev->name, name, C2PORT_NAME_LEN);
919 c2dev->ops = ops;
920 mutex_init(&c2dev->mutex);
921
922 /* Create binary file */
923 c2port_bin_attrs.size = ops->blocks_num * ops->block_size;
924 ret = device_create_bin_file(c2dev->dev, &c2port_bin_attrs);
925 if (unlikely(ret))
926 goto error_device_create_bin_file;
927
928 /* By default C2 port access is off */
929 c2dev->access = c2dev->flash_access = 0;
930 ops->access(c2dev, 0);
931
932 dev_info(c2dev->dev, "C2 port %s added\n", name);
933 dev_info(c2dev->dev, "%s flash has %d blocks x %d bytes "
934 "(%d bytes total)\n",
935 name, ops->blocks_num, ops->block_size,
936 ops->blocks_num * ops->block_size);
937
938 return c2dev;
939
940error_device_create_bin_file:
941 device_destroy(c2port_class, 0);
942
943error_device_create:
944 spin_lock_irq(&c2port_idr_lock);
945 idr_remove(&c2port_idr, id);
946 spin_unlock_irq(&c2port_idr_lock);
947
948error_idr_get_new:
949 kfree(c2dev);
950
951 return ERR_PTR(ret);
952}
953EXPORT_SYMBOL(c2port_device_register);
954
955void c2port_device_unregister(struct c2port_device *c2dev)
956{
957 if (!c2dev)
958 return;
959
960 dev_info(c2dev->dev, "C2 port %s removed\n", c2dev->name);
961
962 device_remove_bin_file(c2dev->dev, &c2port_bin_attrs);
963 spin_lock_irq(&c2port_idr_lock);
964 idr_remove(&c2port_idr, c2dev->id);
965 spin_unlock_irq(&c2port_idr_lock);
966
967 device_destroy(c2port_class, c2dev->id);
968
969 kfree(c2dev);
970}
971EXPORT_SYMBOL(c2port_device_unregister);
972
973/*
974 * Module stuff
975 */
976
977static int __init c2port_init(void)
978{
979 printk(KERN_INFO "Silicon Labs C2 port support v. " DRIVER_VERSION
980 " - (C) 2007 Rodolfo Giometti\n");
981
982 c2port_class = class_create(THIS_MODULE, "c2port");
983 if (!c2port_class) {
984 printk(KERN_ERR "c2port: failed to allocate class\n");
985 return -ENOMEM;
986 }
987 c2port_class->dev_attrs = c2port_attrs;
988
989 return 0;
990}
991
992static void __exit c2port_exit(void)
993{
994 class_destroy(c2port_class);
995}
996
997module_init(c2port_init);
998module_exit(c2port_exit);
999
1000MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
1001MODULE_DESCRIPTION("Silicon Labs C2 port support v. " DRIVER_VERSION);
1002MODULE_LICENSE("GPL");
diff --git a/include/linux/c2port.h b/include/linux/c2port.h
new file mode 100644
index 00000000000..7b5a2388ba6
--- /dev/null
+++ b/include/linux/c2port.h
@@ -0,0 +1,65 @@
1/*
2 * Silicon Labs C2 port Linux support
3 *
4 * Copyright (c) 2007 Rodolfo Giometti <giometti@linux.it>
5 * Copyright (c) 2007 Eurotech S.p.A. <info@eurotech.it>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation
10 */
11
12#include <linux/device.h>
13
14#define C2PORT_NAME_LEN 32
15
16/*
17 * C2 port basic structs
18 */
19
20/* Main struct */
21struct c2port_ops;
22struct c2port_device {
23 unsigned int access:1;
24 unsigned int flash_access:1;
25
26 int id;
27 char name[C2PORT_NAME_LEN];
28 struct c2port_ops *ops;
29 struct mutex mutex; /* prevent races during read/write */
30
31 struct device *dev;
32
33 void *private_data;
34};
35
36/* Basic operations */
37struct c2port_ops {
38 /* Flash layout */
39 unsigned short block_size; /* flash block size in bytes */
40 unsigned short blocks_num; /* flash blocks number */
41
42 /* Enable or disable the access to C2 port */
43 void (*access)(struct c2port_device *dev, int status);
44
45 /* Set C2D data line as input/output */
46 void (*c2d_dir)(struct c2port_device *dev, int dir);
47
48 /* Read/write C2D data line */
49 int (*c2d_get)(struct c2port_device *dev);
50 void (*c2d_set)(struct c2port_device *dev, int status);
51
52 /* Write C2CK clock line */
53 void (*c2ck_set)(struct c2port_device *dev, int status);
54};
55
56/*
57 * Exported functions
58 */
59
60#define to_class_dev(obj) container_of((obj), struct class_device, kobj)
61#define to_c2port_device(obj) container_of((obj), struct c2port_device, class)
62
63extern struct c2port_device *c2port_device_register(char *name,
64 struct c2port_ops *ops, void *devdata);
65extern void c2port_device_unregister(struct c2port_device *dev);