11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Generic i2c interface for ALSA 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> 6c1017a4cSJaroslav Kysela * Modified for the ALSA driver by Jaroslav Kysela <perex@perex.cz> 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/init.h> 101da177e4SLinus Torvalds #include <linux/slab.h> 11da155d5bSPaul Gortmaker #include <linux/module.h> 121da177e4SLinus Torvalds #include <linux/string.h> 131da177e4SLinus Torvalds #include <linux/errno.h> 141da177e4SLinus Torvalds #include <sound/core.h> 151da177e4SLinus Torvalds #include <sound/i2c.h> 161da177e4SLinus Torvalds 17c1017a4cSJaroslav Kysela MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 181da177e4SLinus Torvalds MODULE_DESCRIPTION("Generic i2c interface for ALSA"); 191da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 201da177e4SLinus Torvalds 2197f02e05STakashi Iwai static int snd_i2c_bit_sendbytes(struct snd_i2c_device *device, 2297f02e05STakashi Iwai unsigned char *bytes, int count); 2397f02e05STakashi Iwai static int snd_i2c_bit_readbytes(struct snd_i2c_device *device, 2497f02e05STakashi Iwai unsigned char *bytes, int count); 2597f02e05STakashi Iwai static int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus, 2697f02e05STakashi Iwai unsigned short addr); 271da177e4SLinus Torvalds 285df29bcaSJulia Lawall static const struct snd_i2c_ops snd_i2c_bit_ops = { 291da177e4SLinus Torvalds .sendbytes = snd_i2c_bit_sendbytes, 301da177e4SLinus Torvalds .readbytes = snd_i2c_bit_readbytes, 311da177e4SLinus Torvalds .probeaddr = snd_i2c_bit_probeaddr, 321da177e4SLinus Torvalds }; 331da177e4SLinus Torvalds 3497f02e05STakashi Iwai static int snd_i2c_bus_free(struct snd_i2c_bus *bus) 351da177e4SLinus Torvalds { 3697f02e05STakashi Iwai struct snd_i2c_bus *slave; 3797f02e05STakashi Iwai struct snd_i2c_device *device; 381da177e4SLinus Torvalds 395e246b85STakashi Iwai if (snd_BUG_ON(!bus)) 405e246b85STakashi Iwai return -EINVAL; 411da177e4SLinus Torvalds while (!list_empty(&bus->devices)) { 421da177e4SLinus Torvalds device = snd_i2c_device(bus->devices.next); 431da177e4SLinus Torvalds snd_i2c_device_free(device); 441da177e4SLinus Torvalds } 451da177e4SLinus Torvalds if (bus->master) 461da177e4SLinus Torvalds list_del(&bus->buses); 471da177e4SLinus Torvalds else { 481da177e4SLinus Torvalds while (!list_empty(&bus->buses)) { 491da177e4SLinus Torvalds slave = snd_i2c_slave_bus(bus->buses.next); 501da177e4SLinus Torvalds snd_device_free(bus->card, slave); 511da177e4SLinus Torvalds } 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds if (bus->private_free) 541da177e4SLinus Torvalds bus->private_free(bus); 551da177e4SLinus Torvalds kfree(bus); 561da177e4SLinus Torvalds return 0; 571da177e4SLinus Torvalds } 581da177e4SLinus Torvalds 5997f02e05STakashi Iwai static int snd_i2c_bus_dev_free(struct snd_device *device) 601da177e4SLinus Torvalds { 6197f02e05STakashi Iwai struct snd_i2c_bus *bus = device->device_data; 621da177e4SLinus Torvalds return snd_i2c_bus_free(bus); 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 6597f02e05STakashi Iwai int snd_i2c_bus_create(struct snd_card *card, const char *name, 6697f02e05STakashi Iwai struct snd_i2c_bus *master, struct snd_i2c_bus **ri2c) 671da177e4SLinus Torvalds { 6897f02e05STakashi Iwai struct snd_i2c_bus *bus; 691da177e4SLinus Torvalds int err; 70d23015c1STakashi Iwai static const struct snd_device_ops ops = { 711da177e4SLinus Torvalds .dev_free = snd_i2c_bus_dev_free, 721da177e4SLinus Torvalds }; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds *ri2c = NULL; 75561b220aSTakashi Iwai bus = kzalloc(sizeof(*bus), GFP_KERNEL); 761da177e4SLinus Torvalds if (bus == NULL) 771da177e4SLinus Torvalds return -ENOMEM; 78ef9f0a42SIngo Molnar mutex_init(&bus->lock_mutex); 791da177e4SLinus Torvalds INIT_LIST_HEAD(&bus->devices); 801da177e4SLinus Torvalds INIT_LIST_HEAD(&bus->buses); 811da177e4SLinus Torvalds bus->card = card; 821da177e4SLinus Torvalds bus->ops = &snd_i2c_bit_ops; 831da177e4SLinus Torvalds if (master) { 841da177e4SLinus Torvalds list_add_tail(&bus->buses, &master->buses); 851da177e4SLinus Torvalds bus->master = master; 861da177e4SLinus Torvalds } 87*75b1a8f9SJoe Perches strscpy(bus->name, name, sizeof(bus->name)); 881cff399eSBrian Waters err = snd_device_new(card, SNDRV_DEV_BUS, bus, &ops); 891cff399eSBrian Waters if (err < 0) { 901da177e4SLinus Torvalds snd_i2c_bus_free(bus); 911da177e4SLinus Torvalds return err; 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds *ri2c = bus; 941da177e4SLinus Torvalds return 0; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 9757c65c11STakashi Iwai EXPORT_SYMBOL(snd_i2c_bus_create); 9857c65c11STakashi Iwai 9997f02e05STakashi Iwai int snd_i2c_device_create(struct snd_i2c_bus *bus, const char *name, 10097f02e05STakashi Iwai unsigned char addr, struct snd_i2c_device **rdevice) 1011da177e4SLinus Torvalds { 10297f02e05STakashi Iwai struct snd_i2c_device *device; 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds *rdevice = NULL; 1055e246b85STakashi Iwai if (snd_BUG_ON(!bus)) 1065e246b85STakashi Iwai return -EINVAL; 107561b220aSTakashi Iwai device = kzalloc(sizeof(*device), GFP_KERNEL); 1081da177e4SLinus Torvalds if (device == NULL) 1091da177e4SLinus Torvalds return -ENOMEM; 1101da177e4SLinus Torvalds device->addr = addr; 111*75b1a8f9SJoe Perches strscpy(device->name, name, sizeof(device->name)); 1121da177e4SLinus Torvalds list_add_tail(&device->list, &bus->devices); 1131da177e4SLinus Torvalds device->bus = bus; 1141da177e4SLinus Torvalds *rdevice = device; 1151da177e4SLinus Torvalds return 0; 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds 11857c65c11STakashi Iwai EXPORT_SYMBOL(snd_i2c_device_create); 11957c65c11STakashi Iwai 12097f02e05STakashi Iwai int snd_i2c_device_free(struct snd_i2c_device *device) 1211da177e4SLinus Torvalds { 1221da177e4SLinus Torvalds if (device->bus) 1231da177e4SLinus Torvalds list_del(&device->list); 1241da177e4SLinus Torvalds if (device->private_free) 1251da177e4SLinus Torvalds device->private_free(device); 1261da177e4SLinus Torvalds kfree(device); 1271da177e4SLinus Torvalds return 0; 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds 13057c65c11STakashi Iwai EXPORT_SYMBOL(snd_i2c_device_free); 13157c65c11STakashi Iwai 13297f02e05STakashi Iwai int snd_i2c_sendbytes(struct snd_i2c_device *device, unsigned char *bytes, int count) 1331da177e4SLinus Torvalds { 1341da177e4SLinus Torvalds return device->bus->ops->sendbytes(device, bytes, count); 1351da177e4SLinus Torvalds } 1361da177e4SLinus Torvalds 13757c65c11STakashi Iwai EXPORT_SYMBOL(snd_i2c_sendbytes); 1381da177e4SLinus Torvalds 13997f02e05STakashi Iwai int snd_i2c_readbytes(struct snd_i2c_device *device, unsigned char *bytes, int count) 1401da177e4SLinus Torvalds { 1411da177e4SLinus Torvalds return device->bus->ops->readbytes(device, bytes, count); 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 14457c65c11STakashi Iwai EXPORT_SYMBOL(snd_i2c_readbytes); 14557c65c11STakashi Iwai 14697f02e05STakashi Iwai int snd_i2c_probeaddr(struct snd_i2c_bus *bus, unsigned short addr) 1471da177e4SLinus Torvalds { 1481da177e4SLinus Torvalds return bus->ops->probeaddr(bus, addr); 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 15157c65c11STakashi Iwai EXPORT_SYMBOL(snd_i2c_probeaddr); 15257c65c11STakashi Iwai 1531da177e4SLinus Torvalds /* 1541da177e4SLinus Torvalds * bit-operations 1551da177e4SLinus Torvalds */ 1561da177e4SLinus Torvalds 15797f02e05STakashi Iwai static inline void snd_i2c_bit_hw_start(struct snd_i2c_bus *bus) 1581da177e4SLinus Torvalds { 1591da177e4SLinus Torvalds if (bus->hw_ops.bit->start) 1601da177e4SLinus Torvalds bus->hw_ops.bit->start(bus); 1611da177e4SLinus Torvalds } 1621da177e4SLinus Torvalds 16397f02e05STakashi Iwai static inline void snd_i2c_bit_hw_stop(struct snd_i2c_bus *bus) 1641da177e4SLinus Torvalds { 1651da177e4SLinus Torvalds if (bus->hw_ops.bit->stop) 1661da177e4SLinus Torvalds bus->hw_ops.bit->stop(bus); 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds 16997f02e05STakashi Iwai static void snd_i2c_bit_direction(struct snd_i2c_bus *bus, int clock, int data) 1701da177e4SLinus Torvalds { 1711da177e4SLinus Torvalds if (bus->hw_ops.bit->direction) 1721da177e4SLinus Torvalds bus->hw_ops.bit->direction(bus, clock, data); 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds 17597f02e05STakashi Iwai static void snd_i2c_bit_set(struct snd_i2c_bus *bus, int clock, int data) 1761da177e4SLinus Torvalds { 1771da177e4SLinus Torvalds bus->hw_ops.bit->setlines(bus, clock, data); 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds #if 0 18197f02e05STakashi Iwai static int snd_i2c_bit_clock(struct snd_i2c_bus *bus) 1821da177e4SLinus Torvalds { 1831da177e4SLinus Torvalds if (bus->hw_ops.bit->getclock) 1841da177e4SLinus Torvalds return bus->hw_ops.bit->getclock(bus); 1851da177e4SLinus Torvalds return -ENXIO; 1861da177e4SLinus Torvalds } 1871da177e4SLinus Torvalds #endif 1881da177e4SLinus Torvalds 18997f02e05STakashi Iwai static int snd_i2c_bit_data(struct snd_i2c_bus *bus, int ack) 1901da177e4SLinus Torvalds { 1911da177e4SLinus Torvalds return bus->hw_ops.bit->getdata(bus, ack); 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds 19497f02e05STakashi Iwai static void snd_i2c_bit_start(struct snd_i2c_bus *bus) 1951da177e4SLinus Torvalds { 1961da177e4SLinus Torvalds snd_i2c_bit_hw_start(bus); 1971da177e4SLinus Torvalds snd_i2c_bit_direction(bus, 1, 1); /* SCL - wr, SDA - wr */ 1981da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, 1); 1991da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, 0); 2001da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, 0); 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 20397f02e05STakashi Iwai static void snd_i2c_bit_stop(struct snd_i2c_bus *bus) 2041da177e4SLinus Torvalds { 2051da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, 0); 2061da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, 0); 2071da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, 1); 2081da177e4SLinus Torvalds snd_i2c_bit_hw_stop(bus); 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 21197f02e05STakashi Iwai static void snd_i2c_bit_send(struct snd_i2c_bus *bus, int data) 2121da177e4SLinus Torvalds { 2131da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, data); 2141da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, data); 2151da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, data); 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds 21897f02e05STakashi Iwai static int snd_i2c_bit_ack(struct snd_i2c_bus *bus) 2191da177e4SLinus Torvalds { 2201da177e4SLinus Torvalds int ack; 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, 1); 2231da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, 1); 2241da177e4SLinus Torvalds snd_i2c_bit_direction(bus, 1, 0); /* SCL - wr, SDA - rd */ 2251da177e4SLinus Torvalds ack = snd_i2c_bit_data(bus, 1); 2261da177e4SLinus Torvalds snd_i2c_bit_direction(bus, 1, 1); /* SCL - wr, SDA - wr */ 2271da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, 1); 2281da177e4SLinus Torvalds return ack ? -EIO : 0; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 23197f02e05STakashi Iwai static int snd_i2c_bit_sendbyte(struct snd_i2c_bus *bus, unsigned char data) 2321da177e4SLinus Torvalds { 2331da177e4SLinus Torvalds int i, err; 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds for (i = 7; i >= 0; i--) 2361da177e4SLinus Torvalds snd_i2c_bit_send(bus, !!(data & (1 << i))); 2371cff399eSBrian Waters err = snd_i2c_bit_ack(bus); 2381cff399eSBrian Waters if (err < 0) 2391da177e4SLinus Torvalds return err; 2401da177e4SLinus Torvalds return 0; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 24397f02e05STakashi Iwai static int snd_i2c_bit_readbyte(struct snd_i2c_bus *bus, int last) 2441da177e4SLinus Torvalds { 2451da177e4SLinus Torvalds int i; 2461da177e4SLinus Torvalds unsigned char data = 0; 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, 1); 2491da177e4SLinus Torvalds snd_i2c_bit_direction(bus, 1, 0); /* SCL - wr, SDA - rd */ 2501da177e4SLinus Torvalds for (i = 7; i >= 0; i--) { 2511da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, 1); 2521da177e4SLinus Torvalds if (snd_i2c_bit_data(bus, 0)) 2531da177e4SLinus Torvalds data |= (1 << i); 2541da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, 1); 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds snd_i2c_bit_direction(bus, 1, 1); /* SCL - wr, SDA - wr */ 2571da177e4SLinus Torvalds snd_i2c_bit_send(bus, !!last); 2581da177e4SLinus Torvalds return data; 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds 26197f02e05STakashi Iwai static int snd_i2c_bit_sendbytes(struct snd_i2c_device *device, 26297f02e05STakashi Iwai unsigned char *bytes, int count) 2631da177e4SLinus Torvalds { 26497f02e05STakashi Iwai struct snd_i2c_bus *bus = device->bus; 2651da177e4SLinus Torvalds int err, res = 0; 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds if (device->flags & SND_I2C_DEVICE_ADDRTEN) 2681da177e4SLinus Torvalds return -EIO; /* not yet implemented */ 2691da177e4SLinus Torvalds snd_i2c_bit_start(bus); 2701cff399eSBrian Waters err = snd_i2c_bit_sendbyte(bus, device->addr << 1); 2711cff399eSBrian Waters if (err < 0) { 2721da177e4SLinus Torvalds snd_i2c_bit_hw_stop(bus); 2731da177e4SLinus Torvalds return err; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds while (count-- > 0) { 2761cff399eSBrian Waters err = snd_i2c_bit_sendbyte(bus, *bytes++); 2771cff399eSBrian Waters if (err < 0) { 2781da177e4SLinus Torvalds snd_i2c_bit_hw_stop(bus); 2791da177e4SLinus Torvalds return err; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds res++; 2821da177e4SLinus Torvalds } 2831da177e4SLinus Torvalds snd_i2c_bit_stop(bus); 2841da177e4SLinus Torvalds return res; 2851da177e4SLinus Torvalds } 2861da177e4SLinus Torvalds 28797f02e05STakashi Iwai static int snd_i2c_bit_readbytes(struct snd_i2c_device *device, 28897f02e05STakashi Iwai unsigned char *bytes, int count) 2891da177e4SLinus Torvalds { 29097f02e05STakashi Iwai struct snd_i2c_bus *bus = device->bus; 2911da177e4SLinus Torvalds int err, res = 0; 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds if (device->flags & SND_I2C_DEVICE_ADDRTEN) 2941da177e4SLinus Torvalds return -EIO; /* not yet implemented */ 2951da177e4SLinus Torvalds snd_i2c_bit_start(bus); 2961cff399eSBrian Waters err = snd_i2c_bit_sendbyte(bus, (device->addr << 1) | 1); 2971cff399eSBrian Waters if (err < 0) { 2981da177e4SLinus Torvalds snd_i2c_bit_hw_stop(bus); 2991da177e4SLinus Torvalds return err; 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds while (count-- > 0) { 3021cff399eSBrian Waters err = snd_i2c_bit_readbyte(bus, count == 0); 3031cff399eSBrian Waters if (err < 0) { 3041da177e4SLinus Torvalds snd_i2c_bit_hw_stop(bus); 3051da177e4SLinus Torvalds return err; 3061da177e4SLinus Torvalds } 3071da177e4SLinus Torvalds *bytes++ = (unsigned char)err; 3081da177e4SLinus Torvalds res++; 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds snd_i2c_bit_stop(bus); 3111da177e4SLinus Torvalds return res; 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds 31497f02e05STakashi Iwai static int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus, unsigned short addr) 3151da177e4SLinus Torvalds { 3161da177e4SLinus Torvalds int err; 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds if (addr & 0x8000) /* 10-bit address */ 3191da177e4SLinus Torvalds return -EIO; /* not yet implemented */ 3201da177e4SLinus Torvalds if (addr & 0x7f80) /* invalid address */ 3211da177e4SLinus Torvalds return -EINVAL; 3221da177e4SLinus Torvalds snd_i2c_bit_start(bus); 3231da177e4SLinus Torvalds err = snd_i2c_bit_sendbyte(bus, addr << 1); 3241da177e4SLinus Torvalds snd_i2c_bit_stop(bus); 3251da177e4SLinus Torvalds return err; 3261da177e4SLinus Torvalds } 327