Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
3e42f200
Commit
3e42f200
authored
Dec 14, 2018
by
Linus Walleij
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ib-pca953x' into devel
parents
c5510b8d
b7657430
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
302 additions
and
182 deletions
+302
-182
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-pca953x.c
+302
-182
No files found.
drivers/gpio/gpio-pca953x.c
View file @
3e42f200
...
@@ -20,6 +20,7 @@
...
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/of_platform.h>
#include <linux/platform_data/pca953x.h>
#include <linux/platform_data/pca953x.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/slab.h>
...
@@ -30,6 +31,8 @@
...
@@ -30,6 +31,8 @@
#define PCA953X_INVERT 0x02
#define PCA953X_INVERT 0x02
#define PCA953X_DIRECTION 0x03
#define PCA953X_DIRECTION 0x03
#define REG_ADDR_MASK 0x3f
#define REG_ADDR_EXT 0x40
#define REG_ADDR_AI 0x80
#define REG_ADDR_AI 0x80
#define PCA957X_IN 0x00
#define PCA957X_IN 0x00
...
@@ -58,7 +61,7 @@
...
@@ -58,7 +61,7 @@
#define PCA_GPIO_MASK 0x00FF
#define PCA_GPIO_MASK 0x00FF
#define PCAL_GPIO_MASK 0x1f
#define PCAL_GPIO_MASK 0x1f
#define PCAL_PINCTRL_MASK 0x
e
0
#define PCAL_PINCTRL_MASK 0x
6
0
#define PCA_INT 0x0100
#define PCA_INT 0x0100
#define PCA_PCAL 0x0200
#define PCA_PCAL 0x0200
...
@@ -119,25 +122,27 @@ struct pca953x_reg_config {
...
@@ -119,25 +122,27 @@ struct pca953x_reg_config {
int
direction
;
int
direction
;
int
output
;
int
output
;
int
input
;
int
input
;
int
invert
;
};
};
static
const
struct
pca953x_reg_config
pca953x_regs
=
{
static
const
struct
pca953x_reg_config
pca953x_regs
=
{
.
direction
=
PCA953X_DIRECTION
,
.
direction
=
PCA953X_DIRECTION
,
.
output
=
PCA953X_OUTPUT
,
.
output
=
PCA953X_OUTPUT
,
.
input
=
PCA953X_INPUT
,
.
input
=
PCA953X_INPUT
,
.
invert
=
PCA953X_INVERT
,
};
};
static
const
struct
pca953x_reg_config
pca957x_regs
=
{
static
const
struct
pca953x_reg_config
pca957x_regs
=
{
.
direction
=
PCA957X_CFG
,
.
direction
=
PCA957X_CFG
,
.
output
=
PCA957X_OUT
,
.
output
=
PCA957X_OUT
,
.
input
=
PCA957X_IN
,
.
input
=
PCA957X_IN
,
.
invert
=
PCA957X_INVRT
,
};
};
struct
pca953x_chip
{
struct
pca953x_chip
{
unsigned
gpio_start
;
unsigned
gpio_start
;
u8
reg_output
[
MAX_BANK
];
u8
reg_direction
[
MAX_BANK
];
struct
mutex
i2c_lock
;
struct
mutex
i2c_lock
;
struct
regmap
*
regmap
;
#ifdef CONFIG_GPIO_PCA953X_IRQ
#ifdef CONFIG_GPIO_PCA953X_IRQ
struct
mutex
irq_lock
;
struct
mutex
irq_lock
;
...
@@ -154,87 +159,177 @@ struct pca953x_chip {
...
@@ -154,87 +159,177 @@ struct pca953x_chip {
struct
regulator
*
regulator
;
struct
regulator
*
regulator
;
const
struct
pca953x_reg_config
*
regs
;
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
,
static
int
pca953x_bank_shift
(
struct
pca953x_chip
*
chip
)
int
off
)
{
{
int
ret
;
return
fls
((
chip
->
gpio_chip
.
ngpio
-
1
)
/
BANK_SZ
);
int
bank_shift
=
fls
((
chip
->
gpio_chip
.
ngpio
-
1
)
/
BANK_SZ
);
}
int
offset
=
off
/
BANK_SZ
;
ret
=
i2c_smbus_read_byte_data
(
chip
->
client
,
#define PCA953x_BANK_INPUT BIT(0)
(
reg
<<
bank_shift
)
+
offset
);
#define PCA953x_BANK_OUTPUT BIT(1)
*
val
=
ret
;
#define PCA953x_BANK_POLARITY BIT(2)
#define PCA953x_BANK_CONFIG BIT(3)
if
(
ret
<
0
)
{
#define PCA957x_BANK_INPUT BIT(0)
dev_err
(
&
chip
->
client
->
dev
,
"failed reading register
\n
"
);
#define PCA957x_BANK_POLARITY BIT(1)
return
ret
;
#define PCA957x_BANK_BUSHOLD BIT(2)
#define PCA957x_BANK_CONFIG BIT(4)
#define PCA957x_BANK_OUTPUT BIT(5)
#define PCAL9xxx_BANK_IN_LATCH BIT(8 + 2)
#define PCAL9xxx_BANK_IRQ_MASK BIT(8 + 5)
#define PCAL9xxx_BANK_IRQ_STAT BIT(8 + 6)
/*
* We care about the following registers:
* - Standard set, below 0x40, each port can be replicated up to 8 times
* - PCA953x standard
* Input port 0x00 + 0 * bank_size R
* Output port 0x00 + 1 * bank_size RW
* Polarity Inversion port 0x00 + 2 * bank_size RW
* Configuration port 0x00 + 3 * bank_size RW
* - PCA957x with mixed up registers
* Input port 0x00 + 0 * bank_size R
* Polarity Inversion port 0x00 + 1 * bank_size RW
* Bus hold port 0x00 + 2 * bank_size RW
* Configuration port 0x00 + 4 * bank_size RW
* Output port 0x00 + 5 * bank_size RW
*
* - Extended set, above 0x40, often chip specific.
* - PCAL6524/PCAL9555A with custom PCAL IRQ handling:
* Input latch register 0x40 + 2 * bank_size RW
* Interrupt mask register 0x40 + 5 * bank_size RW
* Interrupt status register 0x40 + 6 * bank_size R
*
* - Registers with bit 0x80 set, the AI bit
* The bit is cleared and the registers fall into one of the
* categories above.
*/
static
bool
pca953x_check_register
(
struct
pca953x_chip
*
chip
,
unsigned
int
reg
,
u32
checkbank
)
{
int
bank_shift
=
pca953x_bank_shift
(
chip
);
int
bank
=
(
reg
&
REG_ADDR_MASK
)
>>
bank_shift
;
int
offset
=
reg
&
(
BIT
(
bank_shift
)
-
1
);
/* Special PCAL extended register check. */
if
(
reg
&
REG_ADDR_EXT
)
{
if
(
!
(
chip
->
driver_data
&
PCA_PCAL
))
return
false
;
bank
+=
8
;
}
}
return
0
;
/* Register is not in the matching bank. */
if
(
!
(
BIT
(
bank
)
&
checkbank
))
return
false
;
/* Register is not within allowed range of bank. */
if
(
offset
>=
NBANK
(
chip
))
return
false
;
return
true
;
}
}
static
int
pca953x_write_single
(
struct
pca953x_chip
*
chip
,
int
reg
,
u32
val
,
static
bool
pca953x_readable_register
(
struct
device
*
dev
,
unsigned
int
reg
)
int
off
)
{
{
int
ret
;
struct
pca953x_chip
*
chip
=
dev_get_drvdata
(
dev
);
int
bank_shift
=
fls
((
chip
->
gpio_chip
.
ngpio
-
1
)
/
BANK_SZ
);
u32
bank
;
int
offset
=
off
/
BANK_SZ
;
ret
=
i2c_smbus_write_byte_data
(
chip
->
client
,
if
(
PCA_CHIP_TYPE
(
chip
->
driver_data
)
==
PCA953X_TYPE
)
{
(
reg
<<
bank_shift
)
+
offset
,
val
);
bank
=
PCA953x_BANK_INPUT
|
PCA953x_BANK_OUTPUT
|
PCA953x_BANK_POLARITY
|
PCA953x_BANK_CONFIG
;
}
else
{
bank
=
PCA957x_BANK_INPUT
|
PCA957x_BANK_OUTPUT
|
PCA957x_BANK_POLARITY
|
PCA957x_BANK_CONFIG
|
PCA957x_BANK_BUSHOLD
;
}
if
(
ret
<
0
)
{
if
(
chip
->
driver_data
&
PCA_PCAL
)
{
dev_err
(
&
chip
->
client
->
dev
,
"failed writing register
\n
"
);
bank
|=
PCAL9xxx_BANK_IN_LATCH
|
PCAL9xxx_BANK_IRQ_MASK
|
return
ret
;
PCAL9xxx_BANK_IRQ_STAT
;
}
}
return
0
;
return
pca953x_check_register
(
chip
,
reg
,
bank
)
;
}
}
static
int
pca953x_write_regs_8
(
struct
pca953x_chip
*
chip
,
int
reg
,
u8
*
val
)
static
bool
pca953x_writeable_register
(
struct
device
*
dev
,
unsigned
int
reg
)
{
{
return
i2c_smbus_write_byte_data
(
chip
->
client
,
reg
,
*
val
);
struct
pca953x_chip
*
chip
=
dev_get_drvdata
(
dev
);
}
u32
bank
;
static
int
pca953x_write_regs_16
(
struct
pca953x_chip
*
chip
,
int
reg
,
u8
*
val
)
if
(
PCA_CHIP_TYPE
(
chip
->
driver_data
)
==
PCA953X_TYPE
)
{
{
bank
=
PCA953x_BANK_OUTPUT
|
PCA953x_BANK_POLARITY
|
u16
word
=
get_unaligned
((
u16
*
)
val
);
PCA953x_BANK_CONFIG
;
}
else
{
bank
=
PCA957x_BANK_OUTPUT
|
PCA957x_BANK_POLARITY
|
PCA957x_BANK_CONFIG
|
PCA957x_BANK_BUSHOLD
;
}
return
i2c_smbus_write_word_data
(
chip
->
client
,
reg
<<
1
,
word
);
if
(
chip
->
driver_data
&
PCA_PCAL
)
bank
|=
PCAL9xxx_BANK_IN_LATCH
|
PCAL9xxx_BANK_IRQ_MASK
;
return
pca953x_check_register
(
chip
,
reg
,
bank
);
}
}
static
int
pca957x_write_regs_16
(
struct
pca953x_chip
*
chip
,
int
reg
,
u8
*
val
)
static
bool
pca953x_volatile_register
(
struct
device
*
dev
,
unsigned
int
reg
)
{
{
int
ret
;
struct
pca953x_chip
*
chip
=
dev_get_drvdata
(
dev
);
u32
bank
;
ret
=
i2c_smbus_write_byte_data
(
chip
->
client
,
reg
<<
1
,
val
[
0
]);
if
(
PCA_CHIP_TYPE
(
chip
->
driver_data
)
==
PCA953X_TYPE
)
if
(
ret
<
0
)
bank
=
PCA953x_BANK_INPUT
;
return
ret
;
else
bank
=
PCA957x_BANK_INPUT
;
return
i2c_smbus_write_byte_data
(
chip
->
client
,
(
reg
<<
1
)
+
1
,
val
[
1
]);
if
(
chip
->
driver_data
&
PCA_PCAL
)
bank
|=
PCAL9xxx_BANK_IRQ_STAT
;
return
pca953x_check_register
(
chip
,
reg
,
bank
);
}
}
static
int
pca953x_write_regs_24
(
struct
pca953x_chip
*
chip
,
int
reg
,
u8
*
val
)
const
struct
regmap_config
pca953x_i2c_regmap
=
{
.
reg_bits
=
8
,
.
val_bits
=
8
,
.
readable_reg
=
pca953x_readable_register
,
.
writeable_reg
=
pca953x_writeable_register
,
.
volatile_reg
=
pca953x_volatile_register
,
.
cache_type
=
REGCACHE_RBTREE
,
.
max_register
=
0x7f
,
};
static
u8
pca953x_recalc_addr
(
struct
pca953x_chip
*
chip
,
int
reg
,
int
off
,
bool
write
,
bool
addrinc
)
{
{
int
bank_shift
=
fls
((
chip
->
gpio_chip
.
ngpio
-
1
)
/
BANK_SZ
);
int
bank_shift
=
pca953x_bank_shift
(
chip
);
int
addr
=
(
reg
&
PCAL_GPIO_MASK
)
<<
bank_shift
;
int
addr
=
(
reg
&
PCAL_GPIO_MASK
)
<<
bank_shift
;
int
pinctrl
=
(
reg
&
PCAL_PINCTRL_MASK
)
<<
1
;
int
pinctrl
=
(
reg
&
PCAL_PINCTRL_MASK
)
<<
1
;
u8
regaddr
=
pinctrl
|
addr
|
(
off
/
BANK_SZ
);
return
i2c_smbus_write_i2c_block_data
(
chip
->
client
,
/* Single byte read doesn't need AI bit set. */
pinctrl
|
addr
|
REG_ADDR_AI
,
if
(
!
addrinc
)
NBANK
(
chip
),
val
);
return
regaddr
;
/* Chips with 24 and more GPIOs always support Auto Increment */
if
(
write
&&
NBANK
(
chip
)
>
2
)
regaddr
|=
REG_ADDR_AI
;
/* PCA9575 needs address-increment on multi-byte writes */
if
(
PCA_CHIP_TYPE
(
chip
->
driver_data
)
==
PCA957X_TYPE
)
regaddr
|=
REG_ADDR_AI
;
return
regaddr
;
}
}
static
int
pca953x_write_regs
(
struct
pca953x_chip
*
chip
,
int
reg
,
u8
*
val
)
static
int
pca953x_write_regs
(
struct
pca953x_chip
*
chip
,
int
reg
,
u8
*
val
)
{
{
int
ret
=
0
;
u8
regaddr
=
pca953x_recalc_addr
(
chip
,
reg
,
0
,
true
,
true
);
int
ret
;
ret
=
chip
->
write_regs
(
chip
,
reg
,
val
);
ret
=
regmap_bulk_write
(
chip
->
regmap
,
regaddr
,
val
,
NBANK
(
chip
)
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
dev_err
(
&
chip
->
client
->
dev
,
"failed writing register
\n
"
);
dev_err
(
&
chip
->
client
->
dev
,
"failed writing register
\n
"
);
return
ret
;
return
ret
;
...
@@ -243,42 +338,12 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
...
@@ -243,42 +338,12 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
return
0
;
return
0
;
}
}
static
int
pca953x_read_regs_8
(
struct
pca953x_chip
*
chip
,
int
reg
,
u8
*
val
)
{
int
ret
;
ret
=
i2c_smbus_read_byte_data
(
chip
->
client
,
reg
);
*
val
=
ret
;
return
ret
;
}
static
int
pca953x_read_regs_16
(
struct
pca953x_chip
*
chip
,
int
reg
,
u8
*
val
)
{
int
ret
;
ret
=
i2c_smbus_read_word_data
(
chip
->
client
,
reg
<<
1
);
put_unaligned
(
ret
,
(
u16
*
)
val
);
return
ret
;
}
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
);
int
addr
=
(
reg
&
PCAL_GPIO_MASK
)
<<
bank_shift
;
int
pinctrl
=
(
reg
&
PCAL_PINCTRL_MASK
)
<<
1
;
return
i2c_smbus_read_i2c_block_data
(
chip
->
client
,
pinctrl
|
addr
|
REG_ADDR_AI
,
NBANK
(
chip
),
val
);
}
static
int
pca953x_read_regs
(
struct
pca953x_chip
*
chip
,
int
reg
,
u8
*
val
)
static
int
pca953x_read_regs
(
struct
pca953x_chip
*
chip
,
int
reg
,
u8
*
val
)
{
{
u8
regaddr
=
pca953x_recalc_addr
(
chip
,
reg
,
0
,
false
,
true
);
int
ret
;
int
ret
;
ret
=
chip
->
read_regs
(
chip
,
reg
,
val
);
ret
=
regmap_bulk_read
(
chip
->
regmap
,
regaddr
,
val
,
NBANK
(
chip
)
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
dev_err
(
&
chip
->
client
->
dev
,
"failed reading register
\n
"
);
dev_err
(
&
chip
->
client
->
dev
,
"failed reading register
\n
"
);
return
ret
;
return
ret
;
...
@@ -290,18 +355,13 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
...
@@ -290,18 +355,13 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
static
int
pca953x_gpio_direction_input
(
struct
gpio_chip
*
gc
,
unsigned
off
)
static
int
pca953x_gpio_direction_input
(
struct
gpio_chip
*
gc
,
unsigned
off
)
{
{
struct
pca953x_chip
*
chip
=
gpiochip_get_data
(
gc
);
struct
pca953x_chip
*
chip
=
gpiochip_get_data
(
gc
);
u8
reg_val
;
u8
dirreg
=
pca953x_recalc_addr
(
chip
,
chip
->
regs
->
direction
,
off
,
true
,
false
);
u8
bit
=
BIT
(
off
%
BANK_SZ
);
int
ret
;
int
ret
;
mutex_lock
(
&
chip
->
i2c_lock
);
mutex_lock
(
&
chip
->
i2c_lock
);
reg_val
=
chip
->
reg_direction
[
off
/
BANK_SZ
]
|
(
1u
<<
(
off
%
BANK_SZ
));
ret
=
regmap_write_bits
(
chip
->
regmap
,
dirreg
,
bit
,
bit
);
ret
=
pca953x_write_single
(
chip
,
chip
->
regs
->
direction
,
reg_val
,
off
);
if
(
ret
)
goto
exit
;
chip
->
reg_direction
[
off
/
BANK_SZ
]
=
reg_val
;
exit:
mutex_unlock
(
&
chip
->
i2c_lock
);
mutex_unlock
(
&
chip
->
i2c_lock
);
return
ret
;
return
ret
;
}
}
...
@@ -310,31 +370,21 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
...
@@ -310,31 +370,21 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
unsigned
off
,
int
val
)
unsigned
off
,
int
val
)
{
{
struct
pca953x_chip
*
chip
=
gpiochip_get_data
(
gc
);
struct
pca953x_chip
*
chip
=
gpiochip_get_data
(
gc
);
u8
reg_val
;
u8
dirreg
=
pca953x_recalc_addr
(
chip
,
chip
->
regs
->
direction
,
off
,
true
,
false
);
u8
outreg
=
pca953x_recalc_addr
(
chip
,
chip
->
regs
->
output
,
off
,
true
,
false
);
u8
bit
=
BIT
(
off
%
BANK_SZ
);
int
ret
;
int
ret
;
mutex_lock
(
&
chip
->
i2c_lock
);
mutex_lock
(
&
chip
->
i2c_lock
);
/* set output level */
/* set output level */
if
(
val
)
ret
=
regmap_write_bits
(
chip
->
regmap
,
outreg
,
bit
,
val
?
bit
:
0
);
reg_val
=
chip
->
reg_output
[
off
/
BANK_SZ
]
|
(
1u
<<
(
off
%
BANK_SZ
));
else
reg_val
=
chip
->
reg_output
[
off
/
BANK_SZ
]
&
~
(
1u
<<
(
off
%
BANK_SZ
));
ret
=
pca953x_write_single
(
chip
,
chip
->
regs
->
output
,
reg_val
,
off
);
if
(
ret
)
if
(
ret
)
goto
exit
;
goto
exit
;
chip
->
reg_output
[
off
/
BANK_SZ
]
=
reg_val
;
/* then direction */
/* then direction */
reg_val
=
chip
->
reg_direction
[
off
/
BANK_SZ
]
&
~
(
1u
<<
(
off
%
BANK_SZ
));
ret
=
regmap_write_bits
(
chip
->
regmap
,
dirreg
,
bit
,
0
);
ret
=
pca953x_write_single
(
chip
,
chip
->
regs
->
direction
,
reg_val
,
off
);
if
(
ret
)
goto
exit
;
chip
->
reg_direction
[
off
/
BANK_SZ
]
=
reg_val
;
exit:
exit:
mutex_unlock
(
&
chip
->
i2c_lock
);
mutex_unlock
(
&
chip
->
i2c_lock
);
return
ret
;
return
ret
;
...
@@ -343,11 +393,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
...
@@ -343,11 +393,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
static
int
pca953x_gpio_get_value
(
struct
gpio_chip
*
gc
,
unsigned
off
)
static
int
pca953x_gpio_get_value
(
struct
gpio_chip
*
gc
,
unsigned
off
)
{
{
struct
pca953x_chip
*
chip
=
gpiochip_get_data
(
gc
);
struct
pca953x_chip
*
chip
=
gpiochip_get_data
(
gc
);
u8
inreg
=
pca953x_recalc_addr
(
chip
,
chip
->
regs
->
input
,
off
,
true
,
false
);
u8
bit
=
BIT
(
off
%
BANK_SZ
);
u32
reg_val
;
u32
reg_val
;
int
ret
;
int
ret
;
mutex_lock
(
&
chip
->
i2c_lock
);
mutex_lock
(
&
chip
->
i2c_lock
);
ret
=
pca953x_read_single
(
chip
,
chip
->
regs
->
input
,
&
reg_val
,
off
);
ret
=
regmap_read
(
chip
->
regmap
,
inreg
,
&
reg_val
);
mutex_unlock
(
&
chip
->
i2c_lock
);
mutex_unlock
(
&
chip
->
i2c_lock
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
/* NOTE: diagnostic already emitted; that's all we should
/* NOTE: diagnostic already emitted; that's all we should
...
@@ -357,45 +410,37 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
...
@@ -357,45 +410,37 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
return
0
;
return
0
;
}
}
return
(
reg_val
&
(
1u
<<
(
off
%
BANK_SZ
)))
?
1
:
0
;
return
!!
(
reg_val
&
bit
)
;
}
}
static
void
pca953x_gpio_set_value
(
struct
gpio_chip
*
gc
,
unsigned
off
,
int
val
)
static
void
pca953x_gpio_set_value
(
struct
gpio_chip
*
gc
,
unsigned
off
,
int
val
)
{
{
struct
pca953x_chip
*
chip
=
gpiochip_get_data
(
gc
);
struct
pca953x_chip
*
chip
=
gpiochip_get_data
(
gc
);
u8
reg_val
;
u8
outreg
=
pca953x_recalc_addr
(
chip
,
chip
->
regs
->
output
,
off
,
int
ret
;
true
,
false
);
u8
bit
=
BIT
(
off
%
BANK_SZ
);
mutex_lock
(
&
chip
->
i2c_lock
);
mutex_lock
(
&
chip
->
i2c_lock
);
if
(
val
)
regmap_write_bits
(
chip
->
regmap
,
outreg
,
bit
,
val
?
bit
:
0
);
reg_val
=
chip
->
reg_output
[
off
/
BANK_SZ
]
|
(
1u
<<
(
off
%
BANK_SZ
));
else
reg_val
=
chip
->
reg_output
[
off
/
BANK_SZ
]
&
~
(
1u
<<
(
off
%
BANK_SZ
));
ret
=
pca953x_write_single
(
chip
,
chip
->
regs
->
output
,
reg_val
,
off
);
if
(
ret
)
goto
exit
;
chip
->
reg_output
[
off
/
BANK_SZ
]
=
reg_val
;
exit:
mutex_unlock
(
&
chip
->
i2c_lock
);
mutex_unlock
(
&
chip
->
i2c_lock
);
}
}
static
int
pca953x_gpio_get_direction
(
struct
gpio_chip
*
gc
,
unsigned
off
)
static
int
pca953x_gpio_get_direction
(
struct
gpio_chip
*
gc
,
unsigned
off
)
{
{
struct
pca953x_chip
*
chip
=
gpiochip_get_data
(
gc
);
struct
pca953x_chip
*
chip
=
gpiochip_get_data
(
gc
);
u8
dirreg
=
pca953x_recalc_addr
(
chip
,
chip
->
regs
->
direction
,
off
,
true
,
false
);
u8
bit
=
BIT
(
off
%
BANK_SZ
);
u32
reg_val
;
u32
reg_val
;
int
ret
;
int
ret
;
mutex_lock
(
&
chip
->
i2c_lock
);
mutex_lock
(
&
chip
->
i2c_lock
);
ret
=
pca953x_read_single
(
chip
,
chip
->
regs
->
direction
,
&
reg_val
,
off
);
ret
=
regmap_read
(
chip
->
regmap
,
dirreg
,
&
reg_val
);
mutex_unlock
(
&
chip
->
i2c_lock
);
mutex_unlock
(
&
chip
->
i2c_lock
);
if
(
ret
<
0
)
if
(
ret
<
0
)
return
ret
;
return
ret
;
return
!!
(
reg_val
&
(
1u
<<
(
off
%
BANK_SZ
))
);
return
!!
(
reg_val
&
bit
);
}
}
static
void
pca953x_gpio_set_multiple
(
struct
gpio_chip
*
gc
,
static
void
pca953x_gpio_set_multiple
(
struct
gpio_chip
*
gc
,
...
@@ -403,14 +448,15 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
...
@@ -403,14 +448,15 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
{
{
struct
pca953x_chip
*
chip
=
gpiochip_get_data
(
gc
);
struct
pca953x_chip
*
chip
=
gpiochip_get_data
(
gc
);
unsigned
int
bank_mask
,
bank_val
;
unsigned
int
bank_mask
,
bank_val
;
int
bank
_shift
,
bank
;
int
bank
;
u8
reg_val
[
MAX_BANK
];
u8
reg_val
[
MAX_BANK
];
int
ret
;
int
ret
;
bank_shift
=
fls
((
chip
->
gpio_chip
.
ngpio
-
1
)
/
BANK_SZ
);
mutex_lock
(
&
chip
->
i2c_lock
);
mutex_lock
(
&
chip
->
i2c_lock
);
memcpy
(
reg_val
,
chip
->
reg_output
,
NBANK
(
chip
));
ret
=
pca953x_read_regs
(
chip
,
chip
->
regs
->
output
,
reg_val
);
if
(
ret
)
goto
exit
;
for
(
bank
=
0
;
bank
<
NBANK
(
chip
);
bank
++
)
{
for
(
bank
=
0
;
bank
<
NBANK
(
chip
);
bank
++
)
{
bank_mask
=
mask
[
bank
/
sizeof
(
*
mask
)]
>>
bank_mask
=
mask
[
bank
/
sizeof
(
*
mask
)]
>>
((
bank
%
sizeof
(
*
mask
))
*
8
);
((
bank
%
sizeof
(
*
mask
))
*
8
);
...
@@ -422,13 +468,7 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
...
@@ -422,13 +468,7 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
}
}
}
}
ret
=
i2c_smbus_write_i2c_block_data
(
chip
->
client
,
pca953x_write_regs
(
chip
,
chip
->
regs
->
output
,
reg_val
);
chip
->
regs
->
output
<<
bank_shift
,
NBANK
(
chip
),
reg_val
);
if
(
ret
)
goto
exit
;
memcpy
(
chip
->
reg_output
,
reg_val
,
NBANK
(
chip
));
exit:
exit:
mutex_unlock
(
&
chip
->
i2c_lock
);
mutex_unlock
(
&
chip
->
i2c_lock
);
}
}
...
@@ -487,6 +527,10 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
...
@@ -487,6 +527,10 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
u8
new_irqs
;
u8
new_irqs
;
int
level
,
i
;
int
level
,
i
;
u8
invert_irq_mask
[
MAX_BANK
];
u8
invert_irq_mask
[
MAX_BANK
];
int
reg_direction
[
MAX_BANK
];
regmap_bulk_read
(
chip
->
regmap
,
chip
->
regs
->
direction
,
reg_direction
,
NBANK
(
chip
));
if
(
chip
->
driver_data
&
PCA_PCAL
)
{
if
(
chip
->
driver_data
&
PCA_PCAL
)
{
/* Enable latch on interrupt-enabled inputs */
/* Enable latch on interrupt-enabled inputs */
...
@@ -502,7 +546,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
...
@@ -502,7 +546,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
/* Look for any newly setup interrupt */
/* Look for any newly setup interrupt */
for
(
i
=
0
;
i
<
NBANK
(
chip
);
i
++
)
{
for
(
i
=
0
;
i
<
NBANK
(
chip
);
i
++
)
{
new_irqs
=
chip
->
irq_trig_fall
[
i
]
|
chip
->
irq_trig_raise
[
i
];
new_irqs
=
chip
->
irq_trig_fall
[
i
]
|
chip
->
irq_trig_raise
[
i
];
new_irqs
&=
~
chip
->
reg_direction
[
i
];
new_irqs
&=
reg_direction
[
i
];
while
(
new_irqs
)
{
while
(
new_irqs
)
{
level
=
__ffs
(
new_irqs
);
level
=
__ffs
(
new_irqs
);
...
@@ -567,6 +611,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
...
@@ -567,6 +611,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
bool
pending_seen
=
false
;
bool
pending_seen
=
false
;
bool
trigger_seen
=
false
;
bool
trigger_seen
=
false
;
u8
trigger
[
MAX_BANK
];
u8
trigger
[
MAX_BANK
];
int
reg_direction
[
MAX_BANK
];
int
ret
,
i
;
int
ret
,
i
;
if
(
chip
->
driver_data
&
PCA_PCAL
)
{
if
(
chip
->
driver_data
&
PCA_PCAL
)
{
...
@@ -597,8 +642,10 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
...
@@ -597,8 +642,10 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
return
false
;
return
false
;
/* Remove output pins from the equation */
/* Remove output pins from the equation */
regmap_bulk_read
(
chip
->
regmap
,
chip
->
regs
->
direction
,
reg_direction
,
NBANK
(
chip
));
for
(
i
=
0
;
i
<
NBANK
(
chip
);
i
++
)
for
(
i
=
0
;
i
<
NBANK
(
chip
);
i
++
)
cur_stat
[
i
]
&=
chip
->
reg_direction
[
i
];
cur_stat
[
i
]
&=
reg_direction
[
i
];
memcpy
(
old_stat
,
chip
->
irq_stat
,
NBANK
(
chip
));
memcpy
(
old_stat
,
chip
->
irq_stat
,
NBANK
(
chip
));
...
@@ -652,6 +699,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
...
@@ -652,6 +699,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
int
irq_base
)
int
irq_base
)
{
{
struct
i2c_client
*
client
=
chip
->
client
;
struct
i2c_client
*
client
=
chip
->
client
;
int
reg_direction
[
MAX_BANK
];
int
ret
,
i
;
int
ret
,
i
;
if
(
client
->
irq
&&
irq_base
!=
-
1
if
(
client
->
irq
&&
irq_base
!=
-
1
...
@@ -666,8 +714,10 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
...
@@ -666,8 +714,10 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
* interrupt. We have to rely on the previous read for
* interrupt. We have to rely on the previous read for
* this purpose.
* this purpose.
*/
*/
regmap_bulk_read
(
chip
->
regmap
,
chip
->
regs
->
direction
,
reg_direction
,
NBANK
(
chip
));
for
(
i
=
0
;
i
<
NBANK
(
chip
);
i
++
)
for
(
i
=
0
;
i
<
NBANK
(
chip
);
i
++
)
chip
->
irq_stat
[
i
]
&=
chip
->
reg_direction
[
i
];
chip
->
irq_stat
[
i
]
&=
reg_direction
[
i
];
mutex_init
(
&
chip
->
irq_lock
);
mutex_init
(
&
chip
->
irq_lock
);
ret
=
devm_request_threaded_irq
(
&
client
->
dev
,
ret
=
devm_request_threaded_irq
(
&
client
->
dev
,
...
@@ -715,20 +765,19 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
...
@@ -715,20 +765,19 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
}
}
#endif
#endif
static
int
device_pca95
3
x_init
(
struct
pca953x_chip
*
chip
,
u32
invert
)
static
int
device_pca95
x
x_init
(
struct
pca953x_chip
*
chip
,
u32
invert
)
{
{
int
ret
;
int
ret
;
u8
val
[
MAX_BANK
];
u8
val
[
MAX_BANK
];
chip
->
regs
=
&
pca953x_regs
;
ret
=
regcache_sync_region
(
chip
->
regmap
,
chip
->
regs
->
output
,
chip
->
regs
->
output
+
NBANK
(
chip
));
ret
=
pca953x_read_regs
(
chip
,
chip
->
regs
->
output
,
chip
->
reg_output
);
if
(
ret
!=
0
)
if
(
ret
)
goto
out
;
goto
out
;
ret
=
pca953x_read_regs
(
chi
p
,
chip
->
regs
->
direction
,
ret
=
regcache_sync_region
(
chip
->
regma
p
,
chip
->
regs
->
direction
,
chip
->
reg_direction
);
chip
->
regs
->
direction
+
NBANK
(
chip
)
);
if
(
ret
)
if
(
ret
!=
0
)
goto
out
;
goto
out
;
/* set platform specific polarity inversion */
/* set platform specific polarity inversion */
...
@@ -737,7 +786,7 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
...
@@ -737,7 +786,7 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
else
else
memset
(
val
,
0
,
NBANK
(
chip
));
memset
(
val
,
0
,
NBANK
(
chip
));
ret
=
pca953x_write_regs
(
chip
,
PCA953X_INVERT
,
val
);
ret
=
pca953x_write_regs
(
chip
,
chip
->
regs
->
invert
,
val
);
out:
out:
return
ret
;
return
ret
;
}
}
...
@@ -747,22 +796,7 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
...
@@ -747,22 +796,7 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
int
ret
;
int
ret
;
u8
val
[
MAX_BANK
];
u8
val
[
MAX_BANK
];
chip
->
regs
=
&
pca957x_regs
;
ret
=
device_pca95xx_init
(
chip
,
invert
);
ret
=
pca953x_read_regs
(
chip
,
chip
->
regs
->
output
,
chip
->
reg_output
);
if
(
ret
)
goto
out
;
ret
=
pca953x_read_regs
(
chip
,
chip
->
regs
->
direction
,
chip
->
reg_direction
);
if
(
ret
)
goto
out
;
/* set platform specific polarity inversion */
if
(
invert
)
memset
(
val
,
0xFF
,
NBANK
(
chip
));
else
memset
(
val
,
0
,
NBANK
(
chip
));
ret
=
pca953x_write_regs
(
chip
,
PCA957X_INVRT
,
val
);
if
(
ret
)
if
(
ret
)
goto
out
;
goto
out
;
...
@@ -853,6 +887,16 @@ static int pca953x_probe(struct i2c_client *client,
...
@@ -853,6 +887,16 @@ static int pca953x_probe(struct i2c_client *client,
}
}
}
}
i2c_set_clientdata
(
client
,
chip
);
chip
->
regmap
=
devm_regmap_init_i2c
(
client
,
&
pca953x_i2c_regmap
);
if
(
IS_ERR
(
chip
->
regmap
))
{
ret
=
PTR_ERR
(
chip
->
regmap
);
goto
err_exit
;
}
regcache_mark_dirty
(
chip
->
regmap
);
mutex_init
(
&
chip
->
i2c_lock
);
mutex_init
(
&
chip
->
i2c_lock
);
/*
/*
* In case we have an i2c-mux controlled by a GPIO provided by an
* In case we have an i2c-mux controlled by a GPIO provided by an
...
@@ -878,24 +922,13 @@ static int pca953x_probe(struct i2c_client *client,
...
@@ -878,24 +922,13 @@ static int pca953x_probe(struct i2c_client *client,
*/
*/
pca953x_setup_gpio
(
chip
,
chip
->
driver_data
&
PCA_GPIO_MASK
);
pca953x_setup_gpio
(
chip
,
chip
->
driver_data
&
PCA_GPIO_MASK
);
if
(
chip
->
gpio_chip
.
ngpio
<=
8
)
{
if
(
PCA_CHIP_TYPE
(
chip
->
driver_data
)
==
PCA953X_TYPE
)
{
chip
->
write_regs
=
pca953x_write_regs_8
;
chip
->
regs
=
&
pca953x_regs
;
chip
->
read_regs
=
pca953x_read_regs_8
;
ret
=
device_pca95xx_init
(
chip
,
invert
);
}
else
if
(
chip
->
gpio_chip
.
ngpio
>=
24
)
{
chip
->
write_regs
=
pca953x_write_regs_24
;
chip
->
read_regs
=
pca953x_read_regs_24
;
}
else
{
}
else
{
if
(
PCA_CHIP_TYPE
(
chip
->
driver_data
)
==
PCA953X_TYPE
)
chip
->
regs
=
&
pca957x_regs
;
chip
->
write_regs
=
pca953x_write_regs_16
;
else
chip
->
write_regs
=
pca957x_write_regs_16
;
chip
->
read_regs
=
pca953x_read_regs_16
;
}
if
(
PCA_CHIP_TYPE
(
chip
->
driver_data
)
==
PCA953X_TYPE
)
ret
=
device_pca953x_init
(
chip
,
invert
);
else
ret
=
device_pca957x_init
(
chip
,
invert
);
ret
=
device_pca957x_init
(
chip
,
invert
);
}
if
(
ret
)
if
(
ret
)
goto
err_exit
;
goto
err_exit
;
...
@@ -914,7 +947,6 @@ static int pca953x_probe(struct i2c_client *client,
...
@@ -914,7 +947,6 @@ static int pca953x_probe(struct i2c_client *client,
dev_warn
(
&
client
->
dev
,
"setup failed, %d
\n
"
,
ret
);
dev_warn
(
&
client
->
dev
,
"setup failed, %d
\n
"
,
ret
);
}
}
i2c_set_clientdata
(
client
,
chip
);
return
0
;
return
0
;
err_exit:
err_exit:
...
@@ -943,6 +975,91 @@ static int pca953x_remove(struct i2c_client *client)
...
@@ -943,6 +975,91 @@ static int pca953x_remove(struct i2c_client *client)
return
ret
;
return
ret
;
}
}
#ifdef CONFIG_PM_SLEEP
static
int
pca953x_regcache_sync
(
struct
device
*
dev
)
{
struct
pca953x_chip
*
chip
=
dev_get_drvdata
(
dev
);
int
ret
;
/*
* The ordering between direction and output is important,
* sync these registers first and only then sync the rest.
*/
ret
=
regcache_sync_region
(
chip
->
regmap
,
chip
->
regs
->
direction
,
chip
->
regs
->
direction
+
NBANK
(
chip
));
if
(
ret
!=
0
)
{
dev_err
(
dev
,
"Failed to sync GPIO dir registers: %d
\n
"
,
ret
);
return
ret
;
}
ret
=
regcache_sync_region
(
chip
->
regmap
,
chip
->
regs
->
output
,
chip
->
regs
->
output
+
NBANK
(
chip
));
if
(
ret
!=
0
)
{
dev_err
(
dev
,
"Failed to sync GPIO out registers: %d
\n
"
,
ret
);
return
ret
;
}
#ifdef CONFIG_GPIO_PCA953X_IRQ
if
(
chip
->
driver_data
&
PCA_PCAL
)
{
ret
=
regcache_sync_region
(
chip
->
regmap
,
PCAL953X_IN_LATCH
,
PCAL953X_IN_LATCH
+
NBANK
(
chip
));
if
(
ret
!=
0
)
{
dev_err
(
dev
,
"Failed to sync INT latch registers: %d
\n
"
,
ret
);
return
ret
;
}
ret
=
regcache_sync_region
(
chip
->
regmap
,
PCAL953X_INT_MASK
,
PCAL953X_INT_MASK
+
NBANK
(
chip
));
if
(
ret
!=
0
)
{
dev_err
(
dev
,
"Failed to sync INT mask registers: %d
\n
"
,
ret
);
return
ret
;
}
}
#endif
return
0
;
}
static
int
pca953x_suspend
(
struct
device
*
dev
)
{
struct
pca953x_chip
*
chip
=
dev_get_drvdata
(
dev
);
regcache_cache_only
(
chip
->
regmap
,
true
);
regulator_disable
(
chip
->
regulator
);
return
0
;
}
static
int
pca953x_resume
(
struct
device
*
dev
)
{
struct
pca953x_chip
*
chip
=
dev_get_drvdata
(
dev
);
int
ret
;
ret
=
regulator_enable
(
chip
->
regulator
);
if
(
ret
!=
0
)
{
dev_err
(
dev
,
"Failed to enable regulator: %d
\n
"
,
ret
);
return
0
;
}
regcache_cache_only
(
chip
->
regmap
,
false
);
regcache_mark_dirty
(
chip
->
regmap
);
ret
=
pca953x_regcache_sync
(
dev
);
if
(
ret
)
return
ret
;
ret
=
regcache_sync
(
chip
->
regmap
);
if
(
ret
!=
0
)
{
dev_err
(
dev
,
"Failed to restore register map: %d
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
#endif
/* convenience to stop overlong match-table lines */
/* convenience to stop overlong match-table lines */
#define OF_953X(__nrgpio, __int) (void *)(__nrgpio | PCA953X_TYPE | __int)
#define OF_953X(__nrgpio, __int) (void *)(__nrgpio | PCA953X_TYPE | __int)
#define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int)
#define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int)
...
@@ -986,9 +1103,12 @@ static const struct of_device_id pca953x_dt_ids[] = {
...
@@ -986,9 +1103,12 @@ static const struct of_device_id pca953x_dt_ids[] = {
MODULE_DEVICE_TABLE
(
of
,
pca953x_dt_ids
);
MODULE_DEVICE_TABLE
(
of
,
pca953x_dt_ids
);
static
SIMPLE_DEV_PM_OPS
(
pca953x_pm_ops
,
pca953x_suspend
,
pca953x_resume
);
static
struct
i2c_driver
pca953x_driver
=
{
static
struct
i2c_driver
pca953x_driver
=
{
.
driver
=
{
.
driver
=
{
.
name
=
"pca953x"
,
.
name
=
"pca953x"
,
.
pm
=
&
pca953x_pm_ops
,
.
of_match_table
=
pca953x_dt_ids
,
.
of_match_table
=
pca953x_dt_ids
,
.
acpi_match_table
=
ACPI_PTR
(
pca953x_acpi_ids
),
.
acpi_match_table
=
ACPI_PTR
(
pca953x_acpi_ids
),
},
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment