Ejemplo n.º 1
0
static int __devinit pm8038_probe(struct platform_device *pdev)
{
	const struct pm8038_platform_data *pdata = pdev->dev.platform_data;
	const char *revision_name = "unknown";
	struct pm8038 *pmic;
	enum pm8xxx_version version;
	int revision;
	int rc;
	u8 val;

	if (!pdata) {
		pr_err("missing platform data\n");
		return -EINVAL;
	}

	pmic = kzalloc(sizeof(struct pm8038), GFP_KERNEL);
	if (!pmic) {
		pr_err("Cannot alloc pm8038 struct\n");
		return -ENOMEM;
	}

	/* Read PMIC chip revision */
	rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
	if (rc) {
		pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
		goto err_read_rev;
	}
	pr_info("PMIC revision 1: PM8038 rev %02X\n", val);
	pmic->rev_registers = val;

	/* Read PMIC chip revision 2 */
	rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
	if (rc) {
		pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
			REG_HWREV_2, rc);
		goto err_read_rev;
	}
	pr_info("PMIC revision 2: PM8038 rev %02X\n", val);
	pmic->rev_registers |= val << BITS_PER_BYTE;

	pmic->dev = &pdev->dev;
	pm8038_drvdata.pm_chip_data = pmic;
	platform_set_drvdata(pdev, &pm8038_drvdata);

	/* Print out human readable version and revision names. */
	version = pm8xxx_get_version(pmic->dev);
	if (version == PM8XXX_VERSION_8038) {
		revision = pm8xxx_get_revision(pmic->dev);
		if (revision >= 0 && revision < ARRAY_SIZE(pm8038_rev_names))
			revision_name = pm8038_rev_names[revision];
		pr_info("PMIC version: PM8038 ver %s\n", revision_name);
	} else {
		WARN_ON(version != PM8XXX_VERSION_8038);
	}

	/* Log human readable restart reason */
	rc = msm_ssbi_read(pdev->dev.parent, REG_PM8038_PON_CNTRL_3, &val, 1);
	if (rc) {
		pr_err("Cannot read restart reason rc=%d\n", rc);
		goto err_read_rev;
	}
	val &= PM8038_RESTART_REASON_MASK;
	pr_info("PMIC Restart Reason: %s\n", pm8038_restart_reason[val]);

	rc = pm8038_add_subdevices(pdata, pmic);
	if (rc) {
		pr_err("Cannot add subdevices rc=%d\n", rc);
		goto err;
	}

	return 0;

err:
	mfd_remove_devices(pmic->dev);
	platform_set_drvdata(pdev, NULL);
	kfree(pmic->mfd_regulators);
	kfree(pmic->regulator_cdata);
err_read_rev:
	kfree(pmic);
	return rc;
}
Ejemplo n.º 2
0
static int __devinit
pm8921_add_subdevices(const struct pm8921_platform_data *pdata,
		      struct pm8921 *pmic)
{
	int ret = 0, irq_base = 0;
	struct pm_irq_chip *irq_chip;
	enum pm8xxx_version version;

	version = pm8xxx_get_version(pmic->dev);

	version = pm8xxx_get_version(pmic->dev);

	if (pdata->irq_pdata) {
		pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
		pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
		irq_base = pdata->irq_pdata->irq_base;
		irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);

