1 /* 2 * (C) Copyright 2011 3 * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de 4 * 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 /* 25 * Driver for NXP's pca9698 40 bit I2C gpio expander 26 */ 27 28 #include <common.h> 29 #include <i2c.h> 30 #include <pca9698.h> 31 32 /* 33 * The pca9698 registers 34 */ 35 36 #define PCA9698_REG_INPUT 0x00 37 #define PCA9698_REG_OUTPUT 0x08 38 #define PCA9698_REG_POLARITY 0x10 39 #define PCA9698_REG_CONFIG 0x18 40 41 #define PCA9698_BUFFER_SIZE 5 42 43 static int pca9698_read40(u8 chip, u8 offset, u8 *buffer) 44 { 45 u8 command = offset | 0x80; /* autoincrement */ 46 47 return i2c_read(chip, command, 1, buffer, PCA9698_BUFFER_SIZE); 48 } 49 50 static int pca9698_write40(u8 chip, u8 offset, u8 *buffer) 51 { 52 u8 command = offset | 0x80; /* autoincrement */ 53 54 return i2c_write(chip, command, 1, buffer, PCA9698_BUFFER_SIZE); 55 } 56 57 static void pca9698_set_bit(unsigned gpio, u8 *buffer, unsigned value) 58 { 59 unsigned byte = gpio / 8; 60 unsigned bit = gpio % 8; 61 62 if (value) 63 buffer[byte] |= (1 << bit); 64 else 65 buffer[byte] &= ~(1 << bit); 66 } 67 68 int pca9698_direction_input(u8 chip, unsigned offset) 69 { 70 u8 data[PCA9698_BUFFER_SIZE]; 71 int res; 72 73 res = pca9698_read40(chip, PCA9698_REG_CONFIG, data); 74 if (res) 75 return res; 76 77 pca9698_set_bit(offset, data, 1); 78 return pca9698_write40(chip, PCA9698_REG_CONFIG, data); 79 } 80 81 int pca9698_direction_output(u8 chip, unsigned offset) 82 { 83 u8 data[PCA9698_BUFFER_SIZE]; 84 int res; 85 86 res = pca9698_read40(chip, PCA9698_REG_CONFIG, data); 87 if (res) 88 return res; 89 90 pca9698_set_bit(offset, data, 0); 91 return pca9698_write40(chip, PCA9698_REG_CONFIG, data); 92 } 93 94 int pca9698_get_input(u8 chip, unsigned offset) 95 { 96 unsigned config_byte = offset / 8; 97 unsigned config_bit = offset % 8; 98 unsigned value; 99 u8 data[PCA9698_BUFFER_SIZE]; 100 int res; 101 102 res = pca9698_read40(chip, PCA9698_REG_INPUT, data); 103 if (res) 104 return -1; 105 106 value = data[config_byte] & (1 << config_bit); 107 108 return !!value; 109 } 110 111 int pca9698_set_output(u8 chip, unsigned offset, int value) 112 { 113 u8 data[PCA9698_BUFFER_SIZE]; 114 int res; 115 116 res = pca9698_read40(chip, PCA9698_REG_OUTPUT, data); 117 if (res) 118 return res; 119 120 memset(data, sizeof(data), 0); 121 pca9698_set_bit(offset, data, value); 122 return pca9698_write40(chip, PCA9698_REG_OUTPUT, data); 123 } 124