Skip to content

Commit 6612f1e

Browse files
Vincent Genevesnashif
authored andcommitted
drivers: gpio: pca95xx: Reduce data transfer over I2C
When accessing GPIO by pin, access only the required port register (instead of systematically accessing both PORT0 and PORT1). Signed-off-by: Vincent Geneves <[email protected]>
1 parent b06e927 commit 6612f1e

File tree

1 file changed

+111
-21
lines changed

1 file changed

+111
-21
lines changed

drivers/gpio/gpio_pca95xx.c

Lines changed: 111 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@
2828
#include <zephyr/logging/log.h>
2929
LOG_MODULE_REGISTER(gpio_pca95xx);
3030

31+
#if CONFIG_LITTLE_ENDIAN
32+
#define LOW_BYTE_LE16_IDX 0
33+
#define HIGH_BYTE_LE16_IDX 1
34+
#else
35+
#define LOW_BYTE_LE16_IDX 1
36+
#define HIGH_BYTE_LE16_IDX 0
37+
#endif
38+
3139
/* Register definitions */
3240
#define REG_INPUT_PORT0 0x00
3341
#define REG_INPUT_PORT1 0x01
@@ -36,7 +44,7 @@ LOG_MODULE_REGISTER(gpio_pca95xx);
3644
#define REG_POL_INV_PORT0 0x04
3745
#define REG_POL_INV_PORT1 0x05
3846
#define REG_CONF_PORT0 0x06
39-
#define REG_CONG_PORT1 0x07
47+
#define REG_CONF_PORT1 0x07
4048
#define REG_OUT_DRV_STRENGTH_PORT0_L 0x40
4149
#define REG_OUT_DRV_STRENGTH_PORT0_H 0x41
4250
#define REG_OUT_DRV_STRENGTH_PORT1_L 0x42
@@ -108,6 +116,37 @@ struct gpio_pca95xx_drv_data {
108116
#endif
109117
};
110118