		if (IS_ERR(irq_chip)) {
			pr_err("Failed to init interrupts ret=%ld\n",
					PTR_ERR(irq_chip));
			return PTR_ERR(irq_chip);
		}
		pmic->irq_chip = irq_chip;
	}

	if (pdata->gpio_pdata) {
		pdata->gpio_pdata->gpio_cdata.ngpios = PM8921_NR_GPIOS;
		gpio_cell.platform_data = pdata->gpio_pdata;
		gpio_cell.pdata_size = sizeof(struct pm8xxx_gpio_platform_data);
		ret = mfd_add_devices(pmic->dev, 0, &gpio_cell, 1,
					NULL, irq_base);
		if (ret) {
			pr_err("Failed to add  gpio subdevice ret=%d\n", ret);
			goto bail;
		}
	}

	if (pdata->mpp_pdata) {
		pdata->mpp_pdata->core_data.nmpps = PM8921_NR_MPPS;
		pdata->mpp_pdata->core_data.base_addr = REG_MPP_BASE;
		mpp_cell.platform_data = pdata->mpp_pdata;
		mpp_cell.pdata_size = sizeof(struct pm8xxx_mpp_platform_data);
		ret = mfd_add_devices(pmic->dev, 0, &mpp_cell, 1, NULL,
					irq_base);
		if (ret) {
			pr_err("Failed to add mpp subdevice ret=%d\n", ret);
			goto bail;
		}
	}

	if (pdata->rtc_pdata) {
		rtc_cell.platform_data = pdata->rtc_pdata;
		rtc_cell.pdata_size = sizeof(struct pm8xxx_rtc_platform_data);
		ret = mfd_add_devices(pmic->dev, 0, &rtc_cell, 1, NULL,
				irq_base);
		if (ret) {
			pr_err("Failed to add rtc subdevice ret=%d\n", ret);
			goto bail;
		}
	}

	if (pdata->pwrkey_pdata) {
		pwrkey_cell.platform_data = pdata->pwrkey_pdata;
		pwrkey_cell.pdata_size =
			sizeof(struct pm8xxx_pwrkey_platform_data);
		ret = mfd_add_devices(pmic->dev, 0, &pwrkey_cell, 1, NULL,
					irq_base);
		if (ret) {
			pr_err("Failed to add pwrkey subdevice ret=%d\n", ret);
			goto bail;
		}
	}

	if (pdata->keypad_pdata) {
		keypad_cell.platform_data = pdata->keypad_pdata;
		keypad_cell.pdata_size =
			sizeof(struct pm8xxx_keypad_platform_data);
		ret = mfd_add_devices(pmic->dev, 0, &keypad_cell, 1, NULL,
					irq_base);
		if (ret) {
			pr_err("Failed to add keypad subdevice ret=%d\n", ret);
			goto bail;
		}
	}

	if (pdata->charger_pdata) {
		pdata->charger_pdata->charger_cdata.vbat_channel = CHANNEL_VBAT;
		pdata->charger_pdata->charger_cdata.batt_temp_channel
						= CHANNEL_BATT_THERM;
		pdata->charger_pdata->charger_cdata.batt_id_channel
						= CHANNEL_BATT_ID;
		charger_cell.platform_data = pdata->charger_pdata;
		charger_cell.pdata_size =
				sizeof(struct pm8921_charger_platform_data);
		ret = mfd_add_devices(pmic->dev, 0, &charger_cell, 1, NULL,
					irq_base);
		if (ret) {
			pr_err("Failed to add charger subdevice ret=%d\n", ret);
			goto bail;
		}
	}

	if (pdata->adc_pdata) {
		adc_cell.platform_data = pdata->adc_pdata;
		adc_cell.pdata_size =
			sizeof(struct pm8xxx_adc_platform_data);
		ret = mfd_add_devices(pmic->dev, 0, &adc_cell, 1, NULL,
					irq_base);
		if (ret) {
			pr_err("Failed to add regulator subdevices ret=%d\n",
					ret);
		}
	}

	if (pdata->bms_pdata) {
		pdata->bms_pdata->bms_cdata.batt_temp_channel
						= CHANNEL_BATT_THERM;
		pdata->bms_pdata->bms_cdata.vbat_channel = CHANNEL_VBAT;
		pdata->bms_pdata->bms_cdata.ref625mv_channel = CHANNEL_625MV;
		pdata->bms_pdata->bms_cdata.ref1p25v_channel = CHANNEL_125V;
		pdata->bms_pdata->bms_cdata.batt_id_channel = CHANNEL_BATT_ID;
		bms_cell.platform_data = pdata->bms_pdata;
		bms_cell.pdata_size = sizeof(struct pm8921_bms_platform_data);
		ret = mfd_add_devices(pmic->dev, 0, &bms_cell, 1, NULL,
					irq_base);
		if (ret) {
			pr_err("Failed to add bms subdevice ret=%d\n", ret);
			goto bail;
		}
	}

	if (pdata->num_regulators > 0 && pdata->regulator_pdatas) {
		ret = pm8921_add_regulators(pdata, pmic, irq_base);
		if (ret) {
			pr_err("Failed to add regulator subdevices ret=%d\n",
				ret);
			goto bail;
		}
	}

	ret = mfd_add_devices(pmic->dev, 0, &debugfs_cell, 1, NULL, irq_base);
	if (ret) {
		pr_err("Failed to add debugfs subdevice ret=%d\n", ret);
		goto bail;
	}

	ret = mfd_add_devices(pmic->dev, 0, &pwm_cell, 1, NULL, 0);
	if (ret) {
		pr_err("Failed to add pwm subdevice ret=%d\n", ret);
		goto bail;
	}

	if (pdata->misc_pdata) {
		misc_cell.platform_data = pdata->misc_pdata;
		misc_cell.pdata_size = sizeof(struct pm8xxx_misc_platform_data);
		ret = mfd_add_devices(pmic->dev, 0, &misc_cell, 1, NULL,
				      irq_base);
		if (ret) {
			pr_err("Failed to add  misc subdevice ret=%d\n", ret);
			goto bail;
		}
	}

	if (pdata->leds_pdata) {
		leds_cell.platform_data = pdata->leds_pdata;
		leds_cell.pdata_size = sizeof(struct pm8xxx_led_platform_data);
		ret = mfd_add_devices(pmic->dev, 0, &leds_cell, 1, NULL, 0);
		if (ret) {
			pr_err("Failed to add leds subdevice ret=%d\n", ret);
			goto bail;
		}
	}

	ret = mfd_add_devices(pmic->dev, 0, &thermal_alarm_cell, 1, NULL,
				irq_base);
	if (ret) {
		pr_err("Failed to add thermal alarm subdevice ret=%d\n",
			ret);
		goto bail;
	}

	ret = mfd_add_devices(pmic->dev, 0, &batt_alarm_cell, 1, NULL,
				irq_base);
	if (ret) {
		pr_err("Failed to add battery alarm subdevice ret=%d\n",
			ret);
		goto bail;
	}

	if (pdata->vibrator_pdata) {
		vibrator_cell.platform_data = pdata->vibrator_pdata;
		vibrator_cell.pdata_size =
				sizeof(struct pm8xxx_vibrator_platform_data);
		ret = mfd_add_devices(pmic->dev, 0, &vibrator_cell, 1, NULL, 0);
		if (ret) {
			pr_err("Failed to add vibrator subdevice ret=%d\n",
									ret);
			goto bail;
		}
	}

	if (pdata->ccadc_pdata) {
		ccadc_cell.platform_data = pdata->ccadc_pdata;
		ccadc_cell.pdata_size =
				sizeof(struct pm8xxx_ccadc_platform_data);

		ret = mfd_add_devices(pmic->dev, 0, &ccadc_cell, 1, NULL,
					irq_base);
		if (ret) {
			pr_err("Failed to add ccadc subdevice ret=%d\n", ret);
			goto bail;
		}
	}

	return 0;
