Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 : /*
3 : * Copyright (C) 2021 Steven Stallion <sstallion@gmail.com>
4 : *
5 : * This library is free software; you can redistribute it and/or modify
6 : * it under the terms of the GNU Lesser General Public License as published
7 : * by the Free Software Foundation; either version 2.1 of the License, or
8 : * (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 : * the GNU Lesser General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, see <http://www.gnu.org/licenses/>.
17 : */
18 :
19 : #include "i2cd-private.h"
20 :
21 : #include <assert.h>
22 : #include <errno.h>
23 : #include <fcntl.h>
24 : #include <limits.h>
25 : #include <stdint.h>
26 : #include <stdio.h>
27 : #include <stdlib.h>
28 : #include <string.h>
29 : #include <unistd.h>
30 : #include <sys/ioctl.h>
31 : #include <sys/stat.h>
32 : #include <sys/types.h>
33 : #include <linux/i2c.h>
34 : #include <linux/i2c-dev.h>
35 :
36 6 : struct i2cd *i2cd_open(const char *path)
37 : {
38 : struct i2cd *dev;
39 : int errsv;
40 :
41 : assert(path != NULL);
42 :
43 6 : dev = calloc(1, sizeof(*dev));
44 6 : if (dev == NULL)
45 1 : return NULL;
46 :
47 5 : dev->path = strdup(path);
48 5 : if (dev->path == NULL)
49 1 : goto err;
50 :
51 4 : dev->fd = open(dev->path, O_RDWR);
52 4 : if (dev->fd < 0)
53 1 : goto err;
54 :
55 3 : return dev;
56 2 : err:
57 2 : errsv = errno;
58 :
59 2 : if (dev->path != NULL)
60 1 : free(dev->path);
61 :
62 2 : free(dev);
63 :
64 2 : errno = errsv;
65 2 : return NULL;
66 : }
67 :
68 1 : struct i2cd *i2cd_open_by_name(const char *name)
69 : {
70 : char path[PATH_MAX];
71 :
72 : assert(name != NULL);
73 :
74 1 : snprintf(path, sizeof(path), "/dev/%s", name);
75 1 : return i2cd_open(path);
76 : }
77 :
78 1 : struct i2cd *i2cd_open_by_number(unsigned int num)
79 : {
80 : char path[PATH_MAX];
81 :
82 1 : snprintf(path, sizeof(path), "/dev/i2c-%u", num);
83 1 : return i2cd_open(path);
84 : }
85 :
86 1 : void i2cd_close(struct i2cd *dev)
87 : {
88 : assert(dev != NULL);
89 :
90 1 : close(dev->fd);
91 :
92 1 : free(dev->path);
93 1 : free(dev);
94 1 : }
95 :
96 0 : const char *i2cd_get_path(struct i2cd *dev)
97 : {
98 : assert(dev != NULL);
99 :
100 0 : return dev->path;
101 : }
102 :
103 1 : int i2cd_set_retries(struct i2cd *dev, unsigned long retries)
104 : {
105 : assert(dev != NULL);
106 :
107 1 : return ioctl(dev->fd, I2C_RETRIES, retries);
108 : }
109 :
110 1 : int i2cd_set_timeout(struct i2cd *dev, unsigned long timeout)
111 : {
112 : assert(dev != NULL);
113 :
114 1 : return ioctl(dev->fd, I2C_TIMEOUT, timeout);
115 : }
116 :
117 1 : int i2cd_get_functionality(struct i2cd *dev, unsigned long *funcs)
118 : {
119 : assert(dev != NULL);
120 : assert(funcs != NULL);
121 :
122 1 : return ioctl(dev->fd, I2C_FUNCS, funcs);
123 : }
124 :
125 3 : int i2cd_transfer(struct i2cd *dev, struct i2c_msg msgs[], size_t nmsgs)
126 : {
127 3 : struct i2c_rdwr_ioctl_data msgset = {msgs, nmsgs};
128 :
129 : assert(dev != NULL);
130 : assert(msgs != NULL);
131 : assert(nmsgs <= I2C_RDWR_IOCTL_MAX_MSGS);
132 :
133 3 : return ioctl(dev->fd, I2C_RDWR, &msgset);
134 : }
135 :
136 1 : int i2cd_read(struct i2cd *dev, uint16_t addr, void *buf, size_t len)
137 : {
138 1 : struct i2c_msg msgs[] = {
139 : {
140 : .addr = addr,
141 : .flags = I2C_M_RD,
142 : .len = len,
143 : .buf = buf
144 : }
145 : };
146 :
147 : assert(buf != NULL);
148 : assert(len <= UINT16_MAX);
149 :
150 1 : return i2cd_transfer(dev, msgs, ARRAY_SIZE(msgs));
151 : }
152 :
153 1 : int i2cd_write(struct i2cd *dev, uint16_t addr, const void *buf, size_t len)
154 : {
155 1 : struct i2c_msg msgs[] = {
156 : {
157 : .addr = addr,
158 : .flags = 0,
159 : .len = len,
160 : .buf = (void *)buf
161 : }
162 : };
163 :
164 : assert(buf != NULL);
165 : assert(len <= UINT16_MAX);
166 :
167 1 : return i2cd_transfer(dev, msgs, ARRAY_SIZE(msgs));
168 : }
169 :
170 1 : int i2cd_write_read(struct i2cd *dev, uint16_t addr,
171 : const void *write_buf, size_t write_len,
172 : void *read_buf, size_t read_len)
173 : {
174 1 : struct i2c_msg msgs[] = {
175 : {
176 : .addr = addr,
177 : .flags = 0,
178 : .len = write_len,
179 : .buf = (void *)write_buf
180 : },
181 : {
182 : .addr = addr,
183 : .flags = I2C_M_RD,
184 : .len = read_len,
185 : .buf = read_buf
186 : }
187 : };
188 :
189 : assert(write_buf != NULL);
190 : assert(write_len <= UINT16_MAX);
191 : assert(read_buf != NULL);
192 : assert(read_len <= UINT16_MAX);
193 :
194 1 : return i2cd_transfer(dev, msgs, ARRAY_SIZE(msgs));
195 : }
|