2021-08-31 14:18:33 +02:00
|
|
|
/*
|
2021-11-23 21:40:48 -05:00
|
|
|
*
|
2021-08-31 14:18:33 +02:00
|
|
|
* Copyright (c) 2021 metraTec GmbH
|
2021-11-23 21:40:48 -05:00
|
|
|
* Copyright (c) 2021 Peter Johanson
|
2021-08-31 14:18:33 +02:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file Driver for MPC230xx I2C-based GPIO driver.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <errno.h>
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/kernel.h>
|
|
|
|
#include <zephyr/device.h>
|
|
|
|
#include <zephyr/sys/byteorder.h>
|
|
|
|
#include <zephyr/drivers/gpio.h>
|
|
|
|
#include <zephyr/drivers/i2c.h>
|
2021-08-31 14:18:33 +02:00
|
|
|
|
2022-10-21 23:48:01 +05:30
|
|
|
#include <zephyr/drivers/gpio/gpio_utils.h>
|
2021-11-23 21:40:48 -05:00
|
|
|
#include "gpio_mcp23xxx.h"
|
2021-08-31 14:18:33 +02:00
|
|
|
|
|
|
|
#define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/logging/log.h>
|
2021-08-31 14:18:33 +02:00
|
|
|
LOG_MODULE_REGISTER(gpio_mcp230xx);
|
|
|
|
|
2021-11-23 21:40:48 -05:00
|
|
|
static int mcp230xx_read_port_regs(const struct device *dev, uint8_t reg, uint16_t *buf)
|
2021-08-31 14:18:33 +02:00
|
|
|
{
|
2021-11-23 21:40:48 -05:00
|
|
|
const struct mcp23xxx_config *config = dev->config;
|
2021-08-31 14:18:33 +02:00
|
|
|
uint16_t port_data = 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
uint8_t nread = (config->ngpios == 8) ? 1 : 2;
|
|
|
|
|
2021-11-23 21:40:48 -05:00
|
|
|
ret = i2c_burst_read_dt(&config->bus.i2c, reg, (uint8_t *)&port_data, nread);
|
|
|
|
if (ret < 0) {
|
2021-08-31 14:18:33 +02:00
|
|
|
LOG_ERR("i2c_read failed!");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
*buf = sys_le16_to_cpu(port_data);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-11-23 21:40:48 -05:00
|
|
|
static int mcp230xx_write_port_regs(const struct device *dev, uint8_t reg, uint16_t value)
|
2021-08-31 14:18:33 +02:00
|
|
|
{
|
2021-11-23 21:40:48 -05:00
|
|
|
const struct mcp23xxx_config *config = dev->config;
|
2021-08-31 14:18:33 +02:00
|
|
|
int ret;
|
|
|
|
|
2021-12-21 01:14:45 -05:00
|
|
|
uint8_t nwrite = (config->ngpios == 8) ? 2 : 3;
|
|
|
|
uint8_t buf[3];
|
2021-08-31 14:18:33 +02:00
|
|
|
|
2021-12-21 01:14:45 -05:00
|
|
|
buf[0] = reg;
|
|
|
|
sys_put_le16(value, &buf[1]);
|
|
|
|
|
|
|
|
ret = i2c_write_dt(&config->bus.i2c, buf, nwrite);
|
2021-11-23 21:40:48 -05:00
|
|
|
if (ret < 0) {
|
2021-08-31 14:18:33 +02:00
|
|
|
LOG_ERR("i2c_write failed!");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-11-23 21:40:48 -05:00
|
|
|
static int mcp230xx_bus_is_ready(const struct device *dev)
|
2021-08-31 14:18:33 +02:00
|
|
|
{
|
2021-11-23 21:40:48 -05:00
|
|
|
const struct mcp23xxx_config *config = dev->config;
|
2021-08-31 14:18:33 +02:00
|
|
|
|
2021-11-23 21:40:48 -05:00
|
|
|
if (!device_is_ready(config->bus.i2c.bus)) {
|
|
|
|
LOG_ERR("I2C bus %s not ready", config->bus.i2c.bus->name);
|
2021-08-31 14:18:33 +02:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-11-27 12:56:51 +09:00
|
|
|
#define GPIO_MCP230XX_DEVICE(inst, num_gpios, open_drain, model) \
|
|
|
|
static struct mcp23xxx_drv_data mcp##model##_##inst##_drvdata = { \
|
2021-08-31 14:18:33 +02:00
|
|
|
/* Default for registers according to datasheet */ \
|
|
|
|
.reg_cache.iodir = 0xFFFF, .reg_cache.ipol = 0x0, .reg_cache.gpinten = 0x0, \
|
|
|
|
.reg_cache.defval = 0x0, .reg_cache.intcon = 0x0, .reg_cache.iocon = 0x0, \
|
2022-11-11 16:27:58 +01:00
|
|
|
.reg_cache.gppu = 0x0, .reg_cache.intf = 0x0, .reg_cache.intcap = 0x0, \
|
|
|
|
.reg_cache.gpio = 0x0, .reg_cache.olat = 0x0, \
|
|
|
|
}; \
|
2024-11-27 12:56:51 +09:00
|
|
|
static const struct mcp23xxx_config mcp##model##_##inst##_config = { \
|
2022-11-11 16:27:58 +01:00
|
|
|
.config = { \
|
2022-11-11 16:29:42 +01:00
|
|
|
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(inst), \
|
2022-11-11 16:27:58 +01:00
|
|
|
}, \
|
|
|
|
.bus = { \
|
2022-11-11 16:29:42 +01:00
|
|
|
.i2c = I2C_DT_SPEC_INST_GET(inst), \
|
2022-11-11 16:27:58 +01:00
|
|
|
}, \
|
2023-02-13 10:15:11 +01:00
|
|
|
.gpio_int = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}), \
|
2023-02-14 10:20:44 +01:00
|
|
|
.gpio_reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {0}), \
|
2024-03-13 09:14:28 +00:00
|
|
|
.ngpios = num_gpios, \
|
2023-11-27 08:39:01 +00:00
|
|
|
.is_open_drain = open_drain, \
|
2022-11-11 16:27:58 +01:00
|
|
|
.read_fn = mcp230xx_read_port_regs, \
|
|
|
|
.write_fn = mcp230xx_write_port_regs, \
|
|
|
|
.bus_fn = mcp230xx_bus_is_ready, \
|
2021-08-31 14:18:33 +02:00
|
|
|
}; \
|
2024-11-27 12:56:51 +09:00
|
|
|
DEVICE_DT_INST_DEFINE(inst, gpio_mcp23xxx_init, NULL, &mcp##model##_##inst##_drvdata, \
|
|
|
|
&mcp##model##_##inst##_config, POST_KERNEL, \
|
2022-11-11 16:27:58 +01:00
|
|
|
CONFIG_GPIO_MCP230XX_INIT_PRIORITY, &gpio_mcp23xxx_api_table);
|
2021-08-31 14:18:33 +02:00
|
|
|
|
2024-03-13 09:14:28 +00:00
|
|
|
#define DT_DRV_COMPAT microchip_mcp23008
|
2024-11-27 12:56:51 +09:00
|
|
|
DT_INST_FOREACH_STATUS_OKAY_VARGS(GPIO_MCP230XX_DEVICE, 8, false, 23008)
|
2024-03-13 09:14:28 +00:00
|
|
|
#undef DT_DRV_COMPAT
|
|
|
|
#define DT_DRV_COMPAT microchip_mcp23009
|
2024-11-27 12:56:51 +09:00
|
|
|
DT_INST_FOREACH_STATUS_OKAY_VARGS(GPIO_MCP230XX_DEVICE, 8, true, 23009)
|
2024-03-13 09:14:28 +00:00
|
|
|
#undef DT_DRV_COMPAT
|
|
|
|
#define DT_DRV_COMPAT microchip_mcp23016
|
2024-11-27 12:56:51 +09:00
|
|
|
DT_INST_FOREACH_STATUS_OKAY_VARGS(GPIO_MCP230XX_DEVICE, 16, false, 23016)
|
2024-03-13 09:14:28 +00:00
|
|
|
#undef DT_DRV_COMPAT
|
|
|
|
#define DT_DRV_COMPAT microchip_mcp23017
|
2024-11-27 12:56:51 +09:00
|
|
|
DT_INST_FOREACH_STATUS_OKAY_VARGS(GPIO_MCP230XX_DEVICE, 16, false, 23017)
|
2024-03-13 09:14:28 +00:00
|
|
|
#undef DT_DRV_COMPAT
|
|
|
|
#define DT_DRV_COMPAT microchip_mcp23018
|
2024-11-27 12:56:51 +09:00
|
|
|
DT_INST_FOREACH_STATUS_OKAY_VARGS(GPIO_MCP230XX_DEVICE, 16, true, 23018)
|
2024-03-13 09:14:28 +00:00
|
|
|
#undef DT_DRV_COMPAT
|