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

Commit ae9ca493 authored by Wei Chen's avatar Wei Chen Committed by Linus Walleij
Browse files

gpio: sx150x: add support for sx1506 gpio expander device



semtech has two series of sx150x gpio expanders: sx150x-456 and
sx150x-789.

The current gpio-150x driver in linux only support sx1508 and
sx1509.

We added sx1506 support code into this driver.

Signed-off-by: default avatarWei Chen <Wei.Chen@csr.com>
Signed-off-by: default avatarBarry Song <Baohua.Song@csr.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 093e9435
Loading
Loading
Loading
Loading
+112 −45
Original line number Original line Diff line number Diff line
@@ -26,20 +26,43 @@


#define NO_UPDATE_PENDING	-1
#define NO_UPDATE_PENDING	-1


/* The chip models of sx150x */
#define SX150X_456 0
#define SX150X_789 1

struct sx150x_456_pri {
	u8 reg_pld_mode;
	u8 reg_pld_table0;
	u8 reg_pld_table1;
	u8 reg_pld_table2;
	u8 reg_pld_table3;
	u8 reg_pld_table4;
	u8 reg_advance;
};

struct sx150x_789_pri {
	u8 reg_drain;
	u8 reg_polarity;
	u8 reg_clock;
	u8 reg_misc;
	u8 reg_reset;
	u8 ngpios;
};

struct sx150x_device_data {
struct sx150x_device_data {
	u8 model;
	u8 reg_pullup;
	u8 reg_pullup;
	u8 reg_pulldn;
	u8 reg_pulldn;
	u8 reg_drain;
	u8 reg_polarity;
	u8 reg_dir;
	u8 reg_dir;
	u8 reg_data;
	u8 reg_data;
	u8 reg_irq_mask;
	u8 reg_irq_mask;
	u8 reg_irq_src;
	u8 reg_irq_src;
	u8 reg_sense;
	u8 reg_sense;
	u8 reg_clock;
	u8 reg_misc;
	u8 reg_reset;
	u8 ngpios;
	u8 ngpios;
	union {
		struct sx150x_456_pri x456;
		struct sx150x_789_pri x789;
	} pri;
};
};


