Skip to content

Commit 7b6e048

Browse files
committed
Improve tcal9539 support
- Fix various bugs - Add helper to synchronize shadow registers from hardware - Add method to read out in/out mode - get_pin() now also works for output pins
1 parent 85d3c8d commit 7b6e048

File tree

2 files changed

+128
-21
lines changed

2 files changed

+128
-21
lines changed

include/mios/io.h

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ typedef struct gpio_vtable {
121121

122122
error_t (*conf_output)(struct indirect_gpio *ig, unsigned int line,
123123
gpio_output_type_t type, gpio_output_speed_t speed,
124-
gpio_pull_t pull);
124+
gpio_pull_t pull, int initial_value);
125125

126126
// Read a single GPIO pin (one bit)
127127
error_t (*set_pin)(struct indirect_gpio *ig, unsigned int line, int on);
@@ -133,8 +133,52 @@ typedef struct gpio_vtable {
133133
error_t (*get_port)(struct indirect_gpio *ig, unsigned int port,
134134
uint32_t *pins);
135135

136+
// Return 1 if port is input, 0 if output
137+
int (*get_mode)(struct indirect_gpio *ig, unsigned int line);
138+
139+
error_t (*refresh_shadow)(struct indirect_gpio *ig);
140+
136141
} gpio_vtable_t;
137142

138143
typedef struct indirect_gpio {
139144
const gpio_vtable_t *vtable;
140145
} indirect_gpio_t;
146+
147+
static inline error_t
148+
indirect_gpio_conf_input(indirect_gpio_t *ig, unsigned int line,
149+
gpio_pull_t pull)
150+
{
151+
return ig->vtable->conf_input(ig, line, pull);
152+
}
153+
154+
static inline error_t
155+
indirect_gpio_conf_output(indirect_gpio_t *ig, unsigned int line,
156+
gpio_output_type_t type, gpio_output_speed_t speed,
157+
gpio_pull_t pull, int initial_value)
158+
{
159+
return ig->vtable->conf_output(ig, line, type, speed, pull, initial_value);
160+
}
161+
162+
static inline error_t
163+
indirect_gpio_set_pin(indirect_gpio_t *ig, unsigned int line, int on)
164+
{
165+
return ig->vtable->set_pin(ig, line, on);
166+
}
167+
168+
static inline error_t
169+
indirect_gpio_get_pin(indirect_gpio_t *ig, unsigned int line, int *status)
170+
{
171+
return ig->vtable->get_pin(ig, line, status);
172+
}
173+
174+
static inline int
175+
indirect_gpio_get_mode(indirect_gpio_t *ig, unsigned int line)
176+
{
177+
return ig->vtable->get_mode(ig, line);
178+
}
179+
180+
static inline error_t
181+
indirect_gpio_refresh_shadow(indirect_gpio_t *ig)
182+
{
183+
return ig->vtable->refresh_shadow(ig);
184+
}

src/drivers/tcal9539.c

