mfd: cpcap-whisper: Report dock ID to system
authorGreg Meiste <w30289@motorola.com>
Thu, 29 Jul 2010 19:23:26 +0000 (14:23 -0500)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:33:36 +0000 (16:33 -0700)
Add support for whisper driver to report the dock ID to the system
via sysfs. The dock ID can be found at:
/sys/class/switch/dock/dock_addr

Change-Id: Iafcc738c5e9bd10f94ee2cab1ab0d39a10b9932e
Signed-off-by: Greg Meiste <w30289@motorola.com>
Signed-off-by: Nick Pelly <npelly@google.com>
drivers/mfd/cpcap-core.c
drivers/mfd/cpcap-whisper.c
include/linux/spi/cpcap.h

index 5015e390b77f5d8ced6fa5e2577d31f892f9e4bd..1bedea917c7ff2480c7381594352136ccad167ba 100644 (file)
@@ -422,10 +422,15 @@ static int adc_ioctl(unsigned int cmd, unsigned long arg)
 static int accy_ioctl(unsigned int cmd, unsigned long arg)
 {
        int retval = -EINVAL;
+       struct cpcap_whisper_request read_data;
 
        switch (cmd) {
        case CPCAP_IOCTL_ACCY_WHISPER:
-               retval = cpcap_accy_whisper(misc_cpcap, arg);
+               if (copy_from_user((void *) &read_data, (void *) arg,
+                                  sizeof(read_data)))
+                       return -EFAULT;
+               retval = cpcap_accy_whisper(misc_cpcap, read_data.cmd,
+                                           read_data.dock_id);
        break;
 
        default:
index f1a1051bbcd138d12bcc3ca78167abdf2619851d..ef35f10196c2331d66b14241b7c2cc2e9ca389e2 100644 (file)
@@ -97,6 +97,7 @@ struct cpcap_whisper_data {
        struct switch_dev wsdev;
        struct switch_dev dsdev;
        struct switch_dev asdev;
+       char dock_id[CPCAP_WHISPER_ID_SIZE];
        struct otg_transceiver *otg;
 };
 
@@ -121,6 +122,17 @@ static ssize_t print_name(struct switch_dev *dsdev, char *buf)
        return -EINVAL;
 }
 
+static ssize_t dock_id_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       struct switch_dev *dsdev = dev_get_drvdata(dev);
+       struct cpcap_whisper_data *data =
+               container_of(dsdev, struct cpcap_whisper_data, dsdev);
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", data->dock_id);
+}
+static DEVICE_ATTR(dock_addr, S_IRUGO | S_IWUSR, dock_id_show, NULL);
+
 static void vusb_enable(struct cpcap_whisper_data *data)
 {
        if (!data->is_vusb_enabled) {
@@ -271,6 +283,7 @@ static void whisper_notify(struct cpcap_whisper_data *di, enum cpcap_accy accy)
                switch_set_state(&di->wsdev, 0);
                switch_set_state(&di->dsdev, NO_DOCK);
                switch_set_state(&di->asdev, 0);
+               memset(di->dock_id, 0, CPCAP_WHISPER_ID_SIZE);
        }
 }
 
@@ -451,7 +464,8 @@ static void whisper_int_handler(enum cpcap_irqs int_event, void *data)
        schedule_delayed_work(&(di->work), 0);
 }
 
-int cpcap_accy_whisper(struct cpcap_device *cpcap, unsigned long cmd)
+int cpcap_accy_whisper(struct cpcap_device *cpcap, unsigned int cmd,
+                      char *dock_id)
 {
        struct cpcap_whisper_data *di = cpcap->accydata;
        int retval = -EAGAIN;
@@ -478,10 +492,11 @@ int cpcap_accy_whisper(struct cpcap_device *cpcap, unsigned long cmd)
                /* Report dock type to system. */
                dock = (cmd & CPCAP_WHISPER_ACCY_MASK) >>
                        CPCAP_WHISPER_ACCY_SHFT;
+               if (dock && (strlen(dock_id) < CPCAP_WHISPER_ID_SIZE))
+                       strncpy(di->dock_id, dock_id, CPCAP_WHISPER_ID_SIZE);
                switch_set_state(&di->dsdev, dock);
 
-               if (dock)
-                       whisper_audio_check(di);
+               whisper_audio_check(di);
        }
 
        return retval;
@@ -510,12 +525,17 @@ static int cpcap_whisper_probe(struct platform_device *pdev)
        data->wsdev.name = "whisper";
        switch_dev_register(&data->wsdev);
 
+       data->asdev.name = "usb_audio";
+       switch_dev_register(&data->asdev);
+
        data->dsdev.name = "dock";
        data->dsdev.print_name = print_name;
        switch_dev_register(&data->dsdev);
-
-       data->asdev.name = "usb_audio";
-       switch_dev_register(&data->asdev);
+       retval = device_create_file(data->dsdev.dev, &dev_attr_dock_addr);
+       if (retval < 0) {
+               dev_err(&pdev->dev, "Failed to create device file\n");
+               goto free_mem;
+       }
 
        platform_set_drvdata(pdev, data);
 
@@ -524,7 +544,7 @@ static int cpcap_whisper_probe(struct platform_device *pdev)
                dev_err(&pdev->dev,
                        "Could not get regulator for cpcap_whisper\n");
                retval = PTR_ERR(data->regulator);
-               goto free_mem;
+               goto free_dock_id;
        }
        regulator_set_voltage(data->regulator, 3300000, 3300000);
 
@@ -566,6 +586,8 @@ free_irqs:
        cpcap_irq_free(data->cpcap, CPCAP_IRQ_IDFLOAT);
        cpcap_irq_free(data->cpcap, CPCAP_IRQ_CHRG_DET);
        regulator_put(data->regulator);
+free_dock_id:
+       device_remove_file(data->dsdev.dev, &dev_attr_dock_addr);
 free_mem:
        switch_dev_unregister(&data->wsdev);
        switch_dev_unregister(&data->dsdev);
@@ -587,6 +609,7 @@ static int __exit cpcap_whisper_remove(struct platform_device *pdev)
        configure_hardware(data, CPCAP_ACCY_NONE);
        cancel_delayed_work_sync(&data->work);
 
+       device_remove_file(data->dsdev.dev, &dev_attr_dock_addr);
        switch_dev_unregister(&data->wsdev);
        switch_dev_unregister(&data->dsdev);
        switch_dev_unregister(&data->asdev);
index b2d9fcf303dd10bacaf4cfc7a762698f6c11638d..09254e9c921f324dbf58797b26c9b01576ec08be 100644 (file)
@@ -41,8 +41,9 @@
 
 #define CPCAP_WHISPER_MODE_PU       0x00000001
 #define CPCAP_WHISPER_ENABLE_UART   0x00000002
-#define CPCAP_WHISPER_ACCY_MASK     0xF1000000
+#define CPCAP_WHISPER_ACCY_MASK     0xF8000000
 #define CPCAP_WHISPER_ACCY_SHFT     27
+#define CPCAP_WHISPER_ID_SIZE       16
 
 enum cpcap_regulator_id {
        CPCAP_SW2,
@@ -596,6 +597,11 @@ struct cpcap_regacc {
        unsigned short mask;
 };
 
+struct cpcap_whisper_request {
+       unsigned int cmd;
+       char dock_id[CPCAP_WHISPER_ID_SIZE];
+};
+
 /*
  * Gets the contents of the specified cpcap register.
  *
@@ -656,7 +662,7 @@ struct cpcap_regacc {
        _IOW(0, CPCAP_IOCTL_NUM_UC_SET_TURBO_MODE, unsigned short)
 
 #define CPCAP_IOCTL_ACCY_WHISPER \
-       _IOW(0, CPCAP_IOCTL_NUM_ACCY_WHISPER, unsigned long)
+       _IOW(0, CPCAP_IOCTL_NUM_ACCY_WHISPER, struct cpcap_whisper_request*)
 
 #ifdef __KERNEL__
 struct cpcap_device {
@@ -746,7 +752,8 @@ int cpcap_uc_stop(struct cpcap_device *cpcap, enum cpcap_macro macro);
 unsigned char cpcap_uc_status(struct cpcap_device *cpcap,
                              enum cpcap_macro macro);
 
-int cpcap_accy_whisper(struct cpcap_device *cpcap, unsigned long cmd);
+int cpcap_accy_whisper(struct cpcap_device *cpcap, unsigned int cmd,
+                      char *dock_id);
 
 #define  cpcap_driver_register platform_driver_register
 #define  cpcap_driver_unregister platform_driver_unregister