qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

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 }