xref: /openbmc/u-boot/drivers/gpio/pca9698.c (revision e8f80a5a)
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 
pca9698_read40(u8 addr,u8 offset,u8 * buffer)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 
pca9698_write40(u8 addr,u8 offset,u8 * buffer)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 
pca9698_set_bit(unsigned gpio,u8 * buffer,unsigned value)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 
pca9698_request(unsigned gpio,const char * label)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 
pca9698_free(unsigned gpio)61042f9f10SDirk Eibach void pca9698_free(unsigned gpio)
62042f9f10SDirk Eibach {
63042f9f10SDirk Eibach }
64042f9f10SDirk Eibach 
pca9698_direction_input(u8 addr,unsigned gpio)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 
pca9698_direction_output(u8 addr,unsigned gpio,int value)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 
pca9698_get_value(u8 addr,unsigned gpio)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 
pca9698_set_value(u8 addr,unsigned gpio,int value)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