119+
static int read_port_reg(const struct device *dev, uint8_t reg, uint8_t pin,
120+
uint16_t *cache, uint16_t *buf)
121+
{
122+
const struct gpio_pca95xx_config * const config = dev->config;
123+
uint8_t b_buf;
124+
int ret;
125+
126+
if (pin >= 8)
127+
reg++;
128+
129+
ret = i2c_reg_read_byte_dt(&config->bus, reg, &b_buf);
130+
if (ret != 0) {
131+
LOG_ERR("PCA95XX[0x%X]: error reading register 0x%X (%d)",
132+
config->bus.addr, reg, ret);
133+
return ret;
134+
}
135+
136+
if (pin < 8) {
137+
((uint8_t *)cache)[LOW_BYTE_LE16_IDX] = b_buf;
138+
} else {
139+
((uint8_t *)cache)[HIGH_BYTE_LE16_IDX] = b_buf;
140+
}
141+
142+
*buf = *cache;
143+
144+
LOG_DBG("PCA95XX[0x%X]: Read: REG[0x%X] = 0x%X",
145+
config->bus.addr, reg, b_buf);
146+
147+
return 0;
148+
}
149+
111150
/**
112151
* @brief Read both port 0 and port 1 registers of certain register function.
113152
*
@@ -145,6 +184,36 @@ static int read_port_regs(const struct device *dev, uint8_t reg,
145184
return 0;
146185
}
147186

187+
188+
static int write_port_reg(const struct device *dev, uint8_t reg, uint8_t pin,
189+
uint16_t *cache, uint16_t value)
190+
{
191+
const struct gpio_pca95xx_config * const config = dev->config;
192+
uint8_t buf[2];
193+
int ret;
194+
195+
if (pin < 8) {
196+
buf[1] = value;
197+
} else {
198+
buf[1] = value >> 8;
199+
reg++;
200+
}
201+
buf[0] = reg;
202+
203+
LOG_DBG("PCA95XX[0x%X]: Write: REG[0x%X] = 0x%X", config->bus.addr,
204+
reg, buf[1]);
205+
206+
ret = i2c_write_dt(&config->bus, buf, sizeof(buf));
207+
if (ret == 0) {
208+
*cache = value;
209+
} else {
210+
LOG_ERR("PCA95XX[0x%X]: error writing to register 0x%X "
211+
"(%d)", config->bus.addr, reg, ret);
212+
}
213+
214+
return ret;
215+
}
216+
148217
/**
149218
* @brief Write both port 0 and port 1 registers of certain register function.
150219
*
@@ -182,6 +251,16 @@ static int write_port_regs(const struct device *dev, uint8_t reg,
182251
return ret;
183252
}
184253

254+
static inline int update_input_reg(const struct device *dev, uint8_t pin,
255+
uint16_t *buf)
256+
{
257+
struct gpio_pca95xx_drv_data * const drv_data =
258+
(struct gpio_pca95xx_drv_data * const)dev->data;
259+
260+
return read_port_reg(dev, REG_INPUT_PORT0, pin,
261+
&drv_data->reg_cache.input, buf);
262+
}
263+
185264
static inline int update_input_regs(const struct device *dev, uint16_t *buf)
186265
{
187266
struct gpio_pca95xx_drv_data * const drv_data =
@@ -191,6 +270,16 @@ static inline int update_input_regs(const struct device *dev, uint16_t *buf)
191270
&drv_data->reg_cache.input, buf);
192271
}
193272

273+
static inline int update_output_reg(const struct device *dev, uint8_t pin,
274+
uint16_t value)
275+
{
276+
struct gpio_pca95xx_drv_data * const drv_data =
277+
(struct gpio_pca95xx_drv_data * const)dev->data;
278+
279+
return write_port_reg(dev, REG_OUTPUT_PORT0, pin,
280+
&drv_data->reg_cache.output, value);
281+
}
282+
194283
static inline int update_output_regs(const struct device *dev, uint16_t value)
195284
{
196285
struct gpio_pca95xx_drv_data * const drv_data =
@@ -200,43 +289,45 @@ static inline int update_output_regs(const struct device *dev, uint16_t value)
200289
&drv_data->reg_cache.output, value);
201290
}
202291

203-
static inline int update_direction_regs(const struct device *dev,
292+
static inline int update_direction_reg(const struct device *dev, uint8_t pin,
204293
uint16_t value)
205294
{
206295
struct gpio_pca95xx_drv_data * const drv_data =
207296
(struct gpio_pca95xx_drv_data * const)dev->data;
208297

209-
return write_port_regs(dev, REG_CONF_PORT0,
210-
&drv_data->reg_cache.dir, value);
298+
return write_port_reg(dev, REG_CONF_PORT0, pin,
299+
&drv_data->reg_cache.dir, value);
211300
}
212301

213-
static inline int update_pul_sel_regs(const struct device *dev,
214-
uint16_t value)
302+
static inline int update_pul_sel_reg(const struct device *dev, uint8_t pin,
303+
uint16_t value)
215304
{
216305
struct gpio_pca95xx_drv_data * const drv_data =
217306
(struct gpio_pca95xx_drv_data * const)dev->data;
218307

219-
return write_port_regs(dev, REG_PUD_SEL_PORT0,
220-
&drv_data->reg_cache.pud_sel, value);
308+
return write_port_reg(dev, REG_PUD_SEL_PORT0, pin,
309+
&drv_data->reg_cache.pud_sel, value);
221310
}
222311

223-
static inline int update_pul_en_regs(const struct device *dev, uint16_t value)
312+
static inline int update_pul_en_reg(const struct device *dev, uint8_t pin,
313+
uint8_t value)
224314
{
225315
struct gpio_pca95xx_drv_data * const drv_data =
226316
(struct gpio_pca95xx_drv_data * const)dev->data;
227317

228-
return write_port_regs(dev, REG_PUD_EN_PORT0,
229-
&drv_data->reg_cache.pud_en, value);
318+
return write_port_reg(dev, REG_PUD_EN_PORT0, pin,
319+
&drv_data->reg_cache.pud_en, value);
230320
}
231321

232322
#ifdef CONFIG_GPIO_PCA95XX_INTERRUPT
233-
static inline int update_int_mask_regs(const struct device *dev, uint16_t value)
323+
static inline int update_int_mask_reg(const struct device *dev, uint8_t pin,
324+
uint16_t value)
234325
{
235326
struct gpio_pca95xx_drv_data * const drv_data =
236327
(struct gpio_pca95xx_drv_data * const)dev->data;
237328

238-
return write_port_regs(dev, REG_INT_MASK_PORT0,
239-
&drv_data->reg_cache.int_mask, value);
329+
return write_port_reg(dev, REG_INT_MASK_PORT0, pin,
330+
&drv_data->reg_cache.int_mask, value);
240331
}
241332
#endif /* CONFIG_GPIO_PCA95XX_INTERRUPT */
242333

