1001 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Silicon Labs C2 port core Linux support4 *5 * Copyright (c) 2007 Rodolfo Giometti <giometti@linux.it>6 * Copyright (c) 2007 Eurotech S.p.A. <info@eurotech.it>7 */8 9#include <linux/module.h>10#include <linux/init.h>11#include <linux/device.h>12#include <linux/errno.h>13#include <linux/err.h>14#include <linux/kernel.h>15#include <linux/ctype.h>16#include <linux/delay.h>17#include <linux/idr.h>18#include <linux/sched.h>19#include <linux/slab.h>20 21#include <linux/c2port.h>22 23#define DRIVER_NAME "c2port"24#define DRIVER_VERSION "0.51.0"25 26static DEFINE_SPINLOCK(c2port_idr_lock);27static DEFINE_IDR(c2port_idr);28 29/*30 * Local variables31 */32 33static struct class *c2port_class;34 35/*36 * C2 registers & commands defines37 */38 39/* C2 registers */40#define C2PORT_DEVICEID 0x0041#define C2PORT_REVID 0x0142#define C2PORT_FPCTL 0x0243#define C2PORT_FPDAT 0xB444 45/* C2 interface commands */46#define C2PORT_GET_VERSION 0x0147#define C2PORT_DEVICE_ERASE 0x0348#define C2PORT_BLOCK_READ 0x0649#define C2PORT_BLOCK_WRITE 0x0750#define C2PORT_PAGE_ERASE 0x0851 52/* C2 status return codes */53#define C2PORT_INVALID_COMMAND 0x0054#define C2PORT_COMMAND_FAILED 0x0255#define C2PORT_COMMAND_OK 0x0d56 57/*58 * C2 port low level signal managements59 */60 61static void c2port_reset(struct c2port_device *dev)62{63 struct c2port_ops *ops = dev->ops;64 65 /* To reset the device we have to keep clock line low for at least66 * 20us.67 */68 local_irq_disable();69 ops->c2ck_set(dev, 0);70 udelay(25);71 ops->c2ck_set(dev, 1);72 local_irq_enable();73 74 udelay(1);75}76 77static void c2port_strobe_ck(struct c2port_device *dev)78{79 struct c2port_ops *ops = dev->ops;80 81 /* During hi-low-hi transition we disable local IRQs to avoid82 * interructions since C2 port specification says that it must be83 * shorter than 5us, otherwise the microcontroller may consider84 * it as a reset signal!85 */86 local_irq_disable();87 ops->c2ck_set(dev, 0);88 udelay(1);89 ops->c2ck_set(dev, 1);90 local_irq_enable();91 92 udelay(1);93}94 95/*96 * C2 port basic functions97 */98 99static void c2port_write_ar(struct c2port_device *dev, u8 addr)100{101 struct c2port_ops *ops = dev->ops;102 int i;103 104 /* START field */105 c2port_strobe_ck(dev);106 107 /* INS field (11b, LSB first) */108 ops->c2d_dir(dev, 0);109 ops->c2d_set(dev, 1);110 c2port_strobe_ck(dev);111 ops->c2d_set(dev, 1);112 c2port_strobe_ck(dev);113 114 /* ADDRESS field */115 for (i = 0; i < 8; i++) {116 ops->c2d_set(dev, addr & 0x01);117 c2port_strobe_ck(dev);118 119 addr >>= 1;120 }121 122 /* STOP field */123 ops->c2d_dir(dev, 1);124 c2port_strobe_ck(dev);125}126 127static int c2port_read_ar(struct c2port_device *dev, u8 *addr)128{129 struct c2port_ops *ops = dev->ops;130 int i;131 132 /* START field */133 c2port_strobe_ck(dev);134 135 /* INS field (10b, LSB first) */136 ops->c2d_dir(dev, 0);137 ops->c2d_set(dev, 0);138 c2port_strobe_ck(dev);139 ops->c2d_set(dev, 1);140 c2port_strobe_ck(dev);141 142 /* ADDRESS field */143 ops->c2d_dir(dev, 1);144 *addr = 0;145 for (i = 0; i < 8; i++) {146 *addr >>= 1; /* shift in 8-bit ADDRESS field LSB first */147 148 c2port_strobe_ck(dev);149 if (ops->c2d_get(dev))150 *addr |= 0x80;151 }152 153 /* STOP field */154 c2port_strobe_ck(dev);155 156 return 0;157}158 159static int c2port_write_dr(struct c2port_device *dev, u8 data)160{161 struct c2port_ops *ops = dev->ops;162 int timeout, i;163 164 /* START field */165 c2port_strobe_ck(dev);166 167 /* INS field (01b, LSB first) */168 ops->c2d_dir(dev, 0);169 ops->c2d_set(dev, 1);170 c2port_strobe_ck(dev);171 ops->c2d_set(dev, 0);172 c2port_strobe_ck(dev);173 174 /* LENGTH field (00b, LSB first -> 1 byte) */175 ops->c2d_set(dev, 0);176 c2port_strobe_ck(dev);177 ops->c2d_set(dev, 0);178 c2port_strobe_ck(dev);179 180 /* DATA field */181 for (i = 0; i < 8; i++) {182 ops->c2d_set(dev, data & 0x01);183 c2port_strobe_ck(dev);184 185 data >>= 1;186 }187 188 /* WAIT field */189 ops->c2d_dir(dev, 1);190 timeout = 20;191 do {192 c2port_strobe_ck(dev);193 if (ops->c2d_get(dev))194 break;195 196 udelay(1);197 } while (--timeout > 0);198 if (timeout == 0)199 return -EIO;200 201 /* STOP field */202 c2port_strobe_ck(dev);203 204 return 0;205}206 207static int c2port_read_dr(struct c2port_device *dev, u8 *data)208{209 struct c2port_ops *ops = dev->ops;210 int timeout, i;211 212 /* START field */213 c2port_strobe_ck(dev);214 215 /* INS field (00b, LSB first) */216 ops->c2d_dir(dev, 0);217 ops->c2d_set(dev, 0);218 c2port_strobe_ck(dev);219 ops->c2d_set(dev, 0);220 c2port_strobe_ck(dev);221 222 /* LENGTH field (00b, LSB first -> 1 byte) */223 ops->c2d_set(dev, 0);224 c2port_strobe_ck(dev);225 ops->c2d_set(dev, 0);226 c2port_strobe_ck(dev);227 228 /* WAIT field */229 ops->c2d_dir(dev, 1);230 timeout = 20;231 do {232 c2port_strobe_ck(dev);233 if (ops->c2d_get(dev))234 break;235 236 udelay(1);237 } while (--timeout > 0);238 if (timeout == 0)239 return -EIO;240 241 /* DATA field */242 *data = 0;243 for (i = 0; i < 8; i++) {244 *data >>= 1; /* shift in 8-bit DATA field LSB first */245 246 c2port_strobe_ck(dev);247 if (ops->c2d_get(dev))248 *data |= 0x80;249 }250 251 /* STOP field */252 c2port_strobe_ck(dev);253 254 return 0;255}256 257static int c2port_poll_in_busy(struct c2port_device *dev)258{259 u8 addr;260 int ret, timeout = 20;261 262 do {263 ret = (c2port_read_ar(dev, &addr));264 if (ret < 0)265 return -EIO;266 267 if (!(addr & 0x02))268 break;269 270 udelay(1);271 } while (--timeout > 0);272 if (timeout == 0)273 return -EIO;274 275 return 0;276}277 278static int c2port_poll_out_ready(struct c2port_device *dev)279{280 u8 addr;281 int ret, timeout = 10000; /* erase flash needs long time... */282 283 do {284 ret = (c2port_read_ar(dev, &addr));285 if (ret < 0)286 return -EIO;287 288 if (addr & 0x01)289 break;290 291 udelay(1);292 } while (--timeout > 0);293 if (timeout == 0)294 return -EIO;295 296 return 0;297}298 299/*300 * sysfs methods301 */302 303static ssize_t c2port_show_name(struct device *dev,304 struct device_attribute *attr, char *buf)305{306 struct c2port_device *c2dev = dev_get_drvdata(dev);307 308 return sprintf(buf, "%s\n", c2dev->name);309}310static DEVICE_ATTR(name, 0444, c2port_show_name, NULL);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}320static DEVICE_ATTR(flash_blocks_num, 0444, c2port_show_flash_blocks_num, NULL);321 322static ssize_t c2port_show_flash_block_size(struct device *dev,323 struct device_attribute *attr, char *buf)324{325 struct c2port_device *c2dev = dev_get_drvdata(dev);326 struct c2port_ops *ops = c2dev->ops;327 328 return sprintf(buf, "%d\n", ops->block_size);329}330static DEVICE_ATTR(flash_block_size, 0444, c2port_show_flash_block_size, NULL);331 332static ssize_t c2port_show_flash_size(struct device *dev,333 struct device_attribute *attr, char *buf)334{335 struct c2port_device *c2dev = dev_get_drvdata(dev);336 struct c2port_ops *ops = c2dev->ops;337 338 return sprintf(buf, "%d\n", ops->blocks_num * ops->block_size);339}340static DEVICE_ATTR(flash_size, 0444, c2port_show_flash_size, NULL);341 342static ssize_t access_show(struct device *dev, struct device_attribute *attr,343 char *buf)344{345 struct c2port_device *c2dev = dev_get_drvdata(dev);346 347 return sprintf(buf, "%d\n", c2dev->access);348}349 350static ssize_t access_store(struct device *dev, struct device_attribute *attr,351 const char *buf, size_t count)352{353 struct c2port_device *c2dev = dev_get_drvdata(dev);354 struct c2port_ops *ops = c2dev->ops;355 int status, ret;356 357 ret = sscanf(buf, "%d", &status);358 if (ret != 1)359 return -EINVAL;360 361 mutex_lock(&c2dev->mutex);362 363 c2dev->access = !!status;364 365 /* If access is "on" clock should be HIGH _before_ setting the line366 * as output and data line should be set as INPUT anyway */367 if (c2dev->access)368 ops->c2ck_set(c2dev, 1);369 ops->access(c2dev, c2dev->access);370 if (c2dev->access)371 ops->c2d_dir(c2dev, 1);372 373 mutex_unlock(&c2dev->mutex);374 375 return count;376}377static DEVICE_ATTR_RW(access);378 379static ssize_t c2port_store_reset(struct device *dev,380 struct device_attribute *attr,381 const char *buf, size_t count)382{383 struct c2port_device *c2dev = dev_get_drvdata(dev);384 385 /* Check the device access status */386 if (!c2dev->access)387 return -EBUSY;388 389 mutex_lock(&c2dev->mutex);390 391 c2port_reset(c2dev);392 c2dev->flash_access = 0;393 394 mutex_unlock(&c2dev->mutex);395 396 return count;397}398static DEVICE_ATTR(reset, 0200, NULL, c2port_store_reset);399 400static ssize_t __c2port_show_dev_id(struct c2port_device *dev, char *buf)401{402 u8 data;403 int ret;404 405 /* Select DEVICEID register for C2 data register accesses */406 c2port_write_ar(dev, C2PORT_DEVICEID);407 408 /* Read and return the device ID register */409 ret = c2port_read_dr(dev, &data);410 if (ret < 0)411 return ret;412 413 return sprintf(buf, "%d\n", data);414}415 416static ssize_t c2port_show_dev_id(struct device *dev,417 struct device_attribute *attr, char *buf)418{419 struct c2port_device *c2dev = dev_get_drvdata(dev);420 ssize_t ret;421 422 /* Check the device access status */423 if (!c2dev->access)424 return -EBUSY;425 426 mutex_lock(&c2dev->mutex);427 ret = __c2port_show_dev_id(c2dev, buf);428 mutex_unlock(&c2dev->mutex);429 430 if (ret < 0)431 dev_err(dev, "cannot read from %s\n", c2dev->name);432 433 return ret;434}435static DEVICE_ATTR(dev_id, 0444, c2port_show_dev_id, NULL);436 437static ssize_t __c2port_show_rev_id(struct c2port_device *dev, char *buf)438{439 u8 data;440 int ret;441 442 /* Select REVID register for C2 data register accesses */443 c2port_write_ar(dev, C2PORT_REVID);444 445 /* Read and return the revision ID register */446 ret = c2port_read_dr(dev, &data);447 if (ret < 0)448 return ret;449 450 return sprintf(buf, "%d\n", data);451}452 453static ssize_t c2port_show_rev_id(struct device *dev,454 struct device_attribute *attr, char *buf)455{456 struct c2port_device *c2dev = dev_get_drvdata(dev);457 ssize_t ret;458 459 /* Check the device access status */460 if (!c2dev->access)461 return -EBUSY;462 463 mutex_lock(&c2dev->mutex);464 ret = __c2port_show_rev_id(c2dev, buf);465 mutex_unlock(&c2dev->mutex);466 467 if (ret < 0)468 dev_err(c2dev->dev, "cannot read from %s\n", c2dev->name);469 470 return ret;471}472static DEVICE_ATTR(rev_id, 0444, c2port_show_rev_id, NULL);473 474static ssize_t c2port_show_flash_access(struct device *dev,475 struct device_attribute *attr, char *buf)476{477 struct c2port_device *c2dev = dev_get_drvdata(dev);478 479 return sprintf(buf, "%d\n", c2dev->flash_access);480}481 482static ssize_t __c2port_store_flash_access(struct c2port_device *dev,483 int status)484{485 int ret;486 487 /* Check the device access status */488 if (!dev->access)489 return -EBUSY;490 491 dev->flash_access = !!status;492 493 /* If flash_access is off we have nothing to do... */494 if (dev->flash_access == 0)495 return 0;496 497 /* Target the C2 flash programming control register for C2 data498 * register access */499 c2port_write_ar(dev, C2PORT_FPCTL);500 501 /* Write the first keycode to enable C2 Flash programming */502 ret = c2port_write_dr(dev, 0x02);503 if (ret < 0)504 return ret;505 506 /* Write the second keycode to enable C2 Flash programming */507 ret = c2port_write_dr(dev, 0x01);508 if (ret < 0)509 return ret;510 511 /* Delay for at least 20ms to ensure the target is ready for512 * C2 flash programming */513 mdelay(25);514 515 return 0;516}517 518static ssize_t c2port_store_flash_access(struct device *dev,519 struct device_attribute *attr,520 const char *buf, size_t count)521{522 struct c2port_device *c2dev = dev_get_drvdata(dev);523 int status;524 ssize_t ret;525 526 ret = sscanf(buf, "%d", &status);527 if (ret != 1)528 return -EINVAL;529 530 mutex_lock(&c2dev->mutex);531 ret = __c2port_store_flash_access(c2dev, status);532 mutex_unlock(&c2dev->mutex);533 534 if (ret < 0) {535 dev_err(c2dev->dev, "cannot enable %s flash programming\n",536 c2dev->name);537 return ret;538 }539 540 return count;541}542static DEVICE_ATTR(flash_access, 0644, c2port_show_flash_access,543 c2port_store_flash_access);544 545static ssize_t __c2port_write_flash_erase(struct c2port_device *dev)546{547 u8 status;548 int ret;549 550 /* Target the C2 flash programming data register for C2 data register551 * access.552 */553 c2port_write_ar(dev, C2PORT_FPDAT);554 555 /* Send device erase command */556 c2port_write_dr(dev, C2PORT_DEVICE_ERASE);557 558 /* Wait for input acknowledge */559 ret = c2port_poll_in_busy(dev);560 if (ret < 0)561 return ret;562 563 /* Should check status before starting FLASH access sequence */564 565 /* Wait for status information */566 ret = c2port_poll_out_ready(dev);567 if (ret < 0)568 return ret;569 570 /* Read flash programming interface status */571 ret = c2port_read_dr(dev, &status);572 if (ret < 0)573 return ret;574 if (status != C2PORT_COMMAND_OK)575 return -EBUSY;576 577 /* Send a three-byte arming sequence to enable the device erase.578 * If the sequence is not received correctly, the command will be579 * ignored.580 * Sequence is: 0xde, 0xad, 0xa5.581 */582 c2port_write_dr(dev, 0xde);583 ret = c2port_poll_in_busy(dev);584 if (ret < 0)585 return ret;586 c2port_write_dr(dev, 0xad);587 ret = c2port_poll_in_busy(dev);588 if (ret < 0)589 return ret;590 c2port_write_dr(dev, 0xa5);591 ret = c2port_poll_in_busy(dev);592 if (ret < 0)593 return ret;594 595 ret = c2port_poll_out_ready(dev);596 if (ret < 0)597 return ret;598 599 return 0;600}601 602static ssize_t c2port_store_flash_erase(struct device *dev,603 struct device_attribute *attr,604 const char *buf, size_t count)605{606 struct c2port_device *c2dev = dev_get_drvdata(dev);607 int ret;608 609 /* Check the device and flash access status */610 if (!c2dev->access || !c2dev->flash_access)611 return -EBUSY;612 613 mutex_lock(&c2dev->mutex);614 ret = __c2port_write_flash_erase(c2dev);615 mutex_unlock(&c2dev->mutex);616 617 if (ret < 0) {618 dev_err(c2dev->dev, "cannot erase %s flash\n", c2dev->name);619 return ret;620 }621 622 return count;623}624static DEVICE_ATTR(flash_erase, 0200, NULL, c2port_store_flash_erase);625 626static ssize_t __c2port_read_flash_data(struct c2port_device *dev,627 char *buffer, loff_t offset, size_t count)628{629 struct c2port_ops *ops = dev->ops;630 u8 status, nread = 128;631 int i, ret;632 633 /* Check for flash end */634 if (offset >= ops->block_size * ops->blocks_num)635 return 0;636 637 if (ops->block_size * ops->blocks_num - offset < nread)638 nread = ops->block_size * ops->blocks_num - offset;639 if (count < nread)640 nread = count;641 if (nread == 0)642 return nread;643 644 /* Target the C2 flash programming data register for C2 data register645 * access */646 c2port_write_ar(dev, C2PORT_FPDAT);647 648 /* Send flash block read command */649 c2port_write_dr(dev, C2PORT_BLOCK_READ);650 651 /* Wait for input acknowledge */652 ret = c2port_poll_in_busy(dev);653 if (ret < 0)654 return ret;655 656 /* Should check status before starting FLASH access sequence */657 658 /* Wait for status information */659 ret = c2port_poll_out_ready(dev);660 if (ret < 0)661 return ret;662 663 /* Read flash programming interface status */664 ret = c2port_read_dr(dev, &status);665 if (ret < 0)666 return ret;667 if (status != C2PORT_COMMAND_OK)668 return -EBUSY;669 670 /* Send address high byte */671 c2port_write_dr(dev, offset >> 8);672 ret = c2port_poll_in_busy(dev);673 if (ret < 0)674 return ret;675 676 /* Send address low byte */677 c2port_write_dr(dev, offset & 0x00ff);678 ret = c2port_poll_in_busy(dev);679 if (ret < 0)680 return ret;681 682 /* Send address block size */683 c2port_write_dr(dev, nread);684 ret = c2port_poll_in_busy(dev);685 if (ret < 0)686 return ret;687 688 /* Should check status before reading FLASH block */689 690 /* Wait for status information */691 ret = c2port_poll_out_ready(dev);692 if (ret < 0)693 return ret;694 695 /* Read flash programming interface status */696 ret = c2port_read_dr(dev, &status);697 if (ret < 0)698 return ret;699 if (status != C2PORT_COMMAND_OK)700 return -EBUSY;701 702 /* Read flash block */703 for (i = 0; i < nread; i++) {704 ret = c2port_poll_out_ready(dev);705 if (ret < 0)706 return ret;707 708 ret = c2port_read_dr(dev, buffer+i);709 if (ret < 0)710 return ret;711 }712 713 return nread;714}715 716static ssize_t c2port_read_flash_data(struct file *filp, struct kobject *kobj,717 struct bin_attribute *attr,718 char *buffer, loff_t offset, size_t count)719{720 struct c2port_device *c2dev = dev_get_drvdata(kobj_to_dev(kobj));721 ssize_t ret;722 723 /* Check the device and flash access status */724 if (!c2dev->access || !c2dev->flash_access)725 return -EBUSY;726 727 mutex_lock(&c2dev->mutex);728 ret = __c2port_read_flash_data(c2dev, buffer, offset, count);729 mutex_unlock(&c2dev->mutex);730 731 if (ret < 0)732 dev_err(c2dev->dev, "cannot read %s flash\n", c2dev->name);733 734 return ret;735}736 737static ssize_t __c2port_write_flash_data(struct c2port_device *dev,738 char *buffer, loff_t offset, size_t count)739{740 struct c2port_ops *ops = dev->ops;741 u8 status, nwrite = 128;742 int i, ret;743 744 if (nwrite > count)745 nwrite = count;746 if (ops->block_size * ops->blocks_num - offset < nwrite)747 nwrite = ops->block_size * ops->blocks_num - offset;748 749 /* Check for flash end */750 if (offset >= ops->block_size * ops->blocks_num)751 return -EINVAL;752 753 /* Target the C2 flash programming data register for C2 data register754 * access */755 c2port_write_ar(dev, C2PORT_FPDAT);756 757 /* Send flash block write command */758 c2port_write_dr(dev, C2PORT_BLOCK_WRITE);759 760 /* Wait for input acknowledge */761 ret = c2port_poll_in_busy(dev);762 if (ret < 0)763 return ret;764 765 /* Should check status before starting FLASH access sequence */766 767 /* Wait for status information */768 ret = c2port_poll_out_ready(dev);769 if (ret < 0)770 return ret;771 772 /* Read flash programming interface status */773 ret = c2port_read_dr(dev, &status);774 if (ret < 0)775 return ret;776 if (status != C2PORT_COMMAND_OK)777 return -EBUSY;778 779 /* Send address high byte */780 c2port_write_dr(dev, offset >> 8);781 ret = c2port_poll_in_busy(dev);782 if (ret < 0)783 return ret;784 785 /* Send address low byte */786 c2port_write_dr(dev, offset & 0x00ff);787 ret = c2port_poll_in_busy(dev);788 if (ret < 0)789 return ret;790 791 /* Send address block size */792 c2port_write_dr(dev, nwrite);793 ret = c2port_poll_in_busy(dev);794 if (ret < 0)795 return ret;796 797 /* Should check status before writing FLASH block */798 799 /* Wait for status information */800 ret = c2port_poll_out_ready(dev);801 if (ret < 0)802 return ret;803 804 /* Read flash programming interface status */805 ret = c2port_read_dr(dev, &status);806 if (ret < 0)807 return ret;808 if (status != C2PORT_COMMAND_OK)809 return -EBUSY;810 811 /* Write flash block */812 for (i = 0; i < nwrite; i++) {813 ret = c2port_write_dr(dev, *(buffer+i));814 if (ret < 0)815 return ret;816 817 ret = c2port_poll_in_busy(dev);818 if (ret < 0)819 return ret;820 821 }822 823 /* Wait for last flash write to complete */824 ret = c2port_poll_out_ready(dev);825 if (ret < 0)826 return ret;827 828 return nwrite;829}830 831static ssize_t c2port_write_flash_data(struct file *filp, struct kobject *kobj,832 struct bin_attribute *attr,833 char *buffer, loff_t offset, size_t count)834{835 struct c2port_device *c2dev = dev_get_drvdata(kobj_to_dev(kobj));836 int ret;837 838 /* Check the device access status */839 if (!c2dev->access || !c2dev->flash_access)840 return -EBUSY;841 842 mutex_lock(&c2dev->mutex);843 ret = __c2port_write_flash_data(c2dev, buffer, offset, count);844 mutex_unlock(&c2dev->mutex);845 846 if (ret < 0)847 dev_err(c2dev->dev, "cannot write %s flash\n", c2dev->name);848 849 return ret;850}851/* size is computed at run-time */852static BIN_ATTR(flash_data, 0644, c2port_read_flash_data,853 c2port_write_flash_data, 0);854 855/*856 * Class attributes857 */858static struct attribute *c2port_attrs[] = {859 &dev_attr_name.attr,860 &dev_attr_flash_blocks_num.attr,861 &dev_attr_flash_block_size.attr,862 &dev_attr_flash_size.attr,863 &dev_attr_access.attr,864 &dev_attr_reset.attr,865 &dev_attr_dev_id.attr,866 &dev_attr_rev_id.attr,867 &dev_attr_flash_access.attr,868 &dev_attr_flash_erase.attr,869 NULL,870};871 872static struct bin_attribute *c2port_bin_attrs[] = {873 &bin_attr_flash_data,874 NULL,875};876 877static const struct attribute_group c2port_group = {878 .attrs = c2port_attrs,879 .bin_attrs = c2port_bin_attrs,880};881 882static const struct attribute_group *c2port_groups[] = {883 &c2port_group,884 NULL,885};886 887/*888 * Exported functions889 */890 891struct c2port_device *c2port_device_register(char *name,892 struct c2port_ops *ops, void *devdata)893{894 struct c2port_device *c2dev;895 int ret;896 897 if (unlikely(!ops) || unlikely(!ops->access) || \898 unlikely(!ops->c2d_dir) || unlikely(!ops->c2ck_set) || \899 unlikely(!ops->c2d_get) || unlikely(!ops->c2d_set))900 return ERR_PTR(-EINVAL);901 902 c2dev = kzalloc(sizeof(struct c2port_device), GFP_KERNEL);903 if (unlikely(!c2dev))904 return ERR_PTR(-ENOMEM);905 906 idr_preload(GFP_KERNEL);907 spin_lock_irq(&c2port_idr_lock);908 ret = idr_alloc(&c2port_idr, c2dev, 0, 0, GFP_NOWAIT);909 spin_unlock_irq(&c2port_idr_lock);910 idr_preload_end();911 912 if (ret < 0)913 goto error_idr_alloc;914 c2dev->id = ret;915 916 bin_attr_flash_data.size = ops->blocks_num * ops->block_size;917 918 c2dev->dev = device_create(c2port_class, NULL, 0, c2dev,919 "c2port%d", c2dev->id);920 if (IS_ERR(c2dev->dev)) {921 ret = PTR_ERR(c2dev->dev);922 goto error_device_create;923 }924 dev_set_drvdata(c2dev->dev, c2dev);925 926 strscpy(c2dev->name, name, sizeof(c2dev->name));927 c2dev->ops = ops;928 mutex_init(&c2dev->mutex);929 930 /* By default C2 port access is off */931 c2dev->access = c2dev->flash_access = 0;932 ops->access(c2dev, 0);933 934 dev_info(c2dev->dev, "C2 port %s added\n", name);935 dev_info(c2dev->dev, "%s flash has %d blocks x %d bytes "936 "(%d bytes total)\n",937 name, ops->blocks_num, ops->block_size,938 ops->blocks_num * ops->block_size);939 940 return c2dev;941 942error_device_create:943 spin_lock_irq(&c2port_idr_lock);944 idr_remove(&c2port_idr, c2dev->id);945 spin_unlock_irq(&c2port_idr_lock);946 947error_idr_alloc:948 kfree(c2dev);949 950 return ERR_PTR(ret);951}952EXPORT_SYMBOL(c2port_device_register);953 954void c2port_device_unregister(struct c2port_device *c2dev)955{956 if (!c2dev)957 return;958 959 dev_info(c2dev->dev, "C2 port %s removed\n", c2dev->name);960 961 spin_lock_irq(&c2port_idr_lock);962 idr_remove(&c2port_idr, c2dev->id);963 spin_unlock_irq(&c2port_idr_lock);964 965 device_destroy(c2port_class, c2dev->id);966 967 kfree(c2dev);968}969EXPORT_SYMBOL(c2port_device_unregister);970 971/*972 * Module stuff973 */974 975static int __init c2port_init(void)976{977 printk(KERN_INFO "Silicon Labs C2 port support v. " DRIVER_VERSION978 " - (C) 2007 Rodolfo Giometti\n");979 980 c2port_class = class_create("c2port");981 if (IS_ERR(c2port_class)) {982 printk(KERN_ERR "c2port: failed to allocate class\n");983 return PTR_ERR(c2port_class);984 }985 c2port_class->dev_groups = c2port_groups;986 987 return 0;988}989 990static void __exit c2port_exit(void)991{992 class_destroy(c2port_class);993}994 995module_init(c2port_init);996module_exit(c2port_exit);997 998MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");999MODULE_DESCRIPTION("Silicon Labs C2 port support v. " DRIVER_VERSION);1000MODULE_LICENSE("GPL");1001