nfs: new subdir Documentation/filesystems/nfs
[safe/jmp/linux-2.6] / drivers / mfd / wm8350-core.c
index 03af3b1..ba27c9d 100644 (file)
@@ -79,10 +79,6 @@ static int wm8350_phys_read(struct wm8350 *wm8350, u8 reg, int num_regs,
                /* Cache is CPU endian */
                dest[i - reg] = be16_to_cpu(dest[i - reg]);
 
-               /* Satisfy non-volatile bits from cache */
-               dest[i - reg] &= wm8350_reg_io_map[i].vol;
-               dest[i - reg] |= wm8350->reg_cache[i];
-
                /* Mask out non-readable bits */
                dest[i - reg] &= wm8350_reg_io_map[i].readable;
        }
@@ -182,9 +178,6 @@ static int wm8350_write(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *src)
                        (wm8350->reg_cache[i] & ~wm8350_reg_io_map[i].writable)
                        | src[i - reg];
 
-               /* Don't store volatile bits */
-               wm8350->reg_cache[i] &= ~wm8350_reg_io_map[i].vol;
-
                src[i - reg] = cpu_to_be16(src[i - reg]);
        }
 
@@ -360,15 +353,15 @@ static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
 }
 
 /*
- * wm8350_irq_worker actually handles the interrupts.  Since all
+ * This is a threaded IRQ handler so can access I2C/SPI.  Since all
  * interrupts are clear on read the IRQ line will be reasserted and
  * the physical IRQ will be handled again if another interrupt is
  * asserted while we run - in the normal course of events this is a
  * rare occurrence so we save I2C/SPI reads.
  */
-static void wm8350_irq_worker(struct work_struct *work)
+static irqreturn_t wm8350_irq(int irq, void *data)
 {
-       struct wm8350 *wm8350 = container_of(work, struct wm8350, irq_work);
+       struct wm8350 *wm8350 = data;
        u16 level_one, status1, status2, comp;
 
        /* TODO: Use block reads to improve performance? */
@@ -559,16 +552,6 @@ static void wm8350_irq_worker(struct work_struct *work)
                }
        }
 
-       enable_irq(wm8350->chip_irq);
-}
-
-static irqreturn_t wm8350_irq(int irq, void *data)
-{
-       struct wm8350 *wm8350 = data;
-
-       disable_irq_nosync(irq);
-       schedule_work(&wm8350->irq_work);
-
        return IRQ_HANDLED;
 }
 
@@ -1111,7 +1094,7 @@ int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
        do {
                schedule_timeout_interruptible(1);
                reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
-       } while (tries-- && (reg & WM8350_AUXADC_POLL));
+       } while ((reg & WM8350_AUXADC_POLL) && --tries);
 
        if (!tries)
                dev_err(wm8350->dev, "adc chn %d read timeout\n", channel);
@@ -1168,6 +1151,37 @@ static int wm8350_create_cache(struct wm8350 *wm8350, int type, int mode)
                                mode);
                        return -EINVAL;
                }
+               break;
+
+       case 1:
+               switch (mode) {
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_0
+               case 0:
+                       reg_map = wm8351_mode0_defaults;
+                       break;
+#endif
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_1
+               case 1:
+                       reg_map = wm8351_mode1_defaults;
+                       break;
+#endif
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_2
+               case 2:
+                       reg_map = wm8351_mode2_defaults;
+                       break;
+#endif
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_3
+               case 3:
+                       reg_map = wm8351_mode3_defaults;
+                       break;
+#endif
+               default:
+                       dev_err(wm8350->dev,
+                               "WM8351 configuration mode %d not supported\n",
+                               mode);
+                       return -EINVAL;
+               }
+               break;
 
        case 2:
                switch (mode) {
@@ -1207,7 +1221,7 @@ static int wm8350_create_cache(struct wm8350 *wm8350, int type, int mode)
        }
 
        wm8350->reg_cache =
