summaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl/pinctrl-cy8c95x0.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:03 +0000
commit01a69402cf9d38ff180345d55c2ee51c7e89fbc7 (patch)
treeb406c5242a088c4f59c6e4b719b783f43aca6ae9 /drivers/pinctrl/pinctrl-cy8c95x0.c
parentAdding upstream version 6.7.12. (diff)
downloadlinux-01a69402cf9d38ff180345d55c2ee51c7e89fbc7.tar.xz
linux-01a69402cf9d38ff180345d55c2ee51c7e89fbc7.zip
Adding upstream version 6.8.9.upstream/6.8.9
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/pinctrl/pinctrl-cy8c95x0.c')
-rw-r--r--drivers/pinctrl/pinctrl-cy8c95x0.c458
1 files changed, 315 insertions, 143 deletions
diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c
index fe9545c630..67b5d160c0 100644
--- a/drivers/pinctrl/pinctrl-cy8c95x0.c
+++ b/drivers/pinctrl/pinctrl-cy8c95x0.c
@@ -58,6 +58,10 @@
#define CY8C95X0_PIN_TO_OFFSET(x) (((x) >= 20) ? ((x) + 4) : (x))
+#define CY8C95X0_MUX_REGMAP_TO_PORT(x) ((x) / MUXED_STRIDE)
+#define CY8C95X0_MUX_REGMAP_TO_REG(x) (((x) % MUXED_STRIDE) + CY8C95X0_INTMASK)
+#define CY8C95X0_MUX_REGMAP_TO_OFFSET(x, p) ((x) - CY8C95X0_INTMASK + (p) * MUXED_STRIDE)
+
static const struct i2c_device_id cy8c95x0_id[] = {
{ "cy8c9520", 20, },
{ "cy8c9540", 40, },
@@ -119,12 +123,13 @@ static const struct dmi_system_id cy8c95x0_dmi_acpi_irq_info[] = {
#define MAX_BANK 8
#define BANK_SZ 8
#define MAX_LINE (MAX_BANK * BANK_SZ)
-
+#define MUXED_STRIDE 16
#define CY8C95X0_GPIO_MASK GENMASK(7, 0)
/**
* struct cy8c95x0_pinctrl - driver data
- * @regmap: Device's regmap
+ * @regmap: Device's regmap. Only direct access registers.
+ * @muxed_regmap: Regmap for all muxed registers.
* @irq_lock: IRQ bus lock
* @i2c_lock: Mutex for the device internal mux register
* @irq_mask: I/O bits affected by interrupts
@@ -147,6 +152,7 @@ static const struct dmi_system_id cy8c95x0_dmi_acpi_irq_info[] = {
*/
struct cy8c95x0_pinctrl {
struct regmap *regmap;
+ struct regmap *muxed_regmap;
struct mutex irq_lock;
struct mutex i2c_lock;
DECLARE_BITMAP(irq_mask, MAX_LINE);
@@ -379,6 +385,54 @@ static bool cy8c95x0_precious_register(struct device *dev, unsigned int reg)
}
}
+static bool cy8c95x0_muxed_register(unsigned int reg)
+{
+ switch (reg) {
+ case CY8C95X0_INTMASK:
+ case CY8C95X0_PWMSEL:
+ case CY8C95X0_INVERT:
+ case CY8C95X0_DIRECTION:
+ case CY8C95X0_DRV_PU:
+ case CY8C95X0_DRV_PD:
+ case CY8C95X0_DRV_ODH:
+ case CY8C95X0_DRV_ODL:
+ case CY8C95X0_DRV_PP_FAST:
+ case CY8C95X0_DRV_PP_SLOW:
+ case CY8C95X0_DRV_HIZ:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cy8c95x0_wc_register(unsigned int reg)
+{
+ switch (reg) {
+ case CY8C95X0_DRV_PU:
+ case CY8C95X0_DRV_PD:
+ case CY8C95X0_DRV_ODH:
+ case CY8C95X0_DRV_ODL:
+ case CY8C95X0_DRV_PP_FAST:
+ case CY8C95X0_DRV_PP_SLOW:
+ case CY8C95X0_DRV_HIZ:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cy8c95x0_quick_path_register(unsigned int reg)
+{
+ switch (reg) {
+ case CY8C95X0_INPUT_(0) ... CY8C95X0_INPUT_(7):
+ case CY8C95X0_INTSTATUS_(0) ... CY8C95X0_INTSTATUS_(7):
+ case CY8C95X0_OUTPUT_(0) ... CY8C95X0_OUTPUT_(7):
+ return true;
+ default:
+ return false;
+ }
+}
+
static const struct reg_default cy8c95x0_reg_defaults[] = {
{ CY8C95X0_OUTPUT_(0), GENMASK(7, 0) },
{ CY8C95X0_OUTPUT_(1), GENMASK(7, 0) },
@@ -392,7 +446,89 @@ static const struct reg_default cy8c95x0_reg_defaults[] = {
{ CY8C95X0_PWMSEL, 0 },
};
+static int
+cy8c95x0_mux_reg_read(void *context, unsigned int off, unsigned int *val)
+{
+ struct cy8c95x0_pinctrl *chip = context;
+ u8 port = CY8C95X0_MUX_REGMAP_TO_PORT(off);
+ int ret, reg = CY8C95X0_MUX_REGMAP_TO_REG(off);
+
+ mutex_lock(&chip->i2c_lock);
+ /* Select the correct bank */
+ ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
+ if (ret < 0)
+ goto out;
+
+ /*
+ * Read the register through direct access regmap. The target range
+ * is marked volatile.
+ */
+ ret = regmap_read(chip->regmap, reg, val);
+out:
+ mutex_unlock(&chip->i2c_lock);
+
+ return ret;
+}
+
+static int
+cy8c95x0_mux_reg_write(void *context, unsigned int off, unsigned int val)
+{
+ struct cy8c95x0_pinctrl *chip = context;
+ u8 port = CY8C95X0_MUX_REGMAP_TO_PORT(off);
+ int ret, reg = CY8C95X0_MUX_REGMAP_TO_REG(off);
+
+ mutex_lock(&chip->i2c_lock);
+ /* Select the correct bank */
+ ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
+ if (ret < 0)
+ goto out;
+
+ /*
+ * Write the register through direct access regmap. The target range
+ * is marked volatile.
+ */
+ ret = regmap_write(chip->regmap, reg, val);
+out:
+ mutex_unlock(&chip->i2c_lock);
+
+ return ret;
+}
+
+static bool cy8c95x0_mux_accessible_register(struct device *dev, unsigned int off)
+{
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct cy8c95x0_pinctrl *chip = i2c_get_clientdata(i2c);
+ u8 port = CY8C95X0_MUX_REGMAP_TO_PORT(off);
+ u8 reg = CY8C95X0_MUX_REGMAP_TO_REG(off);
+
+ if (port >= chip->nport)
+ return false;
+
+ return cy8c95x0_muxed_register(reg);
+}
+
+static struct regmap_bus cy8c95x0_regmap_bus = {
+ .reg_read = cy8c95x0_mux_reg_read,
+ .reg_write = cy8c95x0_mux_reg_write,
+};
+
+/* Regmap for muxed registers CY8C95X0_INTMASK - CY8C95X0_DRV_HIZ */
+static const struct regmap_config cy8c95x0_muxed_regmap = {
+ .name = "muxed",
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_FLAT,
+ .use_single_read = true,
+ .use_single_write = true,
+ .max_register = MUXED_STRIDE * BANK_SZ,
+ .num_reg_defaults_raw = MUXED_STRIDE * BANK_SZ,
+ .readable_reg = cy8c95x0_mux_accessible_register,
+ .writeable_reg = cy8c95x0_mux_accessible_register,
+};
+
+/* Direct access regmap */
static const struct regmap_config cy8c95x0_i2c_regmap = {
+ .name = "direct",
.reg_bits = 8,
.val_bits = 8,
@@ -408,6 +544,147 @@ static const struct regmap_config cy8c95x0_i2c_regmap = {
.max_register = CY8C95X0_COMMAND,
};
+static inline int cy8c95x0_regmap_update_bits_base(struct cy8c95x0_pinctrl *chip,
+ unsigned int reg,
+ unsigned int port,
+ unsigned int mask,
+ unsigned int val,
+ bool *change, bool async,
+ bool force)
+{
+ struct regmap *regmap;
+ int ret, off, i, read_val;
+
+ /* Caller should never modify PORTSEL directly */
+ if (reg == CY8C95X0_PORTSEL)
+ return -EINVAL;
+
+ /* Registers behind the PORTSEL mux have their own regmap */
+ if (cy8c95x0_muxed_register(reg)) {
+ regmap = chip->muxed_regmap;
+ off = CY8C95X0_MUX_REGMAP_TO_OFFSET(reg, port);
+ } else {
+ regmap = chip->regmap;
+ /* Quick path direct access registers honor the port argument */
+ if (cy8c95x0_quick_path_register(reg))
+ off = reg + port;
+ else
+ off = reg;
+ }
+
+ ret = regmap_update_bits_base(regmap, off, mask, val, change, async, force);
+ if (ret < 0)
+ return ret;
+
+ /* Update the cache when a WC bit is written */
+ if (cy8c95x0_wc_register(reg) && (mask & val)) {
+ for (i = CY8C95X0_DRV_PU; i <= CY8C95X0_DRV_HIZ; i++) {
+ if (i == reg)
+ continue;
+ off = CY8C95X0_MUX_REGMAP_TO_OFFSET(i, port);
+
+ ret = regmap_read(regmap, off, &read_val);
+ if (ret < 0)
+ continue;
+
+ if (!(read_val & mask & val))
+ continue;
+
+ regcache_cache_only(regmap, true);
+ regmap_update_bits(regmap, off, mask & val, 0);
+ regcache_cache_only(regmap, false);
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * cy8c95x0_regmap_write_bits() - writes a register using the regmap cache
+ * @chip: The pinctrl to work on
+ * @reg: The register to write to. Can be direct access or muxed register.
+ * MUST NOT be the PORTSEL register.
+ * @port: The port to be used for muxed registers or quick path direct access
+ * registers. Otherwise unused.
+ * @mask: Bitmask to change
+ * @val: New value for bitmask
+ *
+ * This function handles the register writes to the direct access registers and
+ * the muxed registers while caching all register accesses, internally handling
+ * the correct state of the PORTSEL register and protecting the access to muxed
+ * registers.
+ * The caller must only use this function to change registers behind the PORTSEL mux.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int cy8c95x0_regmap_write_bits(struct cy8c95x0_pinctrl *chip, unsigned int reg,
+ unsigned int port, unsigned int mask, unsigned int val)
+{
+ return cy8c95x0_regmap_update_bits_base(chip, reg, port, mask, val, NULL, false, true);
+}
+
+/**
+ * cy8c95x0_regmap_update_bits() - updates a register using the regmap cache
+ * @chip: The pinctrl to work on
+ * @reg: The register to write to. Can be direct access or muxed register.
+ * MUST NOT be the PORTSEL register.
+ * @port: The port to be used for muxed registers or quick path direct access
+ * registers. Otherwise unused.
+ * @mask: Bitmask to change
+ * @val: New value for bitmask
+ *
+ * This function handles the register updates to the direct access registers and
+ * the muxed registers while caching all register accesses, internally handling
+ * the correct state of the PORTSEL register and protecting the access to muxed
+ * registers.
+ * The caller must only use this function to change registers behind the PORTSEL mux.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int cy8c95x0_regmap_update_bits(struct cy8c95x0_pinctrl *chip, unsigned int reg,
+ unsigned int port, unsigned int mask, unsigned int val)
+{
+ return cy8c95x0_regmap_update_bits_base(chip, reg, port, mask, val, NULL, false, false);
+}
+
+/**
+ * cy8c95x0_regmap_read() - reads a register using the regmap cache
+ * @chip: The pinctrl to work on
+ * @reg: The register to read from. Can be direct access or muxed register.
+ * @port: The port to be used for muxed registers or quick path direct access
+ * registers. Otherwise unused.
+ * @read_val: Value read from hardware or cache
+ *
+ * This function handles the register reads from the direct access registers and
+ * the muxed registers while caching all register accesses, internally handling
+ * the correct state of the PORTSEL register and protecting the access to muxed
+ * registers.
+ * The caller must only use this function to read registers behind the PORTSEL mux.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int cy8c95x0_regmap_read(struct cy8c95x0_pinctrl *chip, unsigned int reg,
+ unsigned int port, unsigned int *read_val)
+{
+ struct regmap *regmap;
+ int off;
+
+ /* Registers behind the PORTSEL mux have their own regmap */
+ if (cy8c95x0_muxed_register(reg)) {
+ regmap = chip->muxed_regmap;
+ off = CY8C95X0_MUX_REGMAP_TO_OFFSET(reg, port);
+ } else {
+ regmap = chip->regmap;
+ /* Quick path direct access registers honor the port argument */
+ if (cy8c95x0_quick_path_register(reg))
+ off = reg + port;
+ else
+ off = reg;
+ }
+
+ return regmap_read(regmap, off, read_val);
+}
+
static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
unsigned long *val, unsigned long *mask)
{
@@ -415,7 +692,7 @@ static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
DECLARE_BITMAP(tval, MAX_LINE);
int write_val;
int ret = 0;
- int i, off = 0;
+ int i;
u8 bits;
/* Add the 4 bit gap of Gport2 */
@@ -427,53 +704,22 @@ static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
bitmap_shift_left(tval, tval, 4, MAX_LINE);
bitmap_replace(tval, tval, val, chip->shiftmask, BANK_SZ * 3);
- mutex_lock(&chip->i2c_lock);
for (i = 0; i < chip->nport; i++) {
/* Skip over unused banks */
bits = bitmap_get_value8(tmask, i * BANK_SZ);
if (!bits)
continue;
- switch (reg) {
- /* Muxed registers */
- case CY8C95X0_INTMASK:
- case CY8C95X0_PWMSEL:
- case CY8C95X0_INVERT:
- case CY8C95X0_DIRECTION:
- case CY8C95X0_DRV_PU:
- case CY8C95X0_DRV_PD:
- case CY8C95X0_DRV_ODH:
- case CY8C95X0_DRV_ODL:
- case CY8C95X0_DRV_PP_FAST:
- case CY8C95X0_DRV_PP_SLOW:
- case CY8C95X0_DRV_HIZ:
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, i);
- if (ret < 0)
- goto out;
- off = reg;
- break;
- /* Direct access registers */
- case CY8C95X0_INPUT:
- case CY8C95X0_OUTPUT:
- case CY8C95X0_INTSTATUS:
- off = reg + i;
- break;
- default:
- ret = -EINVAL;
- goto out;
- }
-
write_val = bitmap_get_value8(tval, i * BANK_SZ);
- ret = regmap_update_bits(chip->regmap, off, bits, write_val);
+ ret = cy8c95x0_regmap_update_bits(chip, reg, i, bits, write_val);
if (ret < 0)
goto out;
}
out:
- mutex_unlock(&chip->i2c_lock);
if (ret < 0)
- dev_err(chip->dev, "failed writing register %d: err %d\n", off, ret);
+ dev_err(chip->dev, "failed writing register %d, port %d: err %d\n", reg, i, ret);
return ret;
}
@@ -486,7 +732,7 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
DECLARE_BITMAP(tmp, MAX_LINE);
int read_val;
int ret = 0;
- int i, off = 0;
+ int i;
u8 bits;
/* Add the 4 bit gap of Gport2 */
@@ -498,43 +744,13 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
bitmap_shift_left(tval, tval, 4, MAX_LINE);
bitmap_replace(tval, tval, val, chip->shiftmask, BANK_SZ * 3);
- mutex_lock(&chip->i2c_lock);
for (i = 0; i < chip->nport; i++) {
/* Skip over unused banks */
bits = bitmap_get_value8(tmask, i * BANK_SZ);
if (!bits)
continue;
- switch (reg) {
- /* Muxed registers */
- case CY8C95X0_INTMASK:
- case CY8C95X0_PWMSEL:
- case CY8C95X0_INVERT:
- case CY8C95X0_DIRECTION:
- case CY8C95X0_DRV_PU:
- case CY8C95X0_DRV_PD:
- case CY8C95X0_DRV_ODH:
- case CY8C95X0_DRV_ODL:
- case CY8C95X0_DRV_PP_FAST:
- case CY8C95X0_DRV_PP_SLOW:
- case CY8C95X0_DRV_HIZ:
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, i);
- if (ret < 0)
- goto out;
- off = reg;
- break;
- /* Direct access registers */
- case CY8C95X0_INPUT:
- case CY8C95X0_OUTPUT:
- case CY8C95X0_INTSTATUS:
- off = reg + i;
- break;
- default:
- ret = -EINVAL;
- goto out;
- }
-
- ret = regmap_read(chip->regmap, off, &read_val);
+ ret = cy8c95x0_regmap_read(chip, reg, i, &read_val);
if (ret < 0)
goto out;
@@ -548,10 +764,8 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
bitmap_replace(val, tmp, tval, chip->shiftmask, MAX_LINE);
out:
- mutex_unlock(&chip->i2c_lock);
-
if (ret < 0)
- dev_err(chip->dev, "failed reading register %d: err %d\n", off, ret);
+ dev_err(chip->dev, "failed reading register %d, port %d: err %d\n", reg, i, ret);
return ret;
}
@@ -566,12 +780,11 @@ static int cy8c95x0_gpio_direction_output(struct gpio_chip *gc,
{
struct cy8c95x0_pinctrl *chip = gpiochip_get_data(gc);
u8 port = cypress_get_port(chip, off);
- u8 outreg = CY8C95X0_OUTPUT_(port);
u8 bit = cypress_get_pin_mask(chip, off);
int ret;
/* Set output level */
- ret = regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0);
+ ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_OUTPUT, port, bit, val ? bit : 0);
if (ret)
return ret;
@@ -581,12 +794,12 @@ static int cy8c95x0_gpio_direction_output(struct gpio_chip *gc,
static int cy8c95x0_gpio_get_value(struct gpio_chip *gc, unsigned int off)
{
struct cy8c95x0_pinctrl *chip = gpiochip_get_data(gc);
- u8 inreg = CY8C95X0_INPUT_(cypress_get_port(chip, off));
+ u8 port = cypress_get_port(chip, off);
u8 bit = cypress_get_pin_mask(chip, off);
u32 reg_val;
int ret;
- ret = regmap_read(chip->regmap, inreg, &reg_val);
+ ret = cy8c95x0_regmap_read(chip, CY8C95X0_INPUT, port, &reg_val);
if (ret < 0) {
/*
* NOTE:
@@ -604,10 +817,10 @@ static void cy8c95x0_gpio_set_value(struct gpio_chip *gc, unsigned int off,
int val)
{
struct cy8c95x0_pinctrl *chip = gpiochip_get_data(gc);
- u8 outreg = CY8C95X0_OUTPUT_(cypress_get_port(chip, off));
+ u8 port = cypress_get_port(chip, off);
u8 bit = cypress_get_pin_mask(chip, off);
- regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0);
+ cy8c95x0_regmap_write_bits(chip, CY8C95X0_OUTPUT, port, bit, val ? bit : 0);
}
static int cy8c95x0_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
@@ -618,24 +831,15 @@ static int cy8c95x0_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
u32 reg_val;
int ret;
- mutex_lock(&chip->i2c_lock);
-
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
- if (ret < 0)
- goto out;
-
- ret = regmap_read(chip->regmap, CY8C95X0_DIRECTION, &reg_val);
+ ret = cy8c95x0_regmap_read(chip, CY8C95X0_DIRECTION, port, &reg_val);
if (ret < 0)
goto out;
- mutex_unlock(&chip->i2c_lock);
-
if (reg_val & bit)
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
out:
- mutex_unlock(&chip->i2c_lock);
return ret;
}
@@ -651,13 +855,6 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip,
u16 arg = 0;
int ret;
- mutex_lock(&chip->i2c_lock);
-
- /* Select port */
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
- if (ret < 0)
- goto out;
-
switch (param) {
case PIN_CONFIG_BIAS_PULL_UP:
reg = CY8C95X0_DRV_PU;
@@ -684,7 +881,7 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip,
reg = CY8C95X0_PWMSEL;
break;
case PIN_CONFIG_OUTPUT:
- reg = CY8C95X0_OUTPUT_(port);
+ reg = CY8C95X0_OUTPUT;
break;
case PIN_CONFIG_OUTPUT_ENABLE:
reg = CY8C95X0_DIRECTION;
@@ -712,7 +909,10 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip,
* Writing 1 to one of the drive mode registers will automatically
* clear conflicting set bits in the other drive mode registers.
*/
- ret = regmap_read(chip->regmap, reg, &reg_val);
+ ret = cy8c95x0_regmap_read(chip, reg, port, &reg_val);
+ if (ret < 0)
+ goto out;
+
if (reg_val & bit)
arg = 1;
if (param == PIN_CONFIG_OUTPUT_ENABLE)
@@ -720,8 +920,6 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip,
*config = pinconf_to_config_packed(param, (u16)arg);
out:
- mutex_unlock(&chip->i2c_lock);
-
return ret;
}
@@ -736,13 +934,6 @@ static int cy8c95x0_gpio_set_pincfg(struct cy8c95x0_pinctrl *chip,
unsigned int reg;
int ret;
- mutex_lock(&chip->i2c_lock);
-
- /* Select port */
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
- if (ret < 0)
- goto out;
-
switch (param) {
case PIN_CONFIG_BIAS_PULL_UP:
__clear_bit(off, chip->push_pull);
@@ -785,10 +976,8 @@ static int cy8c95x0_gpio_set_pincfg(struct cy8c95x0_pinctrl *chip,
* Writing 1 to one of the drive mode registers will automatically
* clear conflicting set bits in the other drive mode registers.
*/
- ret = regmap_write_bits(chip->regmap, reg, bit, bit);
-
+ ret = cy8c95x0_regmap_write_bits(chip, reg, port, bit, bit);
out:
- mutex_unlock(&chip->i2c_lock);
return ret;
}
@@ -1105,14 +1294,8 @@ static int cy8c95x0_set_mode(struct cy8c95x0_pinctrl *chip, unsigned int off, bo
{
u8 port = cypress_get_port(chip, off);
u8 bit = cypress_get_pin_mask(chip, off);
- int ret;
- /* Select port */
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
- if (ret < 0)
- return ret;
-
- return regmap_write_bits(chip->regmap, CY8C95X0_PWMSEL, bit, mode ? bit : 0);
+ return cy8c95x0_regmap_write_bits(chip, CY8C95X0_PWMSEL, port, bit, mode ? bit : 0);
}
static int cy8c95x0_pinmux_mode(struct cy8c95x0_pinctrl *chip,
@@ -1130,24 +1313,19 @@ static int cy8c95x0_pinmux_mode(struct cy8c95x0_pinctrl *chip,
return 0;
/* Set direction to output & set output to 1 so that PWM can work */
- ret = regmap_write_bits(chip->regmap, CY8C95X0_DIRECTION, bit, bit);
+ ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DIRECTION, port, bit, bit);
if (ret < 0)
return ret;
- return regmap_write_bits(chip->regmap, CY8C95X0_OUTPUT_(port), bit, bit);
+ return cy8c95x0_regmap_write_bits(chip, CY8C95X0_OUTPUT, port, bit, bit);
}
static int cy8c95x0_set_mux(struct pinctrl_dev *pctldev, unsigned int selector,
unsigned int group)
{
struct cy8c95x0_pinctrl *chip = pinctrl_dev_get_drvdata(pctldev);
- int ret;
- mutex_lock(&chip->i2c_lock);
- ret = cy8c95x0_pinmux_mode(chip, selector, group);
- mutex_unlock(&chip->i2c_lock);
-
- return ret;
+ return cy8c95x0_pinmux_mode(chip, selector, group);
}
static int cy8c95x0_gpio_request_enable(struct pinctrl_dev *pctldev,
@@ -1155,13 +1333,8 @@ static int cy8c95x0_gpio_request_enable(struct pinctrl_dev *pctldev,
unsigned int pin)
{
struct cy8c95x0_pinctrl *chip = pinctrl_dev_get_drvdata(pctldev);
- int ret;
-
- mutex_lock(&chip->i2c_lock);
- ret = cy8c95x0_set_mode(chip, pin, false);
- mutex_unlock(&chip->i2c_lock);
- return ret;
+ return cy8c95x0_set_mode(chip, pin, false);
}
static int cy8c95x0_pinmux_direction(struct cy8c95x0_pinctrl *chip,
@@ -1171,13 +1344,7 @@ static int cy8c95x0_pinmux_direction(struct cy8c95x0_pinctrl *chip,
u8 bit = cypress_get_pin_mask(chip, pin);
int ret;
- /* Select port... */
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
- if (ret)
- return ret;
-
- /* ...then direction */
- ret = regmap_write_bits(chip->regmap, CY8C95X0_DIRECTION, bit, input ? bit : 0);
+ ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DIRECTION, port, bit, input ? bit : 0);
if (ret)
return ret;
@@ -1186,7 +1353,7 @@ static int cy8c95x0_pinmux_direction(struct cy8c95x0_pinctrl *chip,
* the direction register isn't sufficient in Push-Pull mode.
*/
if (input && test_bit(pin, chip->push_pull)) {
- ret = regmap_write_bits(chip->regmap, CY8C95X0_DRV_HIZ, bit, bit);
+ ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DRV_HIZ, port, bit, bit);
if (ret)
return ret;
@@ -1201,13 +1368,8 @@ static int cy8c95x0_gpio_set_direction(struct pinctrl_dev *pctldev,
unsigned int pin, bool input)
{
struct cy8c95x0_pinctrl *chip = pinctrl_dev_get_drvdata(pctldev);
- int ret;
- mutex_lock(&chip->i2c_lock);
- ret = cy8c95x0_pinmux_direction(chip, pin, input);
- mutex_unlock(&chip->i2c_lock);
-
- return ret;
+ return cy8c95x0_pinmux_direction(chip, pin, input);
}
static const struct pinmux_ops cy8c95x0_pmxops = {
@@ -1409,12 +1571,22 @@ static int cy8c95x0_probe(struct i2c_client *client)
gpiod_set_consumer_name(chip->gpio_reset, "CY8C95X0 RESET");
}
+ /* Generic regmap for direct access registers */
chip->regmap = devm_regmap_init_i2c(client, &cy8c95x0_i2c_regmap);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
goto err_exit;
}
+ /* Port specific regmap behind PORTSEL mux */
+ chip->muxed_regmap = devm_regmap_init(&client->dev, &cy8c95x0_regmap_bus,
+ chip, &cy8c95x0_muxed_regmap);
+ if (IS_ERR(chip->muxed_regmap)) {
+ ret = dev_err_probe(&client->dev, PTR_ERR(chip->muxed_regmap),
+ "Failed to register muxed regmap\n");
+ goto err_exit;
+ }
+
bitmap_zero(chip->push_pull, MAX_LINE);
bitmap_zero(chip->shiftmask, MAX_LINE);
bitmap_set(chip->shiftmask, 0, 20);