Commit 4e17e1db96474af5620e3259754df4cb1c46521c

Authored by Rodolfo Giometti
Committed by Linus Torvalds
1 parent e0a29382c6

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>

Showing 8 changed files with 1273 additions and 0 deletions Side-by-side Diff

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.
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
drivers/misc/Kconfig
... ... @@ -498,5 +498,7 @@
498 498 This option enables addition debugging code for the SGI GRU driver. If
499 499 you are unsure, say N.
500 500  
  501 +source "drivers/misc/c2port/Kconfig"
  502 +
501 503 endif # MISC_DEVICES
drivers/misc/Makefile
... ... @@ -32,4 +32,5 @@
32 32 obj-$(CONFIG_SGI_XP) += sgi-xp/
33 33 obj-$(CONFIG_SGI_GRU) += sgi-gru/
34 34 obj-$(CONFIG_HP_ILO) += hpilo.o
  35 +obj-$(CONFIG_C2PORT) += c2port/
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
drivers/misc/c2port/Makefile
  1 +obj-$(CONFIG_C2PORT) += core.o
drivers/misc/c2port/core.c
Changes suppressed. Click to show
  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");
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);