brintos

brintos / linux-shallow public Read only

0
0
Text · 21.4 KiB · 2bb1dd2 Raw
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