]> Pileus Git - ~andy/linux/blobdiff - drivers/mfd/88pm800.c
mfd: 88pm800: Enhance error handling for sub pages probe/remove
[~andy/linux] / drivers / mfd / 88pm800.c
index 582bda543520dcbde0f6baaae86d5f9b626787f0..4ebb2e215bac7ccbbbb59a857794de542ac348df 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/88pm80x.h>
@@ -318,7 +319,7 @@ out:
 static int device_irq_init_800(struct pm80x_chip *chip)
 {
        struct regmap *map = chip->regmap;
-       unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+       unsigned long flags = IRQF_ONESHOT;
        int data, mask, ret = -EINVAL;
 
        if (!map || !chip->irq) {
@@ -362,6 +363,7 @@ static struct regmap_irq_chip pm800_irq_chip = {
        .status_base = PM800_INT_STATUS1,
        .mask_base = PM800_INT_ENA_1,
        .ack_base = PM800_INT_STATUS1,
+       .mask_invert = 1,
 };
 
 static int pm800_pages_init(struct pm80x_chip *chip)
@@ -369,50 +371,64 @@ static int pm800_pages_init(struct pm80x_chip *chip)
        struct pm80x_subchip *subchip;
        struct i2c_client *client = chip->client;
 
+       int ret = 0;
+
        subchip = chip->subchip;
-       /* PM800 block power: i2c addr 0x31 */
-       if (subchip->power_page_addr) {
-               subchip->power_page =
-                   i2c_new_dummy(client->adapter, subchip->power_page_addr);
-               subchip->regmap_power =
-                   devm_regmap_init_i2c(subchip->power_page,
-                                        &pm80x_regmap_config);
-               i2c_set_clientdata(subchip->power_page, chip);
-       } else
-               dev_info(chip->dev,
-                        "PM800 block power 0x31: No power_page_addr\n");
-
-       /* PM800 block GPADC: i2c addr 0x32 */
-       if (subchip->gpadc_page_addr) {
-               subchip->gpadc_page = i2c_new_dummy(client->adapter,
-                                                   subchip->gpadc_page_addr);
-               subchip->regmap_gpadc =
-                   devm_regmap_init_i2c(subchip->gpadc_page,
-                                        &pm80x_regmap_config);
-               i2c_set_clientdata(subchip->gpadc_page, chip);
-       } else
-               dev_info(chip->dev,
-                        "PM800 block GPADC 0x32: No gpadc_page_addr\n");
+       if (!subchip || !subchip->power_page_addr || !subchip->gpadc_page_addr)
+               return -ENODEV;
+
+       /* PM800 block power page */
+       subchip->power_page = i2c_new_dummy(client->adapter,
+                                           subchip->power_page_addr);
+       if (subchip->power_page == NULL) {
+               ret = -ENODEV;
+               goto out;
+       }
 
-       return 0;
+       subchip->regmap_power = devm_regmap_init_i2c(subchip->power_page,
+                                                    &pm80x_regmap_config);
+       if (IS_ERR(subchip->regmap_power)) {
+               ret = PTR_ERR(subchip->regmap_power);
+               dev_err(chip->dev,
+                       "Failed to allocate regmap_power: %d\n", ret);
+               goto out;
+       }
+
+       i2c_set_clientdata(subchip->power_page, chip);
+
+       /* PM800 block GPADC */
+       subchip->gpadc_page = i2c_new_dummy(client->adapter,
+                                           subchip->gpadc_page_addr);
+       if (subchip->gpadc_page == NULL) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       subchip->regmap_gpadc = devm_regmap_init_i2c(subchip->gpadc_page,
+                                                    &pm80x_regmap_config);
+       if (IS_ERR(subchip->regmap_gpadc)) {
+               ret = PTR_ERR(subchip->regmap_gpadc);
+               dev_err(chip->dev,
+                       "Failed to allocate regmap_gpadc: %d\n", ret);
+               goto out;
+       }
+       i2c_set_clientdata(subchip->gpadc_page, chip);
+
+out:
+       return ret;
 }
 
 static void pm800_pages_exit(struct pm80x_chip *chip)
 {
        struct pm80x_subchip *subchip;
 
-       regmap_exit(chip->regmap);
-       i2c_unregister_device(chip->client);
-
        subchip = chip->subchip;
-       if (subchip->power_page) {
-               regmap_exit(subchip->regmap_power);
+
+       if (subchip && subchip->power_page)
                i2c_unregister_device(subchip->power_page);
-       }
-       if (subchip->gpadc_page) {
-               regmap_exit(subchip->regmap_gpadc);
+
+       if (subchip && subchip->gpadc_page)
                i2c_unregister_device(subchip->gpadc_page);
-       }
 }
 
 static int device_800_init(struct pm80x_chip *chip,
@@ -524,28 +540,31 @@ static int pm800_probe(struct i2c_client *client,
                goto err_subchip_alloc;
        }
 
-       subchip->power_page_addr = pdata->power_page_addr;
-       subchip->gpadc_page_addr = pdata->gpadc_page_addr;
+       /* pm800 has 2 addtional pages to support power and gpadc. */
+       subchip->power_page_addr = client->addr + 1;
+       subchip->gpadc_page_addr = client->addr + 2;
        chip->subchip = subchip;
 
-       ret = device_800_init(chip, pdata);
-       if (ret) {
-               dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
-               goto err_subchip_alloc;
-       }
-
        ret = pm800_pages_init(chip);
        if (ret) {
                dev_err(&client->dev, "pm800_pages_init failed!\n");
                goto err_page_init;
        }
 
+       ret = device_800_init(chip, pdata);
+       if (ret) {
+               dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
+               goto err_device_init;
+       }
+
        if (pdata->plat_config)
                pdata->plat_config(chip, pdata);
 
+       return 0;
+
+err_device_init:
+       pm800_pages_exit(chip);
 err_page_init:
-       mfd_remove_devices(chip->dev);
-       device_irq_exit_800(chip);
 err_subchip_alloc:
        pm80x_deinit();
 out_init:
@@ -567,7 +586,7 @@ static int pm800_remove(struct i2c_client *client)
 
 static struct i2c_driver pm800_driver = {
        .driver = {
-               .name = "88PM80X",
+               .name = "88PM800",
                .owner = THIS_MODULE,
                .pm = &pm80x_pm_ops,
                },