bail:
	if (pmic->irq_chip) {
		pm8xxx_irq_exit(pmic->irq_chip);
		pmic->irq_chip = NULL;
	}
	return ret;
}
Ejemplo n.º 3
0
static int __devinit
pm8921_add_regulators(const struct pm8921_platform_data *pdata,
		      struct pm8921 *pmic, int irq_base)
{
	int ret = 0;
	struct mfd_cell *mfd_regulators;
	struct pm8xxx_regulator_core_platform_data *cdata;
	enum pm8xxx_version version;
	int i;

	version = pm8xxx_get_version(pmic->dev);

	/* Add one device for each regulator used by the board. */
	mfd_regulators = kzalloc(sizeof(struct mfd_cell)
				 * (pdata->num_regulators), GFP_KERNEL);
	if (!mfd_regulators) {
		pr_err("Cannot allocate %d bytes for pm8921 regulator "
			"mfd cells\n", sizeof(struct mfd_cell)
					* (pdata->num_regulators));
		return -ENOMEM;
	}
	cdata = kzalloc(sizeof(struct pm8xxx_regulator_core_platform_data)
			* pdata->num_regulators, GFP_KERNEL);
	if (!cdata) {
		pr_err("Cannot allocate %d bytes for pm8921 regulator "
			"core data\n", pdata->num_regulators
			  * sizeof(struct pm8xxx_regulator_core_platform_data));
		kfree(mfd_regulators);
		return -ENOMEM;
	}
	for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
		mutex_init(&regulator_data[i].pc_lock);
	for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++)
		mutex_init(&pm8917_regulator_data[i].pc_lock);

	for (i = 0; i < pdata->num_regulators; i++) {
		if (!pdata->regulator_pdatas[i].init_data.constraints.name) {
			pr_err("name missing for regulator %d\n", i);
			ret = -EINVAL;
			goto bail;
		}
		if (!match_regulator(version, &cdata[i],
		      pdata->regulator_pdatas[i].init_data.constraints.name)) {
			ret = -ENODEV;
			goto bail;
		}
		cdata[i].pdata = &(pdata->regulator_pdatas[i]);
		mfd_regulators[i].name = PM8XXX_REGULATOR_DEV_NAME;
		mfd_regulators[i].id = cdata[i].pdata->id;
		mfd_regulators[i].platform_data = &cdata[i];
		mfd_regulators[i].pdata_size =
			sizeof(struct pm8xxx_regulator_core_platform_data);
	}
	ret = mfd_add_devices(pmic->dev, 0, mfd_regulators,
			pdata->num_regulators, NULL, irq_base);
	if (ret)
		goto bail;

	pmic->mfd_regulators = mfd_regulators;
	pmic->regulator_cdata = cdata;
	return ret;

