esp_io_expander_tca9554.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <inttypes.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include "esp_bit_defs.h"
  10. #include "esp_check.h"
  11. #include "esp_log.h"
  12. #include "esp_io_expander.h"
  13. #include "esp_io_expander_tca9554.h"
  14. /* I2C communication related */
  15. #define I2C_TIMEOUT_MS (1000)
  16. #define I2C_CLK_SPEED (400000)
  17. #define IO_COUNT (8)
  18. /* Register address */
  19. #define INPUT_REG_ADDR (0x00)
  20. #define OUTPUT_REG_ADDR (0x01)
  21. #define DIRECTION_REG_ADDR (0x03)
  22. /* Default register value on power-up */
  23. #define DIR_REG_DEFAULT_VAL (0xff)
  24. #define OUT_REG_DEFAULT_VAL (0xff)
  25. /**
  26. * @brief Device Structure Type
  27. *
  28. */
  29. typedef struct {
  30. esp_io_expander_t base;
  31. i2c_master_dev_handle_t i2c_handle;
  32. struct {
  33. uint8_t direction;
  34. uint8_t output;
  35. } regs;
  36. } esp_io_expander_tca9554_t;
  37. static char *TAG = "tca9554";
  38. static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value);
  39. static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value);
  40. static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value);
  41. static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value);
  42. static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value);
  43. static esp_err_t reset(esp_io_expander_t *handle);
  44. static esp_err_t del(esp_io_expander_t *handle);
  45. esp_err_t esp_io_expander_new_i2c_tca9554(i2c_master_bus_handle_t i2c_bus, uint32_t dev_addr, esp_io_expander_handle_t *handle_ret)
  46. {
  47. ESP_RETURN_ON_FALSE(handle_ret != NULL, ESP_ERR_INVALID_ARG, TAG, "Invalid handle_ret");
  48. // Allocate memory for driver object
  49. esp_io_expander_tca9554_t *tca9554 = (esp_io_expander_tca9554_t *)calloc(1, sizeof(esp_io_expander_tca9554_t));
  50. ESP_RETURN_ON_FALSE(tca9554 != NULL, ESP_ERR_NO_MEM, TAG, "Malloc failed");
  51. // Add new I2C device
  52. esp_err_t ret = ESP_OK;
  53. const i2c_device_config_t i2c_dev_cfg = {
  54. .device_address = dev_addr,
  55. .scl_speed_hz = I2C_CLK_SPEED,
  56. };
  57. ESP_GOTO_ON_ERROR(i2c_master_bus_add_device(i2c_bus, &i2c_dev_cfg, &tca9554->i2c_handle), err, TAG, "Add new I2C device failed");
  58. tca9554->base.config.io_count = IO_COUNT;
  59. tca9554->base.config.flags.dir_out_bit_zero = 1;
  60. tca9554->base.read_input_reg = read_input_reg;
  61. tca9554->base.write_output_reg = write_output_reg;
  62. tca9554->base.read_output_reg = read_output_reg;
  63. tca9554->base.write_direction_reg = write_direction_reg;
  64. tca9554->base.read_direction_reg = read_direction_reg;
  65. tca9554->base.del = del;
  66. tca9554->base.reset = reset;
  67. /* Reset configuration and register status */
  68. ESP_GOTO_ON_ERROR(reset(&tca9554->base), err, TAG, "Reset failed");
  69. *handle_ret = &tca9554->base;
  70. return ESP_OK;
  71. err:
  72. free(tca9554);
  73. return ret;
  74. }
  75. static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value)
  76. {
  77. esp_io_expander_tca9554_t *tca9554 = (esp_io_expander_tca9554_t *)__containerof(handle, esp_io_expander_tca9554_t, base);
  78. uint8_t temp = 0;
  79. ESP_RETURN_ON_ERROR(i2c_master_transmit_receive(tca9554->i2c_handle, (uint8_t[]) {
  80. INPUT_REG_ADDR
  81. }, 1, &temp, sizeof(temp), I2C_TIMEOUT_MS), TAG, "Read input reg failed");
  82. *value = temp;
  83. return ESP_OK;
  84. }
  85. static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value)
  86. {
  87. esp_io_expander_tca9554_t *tca9554 = (esp_io_expander_tca9554_t *)__containerof(handle, esp_io_expander_tca9554_t, base);
  88. value &= 0xff;
  89. uint8_t data[] = {OUTPUT_REG_ADDR, value};
  90. ESP_RETURN_ON_ERROR(i2c_master_transmit(tca9554->i2c_handle, data, sizeof(data), I2C_TIMEOUT_MS), TAG, "Write output reg failed");
  91. tca9554->regs.output = value;
  92. return ESP_OK;
  93. }
  94. static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value)
  95. {
  96. esp_io_expander_tca9554_t *tca9554 = (esp_io_expander_tca9554_t *)__containerof(handle, esp_io_expander_tca9554_t, base);
  97. *value = tca9554->regs.output;
  98. return ESP_OK;
  99. }
  100. static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value)
  101. {
  102. esp_io_expander_tca9554_t *tca9554 = (esp_io_expander_tca9554_t *)__containerof(handle, esp_io_expander_tca9554_t, base);
  103. value &= 0xff;
  104. uint8_t data[] = {DIRECTION_REG_ADDR, value};
  105. ESP_RETURN_ON_ERROR(i2c_master_transmit(tca9554->i2c_handle, data, sizeof(data), I2C_TIMEOUT_MS), TAG, "Write direction reg failed");
  106. tca9554->regs.direction = value;
  107. return ESP_OK;
  108. }
  109. static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value)
  110. {
  111. esp_io_expander_tca9554_t *tca9554 = (esp_io_expander_tca9554_t *)__containerof(handle, esp_io_expander_tca9554_t, base);
  112. *value = tca9554->regs.direction;
  113. return ESP_OK;
  114. }
  115. static esp_err_t reset(esp_io_expander_t *handle)
  116. {
  117. ESP_RETURN_ON_ERROR(write_direction_reg(handle, DIR_REG_DEFAULT_VAL), TAG, "Write dir reg failed");
  118. ESP_RETURN_ON_ERROR(write_output_reg(handle, OUT_REG_DEFAULT_VAL), TAG, "Write output reg failed");
  119. return ESP_OK;
  120. }
  121. static esp_err_t del(esp_io_expander_t *handle)
  122. {
  123. esp_io_expander_tca9554_t *tca9554 = (esp_io_expander_tca9554_t *)__containerof(handle, esp_io_expander_tca9554_t, base);
  124. ESP_RETURN_ON_ERROR(i2c_master_bus_rm_device(tca9554->i2c_handle), TAG, "Remove I2C device failed");
  125. free(tca9554);
  126. return ESP_OK;
  127. }