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