1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 2486cad03SDirk Eibach /* 3486cad03SDirk Eibach * (C) Copyright 2011 4d38826a3SMario Six * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc 5486cad03SDirk Eibach */ 6486cad03SDirk Eibach 7486cad03SDirk Eibach /* 8486cad03SDirk Eibach * Driver for NXP's pca9698 40 bit I2C gpio expander 9486cad03SDirk Eibach */ 10486cad03SDirk Eibach 11486cad03SDirk Eibach #include <common.h> 12486cad03SDirk Eibach #include <i2c.h> 131221ce45SMasahiro Yamada #include <linux/errno.h> 14486cad03SDirk Eibach #include <pca9698.h> 15486cad03SDirk Eibach 16486cad03SDirk Eibach /* 17486cad03SDirk Eibach * The pca9698 registers 18486cad03SDirk Eibach */ 19486cad03SDirk Eibach 20486cad03SDirk Eibach #define PCA9698_REG_INPUT 0x00 21486cad03SDirk Eibach #define PCA9698_REG_OUTPUT 0x08 22486cad03SDirk Eibach #define PCA9698_REG_POLARITY 0x10 23486cad03SDirk Eibach #define PCA9698_REG_CONFIG 0x18 24486cad03SDirk Eibach 25486cad03SDirk Eibach #define PCA9698_BUFFER_SIZE 5 26042f9f10SDirk Eibach #define PCA9698_GPIO_COUNT 40 27486cad03SDirk Eibach 28042f9f10SDirk Eibach static int pca9698_read40(u8 addr, u8 offset, u8 *buffer) 29486cad03SDirk Eibach { 30486cad03SDirk Eibach u8 command = offset | 0x80; /* autoincrement */ 31486cad03SDirk Eibach 32042f9f10SDirk Eibach return i2c_read(addr, command, 1, buffer, PCA9698_BUFFER_SIZE); 33486cad03SDirk Eibach } 34486cad03SDirk Eibach 35042f9f10SDirk Eibach static int pca9698_write40(u8 addr, u8 offset, u8 *buffer) 36486cad03SDirk Eibach { 37486cad03SDirk Eibach u8 command = offset | 0x80; /* autoincrement */ 38486cad03SDirk Eibach 39042f9f10SDirk Eibach return i2c_write(addr, command, 1, buffer, PCA9698_BUFFER_SIZE); 40486cad03SDirk Eibach } 41486cad03SDirk Eibach 42486cad03SDirk Eibach static void pca9698_set_bit(unsigned gpio, u8 *buffer, unsigned value) 43486cad03SDirk Eibach { 44486cad03SDirk Eibach unsigned byte = gpio / 8; 45486cad03SDirk Eibach unsigned bit = gpio % 8; 46486cad03SDirk Eibach 47486cad03SDirk Eibach if (value) 48486cad03SDirk Eibach buffer[byte] |= (1 << bit); 49486cad03SDirk Eibach else 50486cad03SDirk Eibach buffer[byte] &= ~(1 << bit); 51486cad03SDirk Eibach } 52486cad03SDirk Eibach 53042f9f10SDirk Eibach int pca9698_request(unsigned gpio, const char *label) 54042f9f10SDirk Eibach { 55042f9f10SDirk Eibach if (gpio >= PCA9698_GPIO_COUNT) 56042f9f10SDirk Eibach return -EINVAL; 57042f9f10SDirk Eibach 58042f9f10SDirk Eibach return 0; 59042f9f10SDirk Eibach } 60042f9f10SDirk Eibach 61042f9f10SDirk Eibach void pca9698_free(unsigned gpio) 62042f9f10SDirk Eibach { 63042f9f10SDirk Eibach } 64042f9f10SDirk Eibach 65042f9f10SDirk Eibach int pca9698_direction_input(u8 addr, unsigned gpio) 66486cad03SDirk Eibach { 67486cad03SDirk Eibach u8 data[PCA9698_BUFFER_SIZE]; 68486cad03SDirk Eibach int res; 69486cad03SDirk Eibach 70042f9f10SDirk Eibach res = pca9698_read40(addr, PCA9698_REG_CONFIG, data); 71486cad03SDirk Eibach if (res) 72486cad03SDirk Eibach return res; 73486cad03SDirk Eibach 74042f9f10SDirk Eibach pca9698_set_bit(gpio, data, 1); 75042f9f10SDirk Eibach 76042f9f10SDirk Eibach return pca9698_write40(addr, PCA9698_REG_CONFIG, data); 77486cad03SDirk Eibach } 78486cad03SDirk Eibach 79042f9f10SDirk Eibach int pca9698_direction_output(u8 addr, unsigned gpio, int value) 80486cad03SDirk Eibach { 81486cad03SDirk Eibach u8 data[PCA9698_BUFFER_SIZE]; 82486cad03SDirk Eibach int res; 83486cad03SDirk Eibach 84042f9f10SDirk Eibach res = pca9698_set_value(addr, gpio, value); 85486cad03SDirk Eibach if (res) 86486cad03SDirk Eibach return res; 87486cad03SDirk Eibach 88042f9f10SDirk Eibach res = pca9698_read40(addr, PCA9698_REG_CONFIG, data); 89042f9f10SDirk Eibach if (res) 90042f9f10SDirk Eibach return res; 91042f9f10SDirk Eibach 92042f9f10SDirk Eibach pca9698_set_bit(gpio, data, 0); 93042f9f10SDirk Eibach 94042f9f10SDirk Eibach return pca9698_write40(addr, PCA9698_REG_CONFIG, data); 95486cad03SDirk Eibach } 96486cad03SDirk Eibach 97042f9f10SDirk Eibach int pca9698_get_value(u8 addr, unsigned gpio) 98486cad03SDirk Eibach { 99042f9f10SDirk Eibach unsigned config_byte = gpio / 8; 100042f9f10SDirk Eibach unsigned config_bit = gpio % 8; 101486cad03SDirk Eibach unsigned value; 102486cad03SDirk Eibach u8 data[PCA9698_BUFFER_SIZE]; 103486cad03SDirk Eibach int res; 104486cad03SDirk Eibach 105042f9f10SDirk Eibach res = pca9698_read40(addr, PCA9698_REG_INPUT, data); 106486cad03SDirk Eibach if (res) 107486cad03SDirk Eibach return -1; 108486cad03SDirk Eibach 109486cad03SDirk Eibach value = data[config_byte] & (1 << config_bit); 110486cad03SDirk Eibach 111486cad03SDirk Eibach return !!value; 112486cad03SDirk Eibach } 113486cad03SDirk Eibach 114042f9f10SDirk Eibach int pca9698_set_value(u8 addr, unsigned gpio, int value) 115486cad03SDirk Eibach { 116486cad03SDirk Eibach u8 data[PCA9698_BUFFER_SIZE]; 117486cad03SDirk Eibach int res; 118486cad03SDirk Eibach 119042f9f10SDirk Eibach res = pca9698_read40(addr, PCA9698_REG_OUTPUT, data); 120486cad03SDirk Eibach if (res) 121486cad03SDirk Eibach return res; 122486cad03SDirk Eibach 123042f9f10SDirk Eibach pca9698_set_bit(gpio, data, value); 124042f9f10SDirk Eibach 125042f9f10SDirk Eibach return pca9698_write40(addr, PCA9698_REG_OUTPUT, data); 126486cad03SDirk Eibach } 127