drivers:misc: ti-st: move from rfkill to sysfs
[firefly-linux-kernel-4.4.55.git] / drivers / misc / ti-st / st_kim.c
index 707c85826417e40523d325cb89df0ffb81507240..a7fda814175892f2b79cd63aa83bd97124e9732a 100644 (file)
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/sched.h>
-#include <linux/rfkill.h>
+#include <linux/tty.h>
 
 #include <linux/skbuff.h>
 #include <linux/ti_wilink_st.h>
 
 
-static int kim_probe(struct platform_device *pdev);
-static int kim_remove(struct platform_device *pdev);
-
-/* KIM platform device driver structure */
-static struct platform_driver kim_platform_driver = {
-       .probe = kim_probe,
-       .remove = kim_remove,
-       /* TODO: ST driver power management during suspend/resume ?
-        */
-#if 0
-       .suspend = kim_suspend,
-       .resume = kim_resume,
-#endif
-       .driver = {
-                  .name = "kim",
-                  .owner = THIS_MODULE,
-                  },
-};
-
-static int kim_toggle_radio(void*, bool);
-static const struct rfkill_ops kim_rfkill_ops = {
-       .set_block = kim_toggle_radio,
-};
-
-/* strings to be used for rfkill entries and by
- * ST Core to be used for sysfs debug entry
- */
-#define PROTO_ENTRY(type, name)        name
-const unsigned char *protocol_names[] = {
-       PROTO_ENTRY(ST_BT, "Bluetooth"),
-       PROTO_ENTRY(ST_FM, "FM"),
-       PROTO_ENTRY(ST_GPS, "GPS"),
-};
-
 #define MAX_ST_DEVICES 3       /* Imagine 1 on each UART for now */
 static struct platform_device *st_kim_devices[MAX_ST_DEVICES];
 
@@ -371,8 +337,7 @@ void st_kim_chip_toggle(enum proto_type type, enum kim_gpio_state state)
        kim_gdata = dev_get_drvdata(&kim_pdev->dev);
 
        if (kim_gdata->gpios[type] == -1) {
-               pr_info(" gpio not requested for protocol %s",
-                          protocol_names[type]);
+               pr_info("gpio not requested for protocol %d", type);
                return;
        }
        switch (type) {
@@ -450,11 +415,6 @@ long st_kim_start(void *kim_data)
        pr_info(" %s", __func__);
 
        do {
-               /* TODO: this is only because rfkill sub-system
-                * doesn't send events to user-space if the state
-                * isn't changed
-                */
-               rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 1);
                /* Configure BT nShutdown to HIGH state */
                gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
                mdelay(5);      /* FIXME: a proper toggle */
@@ -462,22 +422,20 @@ long st_kim_start(void *kim_data)
                mdelay(100);
                /* re-initialize the completion */
                INIT_COMPLETION(kim_gdata->ldisc_installed);
-#if 0 /* older way of signalling user-space UIM */
-               /* send signal to UIM */
-               err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 0);
-               if (err != 0) {
-                       pr_info(" sending SIGUSR2 to uim failed %ld", err);
-                       err = -1;
-                       continue;
-               }
-#endif
-               /* unblock and send event to UIM via /dev/rfkill */
-               rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 0);
+               /* send notification to UIM */
+               kim_gdata->ldisc_install = 1;
+               pr_info("ldisc_install = 1");
+               sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
+                               NULL, "install");
                /* wait for ldisc to be installed */
                err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
                                msecs_to_jiffies(LDISC_TIME));
                if (!err) {     /* timeout */
                        pr_err("line disc installation timed out ");
+                       kim_gdata->ldisc_install = 0;
+                       pr_info("ldisc_install = 0");
+                       sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
+                                       NULL, "install");
                        err = -1;
                        continue;
                } else {
@@ -486,6 +444,10 @@ long st_kim_start(void *kim_data)
                        err = download_firmware(kim_gdata);
                        if (err != 0) {
                                pr_err("download firmware failed");
+                               kim_gdata->ldisc_install = 0;
+                               pr_info("ldisc_install = 0");
+                               sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
+                                               NULL, "install");
                                continue;
                        } else {        /* on success don't retry */
                                break;
@@ -505,16 +467,15 @@ long st_kim_stop(void *kim_data)
        struct kim_data_s       *kim_gdata = (struct kim_data_s *)kim_data;
 
        INIT_COMPLETION(kim_gdata->ldisc_installed);
-#if 0 /* older way of signalling user-space UIM */
-       /* send signal to UIM */
-       err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 1);
-       if (err != 0) {
-               pr_err("sending SIGUSR2 to uim failed %ld", err);
-               return -1;
-       }
-#endif
-       /* set BT rfkill to be blocked */
-       err = rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 1);
+
+       /* Flush any pending characters in the driver and discipline. */
+       tty_ldisc_flush(kim_gdata->core_data->tty);
+       tty_driver_flush_buffer(kim_gdata->core_data->tty);
+
+       /* send uninstall notification to UIM */
+       pr_info("ldisc_install = 0");
+       kim_gdata->ldisc_install = 0;
+       sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, NULL, "install");
 
        /* wait for ldisc to be un-installed */
        err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
