Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c848bc85 authored by Sangbeom Kim's avatar Sangbeom Kim Committed by Mark Brown
Browse files

regulator: s5m8767a: Support AP watchdog reset operation



The S5M8767A can't know status of ap reset.
So, After AP watchdog reset, AP can't boot normally.

Problem can be happened like below condition.
- AP Bootable lowest voltage(vdd_arm): 0.9v
- AP DVFS voltage table: 0.8v, 0.9v, 1.0v
- During AP works on lowest voltage(0.8V), watchdog reset is asserted
- AP can't boot, because vdd arm is still 0.8v

Solution
- Basic concept:
  After ap watchdog reset, GPIO configuration is changed by default value
- S5M8767A has function of voltage control with gpio (8 levels with 3 gpios)
- Set bootable voltage on level 0 -> can work with default gpio configuration
- In the probing, Change voltage control level from level 0 to level 1
- Execute normal dvfs operation on level 1
- After watchdog reset, ap gpio is set by default value
- PMIC operation mode is changed by ap reset (level1 -> level0)
- Regardless of previous vdd_arm voltage, AP always can be booted.

Signed-off-by: default avatarSangbeom Kim <sbkim73@samsung.com>
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent 852abad2
Loading
Loading
Loading
Loading
+93 −44
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@ struct s5m8767_info {
	u8 buck3_vol[8];
	u8 buck3_vol[8];
	u8 buck4_vol[8];
	u8 buck4_vol[8];
	int buck_gpios[3];
	int buck_gpios[3];
	int buck_ds[3];
	int buck_gpioindex;
	int buck_gpioindex;
};
};


@@ -283,17 +284,17 @@ static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
		reg = S5M8767_REG_BUCK1CTRL2;
		reg = S5M8767_REG_BUCK1CTRL2;
		break;
		break;
	case S5M8767_BUCK2:
	case S5M8767_BUCK2:
		reg = S5M8767_REG_BUCK2DVS1;
		reg = S5M8767_REG_BUCK2DVS2;
		if (s5m8767->buck2_gpiodvs)
		if (s5m8767->buck2_gpiodvs)
			reg += s5m8767->buck_gpioindex;
			reg += s5m8767->buck_gpioindex;
		break;
		break;
	case S5M8767_BUCK3:
	case S5M8767_BUCK3:
		reg = S5M8767_REG_BUCK3DVS1;
		reg = S5M8767_REG_BUCK3DVS2;
		if (s5m8767->buck3_gpiodvs)
		if (s5m8767->buck3_gpiodvs)
			reg += s5m8767->buck_gpioindex;
			reg += s5m8767->buck_gpioindex;
		break;
		break;
	case S5M8767_BUCK4:
	case S5M8767_BUCK4:
		reg = S5M8767_REG_BUCK4DVS1;
		reg = S5M8767_REG_BUCK4DVS2;
		if (s5m8767->buck4_gpiodvs)
		if (s5m8767->buck4_gpiodvs)
			reg += s5m8767->buck_gpioindex;
			reg += s5m8767->buck_gpioindex;
		break;
		break;
