1 /* 2 * (C) Copyright 2011 3 * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 /* 9 * Driver for NXP's pca9698 40 bit I2C gpio expander 10 */ 11 12 #include <common.h> 13 #include <i2c.h> 14 #include <linux/errno.h> 15 #include <pca9698.h> 16 17 /* 18 * The pca9698 registers 19 */ 20 21 #define PCA9698_REG_INPUT 0x00 22 #define PCA9698_REG_OUTPUT 0x08 23 #define PCA9698_REG_POLARITY 0x10 24 #define PCA9698_REG_CONFIG 0x18 25 26 #define PCA9698_BUFFER_SIZE 5 27 #define PCA9698_GPIO_COUNT 40 28 29 static int pca9698_read40(u8 addr, u8 offset, u8 *buffer) 30 { 31 u8 command = offset | 0x80; /* autoincrement */ 32 33 return i2c_read(addr, command, 1, buffer, PCA9698_BUFFER_SIZE); 34 } 35 36 static int pca9698_write40(u8 addr, u8 offset, u8 *buffer) 37 { 38 u8 command = offset | 0x80; /* autoincrement */ 39 40 return i2c_write(addr, command, 1, buffer, PCA9698_BUFFER_SIZE); 41 } 42 43 static void pca9698_set_bit(unsigned gpio, u8 *buffer, unsigned value) 44 { 45 unsigned byte = gpio / 8; 46 unsigned bit = gpio % 8; 47 48 if (value) 49 buffer[byte] |= (1 << bit); 50 else 51 buffer[byte] &= ~(1 << bit); 52 } 53 54 int pca9698_request(unsigned gpio, const char *label) 55 { 56 if (gpio >= PCA9698_GPIO_COUNT) 57 return -EINVAL; 58 59 return 0; 60 } 61 62 void pca9698_free(unsigned gpio) 63 { 64 } 65 66 int pca9698_direction_input(u8 addr, unsigned gpio) 67 { 68 u8 data[PCA9698_BUFFER_SIZE]; 69 int res; 70 71 res = pca9698_read40(addr, PCA9698_REG_CONFIG, data); 72 if (res) 73 return res; 74 75 pca9698_set_bit(gpio, data, 1); 76 77 return pca9698_write40(addr, PCA9698_REG_CONFIG, data); 78 } 79 80 int pca9698_direction_output(u8 addr, unsigned gpio, int value) 81 { 82 u8 data[PCA9698_BUFFER_SIZE]; 83 int res; 84 85 res = pca9698_set_value(addr, gpio, value); 86 if (res) 87 return res; 88 89 res = pca9698_read40(addr, PCA9698_REG_CONFIG, data); 90 if (res) 91 return res; 92 93 pca9698_set_bit(gpio, data, 0); 94 95 return pca9698_write40(addr, PCA9698_REG_CONFIG, data); 96 } 97 98 int pca9698_get_value(u8 addr, unsigned gpio) 99 { 100 unsigned config_byte = gpio / 8; 101 unsigned config_bit = gpio % 8; 102 unsigned value; 103 u8 data[PCA9698_BUFFER_SIZE]; 104 int res; 105 106 res = pca9698_read40(addr, PCA9698_REG_INPUT, data); 107 if (res) 108 return -1; 109 110 value = data[config_byte] & (1 << config_bit); 111 112 return !!value; 113 } 114 115 int pca9698_set_value(u8 addr, unsigned gpio, int value) 116 { 117 u8 data[PCA9698_BUFFER_SIZE]; 118 int res; 119 120 res = pca9698_read40(addr, PCA9698_REG_OUTPUT, data); 121 if (res) 122 return res; 123 124 pca9698_set_bit(gpio, data, value); 125 126 return pca9698_write40(addr, PCA9698_REG_OUTPUT, data); 127 } 128