@@ -264,7 +355,7 @@ static int setup_pin_dir(const struct device *dev, uint32_t pin, int flags)
264355
} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) {
265356
reg_out &= ~BIT(pin);
266357
}
267-
ret = update_output_regs(dev, reg_out);
358+
ret = update_output_reg(dev, pin, reg_out);
268359
if (ret != 0) {
269360
return ret;
270361
}
@@ -273,7 +364,7 @@ static int setup_pin_dir(const struct device *dev, uint32_t pin, int flags)
273364
reg_dir |= BIT(pin);
274365
}
275366

276-
ret = update_direction_regs(dev, reg_dir);
367+
ret = update_direction_reg(dev, pin, reg_dir);
277368

278369
return ret;
279370
}
@@ -319,7 +410,7 @@ static int setup_pin_pullupdown(const struct device *dev, uint32_t pin,
319410
/* pull down == 0, pull up == 1 */
320411
WRITE_BIT(reg_pud, pin, (flags & GPIO_PULL_UP) != 0U);
321412

322-
ret = update_pul_sel_regs(dev, reg_pud);
413+
ret = update_pul_sel_reg(dev, pin, reg_pud);
323414
if (ret) {
324415
return ret;
325416
}
@@ -331,7 +422,7 @@ static int setup_pin_pullupdown(const struct device *dev, uint32_t pin,
331422
WRITE_BIT(reg_pud, pin,
332423
(flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0U);
333424

334-
ret = update_pul_en_regs(dev, reg_pud);
425+
ret = update_pul_en_reg(dev, pin, reg_pud);
335426

336427
return ret;
337428
}
@@ -394,8 +485,7 @@ static int gpio_pca95xx_config(const struct device *dev,
394485
return ret;
395486
}
396487

397-
static int gpio_pca95xx_port_get_raw(const struct device *dev,
398-
uint32_t *value)
488+
static int gpio_pca95xx_port_get_raw(const struct device *dev, uint32_t *value)
399489
{
400490
struct gpio_pca95xx_drv_data * const drv_data =
401491
(struct gpio_pca95xx_drv_data * const)dev->data;
@@ -587,7 +677,7 @@ static int gpio_pca95xx_pin_interrupt_configure(const struct device *dev,
587677
reg_out = drv_data->reg_cache.int_mask;
588678
WRITE_BIT(reg_out, pin, (mode == GPIO_INT_MODE_DISABLED));
589679

590-
ret = update_int_mask_regs(dev, reg_out);
680+
ret = update_int_mask_reg(dev, pin, reg_out);
591681
if (ret != 0) {
592682
LOG_ERR("PCA95XX[0x%X]: failed to update int mask (%d)",
593683
config->bus.addr, ret);

0 commit comments

Comments
 (0)