Merge branch 'ib-pca953x' into devel
This commit is contained in:
commit
3e42f200c1
|
@ -20,6 +20,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_data/pca953x.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -30,6 +31,8 @@
|
|||
#define PCA953X_INVERT 0x02
|
||||
#define PCA953X_DIRECTION 0x03
|
||||
|
||||
#define REG_ADDR_MASK 0x3f
|
||||
#define REG_ADDR_EXT 0x40
|
||||
#define REG_ADDR_AI 0x80
|
||||
|
||||
#define PCA957X_IN 0x00
|
||||
|
@ -58,7 +61,7 @@
|
|||
#define PCA_GPIO_MASK 0x00FF
|
||||
|
||||
#define PCAL_GPIO_MASK 0x1f
|
||||
#define PCAL_PINCTRL_MASK 0xe0
|
||||
#define PCAL_PINCTRL_MASK 0x60
|
||||
|
||||
#define PCA_INT 0x0100
|
||||
#define PCA_PCAL 0x0200
|
||||
|
@ -119,25 +122,27 @@ struct pca953x_reg_config {
|
|||
int direction;
|
||||
int output;
|
||||
int input;
|
||||
int invert;
|
||||
};
|
||||
|
||||
static const struct pca953x_reg_config pca953x_regs = {
|
||||
.direction = PCA953X_DIRECTION,
|
||||
.output = PCA953X_OUTPUT,
|
||||
.input = PCA953X_INPUT,
|
||||
.invert = PCA953X_INVERT,
|
||||
};
|
||||
|
||||
static const struct pca953x_reg_config pca957x_regs = {
|
||||
.direction = PCA957X_CFG,
|
||||
.output = PCA957X_OUT,
|
||||
.input = PCA957X_IN,
|
||||
.invert = PCA957X_INVRT,
|
||||
};
|
||||
|
||||
struct pca953x_chip {
|
||||
unsigned gpio_start;
|
||||
u8 reg_output[MAX_BANK];
|
||||
u8 reg_direction[MAX_BANK];
|
||||
struct mutex i2c_lock;
|
||||
struct regmap *regmap;
|
||||
|
||||
#ifdef CONFIG_GPIO_PCA953X_IRQ
|
||||
struct mutex irq_lock;
|
||||
|
@ -154,87 +159,177 @@ struct pca953x_chip {
|
|||
struct regulator *regulator;
|
||||
|
||||
const struct pca953x_reg_config *regs;
|
||||
|
||||
int (*write_regs)(struct pca953x_chip *, int, u8 *);
|
||||
int (*read_regs)(struct pca953x_chip *, int, u8 *);
|
||||
};
|
||||
|
||||
static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
|
||||
int off)
|
||||
static int pca953x_bank_shift(struct pca953x_chip *chip)
|
||||
{
|
||||
int ret;
|
||||
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
|
||||
int offset = off / BANK_SZ;
|
||||
return fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_byte_data(chip->client,
|
||||
(reg << bank_shift) + offset);
|
||||
*val = ret;
|
||||
#define PCA953x_BANK_INPUT BIT(0)
|
||||
#define PCA953x_BANK_OUTPUT BIT(1)
|
||||
#define PCA953x_BANK_POLARITY BIT(2)
|
||||
#define PCA953x_BANK_CONFIG BIT(3)
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&chip->client->dev, "failed reading register\n");
|
||||
return ret;
|
||||
#define PCA957x_BANK_INPUT BIT(0)
|
||||
#define PCA957x_BANK_POLARITY BIT(1)
|
||||
#define PCA957x_BANK_BUSHOLD BIT(2)
|
||||
#define PCA957x_BANK_CONFIG BIT(4)
|
||||
#define PCA957x_BANK_OUTPUT BIT(5)
|
||||
|
||||
#define PCAL9xxx_BANK_IN_LATCH BIT(8 + 2)
|
||||
#define PCAL9xxx_BANK_IRQ_MASK BIT(8 + 5)
|
||||
#define PCAL9xxx_BANK_IRQ_STAT BIT(8 + 6)
|
||||
|
||||
/*
|
||||
* We care about the following registers:
|
||||
* - Standard set, below 0x40, each port can be replicated up to 8 times
|
||||
* - PCA953x standard
|
||||
* Input port 0x00 + 0 * bank_size R
|
||||
* Output port 0x00 + 1 * bank_size RW
|
||||
* Polarity Inversion port 0x00 + 2 * bank_size RW
|
||||
* Configuration port 0x00 + 3 * bank_size RW
|
||||
* - PCA957x with mixed up registers
|
||||
* Input port 0x00 + 0 * bank_size R
|
||||
* Polarity Inversion port 0x00 + 1 * bank_size RW
|
||||
* Bus hold port 0x00 + 2 * bank_size RW
|
||||
* Configuration port 0x00 + 4 * bank_size RW
|
||||
* Output port 0x00 + 5 * bank_size RW
|
||||
*
|
||||
* - Extended set, above 0x40, often chip specific.
|
||||
* - PCAL6524/PCAL9555A with custom PCAL IRQ handling:
|
||||
* Input latch register 0x40 + 2 * bank_size RW
|
||||
* Interrupt mask register 0x40 + 5 * bank_size RW
|
||||
* Interrupt status register 0x40 + 6 * bank_size R
|
||||
*
|
||||
* - Registers with bit 0x80 set, the AI bit
|
||||
* The bit is cleared and the registers fall into one of the
|
||||
* categories above.
|
||||
*/
|
||||
|
||||
static bool pca953x_check_register(struct pca953x_chip *chip, unsigned int reg,
|
||||
u32 checkbank)
|
||||
{
|
||||
int bank_shift = pca953x_bank_shift(chip);
|
||||
int bank = (reg & REG_ADDR_MASK) >> bank_shift;
|
||||
int offset = reg & (BIT(bank_shift) - 1);
|
||||
|
||||
/* Special PCAL extended register check. */
|
||||
if (reg & REG_ADDR_EXT) {
|
||||
if (!(chip->driver_data & PCA_PCAL))
|
||||
return false;
|
||||
bank += 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* Register is not in the matching bank. */
|
||||
if (!(BIT(bank) & checkbank))
|
||||
return false;
|
||||
|
||||
/* Register is not within allowed range of bank. */
|
||||
if (offset >= NBANK(chip))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val,
|
||||
int off)
|
||||
static bool pca953x_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
int ret;
|
||||
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
|
||||
int offset = off / BANK_SZ;
|
||||
struct pca953x_chip *chip = dev_get_drvdata(dev);
|
||||
u32 bank;
|
||||
|
||||
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;
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
|
||||
bank = PCA953x_BANK_INPUT | PCA953x_BANK_OUTPUT |
|
||||
PCA953x_BANK_POLARITY | PCA953x_BANK_CONFIG;
|
||||
} else {
|
||||
bank = PCA957x_BANK_INPUT | PCA957x_BANK_OUTPUT |
|
||||
PCA957x_BANK_POLARITY | PCA957x_BANK_CONFIG |
|
||||
PCA957x_BANK_BUSHOLD;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (chip->driver_data & PCA_PCAL) {
|
||||
bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_IRQ_MASK |
|
||||
PCAL9xxx_BANK_IRQ_STAT;
|
||||
}
|
||||
|
||||
return pca953x_check_register(chip, reg, bank);
|
||||
}
|
||||
|
||||
static int pca953x_write_regs_8(struct pca953x_chip *chip, int reg, u8 *val)
|
||||
static bool pca953x_writeable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(chip->client, reg, *val);
|
||||
struct pca953x_chip *chip = dev_get_drvdata(dev);
|
||||
u32 bank;
|
||||
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
|
||||
bank = PCA953x_BANK_OUTPUT | PCA953x_BANK_POLARITY |
|
||||
PCA953x_BANK_CONFIG;
|
||||
} else {
|
||||
bank = PCA957x_BANK_OUTPUT | PCA957x_BANK_POLARITY |
|
||||
PCA957x_BANK_CONFIG | PCA957x_BANK_BUSHOLD;
|
||||
}
|
||||
|
||||
if (chip->driver_data & PCA_PCAL)
|
||||
bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_IRQ_MASK;
|
||||
|
||||
return pca953x_check_register(chip, reg, bank);
|
||||
}
|
||||
|
||||
static int pca953x_write_regs_16(struct pca953x_chip *chip, int reg, u8 *val)
|
||||
static bool pca953x_volatile_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
u16 word = get_unaligned((u16 *)val);
|
||||
struct pca953x_chip *chip = dev_get_drvdata(dev);
|
||||
u32 bank;
|
||||
|
||||
return i2c_smbus_write_word_data(chip->client, reg << 1, word);
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE)
|
||||
bank = PCA953x_BANK_INPUT;
|
||||
else
|
||||
bank = PCA957x_BANK_INPUT;
|
||||
|
||||
if (chip->driver_data & PCA_PCAL)
|
||||
bank |= PCAL9xxx_BANK_IRQ_STAT;
|
||||
|
||||
return pca953x_check_register(chip, reg, bank);
|
||||
}
|
||||
|
||||
static int pca957x_write_regs_16(struct pca953x_chip *chip, int reg, u8 *val)
|
||||
const struct regmap_config pca953x_i2c_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.readable_reg = pca953x_readable_register,
|
||||
.writeable_reg = pca953x_writeable_register,
|
||||
.volatile_reg = pca953x_volatile_register,
|
||||
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.max_register = 0x7f,
|
||||
};
|
||||
|
||||
static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off,
|
||||
bool write, bool addrinc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(chip->client, reg << 1, val[0]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return i2c_smbus_write_byte_data(chip->client, (reg << 1) + 1, val[1]);
|
||||
}
|
||||
|
||||
static int pca953x_write_regs_24(struct pca953x_chip *chip, int reg, u8 *val)
|
||||
{
|
||||
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
|
||||
int bank_shift = pca953x_bank_shift(chip);
|
||||
int addr = (reg & PCAL_GPIO_MASK) << bank_shift;
|
||||
int pinctrl = (reg & PCAL_PINCTRL_MASK) << 1;
|
||||
u8 regaddr = pinctrl | addr | (off / BANK_SZ);
|
||||
|
||||
return i2c_smbus_write_i2c_block_data(chip->client,
|
||||
pinctrl | addr | REG_ADDR_AI,
|
||||
NBANK(chip), val);
|
||||
/* Single byte read doesn't need AI bit set. */
|
||||
if (!addrinc)
|
||||
return regaddr;
|
||||
|
||||
/* Chips with 24 and more GPIOs always support Auto Increment */
|
||||
if (write && NBANK(chip) > 2)
|
||||
regaddr |= REG_ADDR_AI;
|
||||
|
||||
/* PCA9575 needs address-increment on multi-byte writes */
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE)
|
||||
regaddr |= REG_ADDR_AI;
|
||||
|
||||
return regaddr;
|
||||
}
|
||||
|
||||
static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 regaddr = pca953x_recalc_addr(chip, reg, 0, true, true);
|
||||
int ret;
|
||||
|
||||
ret = chip->write_regs(chip, reg, val);
|
||||
ret = regmap_bulk_write(chip->regmap, regaddr, val, NBANK(chip));
|
||||
if (ret < 0) {
|
||||
dev_err(&chip->client->dev, "failed writing register\n");
|
||||
return ret;
|
||||
|
@ -243,42 +338,12 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pca953x_read_regs_8(struct pca953x_chip *chip, int reg, u8 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(chip->client, reg);
|
||||
*val = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pca953x_read_regs_16(struct pca953x_chip *chip, int reg, u8 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_word_data(chip->client, reg << 1);
|
||||
put_unaligned(ret, (u16 *)val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pca953x_read_regs_24(struct pca953x_chip *chip, int reg, u8 *val)
|
||||
{
|
||||
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
|
||||
int addr = (reg & PCAL_GPIO_MASK) << bank_shift;
|
||||
int pinctrl = (reg & PCAL_PINCTRL_MASK) << 1;
|
||||
|
||||
return i2c_smbus_read_i2c_block_data(chip->client,
|
||||
pinctrl | addr | REG_ADDR_AI,
|
||||
NBANK(chip), val);
|
||||
}
|
||||
|
||||
static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
|
||||
{
|
||||
u8 regaddr = pca953x_recalc_addr(chip, reg, 0, false, true);
|
||||
int ret;
|
||||
|
||||
ret = chip->read_regs(chip, reg, val);
|
||||
ret = regmap_bulk_read(chip->regmap, regaddr, val, NBANK(chip));
|
||||
if (ret < 0) {
|
||||
dev_err(&chip->client->dev, "failed reading register\n");
|
||||
return ret;
|
||||
|
@ -290,18 +355,13 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
|
|||
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
|
||||
{
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
u8 reg_val;
|
||||
u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off,
|
||||
true, false);
|
||||
u8 bit = BIT(off % BANK_SZ);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ));
|
||||
|
||||
ret = pca953x_write_single(chip, chip->regs->direction, reg_val, off);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
chip->reg_direction[off / BANK_SZ] = reg_val;
|
||||
exit:
|
||||
ret = regmap_write_bits(chip->regmap, dirreg, bit, bit);
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
return ret;
|
||||
}
|
||||
|
@ -310,31 +370,21 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
|||
unsigned off, int val)
|
||||
{
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
u8 reg_val;
|
||||
u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off,
|
||||
true, false);
|
||||
u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off,
|
||||
true, false);
|
||||
u8 bit = BIT(off % BANK_SZ);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
/* set output level */
|
||||
if (val)
|
||||
reg_val = chip->reg_output[off / BANK_SZ]
|
||||
| (1u << (off % BANK_SZ));
|
||||
else
|
||||
reg_val = chip->reg_output[off / BANK_SZ]
|
||||
& ~(1u << (off % BANK_SZ));
|
||||
|
||||
ret = pca953x_write_single(chip, chip->regs->output, reg_val, off);
|
||||
ret = regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
chip->reg_output[off / BANK_SZ] = reg_val;
|
||||
|
||||
/* then direction */
|
||||
reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ));
|
||||
ret = pca953x_write_single(chip, chip->regs->direction, reg_val, off);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
chip->reg_direction[off / BANK_SZ] = reg_val;
|
||||
ret = regmap_write_bits(chip->regmap, dirreg, bit, 0);
|
||||
exit:
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
return ret;
|
||||
|
@ -343,11 +393,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
|||
static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
|
||||
{
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
u8 inreg = pca953x_recalc_addr(chip, chip->regs->input, off,
|
||||
true, false);
|
||||
u8 bit = BIT(off % BANK_SZ);
|
||||
u32 reg_val;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
ret = pca953x_read_single(chip, chip->regs->input, ®_val, off);
|
||||
ret = regmap_read(chip->regmap, inreg, ®_val);
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
if (ret < 0) {
|
||||
/* NOTE: diagnostic already emitted; that's all we should
|
||||
|
@ -357,45 +410,37 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
|
|||
return 0;
|
||||
}
|
||||
|
||||
return (reg_val & (1u << (off % BANK_SZ))) ? 1 : 0;
|
||||
return !!(reg_val & bit);
|
||||
}
|
||||
|
||||
static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
|
||||
{
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
u8 reg_val;
|
||||
int ret;
|
||||
u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off,
|
||||
true, false);
|
||||
u8 bit = BIT(off % BANK_SZ);
|
||||
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
if (val)
|
||||
reg_val = chip->reg_output[off / BANK_SZ]
|
||||
| (1u << (off % BANK_SZ));
|
||||
else
|
||||
reg_val = chip->reg_output[off / BANK_SZ]
|
||||
& ~(1u << (off % BANK_SZ));
|
||||
|
||||
ret = pca953x_write_single(chip, chip->regs->output, reg_val, off);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
chip->reg_output[off / BANK_SZ] = reg_val;
|
||||
exit:
|
||||
regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0);
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
}
|
||||
|
||||
static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off)
|
||||
{
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off,
|
||||
true, false);
|
||||
u8 bit = BIT(off % BANK_SZ);
|
||||
u32 reg_val;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
ret = pca953x_read_single(chip, chip->regs->direction, ®_val, off);
|
||||
ret = regmap_read(chip->regmap, dirreg, ®_val);
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !!(reg_val & (1u << (off % BANK_SZ)));
|
||||
return !!(reg_val & bit);
|
||||
}
|
||||
|
||||
static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
|
||||
|
@ -403,14 +448,15 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
|
|||
{
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
unsigned int bank_mask, bank_val;
|
||||
int bank_shift, bank;
|
||||
int bank;
|
||||
u8 reg_val[MAX_BANK];
|
||||
int ret;
|
||||
|
||||
bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
|
||||
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
memcpy(reg_val, chip->reg_output, NBANK(chip));
|
||||
ret = pca953x_read_regs(chip, chip->regs->output, reg_val);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
for (bank = 0; bank < NBANK(chip); bank++) {
|
||||
bank_mask = mask[bank / sizeof(*mask)] >>
|
||||
((bank % sizeof(*mask)) * 8);
|
||||
|
@ -422,13 +468,7 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
|
|||
}
|
||||
}
|
||||
|
||||
ret = i2c_smbus_write_i2c_block_data(chip->client,
|
||||
chip->regs->output << bank_shift,
|
||||
NBANK(chip), reg_val);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
memcpy(chip->reg_output, reg_val, NBANK(chip));
|
||||
pca953x_write_regs(chip, chip->regs->output, reg_val);
|
||||
exit:
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
}
|
||||
|
@ -487,6 +527,10 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
|
|||
u8 new_irqs;
|
||||
int level, i;
|
||||
u8 invert_irq_mask[MAX_BANK];
|
||||
int reg_direction[MAX_BANK];
|
||||
|
||||
regmap_bulk_read(chip->regmap, chip->regs->direction, reg_direction,
|
||||
NBANK(chip));
|
||||
|
||||
if (chip->driver_data & PCA_PCAL) {
|
||||
/* Enable latch on interrupt-enabled inputs */
|
||||
|
@ -502,7 +546,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
|
|||
/* Look for any newly setup interrupt */
|
||||
for (i = 0; i < NBANK(chip); i++) {
|
||||
new_irqs = chip->irq_trig_fall[i] | chip->irq_trig_raise[i];
|
||||
new_irqs &= ~chip->reg_direction[i];
|
||||
new_irqs &= reg_direction[i];
|
||||
|
||||
while (new_irqs) {
|
||||
level = __ffs(new_irqs);
|
||||
|
@ -567,6 +611,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
|
|||
bool pending_seen = false;
|
||||
bool trigger_seen = false;
|
||||
u8 trigger[MAX_BANK];
|
||||
int reg_direction[MAX_BANK];
|
||||
int ret, i;
|
||||
|
||||
if (chip->driver_data & PCA_PCAL) {
|
||||
|
@ -597,8 +642,10 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
|
|||
return false;
|
||||
|
||||
/* Remove output pins from the equation */
|
||||
regmap_bulk_read(chip->regmap, chip->regs->direction, reg_direction,
|
||||
NBANK(chip));
|
||||
for (i = 0; i < NBANK(chip); i++)
|
||||
cur_stat[i] &= chip->reg_direction[i];
|
||||
cur_stat[i] &= reg_direction[i];
|
||||
|
||||
memcpy(old_stat, chip->irq_stat, NBANK(chip));
|
||||
|
||||
|
@ -652,6 +699,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
|
|||
int irq_base)
|
||||
{
|
||||
struct i2c_client *client = chip->client;
|
||||
int reg_direction[MAX_BANK];
|
||||
int ret, i;
|
||||
|
||||
if (client->irq && irq_base != -1
|
||||
|
@ -666,8 +714,10 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
|
|||
* interrupt. We have to rely on the previous read for
|
||||
* this purpose.
|
||||
*/
|
||||
regmap_bulk_read(chip->regmap, chip->regs->direction,
|
||||
reg_direction, NBANK(chip));
|
||||
for (i = 0; i < NBANK(chip); i++)
|
||||
chip->irq_stat[i] &= chip->reg_direction[i];
|
||||
chip->irq_stat[i] &= reg_direction[i];
|
||||
mutex_init(&chip->irq_lock);
|
||||
|
||||
ret = devm_request_threaded_irq(&client->dev,
|
||||
|
@ -715,20 +765,19 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
|
|||
}
|
||||
#endif
|
||||
|
||||
static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
|
||||
static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
|
||||
{
|
||||
int ret;
|
||||
u8 val[MAX_BANK];
|
||||
|
||||
chip->regs = &pca953x_regs;
|
||||
|
||||
ret = pca953x_read_regs(chip, chip->regs->output, chip->reg_output);
|
||||
if (ret)
|
||||
ret = regcache_sync_region(chip->regmap, chip->regs->output,
|
||||
chip->regs->output + NBANK(chip));
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
|
||||
ret = pca953x_read_regs(chip, chip->regs->direction,
|
||||
chip->reg_direction);
|
||||
if (ret)
|
||||
ret = regcache_sync_region(chip->regmap, chip->regs->direction,
|
||||
chip->regs->direction + NBANK(chip));
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
|
||||
/* set platform specific polarity inversion */
|
||||
|
@ -737,7 +786,7 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
|
|||
else
|
||||
memset(val, 0, NBANK(chip));
|
||||
|
||||
ret = pca953x_write_regs(chip, PCA953X_INVERT, val);
|
||||
ret = pca953x_write_regs(chip, chip->regs->invert, val);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
@ -747,22 +796,7 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
|
|||
int ret;
|
||||
u8 val[MAX_BANK];
|
||||
|
||||
chip->regs = &pca957x_regs;
|
||||
|
||||
ret = pca953x_read_regs(chip, chip->regs->output, chip->reg_output);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = pca953x_read_regs(chip, chip->regs->direction,
|
||||
chip->reg_direction);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* set platform specific polarity inversion */
|
||||
if (invert)
|
||||
memset(val, 0xFF, NBANK(chip));
|
||||
else
|
||||
memset(val, 0, NBANK(chip));
|
||||
ret = pca953x_write_regs(chip, PCA957X_INVRT, val);
|
||||
ret = device_pca95xx_init(chip, invert);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
@ -853,6 +887,16 @@ static int pca953x_probe(struct i2c_client *client,
|
|||
}
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, chip);
|
||||
|
||||
chip->regmap = devm_regmap_init_i2c(client, &pca953x_i2c_regmap);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
ret = PTR_ERR(chip->regmap);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
regcache_mark_dirty(chip->regmap);
|
||||
|
||||
mutex_init(&chip->i2c_lock);
|
||||
/*
|
||||
* In case we have an i2c-mux controlled by a GPIO provided by an
|
||||
|
@ -878,24 +922,13 @@ static int pca953x_probe(struct i2c_client *client,
|
|||
*/
|
||||
pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK);
|
||||
|
||||
if (chip->gpio_chip.ngpio <= 8) {
|
||||
chip->write_regs = pca953x_write_regs_8;
|
||||
chip->read_regs = pca953x_read_regs_8;
|
||||
} else if (chip->gpio_chip.ngpio >= 24) {
|
||||
chip->write_regs = pca953x_write_regs_24;
|
||||
chip->read_regs = pca953x_read_regs_24;
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
|
||||
chip->regs = &pca953x_regs;
|
||||
ret = device_pca95xx_init(chip, invert);
|
||||
} else {
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE)
|
||||
chip->write_regs = pca953x_write_regs_16;
|
||||
else
|
||||
chip->write_regs = pca957x_write_regs_16;
|
||||
chip->read_regs = pca953x_read_regs_16;
|
||||
}
|
||||
|
||||
if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE)
|
||||
ret = device_pca953x_init(chip, invert);
|
||||
else
|
||||
chip->regs = &pca957x_regs;
|
||||
ret = device_pca957x_init(chip, invert);
|
||||
}
|
||||
if (ret)
|
||||
goto err_exit;
|
||||
|
||||
|
@ -914,7 +947,6 @@ static int pca953x_probe(struct i2c_client *client,
|
|||
dev_warn(&client->dev, "setup failed, %d\n", ret);
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, chip);
|
||||
return 0;
|
||||
|
||||
err_exit:
|
||||
|
@ -943,6 +975,91 @@ static int pca953x_remove(struct i2c_client *client)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pca953x_regcache_sync(struct device *dev)
|
||||
{
|
||||
struct pca953x_chip *chip = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The ordering between direction and output is important,
|
||||
* sync these registers first and only then sync the rest.
|
||||
*/
|
||||
ret = regcache_sync_region(chip->regmap, chip->regs->direction,
|
||||
chip->regs->direction + NBANK(chip));
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to sync GPIO dir registers: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regcache_sync_region(chip->regmap, chip->regs->output,
|
||||
chip->regs->output + NBANK(chip));
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to sync GPIO out registers: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GPIO_PCA953X_IRQ
|
||||
if (chip->driver_data & PCA_PCAL) {
|
||||
ret = regcache_sync_region(chip->regmap, PCAL953X_IN_LATCH,
|
||||
PCAL953X_IN_LATCH + NBANK(chip));
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to sync INT latch registers: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regcache_sync_region(chip->regmap, PCAL953X_INT_MASK,
|
||||
PCAL953X_INT_MASK + NBANK(chip));
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to sync INT mask registers: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pca953x_suspend(struct device *dev)
|
||||
{
|
||||
struct pca953x_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
regcache_cache_only(chip->regmap, true);
|
||||
|
||||
regulator_disable(chip->regulator);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pca953x_resume(struct device *dev)
|
||||
{
|
||||
struct pca953x_chip *chip = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(chip->regulator);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to enable regulator: %d\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
regcache_cache_only(chip->regmap, false);
|
||||
regcache_mark_dirty(chip->regmap);
|
||||
ret = pca953x_regcache_sync(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regcache_sync(chip->regmap);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to restore register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* convenience to stop overlong match-table lines */
|
||||
#define OF_953X(__nrgpio, __int) (void *)(__nrgpio | PCA953X_TYPE | __int)
|
||||
#define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int)
|
||||
|
@ -986,9 +1103,12 @@ static const struct of_device_id pca953x_dt_ids[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(of, pca953x_dt_ids);
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pca953x_pm_ops, pca953x_suspend, pca953x_resume);
|
||||
|
||||
static struct i2c_driver pca953x_driver = {
|
||||
.driver = {
|
||||
.name = "pca953x",
|
||||
.pm = &pca953x_pm_ops,
|
||||
.of_match_table = pca953x_dt_ids,
|
||||
.acpi_match_table = ACPI_PTR(pca953x_acpi_ids),
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue
Block a user