Lines changed: 83 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ tcal9539_write_shadow(tcal9539_t *tc, unsigned int line,
3636
uint16_t shadow, int reg)
3737
{
3838
if(line < 8) {
39-
return i2c_write_u8(tc->i2c, tc->address, reg, shadow && 0xff);
39+
return i2c_write_u8(tc->i2c, tc->address, reg, shadow & 0xff);
4040
} else {
4141
return i2c_write_u8(tc->i2c, tc->address, reg + 1, shadow >> 8);
4242
}
@@ -109,38 +109,44 @@ tcal9539_conf_input(indirect_gpio_t *ig, unsigned int line, gpio_pull_t pull)
109109

110110

111111
static error_t
112-
tcal9539_conf_output(indirect_gpio_t *ig, unsigned int line,
113-
gpio_output_type_t type, gpio_output_speed_t speed,
114-
gpio_pull_t pull)
112+
tcal9539_set_pin(indirect_gpio_t *ig, unsigned int line, int on)
115113
{
116114
tcal9539_t *tc = (tcal9539_t *)ig;
117115

118116
if(line >= 16)
119117
return ERR_INVALID_ID;
120118

121-
error_t err = tcal9539_conf_pull(tc, line, pull);
122-
if(err)
123-
return err;
119+
if(on) {
120+
return tcal9539_set_bit_in_reg(tc, line, &tc->output, TCAL9539_OUTPUT0);
121+
} else {
122+
return tcal9539_clr_bit_in_reg(tc, line, &tc->output, TCAL9539_OUTPUT0);
123+
}
124124

125-
return tcal9539_clr_bit_in_reg(tc, line, &tc->direction, TCAL9539_CFG0);
125+
return ERR_NOT_IMPLEMENTED;
126126
}
127127

128128

129129
static error_t
130-
tcal9539_set_pin(indirect_gpio_t *ig, unsigned int line, int on)
130+
tcal9539_conf_output(indirect_gpio_t *ig, unsigned int line,
131+
gpio_output_type_t type, gpio_output_speed_t speed,
132+
gpio_pull_t pull, int initial_value)
131133
{
132134
tcal9539_t *tc = (tcal9539_t *)ig;
133135

134136
if(line >= 16)
135137
return ERR_INVALID_ID;
136138

137-
if(on) {
138-
return tcal9539_set_bit_in_reg(tc, line, &tc->output, TCAL9539_OUTPUT0);
139-
} else {
140-
return tcal9539_clr_bit_in_reg(tc, line, &tc->output, TCAL9539_OUTPUT0);
139+
error_t err = tcal9539_conf_pull(tc, line, pull);
140+
if(err)
141+
return err;
142+
143+
if(initial_value != -1) {
144+
err = tcal9539_set_pin(ig, line, initial_value);
145+
if(err)
146+
return err;
141147
}
142148

143-
return ERR_NOT_IMPLEMENTED;
149+
return tcal9539_clr_bit_in_reg(tc, line, &tc->direction, TCAL9539_CFG0);
144150
}
145151

146152

@@ -152,13 +158,20 @@ tcal9539_get_pin(indirect_gpio_t *ig, unsigned int line, int *status)
152158
if(line >= 16)
153159
return ERR_INVALID_ID;
154160

155-
uint8_t val;
156-
error_t err = i2c_read_u8(tc->i2c, tc->address, line >> 3, &val);
157-
if(err)
158-
return err;
159161

160-
int bit = line & 0x7;
161-
*status = !!(val & (1 << bit));
162+
if((1 << line) & tc->direction) {
163+
164+
uint8_t val;
165+
error_t err = i2c_read_u8(tc->i2c, tc->address, line >> 3, &val);
166+
if(err)
167+
return err;
168+
169+
int bit = line & 0x7;
170+
*status = !!(val & (1 << bit));
171+
} else {
172+
*status = (tc->output >> line) & 1;
173+
}
174+
162175
return 0;
163176
}
164177

@@ -179,13 +192,63 @@ tcal9539_get_port(indirect_gpio_t *ig, unsigned int port, uint32_t *status)
179192
return 0;
180193
}
181194

195+
static int
196+
tcal9539_get_mode(indirect_gpio_t *ig, unsigned int line)
197+
{
198+
tcal9539_t *tc = (tcal9539_t *)ig;
199+
return (tc->direction >> line) & 1;
200+
}
201+
202+
203+
204+
205+
206+
static error_t
207+
tcal9539_read_u16(tcal9539_t *tc, uint8_t reg, uint16_t *value)
208+
{
209+
uint8_t lo, hi;
210+
error_t err;
211+
212+
err = i2c_read_u8(tc->i2c, tc->address, reg, &lo);
213+
if(err)
214+
return err;
215+
err = i2c_read_u8(tc->i2c, tc->address, reg + 1, &hi);
216+
if(err)
217+
return err;
218+
219+
*value = ((uint16_t)hi << 8) | lo;
220+
return 0;
221+
}
222+
223+
224+
static error_t
225+
tcal9539_refresh_shadow(indirect_gpio_t *ig)
226+
{
227+
tcal9539_t *tc = (tcal9539_t *)ig;
228+
error_t err;
229+
230+
err = tcal9539_read_u16(tc, TCAL9539_OUTPUT0, &tc->output);
231+
if(err)
232+
return err;
233+
err = tcal9539_read_u16(tc, TCAL9539_CFG0, &tc->direction);
234+
if(err)
235+
return err;
236+
err = tcal9539_read_u16(tc, TCAL9539_PUD0, &tc->pull_direction);
237+
if(err)
238+
return err;
239+
240+
return tcal9539_read_u16(tc, TCAL9539_PE0, &tc->pull_enable);
241+
}
242+
182243

183244
static const gpio_vtable_t tcal9539_vtable = {
184245
.conf_input = tcal9539_conf_input,
185246
.conf_output = tcal9539_conf_output,
186247
.set_pin = tcal9539_set_pin,
187248
.get_pin = tcal9539_get_pin,
188249
.get_port = tcal9539_get_port,
250+
.get_mode = tcal9539_get_mode,
251+
.refresh_shadow = tcal9539_refresh_shadow,
189252
};
190253

191254

0 commit comments

Comments
 (0)