nfsd4: don't check ip address in setclientid
[safe/jmp/linux-2.6] / drivers / mfd / wm8350-core.c
index d63a530..b457a05 100644 (file)
@@ -63,7 +63,6 @@
  */
 static DEFINE_MUTEX(io_mutex);
 static DEFINE_MUTEX(reg_lock_mutex);
-static DEFINE_MUTEX(auxadc_mutex);
 
 /* Perform a physical read from the device.
  */
@@ -1082,38 +1081,158 @@ int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
 }
 EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
 
+int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
+{
+       u16 reg, result = 0;
+       int tries = 5;
+
+       if (channel < WM8350_AUXADC_AUX1 || channel > WM8350_AUXADC_TEMP)
+               return -EINVAL;
+       if (channel >= WM8350_AUXADC_USB && channel <= WM8350_AUXADC_TEMP
+           && (scale != 0 || vref != 0))
+               return -EINVAL;
+
+       mutex_lock(&wm8350->auxadc_mutex);
+
+       /* Turn on the ADC */
+       reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
+       wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5, reg | WM8350_AUXADC_ENA);
+
+       if (scale || vref) {
+               reg = scale << 13;
+               reg |= vref << 12;
+               wm8350_reg_write(wm8350, WM8350_AUX1_READBACK + channel, reg);
+       }
+
+       reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
+       reg |= 1 << channel | WM8350_AUXADC_POLL;
+       wm8350_reg_write(wm8350, WM8350_DIGITISER_CONTROL_1, reg);
+
+       do {
+               schedule_timeout_interruptible(1);
+               reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
+       } while (--tries && (reg & WM8350_AUXADC_POLL));
+
+       if (!tries)
+               dev_err(wm8350->dev, "adc chn %d read timeout\n", channel);
+       else
+               result = wm8350_reg_read(wm8350,
+                                        WM8350_AUX1_READBACK + channel);
+
+       /* Turn off the ADC */
+       reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
+       wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5,
+                        reg & ~WM8350_AUXADC_ENA);
+
+       mutex_unlock(&wm8350->auxadc_mutex);
+
+       return result & WM8350_AUXADC_DATA1_MASK;
+}
+EXPORT_SYMBOL_GPL(wm8350_read_auxadc);
+
 /*
  * Cache is always host endian.
  */
