xref: /openbmc/u-boot/drivers/gpio/pca9698.c (revision e8f80a5a)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2011
4  * Dirk Eibach,  Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
5  */
6 
7 /*
8  * Driver for NXP's pca9698 40 bit I2C gpio expander
9  */
10 
11 #include <common.h>
12 #include <i2c.h>
13 #include <linux/errno.h>
14 #include <pca9698.h>
15 
16 /*
17  * The pca9698 registers
18  */
19 
20 #define PCA9698_REG_INPUT		0x00
21 #define PCA9698_REG_OUTPUT		0x08
22 #define PCA9698_REG_POLARITY		0x10
23 #define PCA9698_REG_CONFIG		0x18
24 
25 #define PCA9698_BUFFER_SIZE		5
26 #define PCA9698_GPIO_COUNT		40
27 
pca9698_read40(u8 addr,u8 offset,u8 * buffer)28 static int pca9698_read40(u8 addr, u8 offset, u8 *buffer)
29 {
30 	u8 command = offset | 0x80;  /* autoincrement */
31 
32 	return i2c_read(addr, command, 1, buffer, PCA9698_BUFFER_SIZE);
33 }
34 
pca9698_write40(u8 addr,u8 offset,u8 * buffer)35 static int pca9698_write40(u8 addr, u8 offset, u8 *buffer)
36 {
37 	u8 command = offset | 0x80;  /* autoincrement */
38 
39 	return i2c_write(addr, command, 1, buffer, PCA9698_BUFFER_SIZE);
40 }
41 
pca9698_set_bit(unsigned gpio,u8 * buffer,unsigned value)42 static void pca9698_set_bit(unsigned gpio, u8 *buffer, unsigned value)
43 {
44 	unsigned byte = gpio / 8;
45 	unsigned bit = gpio % 8;
46 
47 	if (value)
48 		buffer[byte] |= (1 << bit);
49 	else
50 		buffer[byte] &= ~(1 << bit);
51 }
52 
pca9698_request(unsigned gpio,const char * label)53 int pca9698_request(unsigned gpio, const char *label)
54 {
55 	if (gpio >= PCA9698_GPIO_COUNT)
56 		return -EINVAL;
57 
58 	return 0;
59 }
60 
pca9698_free(unsigned gpio)61 void pca9698_free(unsigned gpio)
62 {
63 }
64 
pca9698_direction_input(u8 addr,unsigned gpio)65 int pca9698_direction_input(u8 addr, unsigned gpio)
66 {
67 	u8 data[PCA9698_BUFFER_SIZE];
68 	int res;
69 
70 	res = pca9698_read40(addr, PCA9698_REG_CONFIG, data);
71 	if (res)
72 		return res;
73 
74 	pca9698_set_bit(gpio, data, 1);
75 
76 	return pca9698_write40(addr, PCA9698_REG_CONFIG, data);
77 }
78 
pca9698_direction_output(u8 addr,unsigned gpio,int value)79 int pca9698_direction_output(u8 addr, unsigned gpio, int value)
80 {
81 	u8 data[PCA9698_BUFFER_SIZE];
82 	int res;
83 
84 	res = pca9698_set_value(addr, gpio, value);
85 	if (res)
86 		return res;
87 
88 	res = pca9698_read40(addr, PCA9698_REG_CONFIG, data);
89 	if (res)
90 		return res;
91 
92 	pca9698_set_bit(gpio, data, 0);
93 
94 	return pca9698_write40(addr, PCA9698_REG_CONFIG, data);
95 }
96 
pca9698_get_value(u8 addr,unsigned gpio)97 int pca9698_get_value(u8 addr, unsigned gpio)
98 {
99 	unsigned config_byte = gpio / 8;
100 	unsigned config_bit = gpio % 8;
101 	unsigned value;
102 	u8 data[PCA9698_BUFFER_SIZE];
103 	int res;
104 
105 	res = pca9698_read40(addr, PCA9698_REG_INPUT, data);
106 	if (res)
107 		return -1;
108 
109 	value = data[config_byte] & (1 << config_bit);
110 
111 	return !!value;
112 }
113 
pca9698_set_value(u8 addr,unsigned gpio,int value)114 int pca9698_set_value(u8 addr, unsigned gpio, int value)
115 {
116 	u8 data[PCA9698_BUFFER_SIZE];
117 	int res;
118 
119 	res = pca9698_read40(addr, PCA9698_REG_OUTPUT, data);
120 	if (res)
121 		return res;
122 
123 	pca9698_set_bit(gpio, data, value);
124 
125 	return pca9698_write40(addr, PCA9698_REG_OUTPUT, data);
126 }
127