bail:
	for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
		mutex_destroy(&regulator_data[i].pc_lock);
	for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++)
		mutex_destroy(&pm8917_regulator_data[i].pc_lock);
	kfree(mfd_regulators);
	kfree(cdata);
	return ret;
}
Ejemplo n.º 4
0
static int __devinit pm8xxx_spk_probe(struct platform_device *pdev)
{
	const struct pm8xxx_spk_platform_data *pdata = pdev->dev.platform_data;
	int ret = 0;
	u8 value = 0;

	if (!pdata) {
		pr_err("missing platform data\n");
		return -EINVAL;
	}

	the_spk_chip = kzalloc(sizeof(struct pm8xxx_spk_chip), GFP_KERNEL);
	if (the_spk_chip == NULL) {
		pr_err("kzalloc() failed.\n");
		return -ENOMEM;
	}

	mutex_init(&the_spk_chip->spk_mutex);

	the_spk_chip->dev = &pdev->dev;
	the_spk_chip->version = pm8xxx_get_version(the_spk_chip->dev->parent);
	switch (pm8xxx_get_version(the_spk_chip->dev->parent)) {
	case PM8XXX_VERSION_8038:
		break;
	default:
		ret = -ENODEV;
		goto err_handle;
	}

	memcpy(&(the_spk_chip->pdata), pdata,
			sizeof(struct pm8xxx_spk_platform_data));

	the_spk_chip->base = pdev->resource[0].start;
	the_spk_chip->end = pdev->resource[0].end;

	if (the_spk_chip->pdata.spk_add_enable) {
		int val;
		val = pm8xxx_spk_read(PM8XXX_SPK_CTL1_REG_OFF);
		if (val < 0) {
			ret = val;
			goto err_handle;
		}
		val |= (the_spk_chip->pdata.spk_add_enable & PM8XXX_ADD_EN);
		ret = pm8xxx_spk_write(PM8XXX_SPK_CTL1_REG_OFF, val);
		if (ret < 0)
			goto err_handle;
	}
	value = ((the_spk_chip->pdata.cd_ng_threshold << 5) |
		the_spk_chip->pdata.cd_nf_preamp_bias << 3);
	pr_debug("Setting SPK_CTL2_REG = %02x\n", value);
	pm8xxx_spk_write(PM8XXX_SPK_CTL2_REG_OFF, value);

	value = ((the_spk_chip->pdata.cd_ng_hold << 5) |
		(the_spk_chip->pdata.cd_ng_max_atten << 1) |
		the_spk_chip->pdata.noise_mute);
	pr_debug("Setting SPK_CTL3_REG = %02x\n", value);
	pm8xxx_spk_write(PM8XXX_SPK_CTL3_REG_OFF, value);

	value = ((the_spk_chip->pdata.cd_ng_decay_rate << 5) |
		(the_spk_chip->pdata.cd_ng_attack_rate << 3) |
		the_spk_chip->pdata.cd_delay << 2);
	pr_debug("Setting SPK_CTL4_REG = %02x\n", value);
	pm8xxx_spk_write(PM8XXX_SPK_CTL4_REG_OFF, value);

	return pm8xxx_spk_config();
err_handle:
	pr_err("pm8xxx_spk_probe failed."
			"Audio unavailable on speaker.\n");
	mutex_destroy(&the_spk_chip->spk_mutex);
	kfree(the_spk_chip);
	return ret;
}
Ejemplo n.º 5
0
static int __devinit pm8921_probe(struct platform_device *pdev)
{
	const struct pm8921_platform_data *pdata = pdev->dev.platform_data;
	const char *revision_name = "unknown";
	struct pm8921 *pmic;
	enum pm8xxx_version version;
	int revision;
	int rc;
	u8 val;

	if (!pdata) {
		pr_err("missing platform data\n");
		return -EINVAL;
	}

	pmic = kzalloc(sizeof(struct pm8921), GFP_KERNEL);
	if (!pmic) {
		pr_err("Cannot alloc pm8921 struct\n");
		return -ENOMEM;
	}

	
	rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
	if (rc) {
		pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
		goto err_read_rev;
	}
	pr_info("PMIC revision 1: %02X\n", val);
	pmic->rev_registers = val;

	
	rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
	if (rc) {
		pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
			REG_HWREV_2, rc);
		goto err_read_rev;
	}
	pr_info("PMIC revision 2: %02X\n", val);
	pmic->rev_registers |= val << BITS_PER_BYTE;

	pmic->dev = &pdev->dev;
	pm8921_drvdata.pm_chip_data = pmic;
	platform_set_drvdata(pdev, &pm8921_drvdata);

	
	version = pm8xxx_get_version(pmic->dev);
	revision = pm8xxx_get_revision(pmic->dev);
	if (version == PM8XXX_VERSION_8921) {
		if (revision >= 0 && revision < ARRAY_SIZE(pm8921_rev_names))
			revision_name = pm8921_rev_names[revision];
		pr_info("PMIC version: PM8921 rev %s\n", revision_name);
	} else if (version == PM8XXX_VERSION_8922) {
		if (revision >= 0 && revision < ARRAY_SIZE(pm8922_rev_names))
			revision_name = pm8922_rev_names[revision];
		pr_info("PMIC version: PM8922 rev %s\n", revision_name);
	} else if (version == PM8XXX_VERSION_8917) {
		if (revision >= 0 && revision < ARRAY_SIZE(pm8917_rev_names))
			revision_name = pm8917_rev_names[revision];
		pr_info("PMIC version: PM8917 rev %s\n", revision_name);
	} else {
		WARN_ON(version != PM8XXX_VERSION_8921
			&& version != PM8XXX_VERSION_8922
			&& version != PM8XXX_VERSION_8917);
	}

	
	rc = msm_ssbi_read(pdev->dev.parent, REG_PM8921_PON_CNTRL_3, &val, 1);
	if (rc) {
		pr_err("Cannot read restart reason rc=%d\n", rc);
		goto err_read_rev;
	}
	val &= PM8921_RESTART_REASON_MASK;
	pr_info("PMIC Restart Reason: %s\n", pm8921_restart_reason[val]);

	rc = pm8921_add_subdevices(pdata, pmic);
	if (rc) {
		pr_err("Cannot add subdevices rc=%d\n", rc);
		goto err;
	}

	
	WARN_ON(pmic->irq_chip == NULL);

	pmic8921_chip = pmic;
        register_syscore_ops(&pm8921_pm);

	return 0;

