xref: /openbmc/u-boot/drivers/gpio/pca9698.c (revision 042f9f10)
1486cad03SDirk Eibach /*
2486cad03SDirk Eibach  * (C) Copyright 2011
3486cad03SDirk Eibach  * Dirk Eibach,  Guntermann & Drunck GmbH, eibach@gdsys.de
4486cad03SDirk Eibach  *
5486cad03SDirk Eibach  * See file CREDITS for list of people who contributed to this
6486cad03SDirk Eibach  * project.
7486cad03SDirk Eibach  *
8486cad03SDirk Eibach  * This program is free software; you can redistribute it and/or
9486cad03SDirk Eibach  * modify it under the terms of the GNU General Public License as
10486cad03SDirk Eibach  * published by the Free Software Foundation; either version 2 of
11486cad03SDirk Eibach  * the License, or (at your option) any later version.
12486cad03SDirk Eibach  *
13486cad03SDirk Eibach  * This program is distributed in the hope that it will be useful,
14486cad03SDirk Eibach  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15486cad03SDirk Eibach  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16486cad03SDirk Eibach  * GNU General Public License for more details.
17486cad03SDirk Eibach  *
18486cad03SDirk Eibach  * You should have received a copy of the GNU General Public License
19486cad03SDirk Eibach  * along with this program; if not, write to the Free Software
20486cad03SDirk Eibach  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21486cad03SDirk Eibach  * MA 02111-1307 USA
22486cad03SDirk Eibach  */
23486cad03SDirk Eibach 
24486cad03SDirk Eibach /*
25486cad03SDirk Eibach  * Driver for NXP's pca9698 40 bit I2C gpio expander
26486cad03SDirk Eibach  */
27486cad03SDirk Eibach 
28486cad03SDirk Eibach #include <common.h>
29486cad03SDirk Eibach #include <i2c.h>
30*042f9f10SDirk Eibach #include <asm/errno.h>
31486cad03SDirk Eibach #include <pca9698.h>
32486cad03SDirk Eibach 
33486cad03SDirk Eibach /*
34486cad03SDirk Eibach  * The pca9698 registers
35486cad03SDirk Eibach  */
36486cad03SDirk Eibach 
37486cad03SDirk Eibach #define PCA9698_REG_INPUT		0x00
38486cad03SDirk Eibach #define PCA9698_REG_OUTPUT		0x08
39486cad03SDirk Eibach #define PCA9698_REG_POLARITY		0x10
40486cad03SDirk Eibach #define PCA9698_REG_CONFIG		0x18
41486cad03SDirk Eibach 
42486cad03SDirk Eibach #define PCA9698_BUFFER_SIZE		5
43*042f9f10SDirk Eibach #define PCA9698_GPIO_COUNT		40
44486cad03SDirk Eibach 
45*042f9f10SDirk Eibach static int pca9698_read40(u8 addr, u8 offset, u8 *buffer)
46486cad03SDirk Eibach {
47486cad03SDirk Eibach 	u8 command = offset | 0x80;  /* autoincrement */
48486cad03SDirk Eibach 
49*042f9f10SDirk Eibach 	return i2c_read(addr, command, 1, buffer, PCA9698_BUFFER_SIZE);
50486cad03SDirk Eibach }
51486cad03SDirk Eibach 
52*042f9f10SDirk Eibach static int pca9698_write40(u8 addr, u8 offset, u8 *buffer)
53486cad03SDirk Eibach {
54486cad03SDirk Eibach 	u8 command = offset | 0x80;  /* autoincrement */
55486cad03SDirk Eibach 
56*042f9f10SDirk Eibach 	return i2c_write(addr, command, 1, buffer, PCA9698_BUFFER_SIZE);
57486cad03SDirk Eibach }
58486cad03SDirk Eibach 
59486cad03SDirk Eibach static void pca9698_set_bit(unsigned gpio, u8 *buffer, unsigned value)
60486cad03SDirk Eibach {
61486cad03SDirk Eibach 	unsigned byte = gpio / 8;
62486cad03SDirk Eibach 	unsigned bit = gpio % 8;
63486cad03SDirk Eibach 
64486cad03SDirk Eibach 	if (value)
65486cad03SDirk Eibach 		buffer[byte] |= (1 << bit);
66486cad03SDirk Eibach 	else
67486cad03SDirk Eibach 		buffer[byte] &= ~(1 << bit);
68486cad03SDirk Eibach }
69486cad03SDirk Eibach 
70*042f9f10SDirk Eibach int pca9698_request(unsigned gpio, const char *label)
71*042f9f10SDirk Eibach {
72*042f9f10SDirk Eibach 	if (gpio >= PCA9698_GPIO_COUNT)
73*042f9f10SDirk Eibach 		return -EINVAL;
74*042f9f10SDirk Eibach 
75*042f9f10SDirk Eibach 	return 0;
76*042f9f10SDirk Eibach }
77*042f9f10SDirk Eibach 
78*042f9f10SDirk Eibach void pca9698_free(unsigned gpio)
79*042f9f10SDirk Eibach {
80*042f9f10SDirk Eibach }
81*042f9f10SDirk Eibach 
82*042f9f10SDirk Eibach int pca9698_direction_input(u8 addr, unsigned gpio)
83486cad03SDirk Eibach {
84486cad03SDirk Eibach 	u8 data[PCA9698_BUFFER_SIZE];
85486cad03SDirk Eibach 	int res;
86486cad03SDirk Eibach 
87*042f9f10SDirk Eibach 	res = pca9698_read40(addr, PCA9698_REG_CONFIG, data);
88486cad03SDirk Eibach 	if (res)
89486cad03SDirk Eibach 		return res;
90486cad03SDirk Eibach 
91*042f9f10SDirk Eibach 	pca9698_set_bit(gpio, data, 1);
92*042f9f10SDirk Eibach 
93*042f9f10SDirk Eibach 	return pca9698_write40(addr, PCA9698_REG_CONFIG, data);
94486cad03SDirk Eibach }
95486cad03SDirk Eibach 
96*042f9f10SDirk Eibach int pca9698_direction_output(u8 addr, unsigned gpio, int value)
97486cad03SDirk Eibach {
98486cad03SDirk Eibach 	u8 data[PCA9698_BUFFER_SIZE];
99486cad03SDirk Eibach 	int res;
100486cad03SDirk Eibach 
101*042f9f10SDirk Eibach 	res = pca9698_set_value(addr, gpio, value);
102486cad03SDirk Eibach 	if (res)
103486cad03SDirk Eibach 		return res;
104486cad03SDirk Eibach 
105*042f9f10SDirk Eibach 	res = pca9698_read40(addr, PCA9698_REG_CONFIG, data);
106*042f9f10SDirk Eibach 	if (res)
107*042f9f10SDirk Eibach 		return res;
108*042f9f10SDirk Eibach 
109*042f9f10SDirk Eibach 	pca9698_set_bit(gpio, data, 0);
110*042f9f10SDirk Eibach 
111*042f9f10SDirk Eibach 	return pca9698_write40(addr, PCA9698_REG_CONFIG, data);
112486cad03SDirk Eibach }
113486cad03SDirk Eibach 
114*042f9f10SDirk Eibach int pca9698_get_value(u8 addr, unsigned gpio)
115486cad03SDirk Eibach {
116*042f9f10SDirk Eibach 	unsigned config_byte = gpio / 8;
117*042f9f10SDirk Eibach 	unsigned config_bit = gpio % 8;
118486cad03SDirk Eibach 	unsigned value;
119486cad03SDirk Eibach 	u8 data[PCA9698_BUFFER_SIZE];
120486cad03SDirk Eibach 	int res;
121486cad03SDirk Eibach 
122*042f9f10SDirk Eibach 	res = pca9698_read40(addr, PCA9698_REG_INPUT, data);
123486cad03SDirk Eibach 	if (res)
124486cad03SDirk Eibach 		return -1;
125486cad03SDirk Eibach 
126486cad03SDirk Eibach 	value = data[config_byte] & (1 << config_bit);
127486cad03SDirk Eibach 
128486cad03SDirk Eibach 	return !!value;
129486cad03SDirk Eibach }
130486cad03SDirk Eibach 
131*042f9f10SDirk Eibach int pca9698_set_value(u8 addr, unsigned gpio, int value)
132486cad03SDirk Eibach {
133486cad03SDirk Eibach 	u8 data[PCA9698_BUFFER_SIZE];
134486cad03SDirk Eibach 	int res;
135486cad03SDirk Eibach 
136*042f9f10SDirk Eibach 	res = pca9698_read40(addr, PCA9698_REG_OUTPUT, data);
137486cad03SDirk Eibach 	if (res)
138486cad03SDirk Eibach 		return res;
139486cad03SDirk Eibach 
140*042f9f10SDirk Eibach 	pca9698_set_bit(gpio, data, value);
141*042f9f10SDirk Eibach 
142*042f9f10SDirk Eibach 	return pca9698_write40(addr, PCA9698_REG_OUTPUT, data);
143486cad03SDirk Eibach }
144