mcp23018.c (3067B)
1 // Copyright 2022 zvecr<git@zvecr.com> 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 4 #include "mcp23018.h" 5 #include "i2c_master.h" 6 #include "wait.h" 7 #include "debug.h" 8 9 #define SLAVE_TO_ADDR(n) (n << 1) 10 #define TIMEOUT 100 11 12 enum { 13 CMD_IODIRA = 0x00, // i/o direction register 14 CMD_IODIRB = 0x01, 15 CMD_GPPUA = 0x0C, // GPIO pull-up resistor register 16 CMD_GPPUB = 0x0D, 17 CMD_GPIOA = 0x12, // general purpose i/o port register (write modifies OLAT) 18 CMD_GPIOB = 0x13, 19 }; 20 21 void mcp23018_init(uint8_t addr) { 22 static uint8_t s_init = 0; 23 if (!s_init) { 24 i2c_init(); 25 wait_ms(1000); 26 27 s_init = 1; 28 } 29 } 30 31 bool mcp23018_set_config(uint8_t slave_addr, mcp23018_port_t port, uint8_t conf) { 32 uint8_t addr = SLAVE_TO_ADDR(slave_addr); 33 uint8_t cmdDirection = port ? CMD_IODIRB : CMD_IODIRA; 34 uint8_t cmdPullup = port ? CMD_GPPUB : CMD_GPPUA; 35 36 i2c_status_t ret = i2c_write_register(addr, cmdDirection, &conf, sizeof(conf), TIMEOUT); 37 if (ret != I2C_STATUS_SUCCESS) { 38 dprintf("mcp23018_set_config::directionFAILED::%u\n", ret); 39 return false; 40 } 41 42 ret = i2c_write_register(addr, cmdPullup, &conf, sizeof(conf), TIMEOUT); 43 if (ret != I2C_STATUS_SUCCESS) { 44 dprintf("mcp23018_set_config::pullupFAILED::%u\n", ret); 45 return false; 46 } 47 48 return true; 49 } 50 51 bool mcp23018_set_output(uint8_t slave_addr, mcp23018_port_t port, uint8_t conf) { 52 uint8_t addr = SLAVE_TO_ADDR(slave_addr); 53 uint8_t cmd = port ? CMD_GPIOB : CMD_GPIOA; 54 55 i2c_status_t ret = i2c_write_register(addr, cmd, &conf, sizeof(conf), TIMEOUT); 56 if (ret != I2C_STATUS_SUCCESS) { 57 dprintf("mcp23018_set_output::FAILED::%u\n", ret); 58 return false; 59 } 60 61 return true; 62 } 63 64 bool mcp23018_set_output_all(uint8_t slave_addr, uint8_t confA, uint8_t confB) { 65 uint8_t addr = SLAVE_TO_ADDR(slave_addr); 66 uint8_t conf[2] = {confA, confB}; 67 68 i2c_status_t ret = i2c_write_register(addr, CMD_GPIOA, &conf[0], sizeof(conf), TIMEOUT); 69 if (ret != I2C_STATUS_SUCCESS) { 70 dprintf("mcp23018_set_output::FAILED::%u\n", ret); 71 return false; 72 } 73 74 return true; 75 } 76 77 bool mcp23018_read_pins(uint8_t slave_addr, mcp23018_port_t port, uint8_t* out) { 78 uint8_t addr = SLAVE_TO_ADDR(slave_addr); 79 uint8_t cmd = port ? CMD_GPIOB : CMD_GPIOA; 80 81 i2c_status_t ret = i2c_read_register(addr, cmd, out, sizeof(uint8_t), TIMEOUT); 82 if (ret != I2C_STATUS_SUCCESS) { 83 dprintf("mcp23018_read_pins::FAILED::%u\n", ret); 84 return false; 85 } 86 87 return true; 88 } 89 90 bool mcp23018_read_pins_all(uint8_t slave_addr, uint16_t* out) { 91 uint8_t addr = SLAVE_TO_ADDR(slave_addr); 92 93 typedef union { 94 uint8_t u8[2]; 95 uint16_t u16; 96 } data16; 97 98 data16 data = {.u16 = 0}; 99 100 i2c_status_t ret = i2c_read_register(addr, CMD_GPIOA, &data.u8[0], sizeof(data), TIMEOUT); 101 if (ret != I2C_STATUS_SUCCESS) { 102 dprintf("mcp23018_read_pins_all::FAILED::%u\n", ret); 103 return false; 104 } 105 106 *out = data.u16; 107 return true; 108 }