2 * Industry-pack bus support functions.
4 * Copyright (C) 2011-2012 CERN (www.cern.ch)
5 * Author: Samuel Iglesias Gonsalvez <siglesias@igalia.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; version 2 of the License.
12 #include <linux/module.h>
13 #include <linux/slab.h>
14 #include <linux/idr.h>
16 #include <linux/ipack.h>
18 #define to_ipack_dev(device) container_of(device, struct ipack_device, dev)
19 #define to_ipack_driver(drv) container_of(drv, struct ipack_driver, driver)
21 static DEFINE_IDA(ipack_ida
);
23 static void ipack_device_release(struct device
*dev
)
25 struct ipack_device
*device
= to_ipack_dev(dev
);
27 device
->release(device
);
30 static inline const struct ipack_device_id
*
31 ipack_match_one_device(const struct ipack_device_id
*id
,
32 const struct ipack_device
*device
)
34 if ((id
->format
== IPACK_ANY_FORMAT
||
35 id
->format
== device
->id_format
) &&
36 (id
->vendor
== IPACK_ANY_ID
|| id
->vendor
== device
->id_vendor
) &&
37 (id
->device
== IPACK_ANY_ID
|| id
->device
== device
->id_device
))
42 static const struct ipack_device_id
*
43 ipack_match_id(const struct ipack_device_id
*ids
, struct ipack_device
*idev
)
46 while (ids
->vendor
|| ids
->device
) {
47 if (ipack_match_one_device(ids
, idev
))
55 static int ipack_bus_match(struct device
*dev
, struct device_driver
*drv
)
57 struct ipack_device
*idev
= to_ipack_dev(dev
);
58 struct ipack_driver
*idrv
= to_ipack_driver(drv
);
59 const struct ipack_device_id
*found_id
;
61 found_id
= ipack_match_id(idrv
->id_table
, idev
);
62 return found_id
? 1 : 0;
65 static int ipack_bus_probe(struct device
*device
)
67 struct ipack_device
*dev
= to_ipack_dev(device
);
68 struct ipack_driver
*drv
= to_ipack_driver(device
->driver
);
73 return drv
->ops
->probe(dev
);
76 static int ipack_bus_remove(struct device
*device
)
78 struct ipack_device
*dev
= to_ipack_dev(device
);
79 struct ipack_driver
*drv
= to_ipack_driver(device
->driver
);
81 if (!drv
->ops
->remove
)
84 drv
->ops
->remove(dev
);
88 static int ipack_uevent(struct device
*dev
, struct kobj_uevent_env
*env
)
90 struct ipack_device
*idev
;
95 idev
= to_ipack_dev(dev
);
97 if (add_uevent_var(env
,
98 "MODALIAS=ipack:f%02Xv%08Xd%08X", idev
->id_format
,
99 idev
->id_vendor
, idev
->id_device
))
105 #define ipack_device_attr(field, format_string) \
107 field##_show(struct device *dev, struct device_attribute *attr, \
110 struct ipack_device *idev = to_ipack_dev(dev); \
111 return sprintf(buf, format_string, idev->field); \
114 static ssize_t
id_show(struct device
*dev
,
115 struct device_attribute
*attr
, char *buf
)
117 unsigned int i
, c
, l
, s
;
118 struct ipack_device
*idev
= to_ipack_dev(dev
);
121 switch (idev
->id_format
) {
122 case IPACK_ID_VERSION_1
:
123 l
= 0x7; s
= 1; break;
124 case IPACK_ID_VERSION_2
:
125 l
= 0xf; s
= 2; break;
130 for (i
= 0; i
< idev
->id_avail
; i
++) {
134 else if ((i
& s
) == 0)
137 sprintf(&buf
[c
], "%02x", idev
->id
[i
]);
145 id_vendor_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
147 struct ipack_device
*idev
= to_ipack_dev(dev
);
148 switch (idev
->id_format
) {
149 case IPACK_ID_VERSION_1
:
150 return sprintf(buf
, "0x%02x\n", idev
->id_vendor
);
151 case IPACK_ID_VERSION_2
:
152 return sprintf(buf
, "0x%06x\n", idev
->id_vendor
);
159 id_device_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
161 struct ipack_device
*idev
= to_ipack_dev(dev
);
162 switch (idev
->id_format
) {
163 case IPACK_ID_VERSION_1
:
164 return sprintf(buf
, "0x%02x\n", idev
->id_device
);
165 case IPACK_ID_VERSION_2
:
166 return sprintf(buf
, "0x%04x\n", idev
->id_device
);
172 static ssize_t
modalias_show(struct device
*dev
, struct device_attribute
*attr
,
175 struct ipack_device
*idev
= to_ipack_dev(dev
);
177 return sprintf(buf
, "ipac:f%02Xv%08Xd%08X", idev
->id_format
,
178 idev
->id_vendor
, idev
->id_device
);
181 ipack_device_attr(id_format
, "0x%hhu\n");
183 static struct device_attribute ipack_dev_attrs
[] = {
185 __ATTR_RO(id_device
),
186 __ATTR_RO(id_format
),
187 __ATTR_RO(id_vendor
),
191 static struct bus_type ipack_bus_type
= {
193 .probe
= ipack_bus_probe
,
194 .match
= ipack_bus_match
,
195 .remove
= ipack_bus_remove
,
196 .dev_attrs
= ipack_dev_attrs
,
197 .uevent
= ipack_uevent
,
200 struct ipack_bus_device
*ipack_bus_register(struct device
*parent
, int slots
,
201 const struct ipack_bus_ops
*ops
)
204 struct ipack_bus_device
*bus
;
206 bus
= kzalloc(sizeof(struct ipack_bus_device
), GFP_KERNEL
);
210 bus_nr
= ida_simple_get(&ipack_ida
, 0, 0, GFP_KERNEL
);
216 bus
->bus_nr
= bus_nr
;
217 bus
->parent
= parent
;
222 EXPORT_SYMBOL_GPL(ipack_bus_register
);
224 static int ipack_unregister_bus_member(struct device
*dev
, void *data
)
226 struct ipack_device
*idev
= to_ipack_dev(dev
);
227 struct ipack_bus_device
*bus
= data
;
229 if (idev
->bus
== bus
)
230 ipack_device_unregister(idev
);
235 int ipack_bus_unregister(struct ipack_bus_device
*bus
)
237 bus_for_each_dev(&ipack_bus_type
, NULL
, bus
,
238 ipack_unregister_bus_member
);
239 ida_simple_remove(&ipack_ida
, bus
->bus_nr
);
243 EXPORT_SYMBOL_GPL(ipack_bus_unregister
);
245 int ipack_driver_register(struct ipack_driver
*edrv
, struct module
*owner
,
248 edrv
->driver
.owner
= owner
;
249 edrv
->driver
.name
= name
;
250 edrv
->driver
.bus
= &ipack_bus_type
;
251 return driver_register(&edrv
->driver
);
253 EXPORT_SYMBOL_GPL(ipack_driver_register
);
255 void ipack_driver_unregister(struct ipack_driver
*edrv
)
257 driver_unregister(&edrv
->driver
);
259 EXPORT_SYMBOL_GPL(ipack_driver_unregister
);
261 static u16
ipack_crc_byte(u16 crc
, u8 c
)
266 for (i
= 0; i
< 8; i
++)
267 crc
= (crc
<< 1) ^ ((crc
& 0x8000) ? 0x1021 : 0);
272 * The algorithm in lib/crc-ccitt.c does not seem to apply since it uses the
273 * opposite bit ordering.
275 static u8
ipack_calc_crc1(struct ipack_device
*dev
)
282 for (i
= 0; i
< dev
->id_avail
; i
++) {
283 c
= (i
!= 11) ? dev
->id
[i
] : 0;
284 crc
= ipack_crc_byte(crc
, c
);
290 static u16
ipack_calc_crc2(struct ipack_device
*dev
)
297 for (i
= 0; i
< dev
->id_avail
; i
++) {
298 c
= ((i
!= 0x18) && (i
!= 0x19)) ? dev
->id
[i
] : 0;
299 crc
= ipack_crc_byte(crc
, c
);
305 static void ipack_parse_id1(struct ipack_device
*dev
)
310 dev
->id_vendor
= id
[4];
311 dev
->id_device
= id
[5];
313 dev
->speed_32mhz
= (id
[7] == 'H');
314 crc
= ipack_calc_crc1(dev
);
315 dev
->id_crc_correct
= (crc
== id
[11]);
316 if (!dev
->id_crc_correct
) {
317 dev_warn(&dev
->dev
, "ID CRC invalid found 0x%x, expected 0x%x.\n",
322 static void ipack_parse_id2(struct ipack_device
*dev
)
324 __be16
*id
= (__be16
*) dev
->id
;
327 dev
->id_vendor
= ((be16_to_cpu(id
[3]) & 0xff) << 16)
328 + be16_to_cpu(id
[4]);
329 dev
->id_device
= be16_to_cpu(id
[5]);
330 flags
= be16_to_cpu(id
[10]);
331 dev
->speed_8mhz
= !!(flags
& 2);
332 dev
->speed_32mhz
= !!(flags
& 4);
333 crc
= ipack_calc_crc2(dev
);
334 dev
->id_crc_correct
= (crc
== be16_to_cpu(id
[12]));
335 if (!dev
->id_crc_correct
) {
336 dev_warn(&dev
->dev
, "ID CRC invalid found 0x%x, expected 0x%x.\n",
341 static int ipack_device_read_id(struct ipack_device
*dev
)
347 idmem
= ioremap(dev
->region
[IPACK_ID_SPACE
].start
,
348 dev
->region
[IPACK_ID_SPACE
].size
);
350 dev_err(&dev
->dev
, "error mapping memory\n");
354 /* Determine ID PROM Data Format. If we find the ids "IPAC" or "IPAH"
355 * we are dealing with a IndustryPack format 1 device. If we detect
356 * "VITA4 " (16 bit big endian formatted) we are dealing with a
357 * IndustryPack format 2 device */
358 if ((ioread8(idmem
+ 1) == 'I') &&
359 (ioread8(idmem
+ 3) == 'P') &&
360 (ioread8(idmem
+ 5) == 'A') &&
361 ((ioread8(idmem
+ 7) == 'C') ||
362 (ioread8(idmem
+ 7) == 'H'))) {
363 dev
->id_format
= IPACK_ID_VERSION_1
;
364 dev
->id_avail
= ioread8(idmem
+ 0x15);
365 if ((dev
->id_avail
< 0x0c) || (dev
->id_avail
> 0x40)) {
366 dev_warn(&dev
->dev
, "invalid id size");
367 dev
->id_avail
= 0x0c;
369 } else if ((ioread8(idmem
+ 0) == 'I') &&
370 (ioread8(idmem
+ 1) == 'V') &&
371 (ioread8(idmem
+ 2) == 'A') &&
372 (ioread8(idmem
+ 3) == 'T') &&
373 (ioread8(idmem
+ 4) == ' ') &&
374 (ioread8(idmem
+ 5) == '4')) {
375 dev
->id_format
= IPACK_ID_VERSION_2
;
376 dev
->id_avail
= ioread16be(idmem
+ 0x16);
377 if ((dev
->id_avail
< 0x1a) || (dev
->id_avail
> 0x40)) {
378 dev_warn(&dev
->dev
, "invalid id size");
379 dev
->id_avail
= 0x1a;
382 dev
->id_format
= IPACK_ID_VERSION_INVALID
;
386 if (!dev
->id_avail
) {
391 /* Obtain the amount of memory required to store a copy of the complete
393 dev
->id
= kmalloc(dev
->id_avail
, GFP_KERNEL
);
395 dev_err(&dev
->dev
, "dev->id alloc failed.\n");
399 for (i
= 0; i
< dev
->id_avail
; i
++) {
400 if (dev
->id_format
== IPACK_ID_VERSION_1
)
401 dev
->id
[i
] = ioread8(idmem
+ (i
<< 1) + 1);
403 dev
->id
[i
] = ioread8(idmem
+ i
);
406 /* now we can finally work with the copy */
407 switch (dev
->id_format
) {
408 case IPACK_ID_VERSION_1
:
409 ipack_parse_id1(dev
);
411 case IPACK_ID_VERSION_2
:
412 ipack_parse_id2(dev
);
422 int ipack_device_register(struct ipack_device
*dev
)
426 dev
->dev
.bus
= &ipack_bus_type
;
427 dev
->dev
.release
= ipack_device_release
;
428 dev
->dev
.parent
= dev
->bus
->parent
;
429 dev_set_name(&dev
->dev
,
430 "ipack-dev.%u.%u", dev
->bus
->bus_nr
, dev
->slot
);
432 if (dev
->bus
->ops
->set_clockrate(dev
, 8))
433 dev_warn(&dev
->dev
, "failed to switch to 8 MHz operation for reading of device ID.\n");
434 if (dev
->bus
->ops
->reset_timeout(dev
))
435 dev_warn(&dev
->dev
, "failed to reset potential timeout.");
437 ret
= ipack_device_read_id(dev
);
439 dev_err(&dev
->dev
, "error reading device id section.\n");
443 /* if the device supports 32 MHz operation, use it. */
444 if (dev
->speed_32mhz
) {
445 ret
= dev
->bus
->ops
->set_clockrate(dev
, 32);
447 dev_err(&dev
->dev
, "failed to switch to 32 MHz operation.\n");
450 ret
= device_register(&dev
->dev
);
456 EXPORT_SYMBOL_GPL(ipack_device_register
);
458 void ipack_device_unregister(struct ipack_device
*dev
)
460 device_unregister(&dev
->dev
);
462 EXPORT_SYMBOL_GPL(ipack_device_unregister
);
464 static int __init
ipack_init(void)
466 ida_init(&ipack_ida
);
467 return bus_register(&ipack_bus_type
);
470 static void __exit
ipack_exit(void)
472 bus_unregister(&ipack_bus_type
);
473 ida_destroy(&ipack_ida
);
476 module_init(ipack_init
);
477 module_exit(ipack_exit
);
479 MODULE_AUTHOR("Samuel Iglesias Gonsalvez <siglesias@igalia.com>");
480 MODULE_LICENSE("GPL");
481 MODULE_DESCRIPTION("Industry-pack bus core");