Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Pavan Savoy and committed by
Greg Kroah-Hartman
ec60d0ad 5c88b021

+187 -126
+48
Documentation/ABI/testing/sysfs-platform-kim
··· 1 + What: /sys/devices/platform/kim/dev_name 2 + Date: January 2010 3 + KernelVersion: 2.6.38 4 + Contact: "Pavan Savoy" <pavan_savoy@ti.com> 5 + Description: 6 + Name of the UART device at which the WL128x chip 7 + is connected. example: "/dev/ttyS0". 8 + The device name flows down to architecture specific board 9 + initialization file from the SFI/ATAGS bootloader 10 + firmware. The name exposed is read from the user-space 11 + dameon and opens the device when install is requested. 12 + 13 + What: /sys/devices/platform/kim/baud_rate 14 + Date: January 2010 15 + KernelVersion: 2.6.38 16 + Contact: "Pavan Savoy" <pavan_savoy@ti.com> 17 + Description: 18 + The maximum reliable baud-rate the host can support. 19 + Different platforms tend to have different high-speed 20 + UART configurations, so the baud-rate needs to be set 21 + locally and also sent across to the WL128x via a HCI-VS 22 + command. The entry is read and made use by the user-space 23 + daemon when the ldisc install is requested. 24 + 25 + What: /sys/devices/platform/kim/flow_cntrl 26 + Date: January 2010 27 + KernelVersion: 2.6.38 28 + Contact: "Pavan Savoy" <pavan_savoy@ti.com> 29 + Description: 30 + The WL128x makes use of flow control mechanism, and this 31 + entry most often should be 1, the host's UART is required 32 + to have the capability of flow-control, or else this 33 + entry can be made use of for exceptions. 34 + 35 + What: /sys/devices/platform/kim/install 36 + Date: January 2010 37 + KernelVersion: 2.6.38 38 + Contact: "Pavan Savoy" <pavan_savoy@ti.com> 39 + Description: 40 + When one of the protocols Bluetooth, FM or GPS wants to make 41 + use of the shared UART transport, it registers to the shared 42 + transport driver, which will signal the user-space for opening, 43 + configuring baud and install line discipline via this sysfs 44 + entry. This entry would be polled upon by the user-space 45 + daemon managing the UART, and is notified about the change 46 + by the sysfs_notify. The value would be '1' when UART needs 47 + to be opened/ldisc installed, and would be '0' when UART 48 + is no more required and needs to be closed.
+122 -124
drivers/misc/ti-st/st_kim.c
··· 30 30 #include <linux/debugfs.h> 31 31 #include <linux/seq_file.h> 32 32 #include <linux/sched.h> 33 - #include <linux/rfkill.h> 33 + #include <linux/tty.h> 34 34 35 35 #include <linux/skbuff.h> 36 36 #include <linux/ti_wilink_st.h> 37 37 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 38 73 39 #define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */ 74 40 static struct platform_device *st_kim_devices[MAX_ST_DEVICES]; ··· 337 371 kim_gdata = dev_get_drvdata(&kim_pdev->dev); 338 372 339 373 if (kim_gdata->gpios[type] == -1) { 340 - pr_info(" gpio not requested for protocol %s", 341 - protocol_names[type]); 374 + pr_info("gpio not requested for protocol %d", type); 342 375 return; 343 376 } 344 377 switch (type) { ··· 415 450 pr_info(" %s", __func__); 416 451 417 452 do { 418 - /* TODO: this is only because rfkill sub-system 419 - * doesn't send events to user-space if the state 420 - * isn't changed 421 - */ 422 - rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 1); 423 453 /* Configure BT nShutdown to HIGH state */ 424 454 gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW); 425 455 mdelay(5); /* FIXME: a proper toggle */ ··· 422 462 mdelay(100); 423 463 /* re-initialize the completion */ 424 464 INIT_COMPLETION(kim_gdata->ldisc_installed); 425 - #if 0 /* older way of signalling user-space UIM */ 426 - /* send signal to UIM */ 427 - err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 0); 428 - if (err != 0) { 429 - pr_info(" sending SIGUSR2 to uim failed %ld", err); 430 - err = -1; 431 - continue; 432 - } 433 - #endif 434 - /* unblock and send event to UIM via /dev/rfkill */ 435 - rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 0); 465 + /* send notification to UIM */ 466 + kim_gdata->ldisc_install = 1; 467 + pr_info("ldisc_install = 1"); 468 + sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, 469 + NULL, "install"); 436 470 /* wait for ldisc to be installed */ 437 471 err = wait_for_completion_timeout(&kim_gdata->ldisc_installed, 438 472 msecs_to_jiffies(LDISC_TIME)); 439 473 if (!err) { /* timeout */ 440 474 pr_err("line disc installation timed out "); 475 + kim_gdata->ldisc_install = 0; 476 + pr_info("ldisc_install = 0"); 477 + sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, 478 + NULL, "install"); 441 479 err = -1; 442 480 continue; 443 481 } else { ··· 444 486 err = download_firmware(kim_gdata); 445 487 if (err != 0) { 446 488 pr_err("download firmware failed"); 489 + kim_gdata->ldisc_install = 0; 490 + pr_info("ldisc_install = 0"); 491 + sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, 492 + NULL, "install"); 447 493 continue; 448 494 } else { /* on success don't retry */ 449 495 break; ··· 467 505 struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; 468 506 469 507 INIT_COMPLETION(kim_gdata->ldisc_installed); 470 - #if 0 /* older way of signalling user-space UIM */ 471 - /* send signal to UIM */ 472 - err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 1); 473 - if (err != 0) { 474 - pr_err("sending SIGUSR2 to uim failed %ld", err); 475 - return -1; 476 - } 477 - #endif 478 - /* set BT rfkill to be blocked */ 479 - err = rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 1); 508 + 509 + /* Flush any pending characters in the driver and discipline. */ 510 + tty_ldisc_flush(kim_gdata->core_data->tty); 511 + tty_driver_flush_buffer(kim_gdata->core_data->tty); 512 + 513 + /* send uninstall notification to UIM */ 514 + pr_info("ldisc_install = 0"); 515 + kim_gdata->ldisc_install = 0; 516 + sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, NULL, "install"); 480 517 481 518 /* wait for ldisc to be un-installed */ 482 519 err = wait_for_completion_timeout(&kim_gdata->ldisc_installed, ··· 514 553 return 0; 515 554 } 516 555 517 - /* function called from rfkill subsystem, when someone from 518 - * user space would write 0/1 on the sysfs entry 519 - * /sys/class/rfkill/rfkill0,1,3/state 520 - */ 521 - static int kim_toggle_radio(void *data, bool blocked) 556 + static ssize_t show_install(struct device *dev, 557 + struct device_attribute *attr, char *buf) 522 558 { 523 - enum proto_type type = *((enum proto_type *)data); 524 - pr_debug(" %s: %d ", __func__, type); 525 - 526 - switch (type) { 527 - case ST_BT: 528 - /* do nothing */ 529 - break; 530 - case ST_FM: 531 - case ST_GPS: 532 - if (blocked) 533 - st_kim_chip_toggle(type, KIM_GPIO_INACTIVE); 534 - else 535 - st_kim_chip_toggle(type, KIM_GPIO_ACTIVE); 536 - break; 537 - case ST_MAX_CHANNELS: 538 - pr_err(" wrong proto type "); 539 - break; 540 - } 541 - return 0; 559 + struct kim_data_s *kim_data = dev_get_drvdata(dev); 560 + return sprintf(buf, "%d\n", kim_data->ldisc_install); 542 561 } 562 + 563 + static ssize_t show_dev_name(struct device *dev, 564 + struct device_attribute *attr, char *buf) 565 + { 566 + struct kim_data_s *kim_data = dev_get_drvdata(dev); 567 + return sprintf(buf, "%s\n", kim_data->dev_name); 568 + } 569 + 570 + static ssize_t show_baud_rate(struct device *dev, 571 + struct device_attribute *attr, char *buf) 572 + { 573 + struct kim_data_s *kim_data = dev_get_drvdata(dev); 574 + return sprintf(buf, "%ld\n", kim_data->baud_rate); 575 + } 576 + 577 + static ssize_t show_flow_cntrl(struct device *dev, 578 + struct device_attribute *attr, char *buf) 579 + { 580 + struct kim_data_s *kim_data = dev_get_drvdata(dev); 581 + return sprintf(buf, "%d\n", kim_data->flow_cntrl); 582 + } 583 + 584 + /* structures specific for sysfs entries */ 585 + static struct kobj_attribute ldisc_install = 586 + __ATTR(install, 0444, (void *)show_install, NULL); 587 + 588 + static struct kobj_attribute uart_dev_name = 589 + __ATTR(dev_name, 0444, (void *)show_dev_name, NULL); 590 + 591 + static struct kobj_attribute uart_baud_rate = 592 + __ATTR(baud_rate, 0444, (void *)show_baud_rate, NULL); 593 + 594 + static struct kobj_attribute uart_flow_cntrl = 595 + __ATTR(flow_cntrl, 0444, (void *)show_flow_cntrl, NULL); 596 + 597 + static struct attribute *uim_attrs[] = { 598 + &ldisc_install.attr, 599 + &uart_dev_name.attr, 600 + &uart_baud_rate.attr, 601 + &uart_flow_cntrl.attr, 602 + NULL, 603 + }; 604 + 605 + static struct attribute_group uim_attr_grp = { 606 + .attrs = uim_attrs, 607 + }; 543 608 544 609 /** 545 610 * st_kim_ref - reference the core's data ··· 620 633 { 621 634 long status; 622 635 long proto; 623 - long *gpios = pdev->dev.platform_data; 624 636 struct kim_data_s *kim_gdata; 637 + struct ti_st_plat_data *pdata = pdev->dev.platform_data; 638 + long *gpios = pdata->gpios; 625 639 626 640 if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) { 627 641 /* multiple devices could exist */ ··· 688 700 init_completion(&kim_gdata->kim_rcvd); 689 701 init_completion(&kim_gdata->ldisc_installed); 690 702 691 - for (proto = 0; (proto < ST_MAX_CHANNELS) 692 - && (gpios[proto] != -1); proto++) { 693 - /* TODO: should all types be rfkill_type_bt ? */ 694 - kim_gdata->rf_protos[proto] = proto; 695 - kim_gdata->rfkill[proto] = rfkill_alloc(protocol_names[proto], 696 - &pdev->dev, RFKILL_TYPE_BLUETOOTH, 697 - &kim_rfkill_ops, &kim_gdata->rf_protos[proto]); 698 - if (kim_gdata->rfkill[proto] == NULL) { 699 - pr_err("cannot create rfkill entry for gpio %ld", 700 - gpios[proto]); 701 - continue; 702 - } 703 - /* block upon creation */ 704 - rfkill_init_sw_state(kim_gdata->rfkill[proto], 1); 705 - status = rfkill_register(kim_gdata->rfkill[proto]); 706 - if (unlikely(status)) { 707 - pr_err("rfkill registration failed for gpio %ld", 708 - gpios[proto]); 709 - rfkill_unregister(kim_gdata->rfkill[proto]); 710 - continue; 711 - } 712 - pr_info("rfkill entry created for %ld", gpios[proto]); 703 + status = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp); 704 + if (status) { 705 + pr_err("failed to create sysfs entries"); 706 + return status; 713 707 } 708 + 709 + /* copying platform data */ 710 + strncpy(kim_gdata->dev_name, pdata->dev_name, UART_DEV_NAME_LEN); 711 + kim_gdata->flow_cntrl = pdata->flow_cntrl; 712 + kim_gdata->baud_rate = pdata->baud_rate; 713 + pr_info("sysfs entries created\n"); 714 714 715 715 kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); 716 716 if (IS_ERR(kim_debugfs_dir)) { ··· 717 741 718 742 static int kim_remove(struct platform_device *pdev) 719 743 { 720 - /* free the GPIOs requested 721 - */ 722 - long *gpios = pdev->dev.platform_data; 744 + /* free the GPIOs requested */ 745 + struct ti_st_plat_data *pdata = pdev->dev.platform_data; 746 + long *gpios = pdata->gpios; 723 747 long proto; 724 748 struct kim_data_s *kim_gdata; 725 749 ··· 731 755 * nShutdown gpio from the system 732 756 */ 733 757 gpio_free(gpios[proto]); 734 - rfkill_unregister(kim_gdata->rfkill[proto]); 735 - rfkill_destroy(kim_gdata->rfkill[proto]); 736 - kim_gdata->rfkill[proto] = NULL; 737 758 } 738 759 pr_info("kim: GPIO Freed"); 739 760 debugfs_remove_recursive(kim_debugfs_dir); 761 + 762 + sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp); 740 763 kim_gdata->kim_pdev = NULL; 741 764 st_core_exit(kim_gdata->core_data); 742 765 ··· 744 769 return 0; 745 770 } 746 771 772 + int kim_suspend(struct platform_device *pdev, pm_message_t state) 773 + { 774 + struct ti_st_plat_data *pdata = pdev->dev.platform_data; 775 + 776 + if (pdata->suspend) 777 + return pdata->suspend(pdev, state); 778 + 779 + return -EOPNOTSUPP; 780 + } 781 + 782 + int kim_resume(struct platform_device *pdev) 783 + { 784 + struct ti_st_plat_data *pdata = pdev->dev.platform_data; 785 + 786 + if (pdata->resume) 787 + return pdata->resume(pdev); 788 + 789 + return -EOPNOTSUPP; 790 + } 791 + 747 792 /**********************************************************************/ 748 793 /* entry point for ST KIM module, called in from ST Core */ 794 + static struct platform_driver kim_platform_driver = { 795 + .probe = kim_probe, 796 + .remove = kim_remove, 797 + .suspend = kim_suspend, 798 + .resume = kim_resume, 799 + .driver = { 800 + .name = "kim", 801 + .owner = THIS_MODULE, 802 + }, 803 + }; 749 804 750 805 static int __init st_kim_init(void) 751 806 { 752 - long ret = 0; 753 - ret = platform_driver_register(&kim_platform_driver); 754 - if (ret != 0) { 755 - pr_err("platform drv registration failed"); 756 - return -1; 757 - } 758 - return 0; 807 + return platform_driver_register(&kim_platform_driver); 759 808 } 760 809 761 810 static void __exit st_kim_deinit(void) 762 811 { 763 - /* the following returns void */ 764 812 platform_driver_unregister(&kim_platform_driver); 765 813 } 766 814