diff options
Diffstat (limited to 'drivers/mfd/kempld-core.c')
-rw-r--r-- | drivers/mfd/kempld-core.c | 129 |
1 files changed, 107 insertions, 22 deletions
diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index 07692604e119..f7ff0188603d 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c | |||
@@ -86,7 +86,7 @@ enum kempld_cells { | |||
86 | KEMPLD_UART, | 86 | KEMPLD_UART, |
87 | }; | 87 | }; |
88 | 88 | ||
89 | static struct mfd_cell kempld_devs[] = { | 89 | static const struct mfd_cell kempld_devs[] = { |
90 | [KEMPLD_I2C] = { | 90 | [KEMPLD_I2C] = { |
91 | .name = "kempld-i2c", | 91 | .name = "kempld-i2c", |
92 | }, | 92 | }, |
@@ -288,9 +288,38 @@ EXPORT_SYMBOL_GPL(kempld_release_mutex); | |||
288 | */ | 288 | */ |
289 | static int kempld_get_info(struct kempld_device_data *pld) | 289 | static int kempld_get_info(struct kempld_device_data *pld) |
290 | { | 290 | { |
291 | int ret; | ||
291 | struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); | 292 | struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); |
293 | char major, minor; | ||
294 | |||
295 | ret = pdata->get_info(pld); | ||
296 | if (ret) | ||
297 | return ret; | ||
298 | |||
299 | /* The Kontron PLD firmware version string has the following format: | ||
300 | * Pwxy.zzzz | ||
301 | * P: Fixed | ||
302 | * w: PLD number - 1 hex digit | ||
303 | * x: Major version - 1 alphanumerical digit (0-9A-V) | ||
304 | * y: Minor version - 1 alphanumerical digit (0-9A-V) | ||
305 | * zzzz: Build number - 4 zero padded hex digits */ | ||
292 | 306 | ||
293 | return pdata->get_info(pld); | 307 | if (pld->info.major < 10) |
308 | major = pld->info.major + '0'; | ||
309 | else | ||
310 | major = (pld->info.major - 10) + 'A'; | ||
311 | if (pld->info.minor < 10) | ||
312 | minor = pld->info.minor + '0'; | ||
313 | else | ||
314 | minor = (pld->info.minor - 10) + 'A'; | ||
315 | |||
316 | ret = scnprintf(pld->info.version, sizeof(pld->info.version), | ||
317 | "P%X%c%c.%04X", pld->info.number, major, minor, | ||
318 | pld->info.buildnr); | ||
319 | if (ret < 0) | ||
320 | return ret; | ||
321 | |||
322 | return 0; | ||
294 | } | 323 | } |
295 | 324 | ||
296 | /* | 325 | /* |
@@ -307,9 +336,71 @@ static int kempld_register_cells(struct kempld_device_data *pld) | |||
307 | return pdata->register_cells(pld); | 336 | return pdata->register_cells(pld); |
308 | } | 337 | } |
309 | 338 | ||
339 | static const char *kempld_get_type_string(struct kempld_device_data *pld) | ||
340 | { | ||
341 | const char *version_type; | ||
342 | |||
343 | switch (pld->info.type) { | ||
344 | case 0: | ||
345 | version_type = "release"; | ||
346 | break; | ||
347 | case 1: | ||
348 | version_type = "debug"; | ||
349 | break; | ||
350 | case 2: | ||
351 | version_type = "custom"; | ||
352 | break; | ||
353 | default: | ||
354 | version_type = "unspecified"; | ||
355 | break; | ||
356 | } | ||
357 | |||
358 | return version_type; | ||
359 | } | ||
360 | |||
361 | static ssize_t kempld_version_show(struct device *dev, | ||
362 | struct device_attribute *attr, char *buf) | ||
363 | { | ||
364 | struct kempld_device_data *pld = dev_get_drvdata(dev); | ||
365 | |||
366 | return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version); | ||
367 | } | ||
368 | |||
369 | static ssize_t kempld_specification_show(struct device *dev, | ||
370 | struct device_attribute *attr, char *buf) | ||
371 | { | ||
372 | struct kempld_device_data *pld = dev_get_drvdata(dev); | ||
373 | |||
374 | return scnprintf(buf, PAGE_SIZE, "%d.%d\n", pld->info.spec_major, | ||
375 | pld->info.spec_minor); | ||
376 | } | ||
377 | |||
378 | static ssize_t kempld_type_show(struct device *dev, | ||
379 | struct device_attribute *attr, char *buf) | ||
380 | { | ||
381 | struct kempld_device_data *pld = dev_get_drvdata(dev); | ||
382 | |||
383 | return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld)); | ||
384 | } | ||
385 | |||
386 | static DEVICE_ATTR(pld_version, S_IRUGO, kempld_version_show, NULL); | ||
387 | static DEVICE_ATTR(pld_specification, S_IRUGO, kempld_specification_show, | ||
388 | NULL); | ||
389 | static DEVICE_ATTR(pld_type, S_IRUGO, kempld_type_show, NULL); | ||
390 | |||
391 | static struct attribute *pld_attributes[] = { | ||
392 | &dev_attr_pld_version.attr, | ||
393 | &dev_attr_pld_specification.attr, | ||
394 | &dev_attr_pld_type.attr, | ||
395 | NULL | ||
396 | }; | ||
397 | |||
398 | static const struct attribute_group pld_attr_group = { | ||
399 | .attrs = pld_attributes, | ||
400 | }; | ||
401 | |||
310 | static int kempld_detect_device(struct kempld_device_data *pld) | 402 | static int kempld_detect_device(struct kempld_device_data *pld) |
311 | { | 403 | { |
312 | char *version_type; | ||
313 | u8 index_reg; | 404 | u8 index_reg; |
314 | int ret; | 405 | int ret; |
315 | 406 | ||
@@ -335,27 +426,19 @@ static int kempld_detect_device(struct kempld_device_data *pld) | |||
335 | if (ret) | 426 | if (ret) |
336 | return ret; | 427 | return ret; |
337 | 428 | ||
338 | switch (pld->info.type) { | 429 | dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n", |
339 | case 0: | 430 | pld->info.version, kempld_get_type_string(pld), |
340 | version_type = "release"; | 431 | pld->info.spec_major, pld->info.spec_minor); |
341 | break; | 432 | |
342 | case 1: | 433 | ret = sysfs_create_group(&pld->dev->kobj, &pld_attr_group); |
343 | version_type = "debug"; | 434 | if (ret) |
344 | break; | 435 | return ret; |
345 | case 2: | ||
346 | version_type = "custom"; | ||
347 | break; | ||
348 | default: | ||
349 | version_type = "unspecified"; | ||
350 | } | ||
351 | 436 | ||
352 | dev_info(pld->dev, "Found Kontron PLD %d\n", pld->info.number); | 437 | ret = kempld_register_cells(pld); |
353 | dev_info(pld->dev, "%s version %d.%d build %d, specification %d.%d\n", | 438 | if (ret) |
354 | version_type, pld->info.major, pld->info.minor, | 439 | sysfs_remove_group(&pld->dev->kobj, &pld_attr_group); |
355 | pld->info.buildnr, pld->info.spec_major, | ||
356 | pld->info.spec_minor); | ||
357 | 440 | ||
358 | return kempld_register_cells(pld); | 441 | return ret; |
359 | } | 442 | } |
360 | 443 | ||
361 | static int kempld_probe(struct platform_device *pdev) | 444 | static int kempld_probe(struct platform_device *pdev) |
@@ -399,6 +482,8 @@ static int kempld_remove(struct platform_device *pdev) | |||
399 | struct kempld_device_data *pld = platform_get_drvdata(pdev); | 482 | struct kempld_device_data *pld = platform_get_drvdata(pdev); |
400 | struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); | 483 | struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); |
401 | 484 | ||
485 | sysfs_remove_group(&pld->dev->kobj, &pld_attr_group); | ||
486 | |||
402 | mfd_remove_devices(&pdev->dev); | 487 | mfd_remove_devices(&pdev->dev); |
403 | pdata->release_hardware_mutex(pld); | 488 | pdata->release_hardware_mutex(pld); |
404 | 489 | ||