@@ -553,33 +514,59 @@ static int show_list(struct seq_file *s, void *unused)
        return 0;
 }
 
-/* function called from rfkill subsystem, when someone from
- * user space would write 0/1 on the sysfs entry
- * /sys/class/rfkill/rfkill0,1,3/state
- */
-static int kim_toggle_radio(void *data, bool blocked)
+static ssize_t show_install(struct device *dev,
+               struct device_attribute *attr, char *buf)
 {
-       enum proto_type type = *((enum proto_type *)data);
-       pr_debug(" %s: %d ", __func__, type);
+       struct kim_data_s *kim_data = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", kim_data->ldisc_install);
+}
 
-       switch (type) {
-       case ST_BT:
-               /* do nothing */
-       break;
-       case ST_FM:
-       case ST_GPS:
-               if (blocked)
-                       st_kim_chip_toggle(type, KIM_GPIO_INACTIVE);
-               else
-                       st_kim_chip_toggle(type, KIM_GPIO_ACTIVE);
-       break;
-       case ST_MAX_CHANNELS:
-               pr_err(" wrong proto type ");
-       break;
-       }
-       return 0;
+static ssize_t show_dev_name(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct kim_data_s *kim_data = dev_get_drvdata(dev);
+       return sprintf(buf, "%s\n", kim_data->dev_name);
+}
+
+static ssize_t show_baud_rate(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct kim_data_s *kim_data = dev_get_drvdata(dev);
+       return sprintf(buf, "%ld\n", kim_data->baud_rate);
+}
+
+static ssize_t show_flow_cntrl(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct kim_data_s *kim_data = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", kim_data->flow_cntrl);
 }
 
+/* structures specific for sysfs entries */
+static struct kobj_attribute ldisc_install =
+__ATTR(install, 0444, (void *)show_install, NULL);
+
+static struct kobj_attribute uart_dev_name =
+__ATTR(dev_name, 0444, (void *)show_dev_name, NULL);
+
+static struct kobj_attribute uart_baud_rate =
+__ATTR(baud_rate, 0444, (void *)show_baud_rate, NULL);
+
+static struct kobj_attribute uart_flow_cntrl =
+__ATTR(flow_cntrl, 0444, (void *)show_flow_cntrl, NULL);
+
+static struct attribute *uim_attrs[] = {
+       &ldisc_install.attr,
+       &uart_dev_name.attr,
+       &uart_baud_rate.attr,
+       &uart_flow_cntrl.attr,
+       NULL,
+};
+
+static struct attribute_group uim_attr_grp = {
+       .attrs = uim_attrs,
+};
+
 /**
  * st_kim_ref - reference the core's data
  *     This references the per-ST platform device in the arch/xx/
@@ -633,8 +620,9 @@ static int kim_probe(struct platform_device *pdev)
 {
        long status;
        long proto;
-       long *gpios = pdev->dev.platform_data;
        struct kim_data_s       *kim_gdata;
+       struct ti_st_plat_data  *pdata = pdev->dev.platform_data;
+       long *gpios = pdata->gpios;
 
        if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) {
                /* multiple devices could exist */
@@ -700,30 +688,18 @@ static int kim_probe(struct platform_device *pdev)
        init_completion(&kim_gdata->kim_rcvd);
        init_completion(&kim_gdata->ldisc_installed);
 
