/*
* PCA953x 4/8/16/24/40 bit I/O ports
*
* Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
* Copyright (C) 2007 Marvell International Ltd.
*
* Derived from drivers/i2c/chips/pca9539.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*/
#include <linux/acpi.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_data/pca953x.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
#define PCA953X_INPUT 0
#define PCA953X_OUTPUT 1
#define PCA953X_INVERT 2
#define PCA953X_DIRECTION 3
#define REG_ADDR_AI 0x80
#define PCA957X_IN 0
#define PCA957X_INVRT 1
#define PCA957X_BKEN 2
#define PCA957X_PUPD 3
#define PCA957X_CFG 4
#define PCA957X_OUT 5
#define PCA957X_MSK 6
#define PCA957X_INTS 7
#define PCAL953X_IN_LATCH 34
#define PCAL953X_INT_MASK 37
#define PCAL953X_INT_STAT 38
#define PCA_GPIO_MASK 0x00FF
#define PCA_INT 0x0100
#define PCA_PCAL 0x0200
#define PCA953X_TYPE 0x1000
#define PCA957X_TYPE 0x2000
#define PCA_TYPE_MASK 0xF000
#define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK)
static const struct i2c_device_id pca953x_id[] = {
{ "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
{ "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
{ "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
{ "pca9536", 4 | PCA953X_TYPE, },
{ "pca9537", 4 | PCA953X_TYPE | PCA_INT, },
{ "pca9538", 8 | PCA953X_TYPE | PCA_INT, },
{ "pca9539", 16 | PCA953X_TYPE | PCA_INT, },
{ "pca9554", 8 | PCA953X_TYPE | PCA_INT, },
{ "pca9555", 16 | PCA953X_TYPE | PCA_INT, },
{ "pca9556", 8 | PCA953X_TYPE, },
{ "pca9557", 8 | PCA953X_TYPE, },
{ "pca9574", 8 | PCA957X_TYPE | PCA_INT, },
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
{ "pca9698", 40 | PCA953X_TYPE, },
{ "pcal9555a", 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL, },
{ "max7310", 8 | PCA953X_TYPE, },
{ "max7312", 16 | PCA953X_TYPE | PCA_INT, },
{ "max7313", 16 | PCA953X_TYPE | PCA_INT, },
{ "max7315", 8 | PCA953X_TYPE | PCA_INT, },
{ "max7318", 16 | PCA953X_TYPE | PCA_INT, },
{ "pca6107", 8 | PCA953X_TYPE | PCA_INT, },
{ "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
{ "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
{ "tca9539", 16 | PCA953X_TYPE | PCA_INT, },
{ "tca9554", 8 | PCA953X_TYPE | PCA_INT, },
{ "xra1202", 8 | PCA953X_TYPE },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca953x_id);
static const struct acpi_device_id pca953x_acpi_ids[] = {
{ "INT3491", 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL, },
{ }
};
MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
#define MAX_BANK 5
#define BANK_SZ 8
#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];
u8 reg_direction[MAX_BANK];
struct mutex i2c_lock;
#ifdef CONFIG_GPIO_PCA953X_IRQ
struct mutex irq_lock;
u8 irq_mask[MAX_BANK];
u8 irq_stat[MAX_BANK];
u8 irq_trig_raise[MAX_BANK];
u8 irq_trig_fall[MAX_BANK];
#endif
struct i2c_client *client;
struct gpio_chip gpio_chip;
const char *const *names;
unsigned long driver_data;
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)
{
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;
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_8(struct pca953x_chip *chip, int reg, u8 *val)
{
return i2c_smbus_write_byte_data(chip->client, reg, *val);
}
static int pca953x_write_regs_16(struct pca953x_chip *chip, int