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>

authored by Rodolfo Giometti and committed by Linus Torvalds 4e17e1db e0a29382

+1273
+88
Documentation/ABI/testing/sysfs-c2port
···
··· 1 + What: /sys/class/c2port/ 2 + Date: October 2008 3 + Contact: Rodolfo Giometti <giometti@linux.it> 4 + Description: 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 + 9 + What: /sys/class/c2port/c2portX 10 + Date: October 2008 11 + Contact: Rodolfo Giometti <giometti@linux.it> 12 + Description: 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 + 17 + What: /sys/class/c2port/c2portX/access 18 + Date: October 2008 19 + Contact: Rodolfo Giometti <giometti@linux.it> 20 + Description: 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 + 25 + What: /sys/class/c2port/c2portX/dev_id 26 + Date: October 2008 27 + Contact: Rodolfo Giometti <giometti@linux.it> 28 + Description: 29 + The /sys/class/c2port/c2portX/dev_id file show the device ID 30 + of the connected micro. 31 + 32 + What: /sys/class/c2port/c2portX/flash_access 33 + Date: October 2008 34 + Contact: Rodolfo Giometti <giometti@linux.it> 35 + Description: 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 + 40 + What: /sys/class/c2port/c2portX/flash_block_size 41 + Date: October 2008 42 + Contact: Rodolfo Giometti <giometti@linux.it> 43 + Description: 44 + The /sys/class/c2port/c2portX/flash_block_size file show 45 + the on-board flash block size of the connected micro. 46 + 47 + What: /sys/class/c2port/c2portX/flash_blocks_num 48 + Date: October 2008 49 + Contact: Rodolfo Giometti <giometti@linux.it> 50 + Description: 51 + The /sys/class/c2port/c2portX/flash_blocks_num file show 52 + the on-board flash blocks number of the connected micro. 53 + 54 + What: /sys/class/c2port/c2portX/flash_data 55 + Date: October 2008 56 + Contact: Rodolfo Giometti <giometti@linux.it> 57 + Description: 58 + The /sys/class/c2port/c2portX/flash_data file export 59 + the content of the on-board flash of the connected micro. 60 + 61 + What: /sys/class/c2port/c2portX/flash_erase 62 + Date: October 2008 63 + Contact: Rodolfo Giometti <giometti@linux.it> 64 + Description: 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 + 69 + What: /sys/class/c2port/c2portX/flash_erase 70 + Date: October 2008 71 + Contact: Rodolfo Giometti <giometti@linux.it> 72 + Description: 73 + The /sys/class/c2port/c2portX/flash_erase file show the 74 + on-board flash size of the connected micro. 75 + 76 + What: /sys/class/c2port/c2portX/reset 77 + Date: October 2008 78 + Contact: Rodolfo Giometti <giometti@linux.it> 79 + Description: 80 + The /sys/class/c2port/c2portX/reset file execute a "reset" 81 + command on the connected micro. 82 + 83 + What: /sys/class/c2port/c2portX/rev_id 84 + Date: October 2008 85 + Contact: Rodolfo Giometti <giometti@linux.it> 86 + Description: 87 + The /sys/class/c2port/c2portX/rev_id file show the revision ID 88 + of the connected micro.
+90
Documentation/c2port.txt
···
··· 1 + C2 port support 2 + --------------- 3 + 4 + (C) Copyright 2007 Rodolfo Giometti <giometti@enneenne.com> 5 + 6 + This program is free software; you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation; either version 2 of the License, or 9 + (at your option) any later version. 10 + 11 + This program is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + 17 + 18 + Overview 19 + -------- 20 + 21 + This driver implements the support for Linux of Silicon Labs (Silabs) 22 + C2 Interface used for in-system programming of micro controllers. 23 + 24 + By using this driver you can reprogram the in-system flash without EC2 25 + or EC3 debug adapter. This solution is also useful in those systems 26 + where the micro controller is connected via special GPIOs pins. 27 + 28 + References 29 + ---------- 30 + 31 + The C2 Interface main references are at (http://www.silabs.com) 32 + Silicon Laboratories site], see: 33 + 34 + - AN127: FLASH Programming via the C2 Interface at 35 + http://www.silabs.com/public/documents/tpub_doc/anote/Microcontrollers/Small_Form_Factor/en/an127.pdf, and 36 + 37 + - C2 Specification at 38 + http://www.silabs.com/public/documents/tpub_doc/spec/Microcontrollers/en/C2spec.pdf, 39 + 40 + however it implements a two wire serial communication protocol (bit 41 + banging) designed to enable in-system programming, debugging, and 42 + boundary-scan testing on low pin-count Silicon Labs devices. Currently 43 + this code supports only flash programming but extensions are easy to 44 + add. 45 + 46 + Using the driver 47 + ---------------- 48 + 49 + Once the driver is loaded you can use sysfs support to get C2port's 50 + info or read/write in-system flash. 51 + 52 + # ls /sys/class/c2port/c2port0/ 53 + access flash_block_size flash_erase rev_id 54 + dev_id flash_blocks_num flash_size subsystem/ 55 + flash_access flash_data reset uevent 56 + 57 + Initially the C2port access is disabled since you hardware may have 58 + such lines multiplexed with other devices so, to get access to the 59 + C2port, you need the command: 60 + 61 + # echo 1 > /sys/class/c2port/c2port0/access 62 + 63 + after that you should read the device ID and revision ID of the 64 + connected micro controller: 65 + 66 + # cat /sys/class/c2port/c2port0/dev_id 67 + 8 68 + # cat /sys/class/c2port/c2port0/rev_id 69 + 1 70 + 71 + However, for security reasons, the in-system flash access in not 72 + enabled yet, to do so you need the command: 73 + 74 + # echo 1 > /sys/class/c2port/c2port0/flash_access 75 + 76 + After that you can read the whole flash: 77 + 78 + # cat /sys/class/c2port/c2port0/flash_data > image 79 + 80 + erase it: 81 + 82 + # echo 1 > /sys/class/c2port/c2port0/flash_erase 83 + 84 + and write it: 85 + 86 + # cat image > /sys/class/c2port/c2port0/flash_data 87 + 88 + after writing you have to reset the device to execute the new code: 89 + 90 + # echo 1 > /sys/class/c2port/c2port0/reset
+2
drivers/misc/Kconfig
··· 498 This option enables addition debugging code for the SGI GRU driver. If 499 you are unsure, say N. 500 501 endif # MISC_DEVICES
··· 498 This option enables addition debugging code for the SGI GRU driver. If 499 you are unsure, say N. 500 501 + source "drivers/misc/c2port/Kconfig" 502 + 503 endif # MISC_DEVICES
+1
drivers/misc/Makefile
··· 32 obj-$(CONFIG_SGI_XP) += sgi-xp/ 33 obj-$(CONFIG_SGI_GRU) += sgi-gru/ 34 obj-$(CONFIG_HP_ILO) += hpilo.o
··· 32 obj-$(CONFIG_SGI_XP) += sgi-xp/ 33 obj-$(CONFIG_SGI_GRU) += sgi-gru/ 34 obj-$(CONFIG_HP_ILO) += hpilo.o 35 + obj-$(CONFIG_C2PORT) += c2port/
+24
drivers/misc/c2port/Kconfig
···
··· 1 + # 2 + # C2 port devices 3 + # 4 + 5 + menuconfig 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 + 22 + if C2PORT 23 + 24 + endif # C2PORT
+1
drivers/misc/c2port/Makefile
···
··· 1 + obj-$(CONFIG_C2PORT) += core.o
+1002
drivers/misc/c2port/core.c
···
··· 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 + 27 + static DEFINE_SPINLOCK(c2port_idr_lock); 28 + static DEFINE_IDR(c2port_idr); 29 + 30 + /* 31 + * Local variables 32 + */ 33 + 34 + static 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 + 62 + static 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 + 78 + static 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 + 100 + static 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 + 128 + static 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 + 160 + static 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 + 208 + static 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 + 258 + static 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 + 279 + static 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 + 304 + static 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 + 312 + static 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 + 321 + static 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 + 330 + static 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 + 339 + static 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 + 347 + static 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 + 376 + static 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 + 396 + static 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 + 412 + static 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 + 432 + static 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 + 448 + static 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 + 468 + static 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 + 476 + static 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 + 512 + static 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 + 537 + static 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 + 594 + static 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 + 617 + static 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 + 707 + static 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 + 730 + static 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 + 824 + static 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 + 851 + static 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 + 867 + static 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 + 881 + struct 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 + 940 + error_device_create_bin_file: 941 + device_destroy(c2port_class, 0); 942 + 943 + error_device_create: 944 + spin_lock_irq(&c2port_idr_lock); 945 + idr_remove(&c2port_idr, id); 946 + spin_unlock_irq(&c2port_idr_lock); 947 + 948 + error_idr_get_new: 949 + kfree(c2dev); 950 + 951 + return ERR_PTR(ret); 952 + } 953 + EXPORT_SYMBOL(c2port_device_register); 954 + 955 + void 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 + } 971 + EXPORT_SYMBOL(c2port_device_unregister); 972 + 973 + /* 974 + * Module stuff 975 + */ 976 + 977 + static 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 + 992 + static void __exit c2port_exit(void) 993 + { 994 + class_destroy(c2port_class); 995 + } 996 + 997 + module_init(c2port_init); 998 + module_exit(c2port_exit); 999 + 1000 + MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); 1001 + MODULE_DESCRIPTION("Silicon Labs C2 port support v. " DRIVER_VERSION); 1002 + MODULE_LICENSE("GPL");
+65
include/linux/c2port.h
···
··· 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 */ 21 + struct c2port_ops; 22 + struct 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 */ 37 + struct 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 + 63 + extern struct c2port_device *c2port_device_register(char *name, 64 + struct c2port_ops *ops, void *devdata); 65 + extern void c2port_device_unregister(struct c2port_device *dev);