1486cad03SDirk Eibach /* 2486cad03SDirk Eibach * (C) Copyright 2011 3486cad03SDirk Eibach * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de 4486cad03SDirk Eibach * 51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 6486cad03SDirk Eibach */ 7486cad03SDirk Eibach 8486cad03SDirk Eibach /* 9486cad03SDirk Eibach * Driver for NXP's pca9698 40 bit I2C gpio expander 10486cad03SDirk Eibach */ 11486cad03SDirk Eibach 12486cad03SDirk Eibach #include <common.h> 13486cad03SDirk Eibach #include <i2c.h> 14*1221ce45SMasahiro Yamada #include <linux/errno.h> 15486cad03SDirk Eibach #include <pca9698.h> 16486cad03SDirk Eibach 17486cad03SDirk Eibach /* 18486cad03SDirk Eibach * The pca9698 registers 19486cad03SDirk Eibach */ 20486cad03SDirk Eibach 21486cad03SDirk Eibach #define PCA9698_REG_INPUT 0x00 22486cad03SDirk Eibach #define PCA9698_REG_OUTPUT 0x08 23486cad03SDirk Eibach #define PCA9698_REG_POLARITY 0x10 24486cad03SDirk Eibach #define PCA9698_REG_CONFIG 0x18 25486cad03SDirk Eibach 26486cad03SDirk Eibach #define PCA9698_BUFFER_SIZE 5 27042f9f10SDirk Eibach #define PCA9698_GPIO_COUNT 40 28486cad03SDirk Eibach 29042f9f10SDirk Eibach static int pca9698_read40(u8 addr, u8 offset, u8 *buffer) 30486cad03SDirk Eibach { 31486cad03SDirk Eibach u8 command = offset | 0x80; /* autoincrement */ 32486cad03SDirk Eibach 33042f9f10SDirk Eibach return i2c_read(addr, command, 1, buffer, PCA9698_BUFFER_SIZE); 34486cad03SDirk Eibach } 35486cad03SDirk Eibach 36042f9f10SDirk Eibach static int pca9698_write40(u8 addr, u8 offset, u8 *buffer) 37486cad03SDirk Eibach { 38486cad03SDirk Eibach u8 command = offset | 0x80; /* autoincrement */ 39486cad03SDirk Eibach 40042f9f10SDirk Eibach return i2c_write(addr, command, 1, buffer, PCA9698_BUFFER_SIZE); 41486cad03SDirk Eibach } 42486cad03SDirk Eibach 43486cad03SDirk Eibach static void pca9698_set_bit(unsigned gpio, u8 *buffer, unsigned value) 44486cad03SDirk Eibach { 45486cad03SDirk Eibach unsigned byte = gpio / 8; 46486cad03SDirk Eibach unsigned bit = gpio % 8; 47486cad03SDirk Eibach 48486cad03SDirk Eibach if (value) 49486cad03SDirk Eibach buffer[byte] |= (1 << bit); 50486cad03SDirk Eibach else 51486cad03SDirk Eibach buffer[byte] &= ~(1 << bit); 52486cad03SDirk Eibach } 53486cad03SDirk Eibach 54042f9f10SDirk Eibach int pca9698_request(unsigned gpio, const char *label) 55042f9f10SDirk Eibach { 56042f9f10SDirk Eibach if (gpio >= PCA9698_GPIO_COUNT) 57042f9f10SDirk Eibach return -EINVAL; 58042f9f10SDirk Eibach 59042f9f10SDirk Eibach return 0; 60042f9f10SDirk Eibach } 61042f9f10SDirk Eibach 62042f9f10SDirk Eibach void pca9698_free(unsigned gpio) 63042f9f10SDirk Eibach { 64042f9f10SDirk Eibach } 65042f9f10SDirk Eibach 66042f9f10SDirk Eibach int pca9698_direction_input(u8 addr, unsigned gpio) 67486cad03SDirk Eibach { 68486cad03SDirk Eibach u8 data[PCA9698_BUFFER_SIZE]; 69486cad03SDirk Eibach int res; 70486cad03SDirk Eibach 71042f9f10SDirk Eibach res = pca9698_read40(addr, PCA9698_REG_CONFIG, data); 72486cad03SDirk Eibach if (res) 73486cad03SDirk Eibach return res; 74486cad03SDirk Eibach 75042f9f10SDirk Eibach pca9698_set_bit(gpio, data, 1); 76042f9f10SDirk Eibach 77042f9f10SDirk Eibach return pca9698_write40(addr, PCA9698_REG_CONFIG, data); 78486cad03SDirk Eibach } 79486cad03SDirk Eibach 80042f9f10SDirk Eibach int pca9698_direction_output(u8 addr, unsigned gpio, int value) 81486cad03SDirk Eibach { 82486cad03SDirk Eibach u8 data[PCA9698_BUFFER_SIZE]; 83486cad03SDirk Eibach int res; 84486cad03SDirk Eibach 85042f9f10SDirk Eibach res = pca9698_set_value(addr, gpio, value); 86486cad03SDirk Eibach if (res) 87486cad03SDirk Eibach return res; 88486cad03SDirk Eibach 89042f9f10SDirk Eibach res = pca9698_read40(addr, PCA9698_REG_CONFIG, data); 90042f9f10SDirk Eibach if (res) 91042f9f10SDirk Eibach return res; 92042f9f10SDirk Eibach 93042f9f10SDirk Eibach pca9698_set_bit(gpio, data, 0); 94042f9f10SDirk Eibach 95042f9f10SDirk Eibach return pca9698_write40(addr, PCA9698_REG_CONFIG, data); 96486cad03SDirk Eibach } 97486cad03SDirk Eibach 98042f9f10SDirk Eibach int pca9698_get_value(u8 addr, unsigned gpio) 99486cad03SDirk Eibach { 100042f9f10SDirk Eibach unsigned config_byte = gpio / 8; 101042f9f10SDirk Eibach unsigned config_bit = gpio % 8; 102486cad03SDirk Eibach unsigned value; 103486cad03SDirk Eibach u8 data[PCA9698_BUFFER_SIZE]; 104486cad03SDirk Eibach int res; 105486cad03SDirk Eibach 106042f9f10SDirk Eibach res = pca9698_read40(addr, PCA9698_REG_INPUT, data); 107486cad03SDirk Eibach if (res) 108486cad03SDirk Eibach return -1; 109486cad03SDirk Eibach 110486cad03SDirk Eibach value = data[config_byte] & (1 << config_bit); 111486cad03SDirk Eibach 112486cad03SDirk Eibach return !!value; 113486cad03SDirk Eibach } 114486cad03SDirk Eibach 115042f9f10SDirk Eibach int pca9698_set_value(u8 addr, unsigned gpio, int value) 116486cad03SDirk Eibach { 117486cad03SDirk Eibach u8 data[PCA9698_BUFFER_SIZE]; 118486cad03SDirk Eibach int res; 119486cad03SDirk Eibach 120042f9f10SDirk Eibach res = pca9698_read40(addr, PCA9698_REG_OUTPUT, data); 121486cad03SDirk Eibach if (res) 122486cad03SDirk Eibach return res; 123486cad03SDirk Eibach 124042f9f10SDirk Eibach pca9698_set_bit(gpio, data, value); 125042f9f10SDirk Eibach 126042f9f10SDirk Eibach return pca9698_write40(addr, PCA9698_REG_OUTPUT, data); 127486cad03SDirk Eibach } 128