struct sx150x_chip {
struct sx150x_chip {
@@ -59,33 +82,59 @@ struct sx150x_chip {


static const struct sx150x_device_data sx150x_devices[] = {
static const struct sx150x_device_data sx150x_devices[] = {
	[0] = { /* sx1508q */
	[0] = { /* sx1508q */
		.model = SX150X_789,
		.reg_pullup	= 0x03,
		.reg_pullup	= 0x03,
		.reg_pulldn	= 0x04,
		.reg_pulldn	= 0x04,
		.reg_drain    = 0x05,
		.reg_polarity = 0x06,
		.reg_dir	= 0x07,
		.reg_dir	= 0x07,
		.reg_data	= 0x08,
		.reg_data	= 0x08,
		.reg_irq_mask	= 0x09,
		.reg_irq_mask	= 0x09,
		.reg_irq_src	= 0x0c,
		.reg_irq_src	= 0x0c,
		.reg_sense	= 0x0b,
		.reg_sense	= 0x0b,
		.pri.x789 = {
			.reg_drain	= 0x05,
			.reg_polarity	= 0x06,
			.reg_clock	= 0x0f,
			.reg_clock	= 0x0f,
			.reg_misc	= 0x10,
			.reg_misc	= 0x10,
			.reg_reset	= 0x7d,
			.reg_reset	= 0x7d,
		.ngpios       = 8
		},
		.ngpios = 8,
	},
	},
	[1] = { /* sx1509q */
	[1] = { /* sx1509q */
		.model = SX150X_789,
		.reg_pullup	= 0x07,
		.reg_pullup	= 0x07,
		.reg_pulldn	= 0x09,
		.reg_pulldn	= 0x09,
		.reg_drain    = 0x0b,
		.reg_polarity = 0x0d,
		.reg_dir	= 0x0f,
		.reg_dir	= 0x0f,
		.reg_data	= 0x11,
		.reg_data	= 0x11,
		.reg_irq_mask	= 0x13,
		.reg_irq_mask	= 0x13,
		.reg_irq_src	= 0x19,
		.reg_irq_src	= 0x19,
		.reg_sense	= 0x17,
		.reg_sense	= 0x17,
		.pri.x789 = {
			.reg_drain	= 0x0b,
			.reg_polarity	= 0x0d,
			.reg_clock	= 0x1e,
			.reg_clock	= 0x1e,
			.reg_misc	= 0x1f,
			.reg_misc	= 0x1f,
			.reg_reset	= 0x7d,
			.reg_reset	= 0x7d,
		},
		.ngpios	= 16
	},
	[2] = { /* sx1506q */
		.model = SX150X_456,
		.reg_pullup	= 0x05,
		.reg_pulldn	= 0x07,
		.reg_dir	= 0x03,
		.reg_data	= 0x01,
		.reg_irq_mask	= 0x09,
		.reg_irq_src	= 0x0f,
		.reg_sense	= 0x0d,
		.pri.x456 = {
			.reg_pld_mode	= 0x21,
			.reg_pld_table0	= 0x23,
			.reg_pld_table1	= 0x25,
			.reg_pld_table2	= 0x27,
			.reg_pld_table3	= 0x29,
			.reg_pld_table4	= 0x2b,
			.reg_advance	= 0xad,
		},
		.ngpios	= 16
		.ngpios	= 16
	},
	},
};
};
@@ -93,6 +142,7 @@ static const struct sx150x_device_data sx150x_devices[] = {
static const struct i2c_device_id sx150x_id[] = {
static const struct i2c_device_id sx150x_id[] = {
	{"sx1508q", 0},
	{"sx1508q", 0},
	{"sx1509q", 1},
	{"sx1509q", 1},
	{"sx1506q", 2},
	{}
	{}
};
};
MODULE_DEVICE_TABLE(i2c, sx150x_id);
MODULE_DEVICE_TABLE(i2c, sx150x_id);
@@ -191,7 +241,7 @@ static int sx150x_get_io(struct sx150x_chip *chip, unsigned offset)
static void sx150x_set_oscio(struct sx150x_chip *chip, int val)
static void sx150x_set_oscio(struct sx150x_chip *chip, int val)
{
{
	sx150x_i2c_write(chip->client,
	sx150x_i2c_write(chip->client,
			chip->dev_cfg->reg_clock,
			chip->dev_cfg->pri.x789.reg_clock,
			(val ? 0x1f : 0x10));
			(val ? 0x1f : 0x10));
}
}


@@ -455,13 +505,13 @@ static int sx150x_reset(struct sx150x_chip *chip)
	int err;
	int err;


	err = i2c_smbus_write_byte_data(chip->client,
	err = i2c_smbus_write_byte_data(chip->client,
					chip->dev_cfg->reg_reset,
					chip->dev_cfg->pri.x789.reg_reset,
					0x12);
					0x12);
	if (err < 0)
	if (err < 0)
		return err;
		return err;


	err = i2c_smbus_write_byte_data(chip->client,
	err = i2c_smbus_write_byte_data(chip->client,
					chip->dev_cfg->reg_reset,
					chip->dev_cfg->pri.x789.reg_reset,
					0x34);
					0x34);
	return err;
	return err;
}
}
@@ -477,9 +527,14 @@ static int sx150x_init_hw(struct sx150x_chip *chip,
			return err;
			return err;
	}
	}


	if (chip->dev_cfg->model == SX150X_789)
		err = sx150x_i2c_write(chip->client,
		err = sx150x_i2c_write(chip->client,
			chip->dev_cfg->reg_misc,
				chip->dev_cfg->pri.x789.reg_misc,
				0x01);
				0x01);
	else
		err = sx150x_i2c_write(chip->client,
				chip->dev_cfg->pri.x456.reg_advance,
				0x04);
	if (err < 0)
	if (err < 0)
		return err;
		return err;


@@ -493,15 +548,27 @@ static int sx150x_init_hw(struct sx150x_chip *chip,
	if (err < 0)
	if (err < 0)
		return err;
		return err;


	err = sx150x_init_io(chip, chip->dev_cfg->reg_drain,
	if (chip->dev_cfg->model == SX150X_789) {
		err = sx150x_init_io(chip,
				chip->dev_cfg->pri.x789.reg_drain,
				pdata->io_open_drain_ena);
				pdata->io_open_drain_ena);
		if (err < 0)
		if (err < 0)
			return err;
			return err;


	err = sx150x_init_io(chip, chip->dev_cfg->reg_polarity,
		err = sx150x_init_io(chip,
				chip->dev_cfg->pri.x789.reg_polarity,
				pdata->io_polarity);
				pdata->io_polarity);
		if (err < 0)
		if (err < 0)
			return err;
			return err;
	} else {
		/* Set all pins to work in normal mode */
		err = sx150x_init_io(chip,
				chip->dev_cfg->pri.x456.reg_pld_mode,
				0);
		if (err < 0)
			return err;
	}



	if (pdata->oscio_is_gpo)
	if (pdata->oscio_is_gpo)
		sx150x_set_oscio(chip, 0);
		sx150x_set_oscio(chip, 0);