err:
	mfd_remove_devices(pmic->dev);
	platform_set_drvdata(pdev, NULL);
	kfree(pmic->mfd_regulators);
	kfree(pmic->regulator_cdata);
err_read_rev:
	kfree(pmic);
	return rc;
}
Ejemplo n.º 6
0
static int __devinit pm8921_probe(struct platform_device *pdev)
{
	const struct pm8921_platform_data *pdata = pdev->dev.platform_data;
	const char *revision_name = "unknown";
	struct pm8921 *pmic;
#ifdef CONFIG_MACH_ACER_A9
	struct kobject *dev_info_pmic_kobj;
#else
	enum pm8xxx_version version;
	int revision;
#endif
	int rc;
	u8 val;

	if (!pdata) {
		pr_err("missing platform data\n");
		return -EINVAL;
	}

	pmic = kzalloc(sizeof(struct pm8921), GFP_KERNEL);
	if (!pmic) {
		pr_err("Cannot alloc pm8921 struct\n");
		return -ENOMEM;
	}

	/* Read PMIC chip revision */
	rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
	if (rc) {
		pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
		goto err_read_rev;
	}
	pr_info("PMIC revision 1: %02X\n", val);
	pmic->rev_registers = val;

	/* Read PMIC chip revision 2 */
	rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
	if (rc) {
		pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
			REG_HWREV_2, rc);
		goto err_read_rev;
	}
	pr_info("PMIC revision 2: %02X\n", val);
	pmic->rev_registers |= val << BITS_PER_BYTE;

	pmic->dev = &pdev->dev;
	pm8921_drvdata.pm_chip_data = pmic;
	platform_set_drvdata(pdev, &pm8921_drvdata);

	/* Print out human readable version and revision names. */
	version = pm8xxx_get_version(pmic->dev);
	revision = pm8xxx_get_revision(pmic->dev);
	if (version == PM8XXX_VERSION_8921) {
		if (revision >= 0 && revision < ARRAY_SIZE(pm8921_rev_names))
			revision_name = pm8921_rev_names[revision];
		pr_info("PMIC version: PM8921 rev %s\n", revision_name);
	} else if (version == PM8XXX_VERSION_8922) {
		if (revision >= 0 && revision < ARRAY_SIZE(pm8922_rev_names))
			revision_name = pm8922_rev_names[revision];
		pr_info("PMIC version: PM8922 rev %s\n", revision_name);
	} else if (version == PM8XXX_VERSION_8917) {
		if (revision >= 0 && revision < ARRAY_SIZE(pm8917_rev_names))
			revision_name = pm8917_rev_names[revision];
		pr_info("PMIC version: PM8917 rev %s\n", revision_name);
	} else {
		WARN_ON(version != PM8XXX_VERSION_8921
			&& version != PM8XXX_VERSION_8922
			&& version != PM8XXX_VERSION_8917);
	}

