162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Generic i2c interface for ALSA 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> 662306a36Sopenharmony_ci * Modified for the ALSA driver by Jaroslav Kysela <perex@perex.cz> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/string.h> 1362306a36Sopenharmony_ci#include <linux/errno.h> 1462306a36Sopenharmony_ci#include <sound/core.h> 1562306a36Sopenharmony_ci#include <sound/i2c.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ciMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 1862306a36Sopenharmony_ciMODULE_DESCRIPTION("Generic i2c interface for ALSA"); 1962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic int snd_i2c_bit_sendbytes(struct snd_i2c_device *device, 2262306a36Sopenharmony_ci unsigned char *bytes, int count); 2362306a36Sopenharmony_cistatic int snd_i2c_bit_readbytes(struct snd_i2c_device *device, 2462306a36Sopenharmony_ci unsigned char *bytes, int count); 2562306a36Sopenharmony_cistatic int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus, 2662306a36Sopenharmony_ci unsigned short addr); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic const struct snd_i2c_ops snd_i2c_bit_ops = { 2962306a36Sopenharmony_ci .sendbytes = snd_i2c_bit_sendbytes, 3062306a36Sopenharmony_ci .readbytes = snd_i2c_bit_readbytes, 3162306a36Sopenharmony_ci .probeaddr = snd_i2c_bit_probeaddr, 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int snd_i2c_bus_free(struct snd_i2c_bus *bus) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct snd_i2c_bus *slave; 3762306a36Sopenharmony_ci struct snd_i2c_device *device; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (snd_BUG_ON(!bus)) 4062306a36Sopenharmony_ci return -EINVAL; 4162306a36Sopenharmony_ci while (!list_empty(&bus->devices)) { 4262306a36Sopenharmony_ci device = snd_i2c_device(bus->devices.next); 4362306a36Sopenharmony_ci snd_i2c_device_free(device); 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci if (bus->master) 4662306a36Sopenharmony_ci list_del(&bus->buses); 4762306a36Sopenharmony_ci else { 4862306a36Sopenharmony_ci while (!list_empty(&bus->buses)) { 4962306a36Sopenharmony_ci slave = snd_i2c_slave_bus(bus->buses.next); 5062306a36Sopenharmony_ci snd_device_free(bus->card, slave); 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci if (bus->private_free) 5462306a36Sopenharmony_ci bus->private_free(bus); 5562306a36Sopenharmony_ci kfree(bus); 5662306a36Sopenharmony_ci return 0; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic int snd_i2c_bus_dev_free(struct snd_device *device) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct snd_i2c_bus *bus = device->device_data; 6262306a36Sopenharmony_ci return snd_i2c_bus_free(bus); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciint snd_i2c_bus_create(struct snd_card *card, const char *name, 6662306a36Sopenharmony_ci struct snd_i2c_bus *master, struct snd_i2c_bus **ri2c) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct snd_i2c_bus *bus; 6962306a36Sopenharmony_ci int err; 7062306a36Sopenharmony_ci static const struct snd_device_ops ops = { 7162306a36Sopenharmony_ci .dev_free = snd_i2c_bus_dev_free, 7262306a36Sopenharmony_ci }; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci *ri2c = NULL; 7562306a36Sopenharmony_ci bus = kzalloc(sizeof(*bus), GFP_KERNEL); 7662306a36Sopenharmony_ci if (bus == NULL) 7762306a36Sopenharmony_ci return -ENOMEM; 7862306a36Sopenharmony_ci mutex_init(&bus->lock_mutex); 7962306a36Sopenharmony_ci INIT_LIST_HEAD(&bus->devices); 8062306a36Sopenharmony_ci INIT_LIST_HEAD(&bus->buses); 8162306a36Sopenharmony_ci bus->card = card; 8262306a36Sopenharmony_ci bus->ops = &snd_i2c_bit_ops; 8362306a36Sopenharmony_ci if (master) { 8462306a36Sopenharmony_ci list_add_tail(&bus->buses, &master->buses); 8562306a36Sopenharmony_ci bus->master = master; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci strscpy(bus->name, name, sizeof(bus->name)); 8862306a36Sopenharmony_ci err = snd_device_new(card, SNDRV_DEV_BUS, bus, &ops); 8962306a36Sopenharmony_ci if (err < 0) { 9062306a36Sopenharmony_ci snd_i2c_bus_free(bus); 9162306a36Sopenharmony_ci return err; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci *ri2c = bus; 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciEXPORT_SYMBOL(snd_i2c_bus_create); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ciint snd_i2c_device_create(struct snd_i2c_bus *bus, const char *name, 10062306a36Sopenharmony_ci unsigned char addr, struct snd_i2c_device **rdevice) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct snd_i2c_device *device; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci *rdevice = NULL; 10562306a36Sopenharmony_ci if (snd_BUG_ON(!bus)) 10662306a36Sopenharmony_ci return -EINVAL; 10762306a36Sopenharmony_ci device = kzalloc(sizeof(*device), GFP_KERNEL); 10862306a36Sopenharmony_ci if (device == NULL) 10962306a36Sopenharmony_ci return -ENOMEM; 11062306a36Sopenharmony_ci device->addr = addr; 11162306a36Sopenharmony_ci strscpy(device->name, name, sizeof(device->name)); 11262306a36Sopenharmony_ci list_add_tail(&device->list, &bus->devices); 11362306a36Sopenharmony_ci device->bus = bus; 11462306a36Sopenharmony_ci *rdevice = device; 11562306a36Sopenharmony_ci return 0; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ciEXPORT_SYMBOL(snd_i2c_device_create); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ciint snd_i2c_device_free(struct snd_i2c_device *device) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci if (device->bus) 12362306a36Sopenharmony_ci list_del(&device->list); 12462306a36Sopenharmony_ci if (device->private_free) 12562306a36Sopenharmony_ci device->private_free(device); 12662306a36Sopenharmony_ci kfree(device); 12762306a36Sopenharmony_ci return 0; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ciEXPORT_SYMBOL(snd_i2c_device_free); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ciint snd_i2c_sendbytes(struct snd_i2c_device *device, unsigned char *bytes, int count) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci return device->bus->ops->sendbytes(device, bytes, count); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ciEXPORT_SYMBOL(snd_i2c_sendbytes); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ciint snd_i2c_readbytes(struct snd_i2c_device *device, unsigned char *bytes, int count) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci return device->bus->ops->readbytes(device, bytes, count); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ciEXPORT_SYMBOL(snd_i2c_readbytes); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ciint snd_i2c_probeaddr(struct snd_i2c_bus *bus, unsigned short addr) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci return bus->ops->probeaddr(bus, addr); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ciEXPORT_SYMBOL(snd_i2c_probeaddr); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/* 15462306a36Sopenharmony_ci * bit-operations 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic inline void snd_i2c_bit_hw_start(struct snd_i2c_bus *bus) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci if (bus->hw_ops.bit->start) 16062306a36Sopenharmony_ci bus->hw_ops.bit->start(bus); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic inline void snd_i2c_bit_hw_stop(struct snd_i2c_bus *bus) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci if (bus->hw_ops.bit->stop) 16662306a36Sopenharmony_ci bus->hw_ops.bit->stop(bus); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic void snd_i2c_bit_direction(struct snd_i2c_bus *bus, int clock, int data) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci if (bus->hw_ops.bit->direction) 17262306a36Sopenharmony_ci bus->hw_ops.bit->direction(bus, clock, data); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic void snd_i2c_bit_set(struct snd_i2c_bus *bus, int clock, int data) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci bus->hw_ops.bit->setlines(bus, clock, data); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci#if 0 18162306a36Sopenharmony_cistatic int snd_i2c_bit_clock(struct snd_i2c_bus *bus) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci if (bus->hw_ops.bit->getclock) 18462306a36Sopenharmony_ci return bus->hw_ops.bit->getclock(bus); 18562306a36Sopenharmony_ci return -ENXIO; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci#endif 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int snd_i2c_bit_data(struct snd_i2c_bus *bus, int ack) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci return bus->hw_ops.bit->getdata(bus, ack); 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic void snd_i2c_bit_start(struct snd_i2c_bus *bus) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci snd_i2c_bit_hw_start(bus); 19762306a36Sopenharmony_ci snd_i2c_bit_direction(bus, 1, 1); /* SCL - wr, SDA - wr */ 19862306a36Sopenharmony_ci snd_i2c_bit_set(bus, 1, 1); 19962306a36Sopenharmony_ci snd_i2c_bit_set(bus, 1, 0); 20062306a36Sopenharmony_ci snd_i2c_bit_set(bus, 0, 0); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic void snd_i2c_bit_stop(struct snd_i2c_bus *bus) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci snd_i2c_bit_set(bus, 0, 0); 20662306a36Sopenharmony_ci snd_i2c_bit_set(bus, 1, 0); 20762306a36Sopenharmony_ci snd_i2c_bit_set(bus, 1, 1); 20862306a36Sopenharmony_ci snd_i2c_bit_hw_stop(bus); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void snd_i2c_bit_send(struct snd_i2c_bus *bus, int data) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci snd_i2c_bit_set(bus, 0, data); 21462306a36Sopenharmony_ci snd_i2c_bit_set(bus, 1, data); 21562306a36Sopenharmony_ci snd_i2c_bit_set(bus, 0, data); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic int snd_i2c_bit_ack(struct snd_i2c_bus *bus) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci int ack; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci snd_i2c_bit_set(bus, 0, 1); 22362306a36Sopenharmony_ci snd_i2c_bit_set(bus, 1, 1); 22462306a36Sopenharmony_ci snd_i2c_bit_direction(bus, 1, 0); /* SCL - wr, SDA - rd */ 22562306a36Sopenharmony_ci ack = snd_i2c_bit_data(bus, 1); 22662306a36Sopenharmony_ci snd_i2c_bit_direction(bus, 1, 1); /* SCL - wr, SDA - wr */ 22762306a36Sopenharmony_ci snd_i2c_bit_set(bus, 0, 1); 22862306a36Sopenharmony_ci return ack ? -EIO : 0; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic int snd_i2c_bit_sendbyte(struct snd_i2c_bus *bus, unsigned char data) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci int i, err; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci for (i = 7; i >= 0; i--) 23662306a36Sopenharmony_ci snd_i2c_bit_send(bus, !!(data & (1 << i))); 23762306a36Sopenharmony_ci err = snd_i2c_bit_ack(bus); 23862306a36Sopenharmony_ci if (err < 0) 23962306a36Sopenharmony_ci return err; 24062306a36Sopenharmony_ci return 0; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic int snd_i2c_bit_readbyte(struct snd_i2c_bus *bus, int last) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci int i; 24662306a36Sopenharmony_ci unsigned char data = 0; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci snd_i2c_bit_set(bus, 0, 1); 24962306a36Sopenharmony_ci snd_i2c_bit_direction(bus, 1, 0); /* SCL - wr, SDA - rd */ 25062306a36Sopenharmony_ci for (i = 7; i >= 0; i--) { 25162306a36Sopenharmony_ci snd_i2c_bit_set(bus, 1, 1); 25262306a36Sopenharmony_ci if (snd_i2c_bit_data(bus, 0)) 25362306a36Sopenharmony_ci data |= (1 << i); 25462306a36Sopenharmony_ci snd_i2c_bit_set(bus, 0, 1); 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci snd_i2c_bit_direction(bus, 1, 1); /* SCL - wr, SDA - wr */ 25762306a36Sopenharmony_ci snd_i2c_bit_send(bus, !!last); 25862306a36Sopenharmony_ci return data; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic int snd_i2c_bit_sendbytes(struct snd_i2c_device *device, 26262306a36Sopenharmony_ci unsigned char *bytes, int count) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct snd_i2c_bus *bus = device->bus; 26562306a36Sopenharmony_ci int err, res = 0; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (device->flags & SND_I2C_DEVICE_ADDRTEN) 26862306a36Sopenharmony_ci return -EIO; /* not yet implemented */ 26962306a36Sopenharmony_ci snd_i2c_bit_start(bus); 27062306a36Sopenharmony_ci err = snd_i2c_bit_sendbyte(bus, device->addr << 1); 27162306a36Sopenharmony_ci if (err < 0) { 27262306a36Sopenharmony_ci snd_i2c_bit_hw_stop(bus); 27362306a36Sopenharmony_ci return err; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci while (count-- > 0) { 27662306a36Sopenharmony_ci err = snd_i2c_bit_sendbyte(bus, *bytes++); 27762306a36Sopenharmony_ci if (err < 0) { 27862306a36Sopenharmony_ci snd_i2c_bit_hw_stop(bus); 27962306a36Sopenharmony_ci return err; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci res++; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci snd_i2c_bit_stop(bus); 28462306a36Sopenharmony_ci return res; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic int snd_i2c_bit_readbytes(struct snd_i2c_device *device, 28862306a36Sopenharmony_ci unsigned char *bytes, int count) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct snd_i2c_bus *bus = device->bus; 29162306a36Sopenharmony_ci int err, res = 0; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (device->flags & SND_I2C_DEVICE_ADDRTEN) 29462306a36Sopenharmony_ci return -EIO; /* not yet implemented */ 29562306a36Sopenharmony_ci snd_i2c_bit_start(bus); 29662306a36Sopenharmony_ci err = snd_i2c_bit_sendbyte(bus, (device->addr << 1) | 1); 29762306a36Sopenharmony_ci if (err < 0) { 29862306a36Sopenharmony_ci snd_i2c_bit_hw_stop(bus); 29962306a36Sopenharmony_ci return err; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci while (count-- > 0) { 30262306a36Sopenharmony_ci err = snd_i2c_bit_readbyte(bus, count == 0); 30362306a36Sopenharmony_ci if (err < 0) { 30462306a36Sopenharmony_ci snd_i2c_bit_hw_stop(bus); 30562306a36Sopenharmony_ci return err; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci *bytes++ = (unsigned char)err; 30862306a36Sopenharmony_ci res++; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci snd_i2c_bit_stop(bus); 31162306a36Sopenharmony_ci return res; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus, unsigned short addr) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci int err; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (addr & 0x8000) /* 10-bit address */ 31962306a36Sopenharmony_ci return -EIO; /* not yet implemented */ 32062306a36Sopenharmony_ci if (addr & 0x7f80) /* invalid address */ 32162306a36Sopenharmony_ci return -EINVAL; 32262306a36Sopenharmony_ci snd_i2c_bit_start(bus); 32362306a36Sopenharmony_ci err = snd_i2c_bit_sendbyte(bus, addr << 1); 32462306a36Sopenharmony_ci snd_i2c_bit_stop(bus); 32562306a36Sopenharmony_ci return err; 32662306a36Sopenharmony_ci} 327