11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Generic i2c interface for ALSA 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> 51da177e4SLinus Torvalds * Modified for the ALSA driver by Jaroslav Kysela <perex@suse.cz> 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 81da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 91da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 101da177e4SLinus Torvalds * (at your option) any later version. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 131da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 141da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 151da177e4SLinus Torvalds * GNU General Public License for more details. 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 181da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 191da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds */ 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #include <sound/driver.h> 241da177e4SLinus Torvalds #include <linux/init.h> 251da177e4SLinus Torvalds #include <linux/slab.h> 261da177e4SLinus Torvalds #include <linux/string.h> 271da177e4SLinus Torvalds #include <linux/errno.h> 281da177e4SLinus Torvalds #include <sound/core.h> 291da177e4SLinus Torvalds #include <sound/i2c.h> 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); 321da177e4SLinus Torvalds MODULE_DESCRIPTION("Generic i2c interface for ALSA"); 331da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds static int snd_i2c_bit_sendbytes(snd_i2c_device_t *device, unsigned char *bytes, int count); 361da177e4SLinus Torvalds static int snd_i2c_bit_readbytes(snd_i2c_device_t *device, unsigned char *bytes, int count); 371da177e4SLinus Torvalds static int snd_i2c_bit_probeaddr(snd_i2c_bus_t *bus, unsigned short addr); 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds static snd_i2c_ops_t snd_i2c_bit_ops = { 401da177e4SLinus Torvalds .sendbytes = snd_i2c_bit_sendbytes, 411da177e4SLinus Torvalds .readbytes = snd_i2c_bit_readbytes, 421da177e4SLinus Torvalds .probeaddr = snd_i2c_bit_probeaddr, 431da177e4SLinus Torvalds }; 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds static int snd_i2c_bus_free(snd_i2c_bus_t *bus) 461da177e4SLinus Torvalds { 471da177e4SLinus Torvalds snd_i2c_bus_t *slave; 481da177e4SLinus Torvalds snd_i2c_device_t *device; 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds snd_assert(bus != NULL, return -EINVAL); 511da177e4SLinus Torvalds while (!list_empty(&bus->devices)) { 521da177e4SLinus Torvalds device = snd_i2c_device(bus->devices.next); 531da177e4SLinus Torvalds snd_i2c_device_free(device); 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds if (bus->master) 561da177e4SLinus Torvalds list_del(&bus->buses); 571da177e4SLinus Torvalds else { 581da177e4SLinus Torvalds while (!list_empty(&bus->buses)) { 591da177e4SLinus Torvalds slave = snd_i2c_slave_bus(bus->buses.next); 601da177e4SLinus Torvalds snd_device_free(bus->card, slave); 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds if (bus->private_free) 641da177e4SLinus Torvalds bus->private_free(bus); 651da177e4SLinus Torvalds kfree(bus); 661da177e4SLinus Torvalds return 0; 671da177e4SLinus Torvalds } 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds static int snd_i2c_bus_dev_free(snd_device_t *device) 701da177e4SLinus Torvalds { 711da177e4SLinus Torvalds snd_i2c_bus_t *bus = device->device_data; 721da177e4SLinus Torvalds return snd_i2c_bus_free(bus); 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds int snd_i2c_bus_create(snd_card_t *card, const char *name, snd_i2c_bus_t *master, snd_i2c_bus_t **ri2c) 761da177e4SLinus Torvalds { 771da177e4SLinus Torvalds snd_i2c_bus_t *bus; 781da177e4SLinus Torvalds int err; 791da177e4SLinus Torvalds static snd_device_ops_t ops = { 801da177e4SLinus Torvalds .dev_free = snd_i2c_bus_dev_free, 811da177e4SLinus Torvalds }; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds *ri2c = NULL; 84*561b220aSTakashi Iwai bus = kzalloc(sizeof(*bus), GFP_KERNEL); 851da177e4SLinus Torvalds if (bus == NULL) 861da177e4SLinus Torvalds return -ENOMEM; 871da177e4SLinus Torvalds init_MUTEX(&bus->lock_mutex); 881da177e4SLinus Torvalds INIT_LIST_HEAD(&bus->devices); 891da177e4SLinus Torvalds INIT_LIST_HEAD(&bus->buses); 901da177e4SLinus Torvalds bus->card = card; 911da177e4SLinus Torvalds bus->ops = &snd_i2c_bit_ops; 921da177e4SLinus Torvalds if (master) { 931da177e4SLinus Torvalds list_add_tail(&bus->buses, &master->buses); 941da177e4SLinus Torvalds bus->master = master; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds strlcpy(bus->name, name, sizeof(bus->name)); 971da177e4SLinus Torvalds if ((err = snd_device_new(card, SNDRV_DEV_BUS, bus, &ops)) < 0) { 981da177e4SLinus Torvalds snd_i2c_bus_free(bus); 991da177e4SLinus Torvalds return err; 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds *ri2c = bus; 1021da177e4SLinus Torvalds return 0; 1031da177e4SLinus Torvalds } 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds int snd_i2c_device_create(snd_i2c_bus_t *bus, const char *name, unsigned char addr, snd_i2c_device_t **rdevice) 1061da177e4SLinus Torvalds { 1071da177e4SLinus Torvalds snd_i2c_device_t *device; 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds *rdevice = NULL; 1101da177e4SLinus Torvalds snd_assert(bus != NULL, return -EINVAL); 111*561b220aSTakashi Iwai device = kzalloc(sizeof(*device), GFP_KERNEL); 1121da177e4SLinus Torvalds if (device == NULL) 1131da177e4SLinus Torvalds return -ENOMEM; 1141da177e4SLinus Torvalds device->addr = addr; 1151da177e4SLinus Torvalds strlcpy(device->name, name, sizeof(device->name)); 1161da177e4SLinus Torvalds list_add_tail(&device->list, &bus->devices); 1171da177e4SLinus Torvalds device->bus = bus; 1181da177e4SLinus Torvalds *rdevice = device; 1191da177e4SLinus Torvalds return 0; 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds int snd_i2c_device_free(snd_i2c_device_t *device) 1231da177e4SLinus Torvalds { 1241da177e4SLinus Torvalds if (device->bus) 1251da177e4SLinus Torvalds list_del(&device->list); 1261da177e4SLinus Torvalds if (device->private_free) 1271da177e4SLinus Torvalds device->private_free(device); 1281da177e4SLinus Torvalds kfree(device); 1291da177e4SLinus Torvalds return 0; 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds int snd_i2c_sendbytes(snd_i2c_device_t *device, unsigned char *bytes, int count) 1331da177e4SLinus Torvalds { 1341da177e4SLinus Torvalds return device->bus->ops->sendbytes(device, bytes, count); 1351da177e4SLinus Torvalds } 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds int snd_i2c_readbytes(snd_i2c_device_t *device, unsigned char *bytes, int count) 1391da177e4SLinus Torvalds { 1401da177e4SLinus Torvalds return device->bus->ops->readbytes(device, bytes, count); 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds int snd_i2c_probeaddr(snd_i2c_bus_t *bus, unsigned short addr) 1441da177e4SLinus Torvalds { 1451da177e4SLinus Torvalds return bus->ops->probeaddr(bus, addr); 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds /* 1491da177e4SLinus Torvalds * bit-operations 1501da177e4SLinus Torvalds */ 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds static inline void snd_i2c_bit_hw_start(snd_i2c_bus_t *bus) 1531da177e4SLinus Torvalds { 1541da177e4SLinus Torvalds if (bus->hw_ops.bit->start) 1551da177e4SLinus Torvalds bus->hw_ops.bit->start(bus); 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds static inline void snd_i2c_bit_hw_stop(snd_i2c_bus_t *bus) 1591da177e4SLinus Torvalds { 1601da177e4SLinus Torvalds if (bus->hw_ops.bit->stop) 1611da177e4SLinus Torvalds bus->hw_ops.bit->stop(bus); 1621da177e4SLinus Torvalds } 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds static void snd_i2c_bit_direction(snd_i2c_bus_t *bus, int clock, int data) 1651da177e4SLinus Torvalds { 1661da177e4SLinus Torvalds if (bus->hw_ops.bit->direction) 1671da177e4SLinus Torvalds bus->hw_ops.bit->direction(bus, clock, data); 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds static void snd_i2c_bit_set(snd_i2c_bus_t *bus, int clock, int data) 1711da177e4SLinus Torvalds { 1721da177e4SLinus Torvalds bus->hw_ops.bit->setlines(bus, clock, data); 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds #if 0 1761da177e4SLinus Torvalds static int snd_i2c_bit_clock(snd_i2c_bus_t *bus) 1771da177e4SLinus Torvalds { 1781da177e4SLinus Torvalds if (bus->hw_ops.bit->getclock) 1791da177e4SLinus Torvalds return bus->hw_ops.bit->getclock(bus); 1801da177e4SLinus Torvalds return -ENXIO; 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds #endif 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds static int snd_i2c_bit_data(snd_i2c_bus_t *bus, int ack) 1851da177e4SLinus Torvalds { 1861da177e4SLinus Torvalds return bus->hw_ops.bit->getdata(bus, ack); 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds static void snd_i2c_bit_start(snd_i2c_bus_t *bus) 1901da177e4SLinus Torvalds { 1911da177e4SLinus Torvalds snd_i2c_bit_hw_start(bus); 1921da177e4SLinus Torvalds snd_i2c_bit_direction(bus, 1, 1); /* SCL - wr, SDA - wr */ 1931da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, 1); 1941da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, 0); 1951da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, 0); 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds static void snd_i2c_bit_stop(snd_i2c_bus_t *bus) 1991da177e4SLinus Torvalds { 2001da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, 0); 2011da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, 0); 2021da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, 1); 2031da177e4SLinus Torvalds snd_i2c_bit_hw_stop(bus); 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds static void snd_i2c_bit_send(snd_i2c_bus_t *bus, int data) 2071da177e4SLinus Torvalds { 2081da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, data); 2091da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, data); 2101da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, data); 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds static int snd_i2c_bit_ack(snd_i2c_bus_t *bus) 2141da177e4SLinus Torvalds { 2151da177e4SLinus Torvalds int ack; 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, 1); 2181da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, 1); 2191da177e4SLinus Torvalds snd_i2c_bit_direction(bus, 1, 0); /* SCL - wr, SDA - rd */ 2201da177e4SLinus Torvalds ack = snd_i2c_bit_data(bus, 1); 2211da177e4SLinus Torvalds snd_i2c_bit_direction(bus, 1, 1); /* SCL - wr, SDA - wr */ 2221da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, 1); 2231da177e4SLinus Torvalds return ack ? -EIO : 0; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds static int snd_i2c_bit_sendbyte(snd_i2c_bus_t *bus, unsigned char data) 2271da177e4SLinus Torvalds { 2281da177e4SLinus Torvalds int i, err; 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds for (i = 7; i >= 0; i--) 2311da177e4SLinus Torvalds snd_i2c_bit_send(bus, !!(data & (1 << i))); 2321da177e4SLinus Torvalds if ((err = snd_i2c_bit_ack(bus)) < 0) 2331da177e4SLinus Torvalds return err; 2341da177e4SLinus Torvalds return 0; 2351da177e4SLinus Torvalds } 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds static int snd_i2c_bit_readbyte(snd_i2c_bus_t *bus, int last) 2381da177e4SLinus Torvalds { 2391da177e4SLinus Torvalds int i; 2401da177e4SLinus Torvalds unsigned char data = 0; 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, 1); 2431da177e4SLinus Torvalds snd_i2c_bit_direction(bus, 1, 0); /* SCL - wr, SDA - rd */ 2441da177e4SLinus Torvalds for (i = 7; i >= 0; i--) { 2451da177e4SLinus Torvalds snd_i2c_bit_set(bus, 1, 1); 2461da177e4SLinus Torvalds if (snd_i2c_bit_data(bus, 0)) 2471da177e4SLinus Torvalds data |= (1 << i); 2481da177e4SLinus Torvalds snd_i2c_bit_set(bus, 0, 1); 2491da177e4SLinus Torvalds } 2501da177e4SLinus Torvalds snd_i2c_bit_direction(bus, 1, 1); /* SCL - wr, SDA - wr */ 2511da177e4SLinus Torvalds snd_i2c_bit_send(bus, !!last); 2521da177e4SLinus Torvalds return data; 2531da177e4SLinus Torvalds } 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds static int snd_i2c_bit_sendbytes(snd_i2c_device_t *device, unsigned char *bytes, int count) 2561da177e4SLinus Torvalds { 2571da177e4SLinus Torvalds snd_i2c_bus_t *bus = device->bus; 2581da177e4SLinus Torvalds int err, res = 0; 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds if (device->flags & SND_I2C_DEVICE_ADDRTEN) 2611da177e4SLinus Torvalds return -EIO; /* not yet implemented */ 2621da177e4SLinus Torvalds snd_i2c_bit_start(bus); 2631da177e4SLinus Torvalds if ((err = snd_i2c_bit_sendbyte(bus, device->addr << 1)) < 0) { 2641da177e4SLinus Torvalds snd_i2c_bit_hw_stop(bus); 2651da177e4SLinus Torvalds return err; 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds while (count-- > 0) { 2681da177e4SLinus Torvalds if ((err = snd_i2c_bit_sendbyte(bus, *bytes++)) < 0) { 2691da177e4SLinus Torvalds snd_i2c_bit_hw_stop(bus); 2701da177e4SLinus Torvalds return err; 2711da177e4SLinus Torvalds } 2721da177e4SLinus Torvalds res++; 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds snd_i2c_bit_stop(bus); 2751da177e4SLinus Torvalds return res; 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds static int snd_i2c_bit_readbytes(snd_i2c_device_t *device, unsigned char *bytes, int count) 2791da177e4SLinus Torvalds { 2801da177e4SLinus Torvalds snd_i2c_bus_t *bus = device->bus; 2811da177e4SLinus Torvalds int err, res = 0; 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds if (device->flags & SND_I2C_DEVICE_ADDRTEN) 2841da177e4SLinus Torvalds return -EIO; /* not yet implemented */ 2851da177e4SLinus Torvalds snd_i2c_bit_start(bus); 2861da177e4SLinus Torvalds if ((err = snd_i2c_bit_sendbyte(bus, (device->addr << 1) | 1)) < 0) { 2871da177e4SLinus Torvalds snd_i2c_bit_hw_stop(bus); 2881da177e4SLinus Torvalds return err; 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds while (count-- > 0) { 2911da177e4SLinus Torvalds if ((err = snd_i2c_bit_readbyte(bus, count == 0)) < 0) { 2921da177e4SLinus Torvalds snd_i2c_bit_hw_stop(bus); 2931da177e4SLinus Torvalds return err; 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds *bytes++ = (unsigned char)err; 2961da177e4SLinus Torvalds res++; 2971da177e4SLinus Torvalds } 2981da177e4SLinus Torvalds snd_i2c_bit_stop(bus); 2991da177e4SLinus Torvalds return res; 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds static int snd_i2c_bit_probeaddr(snd_i2c_bus_t *bus, unsigned short addr) 3031da177e4SLinus Torvalds { 3041da177e4SLinus Torvalds int err; 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds if (addr & 0x8000) /* 10-bit address */ 3071da177e4SLinus Torvalds return -EIO; /* not yet implemented */ 3081da177e4SLinus Torvalds if (addr & 0x7f80) /* invalid address */ 3091da177e4SLinus Torvalds return -EINVAL; 3101da177e4SLinus Torvalds snd_i2c_bit_start(bus); 3111da177e4SLinus Torvalds err = snd_i2c_bit_sendbyte(bus, addr << 1); 3121da177e4SLinus Torvalds snd_i2c_bit_stop(bus); 3131da177e4SLinus Torvalds return err; 3141da177e4SLinus Torvalds } 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds EXPORT_SYMBOL(snd_i2c_bus_create); 3171da177e4SLinus Torvalds EXPORT_SYMBOL(snd_i2c_device_create); 3181da177e4SLinus Torvalds EXPORT_SYMBOL(snd_i2c_device_free); 3191da177e4SLinus Torvalds EXPORT_SYMBOL(snd_i2c_sendbytes); 3201da177e4SLinus Torvalds EXPORT_SYMBOL(snd_i2c_readbytes); 3211da177e4SLinus Torvalds EXPORT_SYMBOL(snd_i2c_probeaddr); 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds static int __init alsa_i2c_init(void) 3241da177e4SLinus Torvalds { 3251da177e4SLinus Torvalds return 0; 3261da177e4SLinus Torvalds } 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds static void __exit alsa_i2c_exit(void) 3291da177e4SLinus Torvalds { 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds module_init(alsa_i2c_init) 3331da177e4SLinus Torvalds module_exit(alsa_i2c_exit) 334