#ifdef CONFIG_MACH_ACER_A9
	dev_info_pmic_kobj = kobject_create_and_add("dev-info_pmic", NULL);
	if (dev_info_pmic_kobj == NULL) {
		pr_err("Failed to create dev-info_pmic kobject\n");
	}

	rc = sysfs_create_group(dev_info_pmic_kobj, &pmic_attr_group);
	if(rc) {
		pr_err("Failed to create dev-info_pmic sysfs group\n");
	}
#endif

	/* Log human readable restart reason */
	rc = msm_ssbi_read(pdev->dev.parent, REG_PM8921_PON_CNTRL_3, &val, 1);
	if (rc) {
		pr_err("Cannot read restart reason rc=%d\n", rc);
		goto err_read_rev;
	}
	val &= PM8921_RESTART_REASON_MASK;
	pr_info("PMIC Restart Reason: %s\n", pm8921_restart_reason[val]);

	rc = pm8921_add_subdevices(pdata, pmic);
	if (rc) {
		pr_err("Cannot add subdevices rc=%d\n", rc);
		goto err;
	}

	/* gpio might not work if no irq device is found */
	WARN_ON(pmic->irq_chip == NULL);

	return 0;

err:
	mfd_remove_devices(pmic->dev);
	platform_set_drvdata(pdev, NULL);
	kfree(pmic->mfd_regulators);
	kfree(pmic->regulator_cdata);
err_read_rev:
	kfree(pmic);
	return rc;
}