-           kzalloc(sizeof(u16) * (WM8350_MAX_REGISTER + 1), GFP_KERNEL);
+               kmalloc(sizeof(u16) * (WM8350_MAX_REGISTER + 1), GFP_KERNEL);
        if (wm8350->reg_cache == NULL)
                return -ENOMEM;
 
@@ -1215,19 +1229,21 @@ static int wm8350_create_cache(struct wm8350 *wm8350, int type, int mode)
         * a PMIC so the device many not be in a virgin state and we
         * can't rely on the silicon values.
         */
+       ret = wm8350->read_dev(wm8350, 0,
+                              sizeof(u16) * (WM8350_MAX_REGISTER + 1),
+                              wm8350->reg_cache);
+       if (ret < 0) {
+               dev_err(wm8350->dev,
+                       "failed to read initial cache values\n");
+               goto out;
+       }
+
+       /* Mask out uncacheable/unreadable bits and the audio. */
        for (i = 0; i < WM8350_MAX_REGISTER; i++) {
-               /* audio register range */
                if (wm8350_reg_io_map[i].readable &&
                    (i < WM8350_CLOCK_CONTROL_1 || i > WM8350_AIF_TEST)) {
-                       ret = wm8350->read_dev(wm8350, i, 2, (char *)&value);
-                       if (ret < 0) {
-                               dev_err(wm8350->dev,
-                                      "failed to read initial cache value\n");
-                               goto out;
-                       }
-                       value = be16_to_cpu(value);
+                       value = be16_to_cpu(wm8350->reg_cache[i]);
                        value &= wm8350_reg_io_map[i].readable;
-                       value &= ~wm8350_reg_io_map[i].vol;
                        wm8350->reg_cache[i] = value;
                } else
                        wm8350->reg_cache[i] = reg_map[i];
@@ -1266,14 +1282,29 @@ static void wm8350_client_dev_register(struct wm8350 *wm8350,
 int wm8350_device_init(struct wm8350 *wm8350, int irq,
                       struct wm8350_platform_data *pdata)
 {
-       int ret = -EINVAL;
+       int ret;
        u16 id1, id2, mask_rev;
        u16 cust_id, mode, chip_rev;
 
        /* get WM8350 revision and config mode */
-       wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
-       wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2);
-       wm8350->read_dev(wm8350, WM8350_REVISION, sizeof(mask_rev), &mask_rev);
+       ret = wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
+       if (ret != 0) {
+               dev_err(wm8350->dev, "Failed to read ID: %d\n", ret);
+               goto err;
+       }
+
+       ret = wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2);
+       if (ret != 0) {
+               dev_err(wm8350->dev, "Failed to read ID: %d\n", ret);
+               goto err;
+       }
+
+       ret = wm8350->read_dev(wm8350, WM8350_REVISION, sizeof(mask_rev),
+                              &mask_rev);
+       if (ret != 0) {
+               dev_err(wm8350->dev, "Failed to read revision: %d\n", ret);
+               goto err;
+       }
 
        id1 = be16_to_cpu(id1);
        id2 = be16_to_cpu(id2);
@@ -1301,6 +1332,9 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
 
        switch (mask_rev) {
        case 0:
+               wm8350->pmic.max_dcdc = WM8350_DCDC_6;
+               wm8350->pmic.max_isink = WM8350_ISINK_B;
+
                switch (chip_rev) {
                case WM8350_REV_E:
                        dev_info(wm8350->dev, "WM8350 Rev E\n");
@@ -1324,7 +1358,32 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
                }
                break;
 
+       case 1:
+               wm8350->pmic.max_dcdc = WM8350_DCDC_4;
+               wm8350->pmic.max_isink = WM8350_ISINK_A;
+
+               switch (chip_rev) {
+               case 0:
+                       dev_info(wm8350->dev, "WM8351 Rev A\n");
+                       wm8350->power.rev_g_coeff = 1;
+                       break;
+
+               case 1:
+                       dev_info(wm8350->dev, "WM8351 Rev B\n");
+                       wm8350->power.rev_g_coeff = 1;
+                       break;
+
+               default:
+                       dev_err(wm8350->dev, "Unknown WM8351 CHIP_REV\n");
+                       ret = -ENODEV;
+                       goto err;
+               }
+               break;
+
        case 2:
+               wm8350->pmic.max_dcdc = WM8350_DCDC_6;
+               wm8350->pmic.max_isink = WM8350_ISINK_B;
+
                switch (chip_rev) {
                case 0:
                        dev_info(wm8350->dev, "WM8352 Rev A\n");
@@ -1350,21 +1409,32 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
                return ret;
        }
 
-       if (pdata && pdata->init) {
-               ret = pdata->init(wm8350);
-               if (ret != 0) {
-                       dev_err(wm8350->dev, "Platform init() failed: %d\n",
-                               ret);
-                       goto err;
-               }
-       }
+       wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF);
 
        mutex_init(&wm8350->auxadc_mutex);
        mutex_init(&wm8350->irq_mutex);
-       INIT_WORK(&wm8350->irq_work, wm8350_irq_worker);
        if (irq) {
-               ret = request_irq(irq, wm8350_irq, 0,
-                                 "wm8350", wm8350);
+               int flags = IRQF_ONESHOT;
+
+               if (pdata && pdata->irq_high) {
+                       flags |= IRQF_TRIGGER_HIGH;
+
+                       wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
+                                       WM8350_IRQ_POL);
+               } else {
+                       flags |= IRQF_TRIGGER_LOW;
+
+                       wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
+                                         WM8350_IRQ_POL);
+               }
+
+               ret = request_threaded_irq(irq, NULL, wm8350_irq, flags,
+                                          "wm8350", wm8350);
                if (ret != 0) {
                        dev_err(wm8350->dev, "Failed to request IRQ: %d\n",
                                ret);
@@ -1376,12 +1446,23 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
        }
        wm8350->chip_irq = irq;
 
+       if (pdata && pdata->init) {
+               ret = pdata->init(wm8350);
+               if (ret != 0) {
+                       dev_err(wm8350->dev, "Platform init() failed: %d\n",
+                               ret);
+                       goto err;
+               }
+       }
+
        wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x0);
 
        wm8350_client_dev_register(wm8350, "wm8350-codec",
                                   &(wm8350->codec.pdev));
        wm8350_client_dev_register(wm8350, "wm8350-gpio",
                                   &(wm8350->gpio.pdev));
+       wm8350_client_dev_register(wm8350, "wm8350-hwmon",
+                                  &(wm8350->hwmon.pdev));
        wm8350_client_dev_register(wm8350, "wm8350-power",
                                   &(wm8350->power.pdev));
        wm8350_client_dev_register(wm8350, "wm8350-rtc", &(wm8350->rtc.pdev));
@@ -1399,17 +1480,20 @@ void wm8350_device_exit(struct wm8350 *wm8350)
 {
        int i;
 
+       for (i = 0; i < ARRAY_SIZE(wm8350->pmic.led); i++)
+               platform_device_unregister(wm8350->pmic.led[i].pdev);
+
        for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++)
                platform_device_unregister(wm8350->pmic.pdev[i]);
 
        platform_device_unregister(wm8350->wdt.pdev);
        platform_device_unregister(wm8350->rtc.pdev);
        platform_device_unregister(wm8350->power.pdev);
+       platform_device_unregister(wm8350->hwmon.pdev);
        platform_device_unregister(wm8350->gpio.pdev);
        platform_device_unregister(wm8350->codec.pdev);
 
        free_irq(wm8350->chip_irq, wm8350);
-       flush_work(&wm8350->irq_work);
        kfree(wm8350->reg_cache);
 }
 EXPORT_SYMBOL_GPL(wm8350_device_exit);