123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- /*
- * Copyright (c) 2018 Justin Watson
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include <errno.h>
- #include <kernel.h>
- #include <device.h>
- #include <init.h>
- #include <drivers/gpio.h>
- #include <drivers/i2c.h>
- #include <board_cfg.h>
- #include "gpio_utils.h"
- #include <logging/log.h>
- //LOG_MODULE_REGISTER(et6416, CONFIG_GPIO_LOG_LEVEL);
- LOG_MODULE_REGISTER(et6416, LOG_LEVEL_DBG);
- #include "gpio_utils.h"
- /* Number of pins supported by the device */
- #define NUM_PINS 16
- /* Max to select all pins supported on the device. */
- #define ALL_PINS ((u16_t)BIT_MASK(NUM_PINS))
- /* Reset delay is 2.5 ms, round up for Zephyr resolution */
- #define RESET_DELAY_MS 3
- #define ET6416_EDGE_FALLING 1
- #define ET6416_EDGE_RISING 2
- #define ET6416_EDGE_BOTH 3
- /** Cache of the output configuration and data of the pins. */
- struct et6416_pin_state {
- u16_t input_dat; /* 0x00 */
- u16_t output_data; /* 0x02 */
- u16_t polarity; /* 0x04 */
- u16_t dir; /* 0x06, 1=input 0= output */
- } ;
- struct et6416_irq_state {
- u16_t interrupt_mask; /* */
- u32_t interrupt_sense; /* */
- };
- /** Runtime driver data */
- struct et6416_drv_data {
- /* gpio_driver_data needs to be first */
- struct gpio_driver_data common;
- const struct device *i2c_master;
- struct et6416_pin_state pin_state;
- struct k_sem lock;
- #ifdef CONFIG_GPIO_ET6416_INTERRUPT
- struct device *gpio_int;
- struct gpio_callback gpio_cb;
- struct k_work work;
- struct et6416_irq_state irq_state;
- struct device *dev;
- /* user ISR cb */
- sys_slist_t cb;
- /* Enabled INT pins generating a cb */
- u16_t cb_pins;
- #endif /* CONFIG_GPIO_ET6416_INTERRUPT */
- };
- /** Configuration data */
- struct et6416_config {
- /* gpio_driver_config needs to be first */
- struct gpio_driver_config common;
- const char *i2c_master_dev_name;
- #ifdef CONFIG_GPIO_ET6416_INTERRUPT
- struct gpio_cfg et6416_irq;
- #endif /* CONFIG_GPIO_ET6416_INTERRUPT */
- u16_t i2c_slave_addr;
- };
- /* Pin configuration register addresses */
- enum {
- ET6416_REG_INPUT = 0x00,
- ET6416_REG_OUTPUT = 0x02,
- ET6416_REG_POLARITY_INVERSION = 0x04,
- ET6416_REG_CFG = 0x06,
- };
- /**
- * @brief Write a word to an internal address of an I2C slave.
- *
- * @param dev Pointer to the device structure for the driver instance.
- * @param dev_addr Address of the I2C device for writing.
- * @param reg_addr Address of the internal register being written.
- * @param value Value to be written to internal register.
- *
- * @retval 0 If successful.
- * @retval -EIO General input / output error.
- */
- static inline int i2c_reg_write_word(const struct device *dev, u16_t dev_addr,
- u8_t reg_addr, u16_t value)
- {
- u8_t tx_buf[3] = { reg_addr, value & 0xff , value >> 8};
- return i2c_write(dev, tx_buf, 3, dev_addr);
- }
- static inline int i2c_reg_read_word(const struct device *dev, u16_t dev_addr,
- u8_t reg_addr, u16_t *value)
- {
- return i2c_burst_read(dev, dev_addr,reg_addr, (u8_t *)value, 2);
- }
- #ifdef CONFIG_GPIO_ET6416_INTERRUPT
- static int et6416_handle_interrupt(void *arg)
- {
- struct device *dev = (struct device *) arg;
- //const struct et6416_config *cfg = dev->config_info;
- struct et6416_drv_data *drv_data = dev->data;
- u16_t pin_data;
- int ret = 0;
- u16_t int_source;
- k_sem_take(&drv_data->lock, K_FOREVER);
- ret = i2c_reg_read_word(drv_data->i2c_master, cfg->i2c_slave_addr,
- ET6416_REG_INPUT,
- &pin_data);
- if (ret != 0) {
- goto out;
- }
- out:
- k_sem_give(&drv_data->lock);
- if ((ret == 0)
- && ((int_source & drv_data->cb_pins) != 0)) {
- gpio_fire_callbacks(&drv_data->cb, dev, int_source);
- }
- return ret;
- }
- static void et6416_work_handler(struct k_work *work)
- {
- struct et6416_drv_data *drv_data =
- CONTAINER_OF(work, struct et6416_drv_data, work);
- et6416_handle_interrupt(drv_data->dev);
- }
- static void et6416_int_cb(struct device *dev, struct gpio_callback *gpio_cb,
- u32_t pins)
- {
- struct et6416_drv_data *drv_data = CONTAINER_OF(gpio_cb,
- struct et6416_drv_data, gpio_cb);
- ARG_UNUSED(pins);
- k_work_submit(&drv_data->work);
- }
- #endif
- static int gpio_et6416_config(const struct device *dev,
- gpio_pin_t pin,
- gpio_flags_t flags)
- {
- const struct et6416_config *cfg = dev->config;
- struct et6416_drv_data *drv_data = dev->data;
- struct et6416_pin_state *pins = &drv_data->pin_state;
- int rc ;
- /* Can't do I2C bus operations from an ISR */
- if (k_is_in_isr()) {
- return -EWOULDBLOCK;
- }
- k_sem_take(&drv_data->lock, K_FOREVER);
- if (flags & GPIO_OUTPUT) {
- pins->dir &= ~BIT(pin);
- }else {
- pins->dir |= BIT(pin); // INPUT
- }
- rc = i2c_reg_write_word(drv_data->i2c_master, cfg->i2c_slave_addr,
- ET6416_REG_CFG, pins->dir);
- if (rc) {
- LOG_ERR("dir write err=%d\n",rc);
- }else{
- LOG_DBG("read dir=0x%x\n", drv_data->pin_state.dir);
- }
- k_sem_give(&drv_data->lock);
- return rc;
- }
- static int port_get(const struct device *dev,
- gpio_port_value_t *value)
- {
- const struct et6416_config *cfg = dev->config;
- struct et6416_drv_data *drv_data = dev->data;
- u16_t pin_data;
- int rc = 0;
- /* Can't do I2C bus operations from an ISR */
- if (k_is_in_isr()) {
- return -EWOULDBLOCK;
- }
- k_sem_take(&drv_data->lock, K_FOREVER);
- rc = i2c_reg_read_word(drv_data->i2c_master, cfg->i2c_slave_addr,
- ET6416_REG_INPUT,
- &pin_data);
- LOG_DBG("read %04x got %d", pin_data, rc);
- if (rc != 0) {
- LOG_ERR("read err=%d\n",rc);
- }else{
- *value = pin_data;
- drv_data->pin_state.input_dat = pin_data;
- }
- k_sem_give(&drv_data->lock);
- return rc;
- }
- static int port_write(const struct device *dev,
- gpio_port_pins_t mask,
- gpio_port_value_t value,
- gpio_port_value_t toggle)
- {
- const struct et6416_config *cfg = dev->config;
- struct et6416_drv_data *drv_data = dev->data;
- u16_t *outp = &drv_data->pin_state.output_data;
- /* Can't do I2C bus operations from an ISR */
- if (k_is_in_isr()) {
- return -EWOULDBLOCK;
- }
- k_sem_take(&drv_data->lock, K_FOREVER);
- u16_t orig_out = *outp;
- u16_t out = ((orig_out & ~mask) | (value & mask)) ^ toggle;
- int rc = i2c_reg_write_word(drv_data->i2c_master, cfg->i2c_slave_addr,
- ET6416_REG_OUTPUT, out);
- if (rc == 0) {
- *outp = out;
- }else{
- LOG_ERR("write err=%d\n",rc);
- }
- k_sem_give(&drv_data->lock);
- LOG_DBG("write %04x msk %04x val %04x => %04x: %d", orig_out, mask, value, out, rc);
- return rc;
- }
- static int port_set_masked(const struct device *dev,
- gpio_port_pins_t mask,
- gpio_port_value_t value)
- {
- return port_write(dev, mask, value, 0);
- }
- static int port_set_bits(const struct device *dev,
- gpio_port_pins_t pins)
- {
- return port_write(dev, pins, pins, 0);
- }
- static int port_clear_bits(const struct device *dev,
- gpio_port_pins_t pins)
- {
- return port_write(dev, pins, 0, 0);
- }
- static int port_toggle_bits(const struct device *dev,
- gpio_port_pins_t pins)
- {
- return port_write(dev, 0, 0, pins);
- }
- static int pin_interrupt_configure(const struct device *dev,
- gpio_pin_t pin,
- enum gpio_int_mode mode,
- enum gpio_int_trig trig)
- {
- int rc = 0;
- if (!IS_ENABLED(CONFIG_GPIO_ET6416_INTERRUPT)
- && (mode != GPIO_INT_MODE_DISABLED)) {
- return -ENOTSUP;
- }
- #ifdef CONFIG_GPIO_ET6416_INTERRUPT
- const struct et6416_config *cfg = dev->config;
- struct et6416_drv_data *drv_data = dev->data;
- struct et6416_irq_state *irq = &drv_data->irq_state;
- k_sem_take(&drv_data->lock, K_FOREVER);
- if (mode == GPIO_INT_MODE_DISABLED) {
- drv_data->cb_pins &= ~BIT(pin);
- irq->interrupt_mask |= BIT(pin);
- } else { /* GPIO_INT_MODE_EDGE */
- drv_data->cb_pins |= BIT(pin);
- irq->interrupt_mask &= ~BIT(pin);
- if (trig == GPIO_INT_TRIG_BOTH) {
- irq->interrupt_sense |= (ET6416_EDGE_BOTH <<
- (pin * 2));
- } else if (trig == GPIO_INT_TRIG_LOW) {
- irq->interrupt_sense |= (ET6416_EDGE_FALLING <<
- (pin * 2));
- } else if (trig == GPIO_INT_TRIG_HIGH) {
- irq->interrupt_sense |= (ET6416_EDGE_RISING <<
- (pin * 2));
- }
- }
- k_sem_give(&drv_data->lock);
- #endif /* CONFIG_GPIO_ET6416_INTERRUPT */
- return rc;
- }
- /**
- * @brief Initialization function of ET6416
- *
- * @param dev Device struct
- * @return 0 if successful, failed otherwise.
- */
- static int vdd18v_power_on(void)
- {
- const struct device *gpio_dev;
- gpio_dev = device_get_binding(CONFIG_GPIO_PIN2NAME(CONFIG_GPIO_VDD18V_POWER_ON));
- if (!gpio_dev){
- printk("%d, vdd18 gpio dev fail!\n", __LINE__);
- return -EINVAL;
- }
- printk("%d, vdd18 poweron!\n", __LINE__);
- //gpio_pin_configure(gpio_dev, CONFIG_GPIO_VDD18V_POWER_ON%32, GPIO_OUTPUT | GPIO_PULL_UP);
- gpio_pin_configure(gpio_dev, CONFIG_GPIO_VDD18V_POWER_ON%32, GPIO_OUTPUT);
- gpio_pin_set(gpio_dev, CONFIG_GPIO_VDD18V_POWER_ON%32, 1);
- return 0;
- }
- static int et6416_init(const struct device *dev)
- {
- const struct et6416_config *cfg = dev->config;
- struct et6416_drv_data *drv_data = dev->data;
- int rc;
- printk("gpio:et6416_init\n");
- vdd18v_power_on();
- drv_data->i2c_master = device_get_binding(cfg->i2c_master_dev_name);
- if (!drv_data->i2c_master) {
- LOG_ERR("%s: no bus %s", dev->name,
- cfg->i2c_master_dev_name);
- return -EINVAL;
- }
- #ifdef CONFIG_GPIO_ET6416_INTERRUPT
- drv_data->dev = dev;
- if(!cfg->et6416_irq.use_gpio){
- LOG_ERR("gpio irq not cfg\n");
- return -EINVAL
- }
- drv_data->gpio_int = device_get_binding(cfg->et6416_irq.gpio_dev_name);
- if (!drv_data->gpio_int) {
- rc = -ENOTSUP;
- goto out;
- }
- k_work_init(&drv_data->work, et6416_work_handler);
- gpio_pin_configure(drv_data->gpio_int, cfg->et6416_irq.gpion,
- GPIO_INPUT | cfg->et6416_irq.flag);
- gpio_pin_interrupt_configure(drv_data->gpio_int, cfg->et6416_irq.gpion,
- GPIO_INT_EDGE_TO_ACTIVE);
- gpio_init_callback(&drv_data->gpio_cb, et6416_int_cb,
- BIT(cfg->et6416_irq.gpion));
- gpio_add_callback(drv_data->gpio_int, &drv_data->gpio_cb);
- #endif
- //rc = i2c_reg_write_word(drv_data->i2c_master, cfg->i2c_slave_addr,
- //ET6416_REG_CFG,0x0000); //output
- //LOG_DBG("write cfg 0x0000 ,rc=%d\n", rc);
- rc = i2c_reg_read_word(drv_data->i2c_master, cfg->i2c_slave_addr,
- ET6416_REG_CFG, &drv_data->pin_state.dir);
- LOG_DBG("read cfg=0x%x,rc=%d\n", drv_data->pin_state.dir, rc);
- rc = i2c_reg_read_word(drv_data->i2c_master, cfg->i2c_slave_addr,
- ET6416_REG_POLARITY_INVERSION, &drv_data->pin_state.polarity);
- LOG_DBG("read POLARITY=0x%x,rc=%d\n", drv_data->pin_state.polarity, rc);
- rc = i2c_reg_read_word(drv_data->i2c_master, cfg->i2c_slave_addr,
- ET6416_REG_INPUT, &drv_data->pin_state.input_dat);
- LOG_DBG("read indata=0x%x,rc=%d\n", drv_data->pin_state.input_dat, rc);
- rc = i2c_reg_read_word(drv_data->i2c_master, cfg->i2c_slave_addr,
- ET6416_REG_OUTPUT, &drv_data->pin_state.output_data);
- LOG_DBG("read outdata=0x%x,rc=%d\n", drv_data->pin_state.output_data, rc);
- //out:
- if (rc != 0) {
- LOG_ERR("%s init failed: %d", dev->name, rc);
- } else {
- LOG_INF("%s init ok", dev->name);
- }
- return rc;
- }
- #ifdef CONFIG_GPIO_ET6416_INTERRUPT
- static int gpio_et6416_manage_callback(const struct device *dev,
- struct gpio_callback *callback,
- bool set)
- {
- struct et6416_drv_data *data = dev->data;
- return gpio_manage_callback(&data->cb, callback, set);
- }
- static int gpio_et6416_enable_callback(const struct device *dev,
- gpio_pin_t pin)
- {
- struct et6416_drv_data *data = dev->data;
- data->cb_pins |= BIT(pin);
- return 0;
- }
- static int gpio_et6416_disable_callback(const struct device *dev,
- gpio_pin_t pin)
- {
- struct et6416_drv_data *data = dev->data;
- data->cb_pins &= ~BIT(pin);
- return 0;
- }
- #endif
- static const struct gpio_driver_api gpio_api_table = {
- .pin_configure = gpio_et6416_config,
- .port_get_raw = port_get,
- .port_set_masked_raw = port_set_masked,
- .port_set_bits_raw = port_set_bits,
- .port_clear_bits_raw = port_clear_bits,
- .port_toggle_bits = port_toggle_bits,
- .pin_interrupt_configure = pin_interrupt_configure,
- #ifdef CONFIG_GPIO_ET6416_INTERRUPT
- .manage_callback = gpio_et6416_manage_callback,
- .enable_callback = gpio_et6416_enable_callback,
- .disable_callback = gpio_et6416_disable_callback,
- #endif
- };
- static const struct et6416_config et6416_cfg = {
- .common = {
- .port_pin_mask = 0xffff,
- },
- .i2c_master_dev_name = CONFIG_EXTEND_GPIO_I2C_NAME,
- #ifdef CONFIG_GPIO_ET6416_INTERRUPT
- .et6416_irq = CONFIG_EXTEND_GPIO_ISR_GPIO,
- #endif
- .i2c_slave_addr = 0x20,
- };
- static struct et6416_drv_data et6416_drvdata = {
- .lock = Z_SEM_INITIALIZER(et6416_drvdata.lock, 1, 1),
- };
- #if IS_ENABLED(CONFIG_EXTEND_GPIO)
- DEVICE_DEFINE(et6416, CONFIG_EXTEND_GPIO_NAME,
- et6416_init, NULL, &et6416_drvdata, &et6416_cfg,
- POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS,
- &gpio_api_table);
- #endif
|