Blame view
sound/i2c/i2c.c
8.29 KB
1da177e4c
|
1 2 3 4 |
/* * Generic i2c interface for ALSA * * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> |
c1017a4cd
|
5 |
* Modified for the ALSA driver by Jaroslav Kysela <perex@perex.cz> |
1da177e4c
|
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ |
1da177e4c
|
22 23 24 25 26 27 |
#include <linux/init.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/errno.h> #include <sound/core.h> #include <sound/i2c.h> |
c1017a4cd
|
28 |
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); |
1da177e4c
|
29 30 |
MODULE_DESCRIPTION("Generic i2c interface for ALSA"); MODULE_LICENSE("GPL"); |
97f02e05f
|
31 32 33 34 35 36 37 38 |
static int snd_i2c_bit_sendbytes(struct snd_i2c_device *device, unsigned char *bytes, int count); static int snd_i2c_bit_readbytes(struct snd_i2c_device *device, unsigned char *bytes, int count); static int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus, unsigned short addr); static struct snd_i2c_ops snd_i2c_bit_ops = { |
1da177e4c
|
39 40 41 42 |
.sendbytes = snd_i2c_bit_sendbytes, .readbytes = snd_i2c_bit_readbytes, .probeaddr = snd_i2c_bit_probeaddr, }; |
97f02e05f
|
43 |
static int snd_i2c_bus_free(struct snd_i2c_bus *bus) |
1da177e4c
|
44 |
{ |
97f02e05f
|
45 46 |
struct snd_i2c_bus *slave; struct snd_i2c_device *device; |
1da177e4c
|
47 |
|
5e246b850
|
48 49 |
if (snd_BUG_ON(!bus)) return -EINVAL; |
1da177e4c
|
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
while (!list_empty(&bus->devices)) { device = snd_i2c_device(bus->devices.next); snd_i2c_device_free(device); } if (bus->master) list_del(&bus->buses); else { while (!list_empty(&bus->buses)) { slave = snd_i2c_slave_bus(bus->buses.next); snd_device_free(bus->card, slave); } } if (bus->private_free) bus->private_free(bus); kfree(bus); return 0; } |
97f02e05f
|
67 |
static int snd_i2c_bus_dev_free(struct snd_device *device) |
1da177e4c
|
68 |
{ |
97f02e05f
|
69 |
struct snd_i2c_bus *bus = device->device_data; |
1da177e4c
|
70 71 |
return snd_i2c_bus_free(bus); } |
97f02e05f
|
72 73 |
int snd_i2c_bus_create(struct snd_card *card, const char *name, struct snd_i2c_bus *master, struct snd_i2c_bus **ri2c) |
1da177e4c
|
74 |
{ |
97f02e05f
|
75 |
struct snd_i2c_bus *bus; |
1da177e4c
|
76 |
int err; |
97f02e05f
|
77 |
static struct snd_device_ops ops = { |
1da177e4c
|
78 79 80 81 |
.dev_free = snd_i2c_bus_dev_free, }; *ri2c = NULL; |
561b220a4
|
82 |
bus = kzalloc(sizeof(*bus), GFP_KERNEL); |
1da177e4c
|
83 84 |
if (bus == NULL) return -ENOMEM; |
ef9f0a42d
|
85 |
mutex_init(&bus->lock_mutex); |
1da177e4c
|
86 87 88 89 90 91 92 93 94 |
INIT_LIST_HEAD(&bus->devices); INIT_LIST_HEAD(&bus->buses); bus->card = card; bus->ops = &snd_i2c_bit_ops; if (master) { list_add_tail(&bus->buses, &master->buses); bus->master = master; } strlcpy(bus->name, name, sizeof(bus->name)); |
1cff399ec
|
95 96 |
err = snd_device_new(card, SNDRV_DEV_BUS, bus, &ops); if (err < 0) { |
1da177e4c
|
97 98 99 100 101 102 |
snd_i2c_bus_free(bus); return err; } *ri2c = bus; return 0; } |
57c65c116
|
103 |
EXPORT_SYMBOL(snd_i2c_bus_create); |
97f02e05f
|
104 105 |
int snd_i2c_device_create(struct snd_i2c_bus *bus, const char *name, unsigned char addr, struct snd_i2c_device **rdevice) |
1da177e4c
|
106 |
{ |
97f02e05f
|
107 |
struct snd_i2c_device *device; |
1da177e4c
|
108 109 |
*rdevice = NULL; |
5e246b850
|
110 111 |
if (snd_BUG_ON(!bus)) return -EINVAL; |
561b220a4
|
112 |
device = kzalloc(sizeof(*device), GFP_KERNEL); |
1da177e4c
|
113 114 115 116 117 118 119 120 121 |
if (device == NULL) return -ENOMEM; device->addr = addr; strlcpy(device->name, name, sizeof(device->name)); list_add_tail(&device->list, &bus->devices); device->bus = bus; *rdevice = device; return 0; } |
57c65c116
|
122 |
EXPORT_SYMBOL(snd_i2c_device_create); |
97f02e05f
|
123 |
int snd_i2c_device_free(struct snd_i2c_device *device) |
1da177e4c
|
124 125 126 127 128 129 130 131 |
{ if (device->bus) list_del(&device->list); if (device->private_free) device->private_free(device); kfree(device); return 0; } |
57c65c116
|
132 |
EXPORT_SYMBOL(snd_i2c_device_free); |
97f02e05f
|
133 |
int snd_i2c_sendbytes(struct snd_i2c_device *device, unsigned char *bytes, int count) |
1da177e4c
|
134 135 136 |
{ return device->bus->ops->sendbytes(device, bytes, count); } |
57c65c116
|
137 |
EXPORT_SYMBOL(snd_i2c_sendbytes); |
1da177e4c
|
138 |
|
97f02e05f
|
139 |
int snd_i2c_readbytes(struct snd_i2c_device *device, unsigned char *bytes, int count) |
1da177e4c
|
140 141 142 |
{ return device->bus->ops->readbytes(device, bytes, count); } |
57c65c116
|
143 |
EXPORT_SYMBOL(snd_i2c_readbytes); |
97f02e05f
|
144 |
int snd_i2c_probeaddr(struct snd_i2c_bus *bus, unsigned short addr) |
1da177e4c
|
145 146 147 |
{ return bus->ops->probeaddr(bus, addr); } |
57c65c116
|
148 |
EXPORT_SYMBOL(snd_i2c_probeaddr); |
1da177e4c
|
149 150 151 |
/* * bit-operations */ |
97f02e05f
|
152 |
static inline void snd_i2c_bit_hw_start(struct snd_i2c_bus *bus) |
1da177e4c
|
153 154 155 156 |
{ if (bus->hw_ops.bit->start) bus->hw_ops.bit->start(bus); } |
97f02e05f
|
157 |
static inline void snd_i2c_bit_hw_stop(struct snd_i2c_bus *bus) |
1da177e4c
|
158 159 160 161 |
{ if (bus->hw_ops.bit->stop) bus->hw_ops.bit->stop(bus); } |
97f02e05f
|
162 |
static void snd_i2c_bit_direction(struct snd_i2c_bus *bus, int clock, int data) |
1da177e4c
|
163 164 165 166 |
{ if (bus->hw_ops.bit->direction) bus->hw_ops.bit->direction(bus, clock, data); } |
97f02e05f
|
167 |
static void snd_i2c_bit_set(struct snd_i2c_bus *bus, int clock, int data) |
1da177e4c
|
168 169 170 171 172 |
{ bus->hw_ops.bit->setlines(bus, clock, data); } #if 0 |
97f02e05f
|
173 |
static int snd_i2c_bit_clock(struct snd_i2c_bus *bus) |
1da177e4c
|
174 175 176 177 178 179 |
{ if (bus->hw_ops.bit->getclock) return bus->hw_ops.bit->getclock(bus); return -ENXIO; } #endif |
97f02e05f
|
180 |
static int snd_i2c_bit_data(struct snd_i2c_bus *bus, int ack) |
1da177e4c
|
181 182 183 |
{ return bus->hw_ops.bit->getdata(bus, ack); } |
97f02e05f
|
184 |
static void snd_i2c_bit_start(struct snd_i2c_bus *bus) |
1da177e4c
|
185 186 187 188 189 190 191 |
{ snd_i2c_bit_hw_start(bus); snd_i2c_bit_direction(bus, 1, 1); /* SCL - wr, SDA - wr */ snd_i2c_bit_set(bus, 1, 1); snd_i2c_bit_set(bus, 1, 0); snd_i2c_bit_set(bus, 0, 0); } |
97f02e05f
|
192 |
static void snd_i2c_bit_stop(struct snd_i2c_bus *bus) |
1da177e4c
|
193 194 195 196 197 198 |
{ snd_i2c_bit_set(bus, 0, 0); snd_i2c_bit_set(bus, 1, 0); snd_i2c_bit_set(bus, 1, 1); snd_i2c_bit_hw_stop(bus); } |
97f02e05f
|
199 |
static void snd_i2c_bit_send(struct snd_i2c_bus *bus, int data) |
1da177e4c
|
200 201 202 203 204 |
{ snd_i2c_bit_set(bus, 0, data); snd_i2c_bit_set(bus, 1, data); snd_i2c_bit_set(bus, 0, data); } |
97f02e05f
|
205 |
static int snd_i2c_bit_ack(struct snd_i2c_bus *bus) |
1da177e4c
|
206 207 208 209 210 211 212 213 214 215 216 |
{ int ack; snd_i2c_bit_set(bus, 0, 1); snd_i2c_bit_set(bus, 1, 1); snd_i2c_bit_direction(bus, 1, 0); /* SCL - wr, SDA - rd */ ack = snd_i2c_bit_data(bus, 1); snd_i2c_bit_direction(bus, 1, 1); /* SCL - wr, SDA - wr */ snd_i2c_bit_set(bus, 0, 1); return ack ? -EIO : 0; } |
97f02e05f
|
217 |
static int snd_i2c_bit_sendbyte(struct snd_i2c_bus *bus, unsigned char data) |
1da177e4c
|
218 219 220 221 222 |
{ int i, err; for (i = 7; i >= 0; i--) snd_i2c_bit_send(bus, !!(data & (1 << i))); |
1cff399ec
|
223 224 |
err = snd_i2c_bit_ack(bus); if (err < 0) |
1da177e4c
|
225 226 227 |
return err; return 0; } |
97f02e05f
|
228 |
static int snd_i2c_bit_readbyte(struct snd_i2c_bus *bus, int last) |
1da177e4c
|
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
{ int i; unsigned char data = 0; snd_i2c_bit_set(bus, 0, 1); snd_i2c_bit_direction(bus, 1, 0); /* SCL - wr, SDA - rd */ for (i = 7; i >= 0; i--) { snd_i2c_bit_set(bus, 1, 1); if (snd_i2c_bit_data(bus, 0)) data |= (1 << i); snd_i2c_bit_set(bus, 0, 1); } snd_i2c_bit_direction(bus, 1, 1); /* SCL - wr, SDA - wr */ snd_i2c_bit_send(bus, !!last); return data; } |
97f02e05f
|
245 246 |
static int snd_i2c_bit_sendbytes(struct snd_i2c_device *device, unsigned char *bytes, int count) |
1da177e4c
|
247 |
{ |
97f02e05f
|
248 |
struct snd_i2c_bus *bus = device->bus; |
1da177e4c
|
249 250 251 252 253 |
int err, res = 0; if (device->flags & SND_I2C_DEVICE_ADDRTEN) return -EIO; /* not yet implemented */ snd_i2c_bit_start(bus); |
1cff399ec
|
254 255 |
err = snd_i2c_bit_sendbyte(bus, device->addr << 1); if (err < 0) { |
1da177e4c
|
256 257 258 259 |
snd_i2c_bit_hw_stop(bus); return err; } while (count-- > 0) { |
1cff399ec
|
260 261 |
err = snd_i2c_bit_sendbyte(bus, *bytes++); if (err < 0) { |
1da177e4c
|
262 263 264 265 266 267 268 269 |
snd_i2c_bit_hw_stop(bus); return err; } res++; } snd_i2c_bit_stop(bus); return res; } |
97f02e05f
|
270 271 |
static int snd_i2c_bit_readbytes(struct snd_i2c_device *device, unsigned char *bytes, int count) |
1da177e4c
|
272 |
{ |
97f02e05f
|
273 |
struct snd_i2c_bus *bus = device->bus; |
1da177e4c
|
274 275 276 277 278 |
int err, res = 0; if (device->flags & SND_I2C_DEVICE_ADDRTEN) return -EIO; /* not yet implemented */ snd_i2c_bit_start(bus); |
1cff399ec
|
279 280 |
err = snd_i2c_bit_sendbyte(bus, (device->addr << 1) | 1); if (err < 0) { |
1da177e4c
|
281 282 283 284 |
snd_i2c_bit_hw_stop(bus); return err; } while (count-- > 0) { |
1cff399ec
|
285 286 |
err = snd_i2c_bit_readbyte(bus, count == 0); if (err < 0) { |
1da177e4c
|
287 288 289 290 291 292 293 294 295 |
snd_i2c_bit_hw_stop(bus); return err; } *bytes++ = (unsigned char)err; res++; } snd_i2c_bit_stop(bus); return res; } |
97f02e05f
|
296 |
static int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus, unsigned short addr) |
1da177e4c
|
297 298 299 300 301 302 303 304 305 306 307 308 |
{ int err; if (addr & 0x8000) /* 10-bit address */ return -EIO; /* not yet implemented */ if (addr & 0x7f80) /* invalid address */ return -EINVAL; snd_i2c_bit_start(bus); err = snd_i2c_bit_sendbyte(bus, addr << 1); snd_i2c_bit_stop(bus); return err; } |
1da177e4c
|
309 310 311 312 313 314 315 316 317 318 319 320 |
static int __init alsa_i2c_init(void) { return 0; } static void __exit alsa_i2c_exit(void) { } module_init(alsa_i2c_init) module_exit(alsa_i2c_exit) |