@@ -512,7 +513,7 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
	struct regulator_config config = { };
	struct regulator_config config = { };
	struct regulator_dev **rdev;
	struct regulator_dev **rdev;
	struct s5m8767_info *s5m8767;
	struct s5m8767_info *s5m8767;
	int i, ret, size;
	int i, ret, size, buck_init;


	if (!pdata) {
	if (!pdata) {
		dev_err(pdev->dev.parent, "Platform data not supplied\n");
		dev_err(pdev->dev.parent, "Platform data not supplied\n");
@@ -563,12 +564,37 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
	s5m8767->buck_gpios[0] = pdata->buck_gpios[0];
	s5m8767->buck_gpios[0] = pdata->buck_gpios[0];
	s5m8767->buck_gpios[1] = pdata->buck_gpios[1];
	s5m8767->buck_gpios[1] = pdata->buck_gpios[1];
	s5m8767->buck_gpios[2] = pdata->buck_gpios[2];
	s5m8767->buck_gpios[2] = pdata->buck_gpios[2];
	s5m8767->buck_ds[0] = pdata->buck_ds[0];
	s5m8767->buck_ds[1] = pdata->buck_ds[1];
	s5m8767->buck_ds[2] = pdata->buck_ds[2];

	s5m8767->ramp_delay = pdata->buck_ramp_delay;
	s5m8767->ramp_delay = pdata->buck_ramp_delay;
	s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
	s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
	s5m8767->buck3_ramp = pdata->buck3_ramp_enable;
	s5m8767->buck3_ramp = pdata->buck3_ramp_enable;
	s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
	s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
	s5m8767->opmode = pdata->opmode;
	s5m8767->opmode = pdata->opmode;


	buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
						pdata->buck2_init,
						pdata->buck2_init +
						buck_voltage_val2.step);

	s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init);

	buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
						pdata->buck3_init,
						pdata->buck3_init +
						buck_voltage_val2.step);

	s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init);

	buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
						pdata->buck4_init,
						pdata->buck4_init +
						buck_voltage_val2.step);

	s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init);

	for (i = 0; i < 8; i++) {
	for (i = 0; i < 8; i++) {
		if (s5m8767->buck2_gpiodvs) {
		if (s5m8767->buck2_gpiodvs) {
			s5m8767->buck2_vol[i] =
			s5m8767->buck2_vol[i] =
@@ -598,25 +624,23 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
		}
		}
	}
	}


	if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
		pdata->buck4_gpiodvs) {
	if (gpio_is_valid(pdata->buck_gpios[0]) &&
	if (gpio_is_valid(pdata->buck_gpios[0]) &&
		gpio_is_valid(pdata->buck_gpios[1]) &&
		gpio_is_valid(pdata->buck_gpios[1]) &&
		gpio_is_valid(pdata->buck_gpios[2])) {
		gpio_is_valid(pdata->buck_gpios[2])) {
			ret = gpio_request(pdata->buck_gpios[0],
		ret = gpio_request(pdata->buck_gpios[0], "S5M8767 SET1");
						"S5M8767 SET1");
		if (ret == -EBUSY)
		if (ret == -EBUSY)
				dev_warn(&pdev->dev, "Duplicated gpio request for SET1\n");
			dev_warn(&pdev->dev, "Duplicated gpio request"
				" for SET1\n");


			ret = gpio_request(pdata->buck_gpios[1],
		ret = gpio_request(pdata->buck_gpios[1], "S5M8767 SET2");
					   "S5M8767 SET2");
		if (ret == -EBUSY)
		if (ret == -EBUSY)
				dev_warn(&pdev->dev, "Duplicated gpio request for SET2\n");
			dev_warn(&pdev->dev, "Duplicated gpio request"
				" for SET2\n");


			ret = gpio_request(pdata->buck_gpios[2],
		ret = gpio_request(pdata->buck_gpios[2], "S5M8767 SET3");
					   "S5M8767 SET3");
		if (ret == -EBUSY)
		if (ret == -EBUSY)
				dev_warn(&pdev->dev, "Duplicated gpio request for SET3\n");
			dev_warn(&pdev->dev, "Duplicated gpio request"
					" for SET3\n");
		/* SET1 GPIO */
		/* SET1 GPIO */
		gpio_direction_output(pdata->buck_gpios[0],
		gpio_direction_output(pdata->buck_gpios[0],
				(s5m8767->buck_gpioindex >> 2) & 0x1);
				(s5m8767->buck_gpioindex >> 2) & 0x1);
@@ -627,19 +651,44 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
		gpio_direction_output(pdata->buck_gpios[2],
		gpio_direction_output(pdata->buck_gpios[2],
				(s5m8767->buck_gpioindex >> 0) & 0x1);
				(s5m8767->buck_gpioindex >> 0) & 0x1);
		ret = 0;
		ret = 0;

	} else {
	} else {
		dev_err(&pdev->dev, "GPIO NOT VALID\n");
		dev_err(&pdev->dev, "GPIO NOT VALID\n");
		ret = -EINVAL;
		ret = -EINVAL;
		return ret;
		return ret;
	}
	}
	}


	ret = gpio_request(pdata->buck_ds[0], "S5M8767 DS2");
	if (ret == -EBUSY)
		dev_warn(&pdev->dev, "Duplicated gpio request for DS2\n");

	ret = gpio_request(pdata->buck_ds[1], "S5M8767 DS3");
	if (ret == -EBUSY)
		dev_warn(&pdev->dev, "Duplicated gpio request for DS3\n");

	ret = gpio_request(pdata->buck_ds[2], "S5M8767 DS4");
	if (ret == -EBUSY)
		dev_warn(&pdev->dev, "Duplicated gpio request for DS4\n");

	/* DS2 GPIO */
	gpio_direction_output(pdata->buck_ds[0], 0x0);
	/* DS3 GPIO */
	gpio_direction_output(pdata->buck_ds[1], 0x0);
	/* DS4 GPIO */
	gpio_direction_output(pdata->buck_ds[2], 0x0);

	if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
	   pdata->buck4_gpiodvs) {
		s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
		s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
			(pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
				(pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1),
				1 << 1);
		s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
		s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
			(pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
				(pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1),
				1 << 1);
		s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
		s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
			(pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
				(pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1),
				1 << 1);
	}


	/* Initialize GPIO DVS registers */
	/* Initialize GPIO DVS registers */
	for (i = 0; i < 8; i++) {
	for (i = 0; i < 8; i++) {
+5 −0
Original line number Original line Diff line number Diff line
@@ -347,6 +347,7 @@ struct s5m_platform_data {
	bool				buck_voltage_lock;
	bool				buck_voltage_lock;


	int				buck_gpios[3];
	int				buck_gpios[3];
	int				buck_ds[3];
	int				buck2_voltage[8];
	int				buck2_voltage[8];
	bool				buck2_gpiodvs;
	bool				buck2_gpiodvs;
	int				buck3_voltage[8];
	int				buck3_voltage[8];
@@ -369,6 +370,10 @@ struct s5m_platform_data {
	bool                            buck2_ramp_enable;
	bool                            buck2_ramp_enable;
	bool                            buck3_ramp_enable;
	bool                            buck3_ramp_enable;
	bool                            buck4_ramp_enable;
	bool                            buck4_ramp_enable;

	int				buck2_init;
	int				buck3_init;
	int				buck4_init;
};
};


#endif /*  __LINUX_MFD_S5M_CORE_H */
#endif /*  __LINUX_MFD_S5M_CORE_H */