pinctrl-sx150x: Convert driver to use regmap API
To allow for future code simplification Tested-by: Neil Armstrong <narmstrong@baylibre.com> Acked-by: Neil Armstrong <narmstrong@baylibre.com> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
b30d31e40e
commit
0db0f26c2c
|
@ -171,6 +171,7 @@ config PINCTRL_SX150X
|
||||||
select PINCONF
|
select PINCONF
|
||||||
select GENERIC_PINCONF
|
select GENERIC_PINCONF
|
||||||
select GPIOLIB_IRQCHIP
|
select GPIOLIB_IRQCHIP
|
||||||
|
select REGMAP
|
||||||
help
|
help
|
||||||
Say yes here to provide support for Semtech SX150x-series I2C
|
Say yes here to provide support for Semtech SX150x-series I2C
|
||||||
GPIO expanders as pinctrl module.
|
GPIO expanders as pinctrl module.
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/regmap.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
@ -45,6 +46,7 @@ enum {
|
||||||
};
|
};
|
||||||
enum {
|
enum {
|
||||||
SX150X_789_REG_MISC_AUTOCLEAR_OFF = 1 << 0,
|
SX150X_789_REG_MISC_AUTOCLEAR_OFF = 1 << 0,
|
||||||
|
SX150X_MAX_REGISTER = 0xad,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sx150x_123_pri {
|
struct sx150x_123_pri {
|
||||||
|
@ -102,6 +104,7 @@ struct sx150x_pinctrl {
|
||||||
struct pinctrl_desc pinctrl_desc;
|
struct pinctrl_desc pinctrl_desc;
|
||||||
struct gpio_chip gpio;
|
struct gpio_chip gpio;
|
||||||
struct irq_chip irq_chip;
|
struct irq_chip irq_chip;
|
||||||
|
struct regmap *regmap;
|
||||||
struct {
|
struct {
|
||||||
int update;
|
int update;
|
||||||
u32 sense;
|
u32 sense;
|
||||||
|
@ -256,30 +259,6 @@ static const struct sx150x_device_data sx1503q_device_data = {
|
||||||
.npins = 16, /* oscio not available */
|
.npins = 16, /* oscio not available */
|
||||||
};
|
};
|
||||||
|
|
||||||
static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val)
|
|
||||||
{
|
|
||||||
s32 err = i2c_smbus_write_byte_data(client, reg, val);
|
|
||||||
|
|
||||||
if (err < 0)
|
|
||||||
dev_warn(&client->dev,
|
|
||||||
"i2c write fail: can't write %02x to %02x: %d\n",
|
|
||||||
val, reg, err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static s32 sx150x_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
|
|
||||||
{
|
|
||||||
s32 err = i2c_smbus_read_byte_data(client, reg);
|
|
||||||
|
|
||||||
if (err >= 0)
|
|
||||||
*val = err;
|
|
||||||
else
|
|
||||||
dev_warn(&client->dev,
|
|
||||||
"i2c read fail: can't read from %02x: %d\n",
|
|
||||||
reg, err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These utility functions solve the common problem of locating and setting
|
* These utility functions solve the common problem of locating and setting
|
||||||
* configuration bits. Configuration bits are grouped into registers
|
* configuration bits. Configuration bits are grouped into registers
|
||||||
|
@ -312,30 +291,32 @@ static int sx150x_write_cfg(struct i2c_client *client,
|
||||||
u8 offset, u8 width, u8 reg, u8 val)
|
u8 offset, u8 width, u8 reg, u8 val)
|
||||||
{
|
{
|
||||||
u8 mask;
|
u8 mask;
|
||||||
u8 data;
|
unsigned int data;
|
||||||
u8 shift;
|
u8 shift;
|
||||||
int err;
|
int err;
|
||||||
|
struct sx150x_pinctrl *pctl = i2c_get_clientdata(client);
|
||||||
|
|
||||||
sx150x_find_cfg(offset, width, ®, &mask, &shift);
|
sx150x_find_cfg(offset, width, ®, &mask, &shift);
|
||||||
err = sx150x_i2c_read(client, reg, &data);
|
err = regmap_read(pctl->regmap, reg, &data);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
data &= ~mask;
|
data &= ~mask;
|
||||||
data |= (val << shift) & mask;
|
data |= (val << shift) & mask;
|
||||||
return sx150x_i2c_write(client, reg, data);
|
return regmap_write(pctl->regmap, reg, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sx150x_read_cfg(struct i2c_client *client,
|
static int sx150x_read_cfg(struct i2c_client *client,
|
||||||
u8 offset, u8 width, u8 reg)
|
u8 offset, u8 width, u8 reg)
|
||||||
{
|
{
|
||||||
u8 mask;
|
u8 mask;
|
||||||
u8 data;
|
unsigned int data;
|
||||||
u8 shift;
|
u8 shift;
|
||||||
int err;
|
int err;
|
||||||
|
struct sx150x_pinctrl *pctl = i2c_get_clientdata(client);
|
||||||
|
|
||||||
sx150x_find_cfg(offset, width, ®, &mask, &shift);
|
sx150x_find_cfg(offset, width, ®, &mask, &shift);
|
||||||
err = sx150x_i2c_read(client, reg, &data);
|
err = regmap_read(pctl->regmap, reg, &data);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -463,11 +444,10 @@ static void sx150x_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||||
struct sx150x_pinctrl *pctl = gpiochip_get_data(chip);
|
struct sx150x_pinctrl *pctl = gpiochip_get_data(chip);
|
||||||
|
|
||||||
if (sx150x_pin_is_oscio(pctl, offset)) {
|
if (sx150x_pin_is_oscio(pctl, offset)) {
|
||||||
|
|
||||||
mutex_lock(&pctl->lock);
|
mutex_lock(&pctl->lock);
|
||||||
sx150x_i2c_write(pctl->client,
|
regmap_write(pctl->regmap,
|
||||||
pctl->data->pri.x789.reg_clock,
|
pctl->data->pri.x789.reg_clock,
|
||||||
(value ? 0x1f : 0x10));
|
(value ? 0x1f : 0x10));
|
||||||
mutex_unlock(&pctl->lock);
|
mutex_unlock(&pctl->lock);
|
||||||
} else {
|
} else {
|
||||||
mutex_lock(&pctl->lock);
|
mutex_lock(&pctl->lock);
|
||||||
|
@ -567,19 +547,19 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id)
|
||||||
unsigned int sub_irq;
|
unsigned int sub_irq;
|
||||||
unsigned int n;
|
unsigned int n;
|
||||||
s32 err;
|
s32 err;
|
||||||
u8 val;
|
unsigned int val;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = (pctl->data->ngpios / 8) - 1; i >= 0; --i) {
|
for (i = (pctl->data->ngpios / 8) - 1; i >= 0; --i) {
|
||||||
err = sx150x_i2c_read(pctl->client,
|
err = regmap_read(pctl->regmap,
|
||||||
pctl->data->reg_irq_src - i,
|
pctl->data->reg_irq_src - i,
|
||||||
&val);
|
&val);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
err = sx150x_i2c_write(pctl->client,
|
err = regmap_write(pctl->regmap,
|
||||||
pctl->data->reg_irq_src - i,
|
pctl->data->reg_irq_src - i,
|
||||||
val);
|
val);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -650,15 +630,15 @@ static int sx150x_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
|
||||||
u32 arg;
|
u32 arg;
|
||||||
|
|
||||||
if (sx150x_pin_is_oscio(pctl, pin)) {
|
if (sx150x_pin_is_oscio(pctl, pin)) {
|
||||||
u8 data;
|
unsigned int data;
|
||||||
|
|
||||||
switch (param) {
|
switch (param) {
|
||||||
case PIN_CONFIG_DRIVE_PUSH_PULL:
|
case PIN_CONFIG_DRIVE_PUSH_PULL:
|
||||||
case PIN_CONFIG_OUTPUT:
|
case PIN_CONFIG_OUTPUT:
|
||||||
mutex_lock(&pctl->lock);
|
mutex_lock(&pctl->lock);
|
||||||
ret = sx150x_i2c_read(pctl->client,
|
ret = regmap_read(pctl->regmap,
|
||||||
pctl->data->pri.x789.reg_clock,
|
pctl->data->pri.x789.reg_clock,
|
||||||
&data);
|
&data);
|
||||||
mutex_unlock(&pctl->lock);
|
mutex_unlock(&pctl->lock);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -904,7 +884,7 @@ static int sx150x_init_io(struct sx150x_pinctrl *pctl, u8 base, u16 cfg)
|
||||||
unsigned int n;
|
unsigned int n;
|
||||||
|
|
||||||
for (n = 0; err >= 0 && n < (pctl->data->ngpios / 8); ++n)
|
for (n = 0; err >= 0 && n < (pctl->data->ngpios / 8); ++n)
|
||||||
err = sx150x_i2c_write(pctl->client, base - n, cfg >> (n * 8));
|
err = regmap_write(pctl->regmap, base - n, cfg >> (n * 8));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -953,7 +933,7 @@ static int sx150x_init_misc(struct sx150x_pinctrl *pctl)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sx150x_i2c_write(pctl->client, reg, value);
|
return i2c_smbus_write_byte_data(pctl->client, reg, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sx150x_init_hw(struct sx150x_pinctrl *pctl)
|
static int sx150x_init_hw(struct sx150x_pinctrl *pctl)
|
||||||
|
@ -997,6 +977,26 @@ static int sx150x_init_hw(struct sx150x_pinctrl *pctl)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool sx150x_reg_volatile(struct device *dev, unsigned int reg)
|
||||||
|
{
|
||||||
|
struct sx150x_pinctrl *pctl = i2c_get_clientdata(to_i2c_client(dev));
|
||||||
|
|
||||||
|
return reg == pctl->data->reg_irq_src ||
|
||||||
|
reg == pctl->data->reg_irq_src - 1 ||
|
||||||
|
reg == pctl->data->reg_data ||
|
||||||
|
reg == pctl->data->reg_data - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct regmap_config sx150x_regmap_config = {
|
||||||
|
.reg_bits = 8,
|
||||||
|
.val_bits = 8,
|
||||||
|
|
||||||
|
.cache_type = REGCACHE_RBTREE,
|
||||||
|
|
||||||
|
.max_register = SX150X_MAX_REGISTER,
|
||||||
|
.volatile_reg = sx150x_reg_volatile,
|
||||||
|
};
|
||||||
|
|
||||||
static int sx150x_probe(struct i2c_client *client,
|
static int sx150x_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
|
@ -1013,6 +1013,8 @@ static int sx150x_probe(struct i2c_client *client,
|
||||||
if (!pctl)
|
if (!pctl)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, pctl);
|
||||||
|
|
||||||
pctl->dev = dev;
|
pctl->dev = dev;
|
||||||
pctl->client = client;
|
pctl->client = client;
|
||||||
|
|
||||||
|
@ -1024,6 +1026,14 @@ static int sx150x_probe(struct i2c_client *client,
|
||||||
if (!pctl->data)
|
if (!pctl->data)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
pctl->regmap = devm_regmap_init_i2c(client, &sx150x_regmap_config);
|
||||||
|
if (IS_ERR(pctl->regmap)) {
|
||||||
|
ret = PTR_ERR(pctl->regmap);
|
||||||
|
dev_err(dev, "Failed to allocate register map: %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_init(&pctl->lock);
|
mutex_init(&pctl->lock);
|
||||||
|
|
||||||
ret = sx150x_init_hw(pctl);
|
ret = sx150x_init_hw(pctl);
|
||||||
|
|
Loading…
Reference in New Issue