diff options
author | Pavan Savoy <pavan_savoy@ti.com> | 2011-02-04 03:23:10 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-02-04 15:41:20 -0500 |
commit | ec60d0ad20ff8796dc41b30a9dce485478ccd263 (patch) | |
tree | 9a0a96e59fb0f193ad25177a54fe16612e2f8545 /drivers/misc/ti-st/st_kim.c | |
parent | 5c88b02196a99332dacf305c8757674dd7a303ff (diff) |
drivers:misc: ti-st: move from rfkill to sysfs
The communication between ST KIM and UIM was interfaced
over the /dev/rfkill device node.
Move the interface to a simpler less abusive sysfs entry
mechanism and document it in Documentation/ABI/testing/
under sysfs-platform-kim.
Shared transport driver would now read the UART details
originally received by bootloader or firmware as platform
data.
The data read will be shared over sysfs entries for the user-space
UIM or other n/w manager/plugins to be read, and assist the driver
by opening up the UART, setting the baud-rate and installing the
line discipline.
Signed-off-by: Pavan Savoy <pavan_savoy@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/misc/ti-st/st_kim.c')
-rw-r--r-- | drivers/misc/ti-st/st_kim.c | 244 |
1 files changed, 121 insertions, 123 deletions
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 707c85826417..a7fda8141758 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c | |||
@@ -30,46 +30,12 @@ | |||
30 | #include <linux/debugfs.h> | 30 | #include <linux/debugfs.h> |
31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
32 | #include <linux/sched.h> | 32 | #include <linux/sched.h> |
33 | #include <linux/rfkill.h> | 33 | #include <linux/tty.h> |
34 | 34 | ||
35 | #include <linux/skbuff.h> | 35 | #include <linux/skbuff.h> |
36 | #include <linux/ti_wilink_st.h> | 36 | #include <linux/ti_wilink_st.h> |
37 | 37 | ||
38 | 38 | ||
39 | static int kim_probe(struct platform_device *pdev); | ||
40 | static int kim_remove(struct platform_device *pdev); | ||
41 | |||
42 | /* KIM platform device driver structure */ | ||
43 | static struct platform_driver kim_platform_driver = { | ||
44 | .probe = kim_probe, | ||
45 | .remove = kim_remove, | ||
46 | /* TODO: ST driver power management during suspend/resume ? | ||
47 | */ | ||
48 | #if 0 | ||
49 | .suspend = kim_suspend, | ||
50 | .resume = kim_resume, | ||
51 | #endif | ||
52 | .driver = { | ||
53 | .name = "kim", | ||
54 | .owner = THIS_MODULE, | ||
55 | }, | ||
56 | }; | ||
57 | |||
58 | static int kim_toggle_radio(void*, bool); | ||
59 | static const struct rfkill_ops kim_rfkill_ops = { | ||
60 | .set_block = kim_toggle_radio, | ||
61 | }; | ||
62 | |||
63 | /* strings to be used for rfkill entries and by | ||
64 | * ST Core to be used for sysfs debug entry | ||
65 | */ | ||
66 | #define PROTO_ENTRY(type, name) name | ||
67 | const unsigned char *protocol_names[] = { | ||
68 | PROTO_ENTRY(ST_BT, "Bluetooth"), | ||
69 | PROTO_ENTRY(ST_FM, "FM"), | ||
70 | PROTO_ENTRY(ST_GPS, "GPS"), | ||
71 | }; | ||
72 | |||
73 | #define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */ | 39 | #define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */ |
74 | static struct platform_device *st_kim_devices[MAX_ST_DEVICES]; | 40 | static struct platform_device *st_kim_devices[MAX_ST_DEVICES]; |
75 | 41 | ||
@@ -371,8 +337,7 @@ void st_kim_chip_toggle(enum proto_type type, enum kim_gpio_state state) | |||
371 | kim_gdata = dev_get_drvdata(&kim_pdev->dev); | 337 | kim_gdata = dev_get_drvdata(&kim_pdev->dev); |
372 | 338 | ||
373 | if (kim_gdata->gpios[type] == -1) { | 339 | if (kim_gdata->gpios[type] == -1) { |
374 | pr_info(" gpio not requested for protocol %s", | 340 | pr_info("gpio not requested for protocol %d", type); |
375 | protocol_names[type]); | ||
376 | return; | 341 | return; |
377 | } | 342 | } |
378 | switch (type) { | 343 | switch (type) { |
@@ -450,11 +415,6 @@ long st_kim_start(void *kim_data) | |||
450 | pr_info(" %s", __func__); | 415 | pr_info(" %s", __func__); |
451 | 416 | ||
452 | do { | 417 | do { |
453 | /* TODO: this is only because rfkill sub-system | ||
454 | * doesn't send events to user-space if the state | ||
455 | * isn't changed | ||
456 | */ | ||
457 | rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 1); | ||
458 | /* Configure BT nShutdown to HIGH state */ | 418 | /* Configure BT nShutdown to HIGH state */ |
459 | gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW); | 419 | gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW); |
460 | mdelay(5); /* FIXME: a proper toggle */ | 420 | mdelay(5); /* FIXME: a proper toggle */ |
@@ -462,22 +422,20 @@ long st_kim_start(void *kim_data) | |||
462 | mdelay(100); | 422 | mdelay(100); |
463 | /* re-initialize the completion */ | 423 | /* re-initialize the completion */ |
464 | INIT_COMPLETION(kim_gdata->ldisc_installed); | 424 | INIT_COMPLETION(kim_gdata->ldisc_installed); |
465 | #if 0 /* older way of signalling user-space UIM */ | 425 | /* send notification to UIM */ |
466 | /* send signal to UIM */ | 426 | kim_gdata->ldisc_install = 1; |
467 | err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 0); | 427 | pr_info("ldisc_install = 1"); |
468 | if (err != 0) { | 428 | sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, |
469 | pr_info(" sending SIGUSR2 to uim failed %ld", err); | 429 | NULL, "install"); |
470 | err = -1; | ||
471 | continue; | ||
472 | } | ||
473 | #endif | ||
474 | /* unblock and send event to UIM via /dev/rfkill */ | ||
475 | rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 0); | ||
476 | /* wait for ldisc to be installed */ | 430 | /* wait for ldisc to be installed */ |
477 | err = wait_for_completion_timeout(&kim_gdata->ldisc_installed, | 431 | err = wait_for_completion_timeout(&kim_gdata->ldisc_installed, |
478 | msecs_to_jiffies(LDISC_TIME)); | 432 | msecs_to_jiffies(LDISC_TIME)); |
479 | if (!err) { /* timeout */ | 433 | if (!err) { /* timeout */ |
480 | pr_err("line disc installation timed out "); | 434 | pr_err("line disc installation timed out "); |
435 | kim_gdata->ldisc_install = 0; | ||
436 | pr_info("ldisc_install = 0"); | ||
437 | sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, | ||
438 | NULL, "install"); | ||
481 | err = -1; | 439 | err = -1; |
482 | continue; | 440 | continue; |
483 | } else { | 441 | } else { |
@@ -486,6 +444,10 @@ long st_kim_start(void *kim_data) | |||
486 | err = download_firmware(kim_gdata); | 444 | err = download_firmware(kim_gdata); |
487 | if (err != 0) { | 445 | if (err != 0) { |
488 | pr_err("download firmware failed"); | 446 | pr_err("download firmware failed"); |
447 | kim_gdata->ldisc_install = 0; | ||
448 | pr_info("ldisc_install = 0"); | ||
449 | sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, | ||
450 | NULL, "install"); | ||
489 | continue; | 451 | continue; |
490 | } else { /* on success don't retry */ | 452 | } else { /* on success don't retry */ |
491 | break; | 453 | break; |
@@ -505,16 +467,15 @@ long st_kim_stop(void *kim_data) | |||
505 | struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; | 467 | struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; |
506 | 468 | ||
507 | INIT_COMPLETION(kim_gdata->ldisc_installed); | 469 | INIT_COMPLETION(kim_gdata->ldisc_installed); |
508 | #if 0 /* older way of signalling user-space UIM */ | 470 | |
509 | /* send signal to UIM */ | 471 | /* Flush any pending characters in the driver and discipline. */ |
510 | err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 1); | 472 | tty_ldisc_flush(kim_gdata->core_data->tty); |
511 | if (err != 0) { | 473 | tty_driver_flush_buffer(kim_gdata->core_data->tty); |
512 | pr_err("sending SIGUSR2 to uim failed %ld", err); | 474 | |
513 | return -1; | 475 | /* send uninstall notification to UIM */ |
514 | } | 476 | pr_info("ldisc_install = 0"); |
515 | #endif | 477 | kim_gdata->ldisc_install = 0; |
516 | /* set BT rfkill to be blocked */ | 478 | sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, NULL, "install"); |
517 | err = rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 1); | ||
518 | 479 | ||
519 | /* wait for ldisc to be un-installed */ | 480 | /* wait for ldisc to be un-installed */ |
520 | err = wait_for_completion_timeout(&kim_gdata->ldisc_installed, | 481 | err = wait_for_completion_timeout(&kim_gdata->ldisc_installed, |
@@ -553,33 +514,59 @@ static int show_list(struct seq_file *s, void *unused) | |||
553 | return 0; | 514 | return 0; |
554 | } | 515 | } |
555 | 516 | ||
556 | /* function called from rfkill subsystem, when someone from | 517 | static ssize_t show_install(struct device *dev, |
557 | * user space would write 0/1 on the sysfs entry | 518 | struct device_attribute *attr, char *buf) |
558 | * /sys/class/rfkill/rfkill0,1,3/state | ||
559 | */ | ||
560 | static int kim_toggle_radio(void *data, bool blocked) | ||
561 | { | 519 | { |
562 | enum proto_type type = *((enum proto_type *)data); | 520 | struct kim_data_s *kim_data = dev_get_drvdata(dev); |
563 | pr_debug(" %s: %d ", __func__, type); | 521 | return sprintf(buf, "%d\n", kim_data->ldisc_install); |
522 | } | ||
564 | 523 | ||
565 | switch (type) { | 524 | static ssize_t show_dev_name(struct device *dev, |
566 | case ST_BT: | 525 | struct device_attribute *attr, char *buf) |
567 | /* do nothing */ | 526 | { |
568 | break; | 527 | struct kim_data_s *kim_data = dev_get_drvdata(dev); |
569 | case ST_FM: | 528 | return sprintf(buf, "%s\n", kim_data->dev_name); |
570 | case ST_GPS: | 529 | } |
571 | if (blocked) | 530 | |
572 | st_kim_chip_toggle(type, KIM_GPIO_INACTIVE); | 531 | static ssize_t show_baud_rate(struct device *dev, |
573 | else | 532 | struct device_attribute *attr, char *buf) |
574 | st_kim_chip_toggle(type, KIM_GPIO_ACTIVE); | 533 | { |
575 | break; | 534 | struct kim_data_s *kim_data = dev_get_drvdata(dev); |
576 | case ST_MAX_CHANNELS: | 535 | return sprintf(buf, "%ld\n", kim_data->baud_rate); |
577 | pr_err(" wrong proto type "); | 536 | } |
578 | break; | 537 | |
579 | } | 538 | static ssize_t show_flow_cntrl(struct device *dev, |
580 | return 0; | 539 | struct device_attribute *attr, char *buf) |
540 | { | ||
541 | struct kim_data_s *kim_data = dev_get_drvdata(dev); | ||
542 | return sprintf(buf, "%d\n", kim_data->flow_cntrl); | ||
581 | } | 543 | } |
582 | 544 | ||
545 | /* structures specific for sysfs entries */ | ||
546 | static struct kobj_attribute ldisc_install = | ||
547 | __ATTR(install, 0444, (void *)show_install, NULL); | ||
548 | |||
549 | static struct kobj_attribute uart_dev_name = | ||
550 | __ATTR(dev_name, 0444, (void *)show_dev_name, NULL); | ||
551 | |||
552 | static struct kobj_attribute uart_baud_rate = | ||
553 | __ATTR(baud_rate, 0444, (void *)show_baud_rate, NULL); | ||
554 | |||
555 | static struct kobj_attribute uart_flow_cntrl = | ||
556 | __ATTR(flow_cntrl, 0444, (void *)show_flow_cntrl, NULL); | ||
557 | |||
558 | static struct attribute *uim_attrs[] = { | ||
559 | &ldisc_install.attr, | ||
560 | &uart_dev_name.attr, | ||
561 | &uart_baud_rate.attr, | ||
562 | &uart_flow_cntrl.attr, | ||
563 | NULL, | ||
564 | }; | ||
565 | |||
566 | static struct attribute_group uim_attr_grp = { | ||
567 | .attrs = uim_attrs, | ||
568 | }; | ||
569 | |||
583 | /** | 570 | /** |
584 | * st_kim_ref - reference the core's data | 571 | * st_kim_ref - reference the core's data |
585 | * This references the per-ST platform device in the arch/xx/ | 572 | * This references the per-ST platform device in the arch/xx/ |
@@ -633,8 +620,9 @@ static int kim_probe(struct platform_device *pdev) | |||
633 | { | 620 | { |
634 | long status; | 621 | long status; |
635 | long proto; | 622 | long proto; |
636 | long *gpios = pdev->dev.platform_data; | ||
637 | struct kim_data_s *kim_gdata; | 623 | struct kim_data_s *kim_gdata; |
624 | struct ti_st_plat_data *pdata = pdev->dev.platform_data; | ||
625 | long *gpios = pdata->gpios; | ||
638 | 626 | ||
639 | if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) { | 627 | if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) { |
640 | /* multiple devices could exist */ | 628 | /* multiple devices could exist */ |
@@ -700,30 +688,18 @@ static int kim_probe(struct platform_device *pdev) | |||
700 | init_completion(&kim_gdata->kim_rcvd); | 688 | init_completion(&kim_gdata->kim_rcvd); |
701 | init_completion(&kim_gdata->ldisc_installed); | 689 | init_completion(&kim_gdata->ldisc_installed); |
702 | 690 | ||
703 | for (proto = 0; (proto < ST_MAX_CHANNELS) | 691 | status = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp); |
704 | && (gpios[proto] != -1); proto++) { | 692 | if (status) { |
705 | /* TODO: should all types be rfkill_type_bt ? */ | 693 | pr_err("failed to create sysfs entries"); |
706 | kim_gdata->rf_protos[proto] = proto; | 694 | return status; |
707 | kim_gdata->rfkill[proto] = rfkill_alloc(protocol_names[proto], | ||
708 | &pdev->dev, RFKILL_TYPE_BLUETOOTH, | ||
709 | &kim_rfkill_ops, &kim_gdata->rf_protos[proto]); | ||
710 | if (kim_gdata->rfkill[proto] == NULL) { | ||
711 | pr_err("cannot create rfkill entry for gpio %ld", | ||
712 | gpios[proto]); | ||
713 | continue; | ||
714 | } | ||
715 | /* block upon creation */ | ||
716 | rfkill_init_sw_state(kim_gdata->rfkill[proto], 1); | ||
717 | status = rfkill_register(kim_gdata->rfkill[proto]); | ||
718 | if (unlikely(status)) { | ||
719 | pr_err("rfkill registration failed for gpio %ld", | ||
720 | gpios[proto]); | ||
721 | rfkill_unregister(kim_gdata->rfkill[proto]); | ||
722 | continue; | ||
723 | } | ||
724 | pr_info("rfkill entry created for %ld", gpios[proto]); | ||
725 | } | 695 | } |
726 | 696 | ||
697 | /* copying platform data */ | ||
698 | strncpy(kim_gdata->dev_name, pdata->dev_name, UART_DEV_NAME_LEN); | ||
699 | kim_gdata->flow_cntrl = pdata->flow_cntrl; | ||
700 | kim_gdata->baud_rate = pdata->baud_rate; | ||
701 | pr_info("sysfs entries created\n"); | ||
702 | |||
727 | kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); | 703 | kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); |
728 | if (IS_ERR(kim_debugfs_dir)) { | 704 | if (IS_ERR(kim_debugfs_dir)) { |
729 | pr_err(" debugfs entries creation failed "); | 705 | pr_err(" debugfs entries creation failed "); |
@@ -741,9 +717,9 @@ static int kim_probe(struct platform_device *pdev) | |||
741 | 717 | ||
742 | static int kim_remove(struct platform_device *pdev) | 718 | static int kim_remove(struct platform_device *pdev) |
743 | { | 719 | { |
744 | /* free the GPIOs requested | 720 | /* free the GPIOs requested */ |
745 | */ | 721 | struct ti_st_plat_data *pdata = pdev->dev.platform_data; |
746 | long *gpios = pdev->dev.platform_data; | 722 | long *gpios = pdata->gpios; |
747 | long proto; | 723 | long proto; |
748 | struct kim_data_s *kim_gdata; | 724 | struct kim_data_s *kim_gdata; |
749 | 725 | ||
@@ -755,12 +731,11 @@ static int kim_remove(struct platform_device *pdev) | |||
755 | * nShutdown gpio from the system | 731 | * nShutdown gpio from the system |
756 | */ | 732 | */ |
757 | gpio_free(gpios[proto]); | 733 | gpio_free(gpios[proto]); |
758 | rfkill_unregister(kim_gdata->rfkill[proto]); | ||
759 | rfkill_destroy(kim_gdata->rfkill[proto]); | ||
760 | kim_gdata->rfkill[proto] = NULL; | ||
761 | } | 734 | } |
762 | pr_info("kim: GPIO Freed"); | 735 | pr_info("kim: GPIO Freed"); |
763 | debugfs_remove_recursive(kim_debugfs_dir); | 736 | debugfs_remove_recursive(kim_debugfs_dir); |
737 | |||
738 | sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp); | ||
764 | kim_gdata->kim_pdev = NULL; | 739 | kim_gdata->kim_pdev = NULL; |
765 | st_core_exit(kim_gdata->core_data); | 740 | st_core_exit(kim_gdata->core_data); |
766 | 741 | ||
@@ -769,23 +744,46 @@ static int kim_remove(struct platform_device *pdev) | |||
769 | return 0; | 744 | return 0; |
770 | } | 745 | } |
771 | 746 | ||
747 | int kim_suspend(struct platform_device *pdev, pm_message_t state) | ||
748 | { | ||
749 | struct ti_st_plat_data *pdata = pdev->dev.platform_data; | ||
750 | |||
751 | if (pdata->suspend) | ||
752 | return pdata->suspend(pdev, state); | ||
753 | |||
754 | return -EOPNOTSUPP; | ||
755 | } | ||
756 | |||
757 | int kim_resume(struct platform_device *pdev) | ||
758 | { | ||
759 | struct ti_st_plat_data *pdata = pdev->dev.platform_data; | ||
760 | |||
761 | if (pdata->resume) | ||
762 | return pdata->resume(pdev); | ||
763 | |||
764 | return -EOPNOTSUPP; | ||
765 | } | ||
766 | |||
772 | /**********************************************************************/ | 767 | /**********************************************************************/ |
773 | /* entry point for ST KIM module, called in from ST Core */ | 768 | /* entry point for ST KIM module, called in from ST Core */ |
769 | static struct platform_driver kim_platform_driver = { | ||
770 | .probe = kim_probe, | ||
771 | .remove = kim_remove, | ||
772 | .suspend = kim_suspend, | ||
773 | .resume = kim_resume, | ||
774 | .driver = { | ||
775 | .name = "kim", | ||
776 | .owner = THIS_MODULE, | ||
777 | }, | ||
778 | }; | ||
774 | 779 | ||
775 | static int __init st_kim_init(void) | 780 | static int __init st_kim_init(void) |
776 | { | 781 | { |
777 | long ret = 0; | 782 | return platform_driver_register(&kim_platform_driver); |
778 | ret = platform_driver_register(&kim_platform_driver); | ||
779 | if (ret != 0) { | ||
780 | pr_err("platform drv registration failed"); | ||
781 | return -1; | ||
782 | } | ||
783 | return 0; | ||
784 | } | 783 | } |
785 | 784 | ||
786 | static void __exit st_kim_deinit(void) | 785 | static void __exit st_kim_deinit(void) |
787 | { | 786 | { |
788 | /* the following returns void */ | ||
789 | platform_driver_unregister(&kim_platform_driver); | 787 | platform_driver_unregister(&kim_platform_driver); |
790 | } | 788 | } |
791 | 789 | ||