Lines Matching +full:has +full:- +full:interrupt +full:- +full:mask +full:- +full:reg
5 * SPDX-License-Identifier: Apache-2.0
9 * @file Driver for MPC23xxx I2C/SPI-based GPIO driver.
35 * @param reg The register to be read.
40 static int read_port_regs(const struct device *dev, uint8_t reg, uint16_t *buf) in read_port_regs() argument
42 const struct mcp23xxx_config *config = dev->config; in read_port_regs()
44 if (config->ngpios == 16U) { in read_port_regs()
45 reg *= 2; in read_port_regs()
48 return config->read_fn(dev, reg, buf); in read_port_regs()
58 * @param reg Register to be written.
63 static int write_port_regs(const struct device *dev, uint8_t reg, uint16_t value) in write_port_regs() argument
65 const struct mcp23xxx_config *config = dev->config; in write_port_regs()
67 if (config->ngpios == 16U) { in write_port_regs()
68 reg *= 2; in write_port_regs()
71 return config->write_fn(dev, reg, value); in write_port_regs()
77 * IOCON is the only register that is not 16 bits wide on 16-pin devices; instead, it is mirrored in
78 * two adjacent memory locations. Because the underlying `write_fn` always does a 16-bit write for
79 * 16-pin devices, make sure we write the same value to both IOCON locations.
88 struct mcp23xxx_drv_data *drv_data = dev->data; in write_iocon()
94 drv_data->reg_cache.iocon = extended_value; in write_iocon()
110 struct mcp23xxx_drv_data *drv_data = dev->data; in setup_pin_dir()
111 uint16_t dir = drv_data->reg_cache.iodir; in setup_pin_dir()
112 uint16_t output = drv_data->reg_cache.gpio; in setup_pin_dir()
131 drv_data->reg_cache.gpio = output; in setup_pin_dir()
135 drv_data->reg_cache.iodir = dir; in setup_pin_dir()
151 struct mcp23xxx_drv_data *drv_data = dev->data; in setup_pin_pull()
155 port = drv_data->reg_cache.gppu; in setup_pin_pull()
158 return -ENOTSUP; in setup_pin_pull()
165 drv_data->reg_cache.gppu = port; in setup_pin_pull()
173 struct mcp23xxx_drv_data *drv_data = dev->data; in mcp23xxx_pin_cfg()
174 const struct mcp23xxx_config *config = dev->config; in mcp23xxx_pin_cfg()
178 return -EWOULDBLOCK; in mcp23xxx_pin_cfg()
181 k_sem_take(&drv_data->lock, K_FOREVER); in mcp23xxx_pin_cfg()
183 if ((bool)(flags & GPIO_SINGLE_ENDED) != config->is_open_drain || in mcp23xxx_pin_cfg()
184 (bool)(flags & GPIO_LINE_OPEN_DRAIN) != config->is_open_drain) { in mcp23xxx_pin_cfg()
185 ret = -ENOTSUP; in mcp23xxx_pin_cfg()
202 k_sem_give(&drv_data->lock); in mcp23xxx_pin_cfg()
208 struct mcp23xxx_drv_data *drv_data = dev->data; in mcp23xxx_port_get_raw()
213 return -EWOULDBLOCK; in mcp23xxx_port_get_raw()
216 k_sem_take(&drv_data->lock, K_FOREVER); in mcp23xxx_port_get_raw()
223 k_sem_give(&drv_data->lock); in mcp23xxx_port_get_raw()
227 static int mcp23xxx_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value) in mcp23xxx_port_set_masked_raw() argument
229 struct mcp23xxx_drv_data *drv_data = dev->data; in mcp23xxx_port_set_masked_raw()
234 return -EWOULDBLOCK; in mcp23xxx_port_set_masked_raw()
237 k_sem_take(&drv_data->lock, K_FOREVER); in mcp23xxx_port_set_masked_raw()
239 buf = drv_data->reg_cache.gpio; in mcp23xxx_port_set_masked_raw()
240 buf = (buf & ~mask) | (mask & value); in mcp23xxx_port_set_masked_raw()
244 drv_data->reg_cache.gpio = buf; in mcp23xxx_port_set_masked_raw()
247 k_sem_give(&drv_data->lock); in mcp23xxx_port_set_masked_raw()
251 static int mcp23xxx_port_set_bits_raw(const struct device *dev, uint32_t mask) in mcp23xxx_port_set_bits_raw() argument
253 return mcp23xxx_port_set_masked_raw(dev, mask, mask); in mcp23xxx_port_set_bits_raw()
256 static int mcp23xxx_port_clear_bits_raw(const struct device *dev, uint32_t mask) in mcp23xxx_port_clear_bits_raw() argument
258 return mcp23xxx_port_set_masked_raw(dev, mask, 0); in mcp23xxx_port_clear_bits_raw()
261 static int mcp23xxx_port_toggle_bits(const struct device *dev, uint32_t mask) in mcp23xxx_port_toggle_bits() argument
263 struct mcp23xxx_drv_data *drv_data = dev->data; in mcp23xxx_port_toggle_bits()
268 return -EWOULDBLOCK; in mcp23xxx_port_toggle_bits()
271 k_sem_take(&drv_data->lock, K_FOREVER); in mcp23xxx_port_toggle_bits()
273 buf = drv_data->reg_cache.gpio; in mcp23xxx_port_toggle_bits()
274 buf ^= mask; in mcp23xxx_port_toggle_bits()
278 drv_data->reg_cache.gpio = buf; in mcp23xxx_port_toggle_bits()
281 k_sem_give(&drv_data->lock); in mcp23xxx_port_toggle_bits()
289 struct mcp23xxx_drv_data *drv_data = dev->data; in mcp23xxx_pin_interrupt_configure()
290 const struct mcp23xxx_config *config = dev->config; in mcp23xxx_pin_interrupt_configure()
292 if (!config->gpio_int.port) { in mcp23xxx_pin_interrupt_configure()
293 return -ENOTSUP; in mcp23xxx_pin_interrupt_configure()
297 return -EWOULDBLOCK; in mcp23xxx_pin_interrupt_configure()
300 k_sem_take(&drv_data->lock, K_FOREVER); in mcp23xxx_pin_interrupt_configure()
302 uint16_t gpinten = drv_data->reg_cache.gpinten; in mcp23xxx_pin_interrupt_configure()
303 uint16_t defval = drv_data->reg_cache.defval; in mcp23xxx_pin_interrupt_configure()
304 uint16_t intcon = drv_data->reg_cache.intcon; in mcp23xxx_pin_interrupt_configure()
326 ret = -ENOTSUP; in mcp23xxx_pin_interrupt_configure()
329 ret = -EINVAL; in mcp23xxx_pin_interrupt_configure()
340 drv_data->rising_edge_ints &= ~BIT(pin); in mcp23xxx_pin_interrupt_configure()
341 drv_data->falling_edge_ints |= BIT(pin); in mcp23xxx_pin_interrupt_configure()
344 drv_data->rising_edge_ints |= BIT(pin); in mcp23xxx_pin_interrupt_configure()
345 drv_data->falling_edge_ints &= ~BIT(pin); in mcp23xxx_pin_interrupt_configure()
348 drv_data->rising_edge_ints |= BIT(pin); in mcp23xxx_pin_interrupt_configure()
349 drv_data->falling_edge_ints |= BIT(pin); in mcp23xxx_pin_interrupt_configure()
352 ret = -EINVAL; in mcp23xxx_pin_interrupt_configure()
362 drv_data->reg_cache.gpinten = gpinten; in mcp23xxx_pin_interrupt_configure()
368 drv_data->reg_cache.defval = defval; in mcp23xxx_pin_interrupt_configure()
374 drv_data->reg_cache.intcon = intcon; in mcp23xxx_pin_interrupt_configure()
377 k_sem_give(&drv_data->lock); in mcp23xxx_pin_interrupt_configure()
385 struct mcp23xxx_drv_data *drv_data = dev->data; in mcp23xxx_manage_callback()
386 const struct mcp23xxx_config *config = dev->config; in mcp23xxx_manage_callback()
388 if (!config->gpio_int.port) { in mcp23xxx_manage_callback()
389 return -ENOTSUP; in mcp23xxx_manage_callback()
393 return -EWOULDBLOCK; in mcp23xxx_manage_callback()
396 k_sem_take(&drv_data->lock, K_FOREVER); in mcp23xxx_manage_callback()
398 int ret = gpio_manage_callback(&drv_data->callbacks, callback, set); in mcp23xxx_manage_callback()
400 k_sem_give(&drv_data->lock); in mcp23xxx_manage_callback()
408 const struct device *dev = drv_data->dev; in mcp23xxx_work_handler()
412 k_sem_take(&drv_data->lock, K_FOREVER); in mcp23xxx_work_handler()
424 * - REG_GPIO was read from somewhere else before the interrupt handler had a chance in mcp23xxx_work_handler()
426 * - Even though the datasheet says differently, reading INTCAP while a level in mcp23xxx_work_handler()
427 * interrupt is active briefly (~2ns) causes the interrupt line to go high and in mcp23xxx_work_handler()
429 * find any active interrupts if the callback has disabled the level interrupt. in mcp23xxx_work_handler()
431 LOG_ERR("Spurious interrupt"); in mcp23xxx_work_handler()
437 /* Read INTCAP to acknowledge the interrupt */ in mcp23xxx_work_handler()
444 /* mcp23xxx does not support single-edge interrupts in hardware, filter them out manually */ in mcp23xxx_work_handler()
445 uint16_t level_ints = drv_data->reg_cache.gpinten & drv_data->reg_cache.intcon; in mcp23xxx_work_handler()
447 intf &= level_ints | (intcap & drv_data->rising_edge_ints) | in mcp23xxx_work_handler()
448 (~intcap & drv_data->falling_edge_ints); in mcp23xxx_work_handler()
450 k_sem_give(&drv_data->lock); in mcp23xxx_work_handler()
451 gpio_fire_callbacks(&drv_data->callbacks, dev, intf); in mcp23xxx_work_handler()
455 k_sem_give(&drv_data->lock); in mcp23xxx_work_handler()
464 k_work_submit(&drv_data->work); in mcp23xxx_int_gpio_handler()
486 const struct mcp23xxx_config *config = dev->config; in gpio_mcp23xxx_init()
487 struct mcp23xxx_drv_data *drv_data = dev->data; in gpio_mcp23xxx_init()
490 if (config->ngpios != 8U && config->ngpios != 16U) { in gpio_mcp23xxx_init()
491 LOG_ERR("Invalid value ngpios=%u. Expected 8 or 16!", config->ngpios); in gpio_mcp23xxx_init()
492 return -EINVAL; in gpio_mcp23xxx_init()
495 err = config->bus_fn(dev); in gpio_mcp23xxx_init()
500 k_sem_init(&drv_data->lock, 0, 1); in gpio_mcp23xxx_init()
503 if (config->gpio_reset.port) { in gpio_mcp23xxx_init()
504 err = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE); in gpio_mcp23xxx_init()
507 return -EIO; in gpio_mcp23xxx_init()
512 err = gpio_pin_set_dt(&config->gpio_reset, 0); in gpio_mcp23xxx_init()
515 return -EIO; in gpio_mcp23xxx_init()
520 if (config->gpio_int.port) { in gpio_mcp23xxx_init()
521 if (config->ngpios == 16) { in gpio_mcp23xxx_init()
527 return -EIO; in gpio_mcp23xxx_init()
531 if (!gpio_is_ready_dt(&config->gpio_int)) { in gpio_mcp23xxx_init()
533 return -ENODEV; in gpio_mcp23xxx_init()
536 drv_data->dev = dev; in gpio_mcp23xxx_init()
537 k_work_init(&drv_data->work, mcp23xxx_work_handler); in gpio_mcp23xxx_init()
539 err = gpio_pin_configure_dt(&config->gpio_int, GPIO_INPUT); in gpio_mcp23xxx_init()
542 return -EIO; in gpio_mcp23xxx_init()
545 gpio_init_callback(&drv_data->int_gpio_cb, mcp23xxx_int_gpio_handler, in gpio_mcp23xxx_init()
546 BIT(config->gpio_int.pin)); in gpio_mcp23xxx_init()
547 err = gpio_add_callback(config->gpio_int.port, &drv_data->int_gpio_cb); in gpio_mcp23xxx_init()
550 return -EIO; in gpio_mcp23xxx_init()
553 err = gpio_pin_interrupt_configure_dt(&config->gpio_int, GPIO_INT_EDGE_TO_ACTIVE); in gpio_mcp23xxx_init()
555 LOG_ERR("Failed to configure INT interrupt: %d", err); in gpio_mcp23xxx_init()
556 return -EIO; in gpio_mcp23xxx_init()
560 k_sem_give(&drv_data->lock); in gpio_mcp23xxx_init()