Commit f5f0b7aa authored by Gregory CLEMENT's avatar Gregory CLEMENT Committed by Linus Walleij

gpio: pca953x: make the register access by GPIO bank

Until now the pca953x driver accessed all the bank of a given register
in a single command using only a 32 bits variable. New expanders from
the pca53x family come with 40 GPIOs which no more fit in a 32
variable. This patch make access to the registers more generic by
relying on an array of u8 variables. This fits exactly the way the
registers are represented in the hardware.

It also adds helpers to access to a single register of a bank instead
of reading or writing all the banks for a given register.
Signed-off-by: default avatarGregory CLEMENT <gregory.clement@free-electrons.com>
Tested-by: default avatarMaxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 5985d76c
...@@ -71,18 +71,23 @@ static const struct i2c_device_id pca953x_id[] = { ...@@ -71,18 +71,23 @@ static const struct i2c_device_id pca953x_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, pca953x_id); MODULE_DEVICE_TABLE(i2c, pca953x_id);
#define MAX_BANK 5
#define BANK_SZ 8
#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ)
struct pca953x_chip { struct pca953x_chip {
unsigned gpio_start; unsigned gpio_start;
u32 reg_output; u8 reg_output[MAX_BANK];
u32 reg_direction; u8 reg_direction[MAX_BANK];
struct mutex i2c_lock; struct mutex i2c_lock;
#ifdef CONFIG_GPIO_PCA953X_IRQ #ifdef CONFIG_GPIO_PCA953X_IRQ
struct mutex irq_lock; struct mutex irq_lock;
u32 irq_mask; u8 irq_mask[MAX_BANK];
u32 irq_stat; u8 irq_stat[MAX_BANK];
u32 irq_trig_raise; u8 irq_trig_raise[MAX_BANK];
u32 irq_trig_fall; u8 irq_trig_fall[MAX_BANK];
int irq_base; int irq_base;
struct irq_domain *domain; struct irq_domain *domain;
#endif #endif
...@@ -93,33 +98,69 @@ struct pca953x_chip { ...@@ -93,33 +98,69 @@ struct pca953x_chip {
int chip_type; int chip_type;
}; };
static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val) static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
int off)
{
int ret;
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
int offset = off / BANK_SZ;
ret = i2c_smbus_read_byte_data(chip->client,
(reg << bank_shift) + offset);
*val = ret;
if (ret < 0) {
dev_err(&chip->client->dev, "failed reading register\n");
return ret;
}
return 0;
}
static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val,
int off)
{
int ret = 0;
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
int offset = off / BANK_SZ;
ret = i2c_smbus_write_byte_data(chip->client,
(reg << bank_shift) + offset, val);
if (ret < 0) {
dev_err(&chip->client->dev, "failed writing register\n");
return ret;
}
return 0;
}
static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
{ {
int ret = 0; int ret = 0;
if (chip->gpio_chip.ngpio <= 8) if (chip->gpio_chip.ngpio <= 8)
ret = i2c_smbus_write_byte_data(chip->client, reg, val); ret = i2c_smbus_write_byte_data(chip->client, reg, *val);
else if (chip->gpio_chip.ngpio == 24) { else if (chip->gpio_chip.ngpio >= 24) {
cpu_to_le32s(&val); int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
ret = i2c_smbus_write_i2c_block_data(chip->client, ret = i2c_smbus_write_i2c_block_data(chip->client,
(reg << 2) | REG_ADDR_AI, (reg << bank_shift) | REG_ADDR_AI,
3, NBANK(chip), val);
(u8 *) &val);
} }
else { else {
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
ret = i2c_smbus_write_word_data(chip->client, ret = i2c_smbus_write_word_data(chip->client,
reg << 1, val); reg << 1, (u16) *val);
break; break;
case PCA957X_TYPE: case PCA957X_TYPE:
ret = i2c_smbus_write_byte_data(chip->client, reg << 1, ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
val & 0xff); val[0]);
if (ret < 0) if (ret < 0)
break; break;
ret = i2c_smbus_write_byte_data(chip->client, ret = i2c_smbus_write_byte_data(chip->client,
(reg << 1) + 1, (reg << 1) + 1,
(val & 0xff00) >> 8); val[1]);
break; break;
} }
} }
...@@ -132,26 +173,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val) ...@@ -132,26 +173,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
return 0; return 0;
} }
static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val) static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
{ {
int ret; int ret;
if (chip->gpio_chip.ngpio <= 8) { if (chip->gpio_chip.ngpio <= 8) {
ret = i2c_smbus_read_byte_data(chip->client, reg); ret = i2c_smbus_read_byte_data(chip->client, reg);
*val = ret; *val = ret;
} } else if (chip->gpio_chip.ngpio >= 24) {
else if (chip->gpio_chip.ngpio == 24) { int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
*val = 0;
ret = i2c_smbus_read_i2c_block_data(chip->client, ret = i2c_smbus_read_i2c_block_data(chip->client,
(reg << 2) | REG_ADDR_AI, (reg << bank_shift) | REG_ADDR_AI,
3, NBANK(chip), val);
(u8 *) val);
le32_to_cpus(val);
} else { } else {
ret = i2c_smbus_read_word_data(chip->client, reg << 1); ret = i2c_smbus_read_word_data(chip->client, reg << 1);
*val = ret; val[0] = (u16)ret & 0xFF;
val[1] = (u16)ret >> 8;
} }
if (ret < 0) { if (ret < 0) {
dev_err(&chip->client->dev, "failed reading register\n"); dev_err(&chip->client->dev, "failed reading register\n");
return ret; return ret;
...@@ -163,13 +202,13 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val) ...@@ -163,13 +202,13 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{ {
struct pca953x_chip *chip; struct pca953x_chip *chip;
uint reg_val; u8 reg_val;
int ret, offset = 0; int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
mutex_lock(&chip->i2c_lock); mutex_lock(&chip->i2c_lock);
reg_val = chip->reg_direction | (1u << off); reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ));
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -179,11 +218,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) ...@@ -179,11 +218,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
offset = PCA957X_CFG; offset = PCA957X_CFG;
break; break;
} }
ret = pca953x_write_reg(chip, offset, reg_val); ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret) if (ret)
goto exit; goto exit;
chip->reg_direction = reg_val; chip->reg_direction[off / BANK_SZ] = reg_val;
ret = 0; ret = 0;
exit: exit:
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
...@@ -194,7 +233,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -194,7 +233,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val) unsigned off, int val)
{ {
struct pca953x_chip *chip; struct pca953x_chip *chip;
uint reg_val; u8 reg_val;
int ret, offset = 0; int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
...@@ -202,9 +241,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -202,9 +241,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
mutex_lock(&chip->i2c_lock); mutex_lock(&chip->i2c_lock);
/* set output level */ /* set output level */
if (val) if (val)
reg_val = chip->reg_output | (1u << off); reg_val = chip->reg_output[off / BANK_SZ]
| (1u << (off % BANK_SZ));
else else
reg_val = chip->reg_output & ~(1u << off); reg_val = chip->reg_output[off / BANK_SZ]
& ~(1u << (off % BANK_SZ));
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -214,14 +255,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -214,14 +255,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
offset = PCA957X_OUT; offset = PCA957X_OUT;
break; break;
} }
ret = pca953x_write_reg(chip, offset, reg_val); ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret) if (ret)
goto exit; goto exit;
chip->reg_output = reg_val; chip->reg_output[off / BANK_SZ] = reg_val;
/* then direction */ /* then direction */
reg_val = chip->reg_direction & ~(1u << off); reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ));
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
offset = PCA953X_DIRECTION; offset = PCA953X_DIRECTION;
...@@ -230,11 +271,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -230,11 +271,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
offset = PCA957X_CFG; offset = PCA957X_CFG;
break; break;
} }
ret = pca953x_write_reg(chip, offset, reg_val); ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret) if (ret)
goto exit; goto exit;
chip->reg_direction = reg_val; chip->reg_direction[off / BANK_SZ] = reg_val;
ret = 0; ret = 0;
exit: exit:
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
...@@ -258,7 +299,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) ...@@ -258,7 +299,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
offset = PCA957X_IN; offset = PCA957X_IN;
break; break;
} }
ret = pca953x_read_reg(chip, offset, &reg_val); ret = pca953x_read_single(chip, offset, &reg_val, off);
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
if (ret < 0) { if (ret < 0) {
/* NOTE: diagnostic already emitted; that's all we should /* NOTE: diagnostic already emitted; that's all we should
...@@ -274,16 +315,18 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) ...@@ -274,16 +315,18 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
{ {
struct pca953x_chip *chip; struct pca953x_chip *chip;
u32 reg_val; u8 reg_val;
int ret, offset = 0; int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
mutex_lock(&chip->i2c_lock); mutex_lock(&chip->i2c_lock);
if (val) if (val)
reg_val = chip->reg_output | (1u << off); reg_val = chip->reg_output[off / BANK_SZ]
| (1u << (off % BANK_SZ));
else else
reg_val = chip->reg_output & ~(1u << off); reg_val = chip->reg_output[off / BANK_SZ]
& ~(1u << (off % BANK_SZ));
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -293,11 +336,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) ...@@ -293,11 +336,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
offset = PCA957X_OUT; offset = PCA957X_OUT;
break; break;
} }
ret = pca953x_write_reg(chip, offset, reg_val); ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret) if (ret)
goto exit; goto exit;
chip->reg_output = reg_val; chip->reg_output[off / BANK_SZ] = reg_val;
exit: exit:
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
} }
...@@ -335,14 +378,14 @@ static void pca953x_irq_mask(struct irq_data *d) ...@@ -335,14 +378,14 @@ static void pca953x_irq_mask(struct irq_data *d)
{ {
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
chip->irq_mask &= ~(1 << d->hwirq); chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ));
} }
static void pca953x_irq_unmask(struct irq_data *d) static void pca953x_irq_unmask(struct irq_data *d)
{ {
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
chip->irq_mask |= 1 << d->hwirq; chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ);
} }
static void pca953x_irq_bus_lock(struct irq_data *d) static void pca953x_irq_bus_lock(struct irq_data *d)
...@@ -355,18 +398,21 @@ static void pca953x_irq_bus_lock(struct irq_data *d) ...@@ -355,18 +398,21 @@ static void pca953x_irq_bus_lock(struct irq_data *d)
static void pca953x_irq_bus_sync_unlock(struct irq_data *d) static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
{ {
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
u32 new_irqs; u8 new_irqs;
u32 level; int level, i;
/* Look for any newly setup interrupt */ /* Look for any newly setup interrupt */
new_irqs = chip->irq_trig_fall | chip->irq_trig_raise; for (i = 0; i < NBANK(chip); i++) {
new_irqs &= ~chip->reg_direction; new_irqs = chip->irq_trig_fall[i] | chip->irq_trig_raise[i];
new_irqs &= ~chip->reg_direction[i];
while (new_irqs) { while (new_irqs) {
level = __ffs(new_irqs); level = __ffs(new_irqs);
pca953x_gpio_direction_input(&chip->gpio_chip, level); pca953x_gpio_direction_input(&chip->gpio_chip,
level + (BANK_SZ * i));
new_irqs &= ~(1 << level); new_irqs &= ~(1 << level);
} }
}
mutex_unlock(&chip->irq_lock); mutex_unlock(&chip->irq_lock);
} }
...@@ -374,7 +420,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) ...@@ -374,7 +420,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
{ {
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
u32 mask = 1 << d->hwirq; int bank_nb = d->hwirq / BANK_SZ;
u8 mask = 1 << (d->hwirq % BANK_SZ);
if (!(type & IRQ_TYPE_EDGE_BOTH)) { if (!(type & IRQ_TYPE_EDGE_BOTH)) {
dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
...@@ -383,14 +430,14 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) ...@@ -383,14 +430,14 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
} }
if (type & IRQ_TYPE_EDGE_FALLING) if (type & IRQ_TYPE_EDGE_FALLING)
chip->irq_trig_fall |= mask; chip->irq_trig_fall[bank_nb] |= mask;
else else
chip->irq_trig_fall &= ~mask; chip->irq_trig_fall[bank_nb] &= ~mask;
if (type & IRQ_TYPE_EDGE_RISING) if (type & IRQ_TYPE_EDGE_RISING)
chip->irq_trig_raise |= mask; chip->irq_trig_raise[bank_nb] |= mask;
else else
chip->irq_trig_raise &= ~mask; chip->irq_trig_raise[bank_nb] &= ~mask;
return 0; return 0;
} }
...@@ -404,13 +451,13 @@ static struct irq_chip pca953x_irq_chip = { ...@@ -404,13 +451,13 @@ static struct irq_chip pca953x_irq_chip = {
.irq_set_type = pca953x_irq_set_type, .irq_set_type = pca953x_irq_set_type,
}; };
static u32 pca953x_irq_pending(struct pca953x_chip *chip) static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
{ {
u32 cur_stat; u8 cur_stat[MAX_BANK];
u32 old_stat; u8 old_stat[MAX_BANK];
u32 pending; u8 pendings = 0;
u32 trigger; u8 trigger[MAX_BANK], triggers = 0;
int ret, offset = 0; int ret, i, offset = 0;
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -420,45 +467,54 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip) ...@@ -420,45 +467,54 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip)
offset = PCA957X_IN; offset = PCA957X_IN;
break; break;
} }
ret = pca953x_read_reg(chip, offset, &cur_stat); ret = pca953x_read_regs(chip, offset, cur_stat);
if (ret) if (ret)
return 0; return 0;
/* Remove output pins from the equation */ /* Remove output pins from the equation */
cur_stat &= chip->reg_direction; for (i = 0; i < NBANK(chip); i++)
cur_stat[i] &= chip->reg_direction[i];
old_stat = chip->irq_stat; memcpy(old_stat, chip->irq_stat, NBANK(chip));
trigger = (cur_stat ^ old_stat) & chip->irq_mask;
if (!trigger) for (i = 0; i < NBANK(chip); i++) {
trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
triggers += trigger[i];
}
if (!triggers)
return 0; return 0;
chip->irq_stat = cur_stat; memcpy(chip->irq_stat, cur_stat, NBANK(chip));
pending = (old_stat & chip->irq_trig_fall) | for (i = 0; i < NBANK(chip); i++) {
(cur_stat & chip->irq_trig_raise); pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
pending &= trigger; (cur_stat[i] & chip->irq_trig_raise[i]);
pending[i] &= trigger[i];
pendings += pending[i];
}
return pending; return pendings;
} }
static irqreturn_t pca953x_irq_handler(int irq, void *devid) static irqreturn_t pca953x_irq_handler(int irq, void *devid)
{ {
struct pca953x_chip *chip = devid; struct pca953x_chip *chip = devid;
u32 pending; u8 pending[MAX_BANK];
u32 level; u8 level;
int i;
pending = pca953x_irq_pending(chip);
if (!pending) if (!pca953x_irq_pending(chip, pending))
return IRQ_HANDLED; return IRQ_HANDLED;
do { for (i = 0; i < NBANK(chip); i++) {
level = __ffs(pending); while (pending[i]) {
handle_nested_irq(irq_find_mapping(chip->domain, level)); level = __ffs(pending[i]);
handle_nested_irq(irq_find_mapping(chip->domain,
pending &= ~(1 << level); level + (BANK_SZ * i)));
} while (pending); pending[i] &= ~(1 << level);
}
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -468,8 +524,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -468,8 +524,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
int irq_base) int irq_base)
{ {
struct i2c_client *client = chip->client; struct i2c_client *client = chip->client;
int ret, offset = 0; int ret, i, offset = 0;
u32 temporary;
if (irq_base != -1 if (irq_base != -1
&& (id->driver_data & PCA_INT)) { && (id->driver_data & PCA_INT)) {
...@@ -483,8 +538,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -483,8 +538,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
offset = PCA957X_IN; offset = PCA957X_IN;
break; break;
} }
ret = pca953x_read_reg(chip, offset, &temporary); ret = pca953x_read_regs(chip, offset, chip->irq_stat);
chip->irq_stat = temporary;
if (ret) if (ret)
goto out_failed; goto out_failed;
...@@ -493,7 +547,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -493,7 +547,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
* interrupt. We have to rely on the previous read for * interrupt. We have to rely on the previous read for
* this purpose. * this purpose.
*/ */
chip->irq_stat &= chip->reg_direction; for (i = 0; i < NBANK(chip); i++)
chip->irq_stat[i] &= chip->reg_direction[i];
mutex_init(&chip->irq_lock); mutex_init(&chip->irq_lock);
chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1); chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1);
...@@ -619,18 +674,24 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) ...@@ -619,18 +674,24 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
static int device_pca953x_init(struct pca953x_chip *chip, u32 invert) static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
{ {
int ret; int ret;
u8 val[MAX_BANK];
ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output); ret = pca953x_read_regs(chip, PCA953X_OUTPUT, chip->reg_output);
if (ret) if (ret)
goto out; goto out;
ret = pca953x_read_reg(chip, PCA953X_DIRECTION, ret = pca953x_read_regs(chip, PCA953X_DIRECTION,
&chip->reg_direction); chip->reg_direction);
if (ret) if (ret)
goto out; goto out;
/* set platform specific polarity inversion */ /* set platform specific polarity inversion */
ret = pca953x_write_reg(chip, PCA953X_INVERT, invert); if (invert)
memset(val, 0xFF, NBANK(chip));
else
memset(val, 0, NBANK(chip));
ret = pca953x_write_regs(chip, PCA953X_INVERT, val);
out: out:
return ret; return ret;
} }
...@@ -638,28 +699,36 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert) ...@@ -638,28 +699,36 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
{ {
int ret; int ret;
u32 val = 0; u8 val[MAX_BANK];
/* Let every port in proper state, that could save power */ /* Let every port in proper state, that could save power */
pca953x_write_reg(chip, PCA957X_PUPD, 0x0); memset(val, 0, NBANK(chip));
pca953x_write_reg(chip, PCA957X_CFG, 0xffff); pca953x_write_regs(chip, PCA957X_PUPD, val);
pca953x_write_reg(chip, PCA957X_OUT, 0x0); memset(val, 0xFF, NBANK(chip));
pca953x_write_regs(chip, PCA957X_CFG, val);
ret = pca953x_read_reg(chip, PCA957X_IN, &val); memset(val, 0, NBANK(chip));
pca953x_write_regs(chip, PCA957X_OUT, val);
ret = pca953x_read_regs(chip, PCA957X_IN, val);
if (ret) if (ret)
goto out; goto out;
ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output); ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output);
if (ret) if (ret)
goto out; goto out;
ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction); ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction);
if (ret) if (ret)
goto out; goto out;
/* set platform specific polarity inversion */ /* set platform specific polarity inversion */
pca953x_write_reg(chip, PCA957X_INVRT, invert); if (invert)
memset(val, 0xFF, NBANK(chip));
else
memset(val, 0, NBANK(chip));
pca953x_write_regs(chip, PCA957X_INVRT, val);
/* To enable register 6, 7 to controll pull up and pull down */ /* To enable register 6, 7 to controll pull up and pull down */
pca953x_write_reg(chip, PCA957X_BKEN, 0x202); memset(val, 0x02, NBANK(chip));
pca953x_write_regs(chip, PCA957X_BKEN, val);
return 0; return 0;
out: out:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment