|
@@ -95,6 +95,24 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
|
|
|
|
|
|
#define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ)
|
|
|
|
|
|
+struct pca953x_reg_config {
|
|
|
+ int direction;
|
|
|
+ int output;
|
|
|
+ int input;
|
|
|
+};
|
|
|
+
|
|
|
+static const struct pca953x_reg_config pca953x_regs = {
|
|
|
+ .direction = PCA953X_DIRECTION,
|
|
|
+ .output = PCA953X_OUTPUT,
|
|
|
+ .input = PCA953X_INPUT,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct pca953x_reg_config pca957x_regs = {
|
|
|
+ .direction = PCA957X_CFG,
|
|
|
+ .output = PCA957X_OUT,
|
|
|
+ .input = PCA957X_IN,
|
|
|
+};
|
|
|
+
|
|
|
struct pca953x_chip {
|
|
|
unsigned gpio_start;
|
|
|
u8 reg_output[MAX_BANK];
|
|
@@ -115,6 +133,8 @@ struct pca953x_chip {
|
|
|
int chip_type;
|
|
|
unsigned long driver_data;
|
|
|
struct regulator *regulator;
|
|
|
+
|
|
|
+ const struct pca953x_reg_config *regs;
|
|
|
};
|
|
|
|
|
|
static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
|
|
@@ -224,20 +244,12 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
|
|
|
{
|
|
|
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
|
|
u8 reg_val;
|
|
|
- int ret, offset = 0;
|
|
|
+ int ret;
|
|
|
|
|
|
mutex_lock(&chip->i2c_lock);
|
|
|
reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ));
|
|
|
|
|
|
- switch (chip->chip_type) {
|
|
|
- case PCA953X_TYPE:
|
|
|
- offset = PCA953X_DIRECTION;
|
|
|
- break;
|
|
|
- case PCA957X_TYPE:
|
|
|
- offset = PCA957X_CFG;
|
|
|
- break;
|
|
|
- }
|
|
|
- ret = pca953x_write_single(chip, offset, reg_val, off);
|
|
|
+ ret = pca953x_write_single(chip, chip->regs->direction, reg_val, off);
|
|
|
if (ret)
|
|
|
goto exit;
|
|
|
|
|
@@ -252,7 +264,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
|
|
{
|
|
|
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
|
|
u8 reg_val;
|
|
|
- int ret, offset = 0;
|
|
|
+ int ret;
|
|
|
|
|
|
mutex_lock(&chip->i2c_lock);
|
|
|
/* set output level */
|
|
@@ -263,15 +275,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
|
|
reg_val = chip->reg_output[off / BANK_SZ]
|
|
|
& ~(1u << (off % BANK_SZ));
|
|
|
|
|
|
- switch (chip->chip_type) {
|
|
|
- case PCA953X_TYPE:
|
|
|
- offset = PCA953X_OUTPUT;
|
|
|
- break;
|
|
|
- case PCA957X_TYPE:
|
|
|
- offset = PCA957X_OUT;
|
|
|
- break;
|
|
|
- }
|
|
|
- ret = pca953x_write_single(chip, offset, reg_val, off);
|
|
|
+ ret = pca953x_write_single(chip, chip->regs->output, reg_val, off);
|
|
|
if (ret)
|
|
|
goto exit;
|
|
|
|
|
@@ -279,15 +283,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
|
|
|
|
|
/* then direction */
|
|
|
reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ));
|
|
|
- switch (chip->chip_type) {
|
|
|
- case PCA953X_TYPE:
|
|
|
- offset = PCA953X_DIRECTION;
|
|
|
- break;
|
|
|
- case PCA957X_TYPE:
|
|
|
- offset = PCA957X_CFG;
|
|
|
- break;
|
|
|
- }
|
|
|
- ret = pca953x_write_single(chip, offset, reg_val, off);
|
|
|
+ ret = pca953x_write_single(chip, chip->regs->direction, reg_val, off);
|
|
|
if (ret)
|
|
|
goto exit;
|
|
|
|
|
@@ -301,18 +297,10 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
|
|
|
{
|
|
|
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
|
|
u32 reg_val;
|
|
|
- int ret, offset = 0;
|
|
|
+ int ret;
|
|
|
|
|
|
mutex_lock(&chip->i2c_lock);
|
|
|
- switch (chip->chip_type) {
|
|
|
- case PCA953X_TYPE:
|
|
|
- offset = PCA953X_INPUT;
|
|
|
- break;
|
|
|
- case PCA957X_TYPE:
|
|
|
- offset = PCA957X_IN;
|
|
|
- break;
|
|
|
- }
|
|
|
- ret = pca953x_read_single(chip, offset, ®_val, off);
|
|
|
+ ret = pca953x_read_single(chip, chip->regs->input, ®_val, off);
|
|
|
mutex_unlock(&chip->i2c_lock);
|
|
|
if (ret < 0) {
|
|
|
/* NOTE: diagnostic already emitted; that's all we should
|
|
@@ -329,7 +317,7 @@ 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, offset = 0;
|
|
|
+ int ret;
|
|
|
|
|
|
mutex_lock(&chip->i2c_lock);
|
|
|
if (val)
|
|
@@ -339,15 +327,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
|
|
|
reg_val = chip->reg_output[off / BANK_SZ]
|
|
|
& ~(1u << (off % BANK_SZ));
|
|
|
|
|
|
- switch (chip->chip_type) {
|
|
|
- case PCA953X_TYPE:
|
|
|
- offset = PCA953X_OUTPUT;
|
|
|
- break;
|
|
|
- case PCA957X_TYPE:
|
|
|
- offset = PCA957X_OUT;
|
|
|
- break;
|
|
|
- }
|
|
|
- ret = pca953x_write_single(chip, offset, reg_val, off);
|
|
|
+ ret = pca953x_write_single(chip, chip->regs->output, reg_val, off);
|
|
|
if (ret)
|
|
|
goto exit;
|
|
|
|
|
@@ -361,19 +341,10 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
|
|
|
{
|
|
|
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
|
|
u8 reg_val[MAX_BANK];
|
|
|
- int ret, offset = 0;
|
|
|
+ int ret;
|
|
|
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
|
|
|
int bank;
|
|
|
|
|
|
- switch (chip->chip_type) {
|
|
|
- case PCA953X_TYPE:
|
|
|
- offset = PCA953X_OUTPUT;
|
|
|
- break;
|
|
|
- case PCA957X_TYPE:
|
|
|
- offset = PCA957X_OUT;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
memcpy(reg_val, chip->reg_output, NBANK(chip));
|
|
|
mutex_lock(&chip->i2c_lock);
|
|
|
for(bank=0; bank<NBANK(chip); bank++) {
|
|
@@ -385,7 +356,9 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
|
|
|
reg_val[bank] = (reg_val[bank] & ~bankmask) | bankval;
|
|
|
}
|
|
|
}
|
|
|
- ret = i2c_smbus_write_i2c_block_data(chip->client, offset << bank_shift, NBANK(chip), reg_val);
|
|
|
+ ret = i2c_smbus_write_i2c_block_data(chip->client,
|
|
|
+ chip->regs->output << bank_shift,
|
|
|
+ NBANK(chip), reg_val);
|
|
|
if (ret)
|
|
|
goto exit;
|
|
|
|
|
@@ -517,7 +490,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 ret, i, offset = 0;
|
|
|
+ int ret, i;
|
|
|
|
|
|
if (chip->driver_data & PCA_PCAL) {
|
|
|
/* Read the current interrupt status from the device */
|
|
@@ -542,15 +515,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
|
|
|
return pending_seen;
|
|
|
}
|
|
|
|
|
|
- switch (chip->chip_type) {
|
|
|
- case PCA953X_TYPE:
|
|
|
- offset = PCA953X_INPUT;
|
|
|
- break;
|
|
|
- case PCA957X_TYPE:
|
|
|
- offset = PCA957X_IN;
|
|
|
- break;
|
|
|
- }
|
|
|
- ret = pca953x_read_regs(chip, offset, cur_stat);
|
|
|
+ ret = pca953x_read_regs(chip, chip->regs->input, cur_stat);
|
|
|
if (ret)
|
|
|
return false;
|
|
|
|
|
@@ -610,20 +575,13 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
|
|
|
int irq_base)
|
|
|
{
|
|
|
struct i2c_client *client = chip->client;
|
|
|
- int ret, i, offset = 0;
|
|
|
+ int ret, i;
|
|
|
|
|
|
if (client->irq && irq_base != -1
|
|
|
&& (chip->driver_data & PCA_INT)) {
|
|
|
|
|
|
- switch (chip->chip_type) {
|
|
|
- case PCA953X_TYPE:
|
|
|
- offset = PCA953X_INPUT;
|
|
|
- break;
|
|
|
- case PCA957X_TYPE:
|
|
|
- offset = PCA957X_IN;
|
|
|
- break;
|
|
|
- }
|
|
|
- ret = pca953x_read_regs(chip, offset, chip->irq_stat);
|
|
|
+ ret = pca953x_read_regs(chip,
|
|
|
+ chip->regs->input, chip->irq_stat);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -686,12 +644,14 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
|
|
|
int ret;
|
|
|
u8 val[MAX_BANK];
|
|
|
|
|
|
- ret = pca953x_read_regs(chip, PCA953X_OUTPUT, chip->reg_output);
|
|
|
+ chip->regs = &pca953x_regs;
|
|
|
+
|
|
|
+ ret = pca953x_read_regs(chip, chip->regs->output, chip->reg_output);
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
|
|
|
- ret = pca953x_read_regs(chip, PCA953X_DIRECTION,
|
|
|
- chip->reg_direction);
|
|
|
+ ret = pca953x_read_regs(chip, chip->regs->direction,
|
|
|
+ chip->reg_direction);
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
|
|
@@ -711,10 +671,13 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
|
|
|
int ret;
|
|
|
u8 val[MAX_BANK];
|
|
|
|
|
|
- ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output);
|
|
|
+ chip->regs = &pca957x_regs;
|
|
|
+
|
|
|
+ ret = pca953x_read_regs(chip, chip->regs->output, chip->reg_output);
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
- ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction);
|
|
|
+ ret = pca953x_read_regs(chip, chip->regs->direction,
|
|
|
+ chip->reg_direction);
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
|