-static int wm8350_create_cache(struct wm8350 *wm8350, int mode)
+static int wm8350_create_cache(struct wm8350 *wm8350, int type, int mode)
 {
        int i, ret = 0;
        u16 value;
        const u16 *reg_map;
 
-       switch (mode) {
-#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
+       switch (type) {
        case 0:
-               reg_map = wm8350_mode0_defaults;
-               break;
+               switch (mode) {
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
+               case 0:
+                       reg_map = wm8350_mode0_defaults;
+                       break;
 #endif
 #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
-       case 1:
-               reg_map = wm8350_mode1_defaults;
-               break;
+               case 1:
+                       reg_map = wm8350_mode1_defaults;
+                       break;
 #endif
 #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
-       case 2:
-               reg_map = wm8350_mode2_defaults;
-               break;
+               case 2:
+                       reg_map = wm8350_mode2_defaults;
+                       break;
 #endif
 #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
-       case 3:
-               reg_map = wm8350_mode3_defaults;
+               case 3:
+                       reg_map = wm8350_mode3_defaults;
+                       break;
+#endif
+               default:
+                       dev_err(wm8350->dev,
+                               "WM8350 configuration mode %d not supported\n",
+                               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) {
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0
+               case 0:
+                       reg_map = wm8352_mode0_defaults;
+                       break;
+#endif
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_1
+               case 1:
+                       reg_map = wm8352_mode1_defaults;
+                       break;
+#endif
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_2
+               case 2:
+                       reg_map = wm8352_mode2_defaults;
+                       break;
+#endif
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_3
+               case 3:
+                       reg_map = wm8352_mode3_defaults;
+                       break;
 #endif
+               default:
+                       dev_err(wm8350->dev,
+                               "WM8352 configuration mode %d not supported\n",
+                               mode);
+                       return -EINVAL;
+               }
+               break;
+
        default:
-               dev_err(wm8350->dev, "Configuration mode %d not supported\n",
+               dev_err(wm8350->dev,
+                       "WM835x configuration mode %d not supported\n",
                        mode);
                return -EINVAL;
        }
@@ -1178,62 +1297,141 @@ 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;
-       u16 id1, id2, mask, mode;
+       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);
+       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);
+       mask_rev = be16_to_cpu(mask_rev);
 
-       if (id1 == 0x6143) {
-               switch ((id2 & WM8350_CHIP_REV_MASK) >> 12) {
+       if (id1 != 0x6143) {
+               dev_err(wm8350->dev,
+                       "Device with ID %x is not a WM8350\n", id1);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       mode = id2 & WM8350_CONF_STS_MASK >> 10;
+       cust_id = id2 & WM8350_CUST_ID_MASK;
+       chip_rev = (id2 & WM8350_CHIP_REV_MASK) >> 12;
+       dev_info(wm8350->dev,
+                "CONF_STS %d, CUST_ID %d, MASK_REV %d, CHIP_REV %d\n",
+                mode, cust_id, mask_rev, chip_rev);
+
+       if (cust_id != 0) {
+               dev_err(wm8350->dev, "Unsupported CUST_ID\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       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, "Found Rev E device\n");
-                       wm8350->rev = WM8350_REV_E;
+                       dev_info(wm8350->dev, "WM8350 Rev E\n");
                        break;
                case WM8350_REV_F:
-                       dev_info(wm8350->dev, "Found Rev F device\n");
-                       wm8350->rev = WM8350_REV_F;
+                       dev_info(wm8350->dev, "WM8350 Rev F\n");
                        break;
                case WM8350_REV_G:
-                       dev_info(wm8350->dev, "Found Rev G device\n");
-                       wm8350->rev = WM8350_REV_G;
+                       dev_info(wm8350->dev, "WM8350 Rev G\n");
+                       wm8350->power.rev_g_coeff = 1;
+                       break;
+               case WM8350_REV_H:
+                       dev_info(wm8350->dev, "WM8350 Rev H\n");
+                       wm8350->power.rev_g_coeff = 1;
                        break;
                default:
                        /* For safety we refuse to run on unknown hardware */
-                       dev_info(wm8350->dev, "Found unknown rev\n");
+                       dev_err(wm8350->dev, "Unknown WM8350 CHIP_REV\n");
                        ret = -ENODEV;
                        goto err;
                }
-       } else {
-               dev_info(wm8350->dev, "Device with ID %x is not a WM8350\n",
-                        id1);
+               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");
+                       wm8350->power.rev_g_coeff = 1;
+                       break;
+
+               default:
+                       dev_err(wm8350->dev, "Unknown WM8352 CHIP_REV\n");
+                       ret = -ENODEV;
+                       goto err;
+               }
+               break;
+
+       default:
+               dev_err(wm8350->dev, "Unknown MASK_REV\n");
                ret = -ENODEV;
                goto err;
        }
 
-       mode = id2 & WM8350_CONF_STS_MASK >> 10;
-       mask = id2 & WM8350_CUST_ID_MASK;
-       dev_info(wm8350->dev, "Config mode %d, ROM mask %d\n", mode, mask);
-
-       ret = wm8350_create_cache(wm8350, mode);
+       ret = wm8350_create_cache(wm8350, mask_rev, mode);
        if (ret < 0) {
-               printk(KERN_ERR "wm8350: failed to create register cache\n");
+               dev_err(wm8350->dev, "Failed to create register cache\n");
                return ret;
        }
 
-       if (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) {
@@ -1250,6 +1448,15 @@ 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",
@@ -1273,6 +1480,9 @@ 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]);