-       for (proto = 0; (proto < ST_MAX_CHANNELS)
-                       && (gpios[proto] != -1); proto++) {
-               /* TODO: should all types be rfkill_type_bt ? */
-               kim_gdata->rf_protos[proto] = proto;
-               kim_gdata->rfkill[proto] = rfkill_alloc(protocol_names[proto],
-                       &pdev->dev, RFKILL_TYPE_BLUETOOTH,
-                       &kim_rfkill_ops, &kim_gdata->rf_protos[proto]);
-               if (kim_gdata->rfkill[proto] == NULL) {
-                       pr_err("cannot create rfkill entry for gpio %ld",
-                                  gpios[proto]);
-                       continue;
-               }
-               /* block upon creation */
-               rfkill_init_sw_state(kim_gdata->rfkill[proto], 1);
-               status = rfkill_register(kim_gdata->rfkill[proto]);
-               if (unlikely(status)) {
-                       pr_err("rfkill registration failed for gpio %ld",
-                                  gpios[proto]);
-                       rfkill_unregister(kim_gdata->rfkill[proto]);
-                       continue;
-               }
-               pr_info("rfkill entry created for %ld", gpios[proto]);
+       status = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp);
+       if (status) {
+               pr_err("failed to create sysfs entries");
+               return status;
        }
 
+       /* copying platform data */
+       strncpy(kim_gdata->dev_name, pdata->dev_name, UART_DEV_NAME_LEN);
+       kim_gdata->flow_cntrl = pdata->flow_cntrl;
+       kim_gdata->baud_rate = pdata->baud_rate;
+       pr_info("sysfs entries created\n");
+
        kim_debugfs_dir = debugfs_create_dir("ti-st", NULL);
        if (IS_ERR(kim_debugfs_dir)) {
                pr_err(" debugfs entries creation failed ");
@@ -741,9 +717,9 @@ static int kim_probe(struct platform_device *pdev)
 
 static int kim_remove(struct platform_device *pdev)
 {
-       /* free the GPIOs requested
-        */
-       long *gpios = pdev->dev.platform_data;
+       /* free the GPIOs requested */
+       struct ti_st_plat_data  *pdata = pdev->dev.platform_data;
+       long *gpios = pdata->gpios;
        long proto;
        struct kim_data_s       *kim_gdata;
 
@@ -755,12 +731,11 @@ static int kim_remove(struct platform_device *pdev)
                 * nShutdown gpio from the system
                 */
                gpio_free(gpios[proto]);
-               rfkill_unregister(kim_gdata->rfkill[proto]);
-               rfkill_destroy(kim_gdata->rfkill[proto]);
-               kim_gdata->rfkill[proto] = NULL;
        }
        pr_info("kim: GPIO Freed");
        debugfs_remove_recursive(kim_debugfs_dir);
+
+       sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp);
        kim_gdata->kim_pdev = NULL;
        st_core_exit(kim_gdata->core_data);
 
@@ -769,23 +744,46 @@ static int kim_remove(struct platform_device *pdev)
        return 0;
 }
 
+int kim_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct ti_st_plat_data  *pdata = pdev->dev.platform_data;
+
+       if (pdata->suspend)
+               return pdata->suspend(pdev, state);
+
+       return -EOPNOTSUPP;
+}
+
+int kim_resume(struct platform_device *pdev)
+{
+       struct ti_st_plat_data  *pdata = pdev->dev.platform_data;
+
+       if (pdata->resume)
+               return pdata->resume(pdev);
+
+       return -EOPNOTSUPP;
+}
+
 /**********************************************************************/
 /* entry point for ST KIM module, called in from ST Core */
+static struct platform_driver kim_platform_driver = {
+       .probe = kim_probe,
+       .remove = kim_remove,
+       .suspend = kim_suspend,
+       .resume = kim_resume,
+       .driver = {
+               .name = "kim",
+               .owner = THIS_MODULE,
+       },
+};
 
 static int __init st_kim_init(void)
 {
-       long ret = 0;
-       ret = platform_driver_register(&kim_platform_driver);
-       if (ret != 0) {
-               pr_err("platform drv registration failed");
-               return -1;
-       }
-       return 0;
+       return platform_driver_register(&kim_platform_driver);
 }
 
 static void __exit st_kim_deinit(void)
 {
-       /* the following returns void */
        platform_driver_unregister(&kim_platform_driver);
 }