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