[v2,2/5] gpio: pca953x: add register definitions for pcal6524 and fix address calculation

Message ID 69ab73657c5e75db94fab027c9957dbbb73047a7.1522868423.git.hns@goldelico.com
State New
Headers show
Series
  • none
Related show

Commit Message

H. Nikolaus Schaller April 4, 2018, 7 p.m.
PCAL chips ("L" seems to stand for "latched") have additional
registers starting at address 0x40 to control the latches,
interrupt mask, pull-up and pull down etc.

The constants are so far defined in a way that they fit for
the pcal9555a when shifted by the number of banks, i.e. multiplied
by 2.

Now the pcal6524 has 3 banks which means the relative offset
must be multiplied by 4 which gives a wrong result if not done
carefully, since the base offset is already included in the offset.

For the basic registers shared with all pca93xx/tca64xx chips
there is no such offset.

Therefore, we add code to adjust the register number for exended
registers in this case.

And we add additional register offset constants (not yet used by
the driver code) which are specific to the pcal6524.

Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
 drivers/gpio/gpio-pca953x.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

Comments

Andy Shevchenko April 10, 2018, 2:41 p.m. | #1
On Wed, Apr 4, 2018 at 10:00 PM, H. Nikolaus Schaller <hns@goldelico.com> wrote:
> PCAL chips ("L" seems to stand for "latched") have additional
> registers starting at address 0x40 to control the latches,
> interrupt mask, pull-up and pull down etc.
>
> The constants are so far defined in a way that they fit for
> the pcal9555a when shifted by the number of banks, i.e. multiplied
> by 2.
>
> Now the pcal6524 has 3 banks which means the relative offset
> must be multiplied by 4 which gives a wrong result if not done
> carefully, since the base offset is already included in the offset.
>
> For the basic registers shared with all pca93xx/tca64xx chips
> there is no such offset.
>
> Therefore, we add code to adjust the register number for exended
> registers in this case.
>
> And we add additional register offset constants (not yet used by
> the driver code) which are specific to the pcal6524.

> -#define PCAL953X_IN_LATCH      34
> -#define PCAL953X_INT_MASK      37
> -#define PCAL953X_INT_STAT      38

I prefer either to change first all the rest to be 2 digit hex values
first, or leave decimal in this patch.

> +#define PCAL953X_OUT_STRENGTH  0x20
> +#define PCAL953X_IN_LATCH      0x22
> +#define PCAL953X_PULL_EN       0x23
> +#define PCAL953X_PULL_SEL      0x24
> +#define PCAL953X_INT_MASK      0x25
> +#define PCAL953X_INT_STAT      0x26
> +#define PCAL953X_OUT_CONF      0x27
> +
> +#define PCAL6524_INT_EDGE      0x28
> +#define PCAL6524_INT_CLR       0x2a
> +#define PCAL6524_IN_STATUS     0x2b
> +#define PCAL6524_OUT_INDCONF   0x2c
> +#define PCAL6524_DEBOUNCE      0x2d

> +       /* adjust register address for pcal6524 */
> +       if (reg >= PCAL953X_OUT_STRENGTH)
> +               reg -= PCAL953X_OUT_STRENGTH >> 1;

I don't like this condition. Can we avoid relying on the register
offset in regard to some flag / compatible string / etc?

> +       /* adjust register address for pcal6524 */
> +       if (reg >= PCAL953X_OUT_STRENGTH)
> +               reg -= PCAL953X_OUT_STRENGTH >> 1;

Ditto.
H. Nikolaus Schaller April 10, 2018, 3:51 p.m. | #2
Hi,

> Am 10.04.2018 um 16:41 schrieb Andy Shevchenko <andy.shevchenko@gmail.com>:
> 
> On Wed, Apr 4, 2018 at 10:00 PM, H. Nikolaus Schaller <hns@goldelico.com> wrote:
>> PCAL chips ("L" seems to stand for "latched") have additional
>> registers starting at address 0x40 to control the latches,
>> interrupt mask, pull-up and pull down etc.
>> 
>> The constants are so far defined in a way that they fit for
>> the pcal9555a when shifted by the number of banks, i.e. multiplied
>> by 2.
>> 
>> Now the pcal6524 has 3 banks which means the relative offset
>> must be multiplied by 4 which gives a wrong result if not done
>> carefully, since the base offset is already included in the offset.
>> 
>> For the basic registers shared with all pca93xx/tca64xx chips
>> there is no such offset.
>> 
>> Therefore, we add code to adjust the register number for exended
>> registers in this case.
>> 
>> And we add additional register offset constants (not yet used by
>> the driver code) which are specific to the pcal6524.
> 
>> -#define PCAL953X_IN_LATCH      34
>> -#define PCAL953X_INT_MASK      37
>> -#define PCAL953X_INT_STAT      38
> 
> I prefer either to change first all the rest to be 2 digit hex values
> first, or leave decimal in this patch.

Ok, let's change them all to hex (like in the data sheets).

> 
>> +#define PCAL953X_OUT_STRENGTH  0x20
>> +#define PCAL953X_IN_LATCH      0x22
>> +#define PCAL953X_PULL_EN       0x23
>> +#define PCAL953X_PULL_SEL      0x24
>> +#define PCAL953X_INT_MASK      0x25
>> +#define PCAL953X_INT_STAT      0x26
>> +#define PCAL953X_OUT_CONF      0x27
>> +
>> +#define PCAL6524_INT_EDGE      0x28
>> +#define PCAL6524_INT_CLR       0x2a
>> +#define PCAL6524_IN_STATUS     0x2b
>> +#define PCAL6524_OUT_INDCONF   0x2c
>> +#define PCAL6524_DEBOUNCE      0x2d
> 
>> +       /* adjust register address for pcal6524 */
>> +       if (reg >= PCAL953X_OUT_STRENGTH)
>> +               reg -= PCAL953X_OUT_STRENGTH >> 1;
> 
> I don't like this condition. Can we avoid relying on the register
> offset in regard to some flag / compatible string / etc?

I don't think so.

for TCA6416 and PCAL9555 the real registers are e.g.:
PCA953X_INPUT		0x00 / 0x01
PCA953X_OUTPUT		0x02 / 0x03

i.e. every address constant is shifted left 1 bit in the 16 bit
accessors.

for PCAL9555 some extended registers:

PCAL953X_OUT_STRENGTH	0x40 / 0x41 / 0x42 / 0x43
PCAL953X_IN_LATCH	0x44 / 0x45

i.e. PCAL953X_IN_LATCH is also simply shifted left by 1 bit
because the extended constants are defined that they fit.

for TCA6424 and PCAL6524:
PCA953X_INPUT		0x00 / 0x01 / 0x02
PCA953X_OUTPUT		0x04 / 0x05 / 0x06

every address is shifted left 2 bits in the 24 bit accessors.

for PCAL6524:
PCAL953X_OUT_STRENGTH	0x40 / 0x41 / 0x42 / 0x43 / 0x44 / 0x45
PCAL953X_IN_LATCH	0x48 / 0x49 / 0x4a

simply shifting left by 2 bits gives wrong result which is this
special case. It is not a general chip property but a mix of chip
bit-width and depends on accessing the first or second bank.

So the full condition to apply this address fix is:

if (24 bit access && second bank access)
	do correction.

and it can be simplified to what I suggest, because the 8/16/24 bit
accessors are already separate functions.

I don't think this can't be hard-coded into flags / compatible string.

> 
>> +       /* adjust register address for pcal6524 */
>> +       if (reg >= PCAL953X_OUT_STRENGTH)
>> +               reg -= PCAL953X_OUT_STRENGTH >> 1;
> 
> Ditto.
> 
> -- 
> With Best Regards,
> Andy Shevchenko

BR and thanks,
Nikolaus

--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 4a075619b93e..c70acba710c7 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -41,9 +41,19 @@ 
 #define PCA957X_MSK		6
 #define PCA957X_INTS		7
 
-#define PCAL953X_IN_LATCH	34
-#define PCAL953X_INT_MASK	37
-#define PCAL953X_INT_STAT	38
+#define PCAL953X_OUT_STRENGTH	0x20
+#define PCAL953X_IN_LATCH	0x22
+#define PCAL953X_PULL_EN	0x23
+#define PCAL953X_PULL_SEL	0x24
+#define PCAL953X_INT_MASK	0x25
+#define PCAL953X_INT_STAT	0x26
+#define PCAL953X_OUT_CONF	0x27
+
+#define PCAL6524_INT_EDGE	0x28
+#define PCAL6524_INT_CLR	0x2a
+#define PCAL6524_IN_STATUS	0x2b
+#define PCAL6524_OUT_INDCONF	0x2c
+#define PCAL6524_DEBOUNCE	0x2d
 
 #define PCA_GPIO_MASK		0x00FF
 #define PCA_INT			0x0100
@@ -208,6 +218,10 @@  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);
 
+	/* adjust register address for pcal6524 */
+	if (reg >= PCAL953X_OUT_STRENGTH)
+		reg -= PCAL953X_OUT_STRENGTH >> 1;
+
 	return i2c_smbus_write_i2c_block_data(chip->client,
 					      (reg << bank_shift) | REG_ADDR_AI,
 					      NBANK(chip), val);
@@ -250,6 +264,10 @@  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);
 
+	/* adjust register address for pcal6524 */
+	if (reg >= PCAL953X_OUT_STRENGTH)
+		reg -= PCAL953X_OUT_STRENGTH >> 1;
+
 	return i2c_smbus_read_i2c_block_data(chip->client,
 					     (reg << bank_shift) | REG_ADDR_AI,
 					     NBANK(chip), val);