Unverified Commit 4866e35e authored by Dave Stevenson's avatar Dave Stevenson Committed by Mark Brown
Browse files

regulator: rpi-panel: Convert to drive lines directly



The Atmel was doing a load of automatic sequencing of
control lines, however it was combining the touch controller's
reset with the bridge/panel control.

Change to control the control signals directly rather than
through the automatic POWERON control.

Signed-off-by: default avatarDave Stevenson <dave.stevenson@raspberrypi.com>
Signed-off-by: default avatarDetlev Casanova <detlev.casanova@collabora.com>
Link: https://lore.kernel.org/r/20220124220129.158891-6-detlev.casanova@collabora.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 89339a2a
Loading
Loading
Loading
Loading
+60 −51
Original line number Diff line number Diff line
@@ -21,11 +21,28 @@
/* I2C registers of the Atmel microcontroller. */
#define REG_ID		0x80
#define REG_PORTA	0x81
#define REG_PORTA_HF	BIT(2)
#define REG_PORTA_VF	BIT(3)
#define REG_PORTB	0x82
#define REG_PORTC	0x83
#define REG_POWERON	0x85
#define REG_PWM		0x86
#define REG_ADDR_L	0x8c
#define REG_ADDR_H	0x8d
#define REG_WRITE_DATA_H	0x90
#define REG_WRITE_DATA_L	0x91

#define PA_LCD_DITHB		BIT(0)
#define PA_LCD_MODE		BIT(1)
#define PA_LCD_LR		BIT(2)
#define PA_LCD_UD		BIT(3)

#define PB_BRIDGE_PWRDNX_N	BIT(0)
#define PB_LCD_VCC_N		BIT(1)
#define PB_LCD_MAIN		BIT(7)

#define PC_LED_EN		BIT(0)
#define PC_RST_TP_N		BIT(1)
#define PC_RST_LCD_N		BIT(2)
#define PC_RST_BRIDGE_N		BIT(3)

struct attiny_lcd {
	/* lock to serialise overall accesses to the Atmel */
@@ -37,99 +54,91 @@ static const struct regmap_config attiny_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.disable_locking = 1,
	.max_register = REG_PWM,
	.max_register = REG_WRITE_DATA_L,
	.cache_type = REGCACHE_NONE,
};

static int attiny_lcd_power_enable(struct regulator_dev *rdev)
{
	struct mutex *lock = rdev_get_drvdata(rdev);
	unsigned int data;
	int ret, i;
	struct attiny_lcd *state = rdev_get_drvdata(rdev);

	mutex_lock(lock);

	regmap_write(rdev->regmap, REG_POWERON, 1);
	msleep(80);

	/* Wait for nPWRDWN to go low to indicate poweron is done. */
	for (i = 0; i < 20; i++) {
		ret = regmap_read(rdev->regmap, REG_PORTB, &data);
		if (!ret) {
			if (data & BIT(0))
				break;
		}
		usleep_range(10000, 12000);
	}
	usleep_range(10000, 12000);
	mutex_lock(&state->lock);

	if (ret)
		pr_err("%s: regmap_read_poll_timeout failed %d\n", __func__, ret);
	/* Ensure bridge, and tp stay in reset */
	regmap_write(rdev->regmap, REG_PORTC, 0);
	usleep_range(5000, 10000);

	/* Default to the same orientation as the closed source
	 * firmware used for the panel.  Runtime rotation
	 * configuration will be supported using VC4's plane
	 * orientation bits.
	 */
	regmap_write(rdev->regmap, REG_PORTA, BIT(2));
	regmap_write(rdev->regmap, REG_PORTA, PA_LCD_LR);
	usleep_range(5000, 10000);
	regmap_write(rdev->regmap, REG_PORTB, PB_LCD_MAIN);
	usleep_range(5000, 10000);
	/* Bring controllers out of reset */
	regmap_write(rdev->regmap, REG_PORTC,
		     PC_LED_EN | PC_RST_BRIDGE_N | PC_RST_LCD_N | PC_RST_TP_N);

	msleep(80);

	regmap_write(rdev->regmap, REG_ADDR_H, 0x04);
	usleep_range(5000, 8000);
	regmap_write(rdev->regmap, REG_ADDR_L, 0x7c);
	usleep_range(5000, 8000);
	regmap_write(rdev->regmap, REG_WRITE_DATA_H, 0x00);
	usleep_range(5000, 8000);
	regmap_write(rdev->regmap, REG_WRITE_DATA_L, 0x00);

	mutex_unlock(lock);
	msleep(100);

	mutex_unlock(&state->lock);

	return 0;
}

static int attiny_lcd_power_disable(struct regulator_dev *rdev)
{
	struct mutex *lock = rdev_get_drvdata(rdev);
	struct attiny_lcd *state = rdev_get_drvdata(rdev);

	mutex_lock(lock);
	mutex_lock(&state->lock);

	regmap_write(rdev->regmap, REG_PWM, 0);
	regmap_write(rdev->regmap, REG_POWERON, 0);
	usleep_range(5000, 10000);
	regmap_write(rdev->regmap, REG_PORTA, 0);
	usleep_range(5000, 10000);
	regmap_write(rdev->regmap, REG_PORTB, PB_LCD_VCC_N);
	usleep_range(5000, 10000);
	regmap_write(rdev->regmap, REG_PORTC, 0);
	msleep(30);

	mutex_unlock(lock);
	mutex_unlock(&state->lock);

	return 0;
}

static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev)
{
	struct mutex *lock = rdev_get_drvdata(rdev);
	struct attiny_lcd *state = rdev_get_drvdata(rdev);
	unsigned int data;
	int ret, i;

	mutex_lock(lock);

	for (i = 0; i < 10; i++) {
		ret = regmap_read(rdev->regmap, REG_POWERON, &data);
		if (!ret)
			break;
		usleep_range(10000, 12000);
	}
	if (ret < 0) {
		mutex_unlock(lock);
		return ret;
	}

	if (!(data & BIT(0))) {
		mutex_unlock(lock);
		return 0;
	}
	mutex_lock(&state->lock);

	for (i = 0; i < 10; i++) {
		ret = regmap_read(rdev->regmap, REG_PORTB, &data);
		ret = regmap_read(rdev->regmap, REG_PORTC, &data);
		if (!ret)
			break;
		usleep_range(10000, 12000);
	}

	mutex_unlock(lock);
	mutex_unlock(&state->lock);

	if (ret < 0)
		return ret;

	return data & BIT(0);
	return data & PC_RST_BRIDGE_N;
}

static const struct regulator_init_data attiny_regulator_default = {
@@ -256,7 +265,7 @@ static int attiny_i2c_probe(struct i2c_client *i2c,
	config.regmap = regmap;
	config.of_node = i2c->dev.of_node;
	config.init_data = &attiny_regulator_default;
	config.driver_data = &state->lock;
	config.driver_data = state;

	rdev = devm_regulator_register(&i2c->dev, &attiny_regulator, &config);
	if (IS_ERR(rdev)) {