diff options
Diffstat (limited to 'sound')
306 files changed, 14625 insertions, 3124 deletions
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 795437b10082..b450a27588c8 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1633,11 +1633,13 @@ static int snd_rawmidi_dev_register(struct snd_device *device) return -EBUSY; } list_add_tail(&rmidi->list, &snd_rawmidi_devices); + mutex_unlock(®ister_mutex); err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device, &snd_rawmidi_f_ops, rmidi, &rmidi->dev); if (err < 0) { rmidi_err(rmidi, "unable to register\n"); + mutex_lock(®ister_mutex); list_del(&rmidi->list); mutex_unlock(®ister_mutex); return err; @@ -1645,6 +1647,7 @@ static int snd_rawmidi_dev_register(struct snd_device *device) if (rmidi->ops && rmidi->ops->dev_register && (err = rmidi->ops->dev_register(rmidi)) < 0) { snd_unregister_device(&rmidi->dev); + mutex_lock(®ister_mutex); list_del(&rmidi->list); mutex_unlock(®ister_mutex); return err; @@ -1677,7 +1680,6 @@ static int snd_rawmidi_dev_register(struct snd_device *device) } } #endif /* CONFIG_SND_OSSEMUL */ - mutex_unlock(®ister_mutex); sprintf(name, "midi%d", rmidi->device); entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root); if (entry) { diff --git a/sound/core/timer.c b/sound/core/timer.c index 9a6157ea6881..fc144f43faa6 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -35,6 +35,9 @@ #include <sound/initval.h> #include <linux/kmod.h> +/* internal flags */ +#define SNDRV_TIMER_IFLG_PAUSED 0x00010000 + #if IS_ENABLED(CONFIG_SND_HRTIMER) #define DEFAULT_TIMER_LIMIT 4 #else @@ -294,8 +297,21 @@ int snd_timer_open(struct snd_timer_instance **ti, get_device(&timer->card->card_dev); timeri->slave_class = tid->dev_sclass; timeri->slave_id = slave_id; - if (list_empty(&timer->open_list_head) && timer->hw.open) - timer->hw.open(timer); + + if (list_empty(&timer->open_list_head) && timer->hw.open) { + int err = timer->hw.open(timer); + if (err) { + kfree(timeri->owner); + kfree(timeri); + + if (timer->card) + put_device(&timer->card->card_dev); + module_put(timer->module); + mutex_unlock(®ister_mutex); + return err; + } + } + list_add_tail(&timeri->open_list, &timer->open_list_head); snd_timer_check_master(timeri); mutex_unlock(®ister_mutex); @@ -526,6 +542,10 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop) } } timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); + if (stop) + timeri->flags &= ~SNDRV_TIMER_IFLG_PAUSED; + else + timeri->flags |= SNDRV_TIMER_IFLG_PAUSED; snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP : SNDRV_TIMER_EVENT_CONTINUE); unlock: @@ -587,6 +607,10 @@ int snd_timer_stop(struct snd_timer_instance *timeri) */ int snd_timer_continue(struct snd_timer_instance *timeri) { + /* timer can continue only after pause */ + if (!(timeri->flags & SNDRV_TIMER_IFLG_PAUSED)) + return -EINVAL; + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) return snd_timer_start_slave(timeri, false); else @@ -813,6 +837,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, timer->tmr_subdevice = tid->subdevice; if (id) strlcpy(timer->id, id, sizeof(timer->id)); + timer->sticks = 1; INIT_LIST_HEAD(&timer->device_list); INIT_LIST_HEAD(&timer->open_list_head); INIT_LIST_HEAD(&timer->active_list_head); @@ -1817,6 +1842,9 @@ static int snd_timer_user_continue(struct file *file) tu = file->private_data; if (!tu->timeri) return -EBADFD; + /* start timer instead of continue if it's not used before */ + if (!(tu->timeri->flags & SNDRV_TIMER_IFLG_PAUSED)) + return snd_timer_user_start(file); tu->timeri->lost = 0; return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; } @@ -1958,6 +1986,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, tu->qused--; spin_unlock_irq(&tu->qlock); + mutex_lock(&tu->ioctl_lock); if (tu->tread) { if (copy_to_user(buffer, &tu->tqueue[qhead], sizeof(struct snd_timer_tread))) @@ -1967,6 +1996,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, sizeof(struct snd_timer_read))) err = -EFAULT; } + mutex_unlock(&tu->ioctl_lock); spin_lock_irq(&tu->qlock); if (err < 0) diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 03ed35237e2b..d73c12b8753d 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -108,7 +108,6 @@ struct snd_efw { u8 *resp_buf; u8 *pull_ptr; u8 *push_ptr; - unsigned int resp_queues; }; int snd_efw_transaction_cmd(struct fw_unit *unit, diff --git a/sound/firewire/fireworks/fireworks_hwdep.c b/sound/firewire/fireworks/fireworks_hwdep.c index 33df8655fe81..2e1d9a23920c 100644 --- a/sound/firewire/fireworks/fireworks_hwdep.c +++ b/sound/firewire/fireworks/fireworks_hwdep.c @@ -25,6 +25,7 @@ hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained, { unsigned int length, till_end, type; struct snd_efw_transaction *t; + u8 *pull_ptr; long count = 0; if (remained < sizeof(type) + sizeof(struct snd_efw_transaction)) @@ -38,8 +39,17 @@ hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained, buf += sizeof(type); /* write into buffer as many responses as possible */ - while (efw->resp_queues > 0) { - t = (struct snd_efw_transaction *)(efw->pull_ptr); + spin_lock_irq(&efw->lock); + + /* + * When another task reaches here during this task's access to user + * space, it picks up current position in buffer and can read the same + * series of responses. + */ + pull_ptr = efw->pull_ptr; + + while (efw->push_ptr != pull_ptr) { + t = (struct snd_efw_transaction *)(pull_ptr); length = be32_to_cpu(t->length) * sizeof(__be32); /* confirm enough space for this response */ @@ -49,26 +59,39 @@ hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained, /* copy from ring buffer to user buffer */ while (length > 0) { till_end = snd_efw_resp_buf_size - - (unsigned int)(efw->pull_ptr - efw->resp_buf); + (unsigned int)(pull_ptr - efw->resp_buf); till_end = min_t(unsigned int, length, till_end); - if (copy_to_user(buf, efw->pull_ptr, till_end)) + spin_unlock_irq(&efw->lock); + + if (copy_to_user(buf, pull_ptr, till_end)) return -EFAULT; - efw->pull_ptr += till_end; - if (efw->pull_ptr >= efw->resp_buf + - snd_efw_resp_buf_size) - efw->pull_ptr -= snd_efw_resp_buf_size; + spin_lock_irq(&efw->lock); + + pull_ptr += till_end; + if (pull_ptr >= efw->resp_buf + snd_efw_resp_buf_size) + pull_ptr -= snd_efw_resp_buf_size; length -= till_end; buf += till_end; count += till_end; remained -= till_end; } - - efw->resp_queues--; } + /* + * All of tasks can read from the buffer nearly simultaneously, but the + * last position for each task is different depending on the length of + * given buffer. Here, for simplicity, a position of buffer is set by + * the latest task. It's better for a listening application to allow one + * thread to read from the buffer. Unless, each task can read different + * sequence of responses depending on variation of buffer length. + */ + efw->pull_ptr = pull_ptr; + + spin_unlock_irq(&efw->lock); + return count; } @@ -76,14 +99,17 @@ static long hwdep_read_locked(struct snd_efw *efw, char __user *buf, long count, loff_t *offset) { - union snd_firewire_event event; + union snd_firewire_event event = { + .lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS, + }; - memset(&event, 0, sizeof(event)); + spin_lock_irq(&efw->lock); - event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; event.lock_status.status = (efw->dev_lock_count > 0); efw->dev_lock_changed = false; + spin_unlock_irq(&efw->lock); + count = min_t(long, count, sizeof(event.lock_status)); if (copy_to_user(buf, &event, count)) @@ -98,10 +124,15 @@ hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, { struct snd_efw *efw = hwdep->private_data; DEFINE_WAIT(wait); + bool dev_lock_changed; + bool queued; spin_lock_irq(&efw->lock); - while ((!efw->dev_lock_changed) && (efw->resp_queues == 0)) { + dev_lock_changed = efw->dev_lock_changed; + queued = efw->push_ptr != efw->pull_ptr; + + while (!dev_lock_changed && !queued) { prepare_to_wait(&efw->hwdep_wait, &wait, TASK_INTERRUPTIBLE); spin_unlock_irq(&efw->lock); schedule(); @@ -109,15 +140,17 @@ hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, if (signal_pending(current)) return -ERESTARTSYS; spin_lock_irq(&efw->lock); + dev_lock_changed = efw->dev_lock_changed; + queued = efw->push_ptr != efw->pull_ptr; } - if (efw->dev_lock_changed) + spin_unlock_irq(&efw->lock); + + if (dev_lock_changed) count = hwdep_read_locked(efw, buf, count, offset); - else if (efw->resp_queues > 0) + else if (queued) count = hwdep_read_resp_buf(efw, buf, count, offset); - spin_unlock_irq(&efw->lock); - return count; } @@ -160,7 +193,7 @@ hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) poll_wait(file, &efw->hwdep_wait, wait); spin_lock_irq(&efw->lock); - if (efw->dev_lock_changed || (efw->resp_queues > 0)) + if (efw->dev_lock_changed || efw->pull_ptr != efw->push_ptr) events = POLLIN | POLLRDNORM; else events = 0; diff --git a/sound/firewire/fireworks/fireworks_proc.c b/sound/firewire/fireworks/fireworks_proc.c index 0639dcb13f7d..beb0a0ffee57 100644 --- a/sound/firewire/fireworks/fireworks_proc.c +++ b/sound/firewire/fireworks/fireworks_proc.c @@ -188,8 +188,8 @@ proc_read_queues_state(struct snd_info_entry *entry, else consumed = (unsigned int)(efw->push_ptr - efw->pull_ptr); - snd_iprintf(buffer, "%d %d/%d\n", - efw->resp_queues, consumed, snd_efw_resp_buf_size); + snd_iprintf(buffer, "%d/%d\n", + consumed, snd_efw_resp_buf_size); } static void diff --git a/sound/firewire/fireworks/fireworks_transaction.c b/sound/firewire/fireworks/fireworks_transaction.c index f550808d1784..36a08ba51ec7 100644 --- a/sound/firewire/fireworks/fireworks_transaction.c +++ b/sound/firewire/fireworks/fireworks_transaction.c @@ -121,11 +121,11 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode) size_t capacity, till_end; struct snd_efw_transaction *t; - spin_lock_irq(&efw->lock); - t = (struct snd_efw_transaction *)data; length = min_t(size_t, be32_to_cpu(t->length) * sizeof(u32), length); + spin_lock_irq(&efw->lock); + if (efw->push_ptr < efw->pull_ptr) capacity = (unsigned int)(efw->pull_ptr - efw->push_ptr); else @@ -155,7 +155,6 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode) } /* for hwdep */ - efw->resp_queues++; wake_up(&efw->hwdep_wait); *rcode = RCODE_COMPLETE; diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c index 131267c3a042..106406cbfaa3 100644 --- a/sound/firewire/tascam/tascam-hwdep.c +++ b/sound/firewire/tascam/tascam-hwdep.c @@ -16,31 +16,14 @@ #include "tascam.h" -static long hwdep_read_locked(struct snd_tscm *tscm, char __user *buf, - long count) -{ - union snd_firewire_event event; - - memset(&event, 0, sizeof(event)); - - event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; - event.lock_status.status = (tscm->dev_lock_count > 0); - tscm->dev_lock_changed = false; - - count = min_t(long, count, sizeof(event.lock_status)); - - if (copy_to_user(buf, &event, count)) - return -EFAULT; - - return count; -} - static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, loff_t *offset) { struct snd_tscm *tscm = hwdep->private_data; DEFINE_WAIT(wait); - union snd_firewire_event event; + union snd_firewire_event event = { + .lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS, + }; spin_lock_irq(&tscm->lock); @@ -54,10 +37,16 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, spin_lock_irq(&tscm->lock); } - memset(&event, 0, sizeof(event)); - count = hwdep_read_locked(tscm, buf, count); + event.lock_status.status = (tscm->dev_lock_count > 0); + tscm->dev_lock_changed = false; + spin_unlock_irq(&tscm->lock); + count = min_t(long, count, sizeof(event.lock_status)); + + if (copy_to_user(buf, &event, count)) + return -EFAULT; + return count; } diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 860f8cad6602..261469188566 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -29,81 +29,6 @@ */ #define HDAC_MAX_CAPS 10 -/** - * snd_hdac_ext_bus_parse_capabilities - parse capablity structure - * @ebus: the pointer to extended bus object - * - * Returns 0 if successful, or a negative error code. - */ -int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus) -{ - unsigned int cur_cap; - unsigned int offset; - struct hdac_bus *bus = &ebus->bus; - unsigned int counter = 0; - - offset = snd_hdac_chip_readl(bus, LLCH); - - /* Lets walk the linked capabilities list */ - do { - cur_cap = _snd_hdac_chip_read(l, bus, offset); - - dev_dbg(bus->dev, "Capability version: 0x%x\n", - ((cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF)); - - dev_dbg(bus->dev, "HDA capability ID: 0x%x\n", - (cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF); - - switch ((cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF) { - case AZX_ML_CAP_ID: - dev_dbg(bus->dev, "Found ML capability\n"); - ebus->mlcap = bus->remap_addr + offset; - break; - - case AZX_GTS_CAP_ID: - dev_dbg(bus->dev, "Found GTS capability offset=%x\n", offset); - ebus->gtscap = bus->remap_addr + offset; - break; - - case AZX_PP_CAP_ID: - /* PP capability found, the Audio DSP is present */ - dev_dbg(bus->dev, "Found PP capability offset=%x\n", offset); - ebus->ppcap = bus->remap_addr + offset; - break; - - case AZX_SPB_CAP_ID: - /* SPIB capability found, handler function */ - dev_dbg(bus->dev, "Found SPB capability\n"); - ebus->spbcap = bus->remap_addr + offset; - break; - - case AZX_DRSM_CAP_ID: - /* DMA resume capability found, handler function */ - dev_dbg(bus->dev, "Found DRSM capability\n"); - ebus->drsmcap = bus->remap_addr + offset; - break; - - default: - dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap); - break; - } - - counter++; - - if (counter > HDAC_MAX_CAPS) { - dev_err(bus->dev, "We exceeded HDAC Ext capablities!!!\n"); - break; - } - - /* read the offset of next capabiity */ - offset = cur_cap & AZX_CAP_HDR_NXT_PTR_MASK; - - } while (offset); - - return 0; -} -EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_parse_capabilities); - /* * processing pipe helpers - these helpers are useful for dealing with HDA * new capability of processing pipelines @@ -118,15 +43,15 @@ void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *ebus, bool enable) { struct hdac_bus *bus = &ebus->bus; - if (!ebus->ppcap) { + if (!bus->ppcap) { dev_err(bus->dev, "Address of PP capability is NULL"); return; } if (enable) - snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN); else - snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable); @@ -139,15 +64,15 @@ void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *ebus, bool enable) { struct hdac_bus *bus = &ebus->bus; - if (!ebus->ppcap) { + if (!bus->ppcap) { dev_err(bus->dev, "Address of PP capability is NULL\n"); return; } if (enable) - snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE); else - snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable); @@ -171,7 +96,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus) struct hdac_ext_link *hlink; struct hdac_bus *bus = &ebus->bus; - link_count = readl(ebus->mlcap + AZX_REG_ML_MLCD) + 1; + link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1; dev_dbg(bus->dev, "In %s Link count: %d\n", __func__, link_count); @@ -181,7 +106,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus) return -ENOMEM; hlink->index = idx; hlink->bus = bus; - hlink->ml_addr = ebus->mlcap + AZX_ML_BASE + + hlink->ml_addr = bus->mlcap + AZX_ML_BASE + (AZX_ML_INTERVAL * idx); hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP); hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index 626f3bb24c55..2441273adcef 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -40,27 +40,27 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus, { struct hdac_bus *bus = &ebus->bus; - if (ebus->ppcap) { - stream->pphc_addr = ebus->ppcap + AZX_PPHC_BASE + + if (bus->ppcap) { + stream->pphc_addr = bus->ppcap + AZX_PPHC_BASE + AZX_PPHC_INTERVAL * idx; - stream->pplc_addr = ebus->ppcap + AZX_PPLC_BASE + + stream->pplc_addr = bus->ppcap + AZX_PPLC_BASE + AZX_PPLC_MULTI * ebus->num_streams + AZX_PPLC_INTERVAL * idx; } - if (ebus->spbcap) { - stream->spib_addr = ebus->spbcap + AZX_SPB_BASE + + if (bus->spbcap) { + stream->spib_addr = bus->spbcap + AZX_SPB_BASE + AZX_SPB_INTERVAL * idx + AZX_SPB_SPIB; - stream->fifo_addr = ebus->spbcap + AZX_SPB_BASE + + stream->fifo_addr = bus->spbcap + AZX_SPB_BASE + AZX_SPB_INTERVAL * idx + AZX_SPB_MAXFIFO; } - if (ebus->drsmcap) - stream->dpibr_addr = ebus->drsmcap + AZX_DRSM_BASE + + if (bus->drsmcap) + stream->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE + AZX_DRSM_INTERVAL * idx; stream->decoupled = false; @@ -131,10 +131,10 @@ void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus, spin_lock_irq(&bus->reg_lock); if (decouple) - snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0, + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PROCEN(hstream->index)); else - snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PROCEN(hstream->index), 0); stream->decoupled = decouple; spin_unlock_irq(&bus->reg_lock); @@ -255,7 +255,7 @@ hdac_ext_link_stream_assign(struct hdac_ext_bus *ebus, struct hdac_stream *stream = NULL; struct hdac_bus *hbus = &ebus->bus; - if (!ebus->ppcap) { + if (!hbus->ppcap) { dev_err(hbus->dev, "stream type not supported\n"); return NULL; } @@ -296,7 +296,7 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus, struct hdac_stream *stream = NULL; struct hdac_bus *hbus = &ebus->bus; - if (!ebus->ppcap) { + if (!hbus->ppcap) { dev_err(hbus->dev, "stream type not supported\n"); return NULL; } @@ -423,21 +423,21 @@ void snd_hdac_ext_stream_spbcap_enable(struct hdac_ext_bus *ebus, u32 register_mask = 0; struct hdac_bus *bus = &ebus->bus; - if (!ebus->spbcap) { + if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL"); return; } mask |= (1 << index); - register_mask = readl(ebus->spbcap + AZX_REG_SPB_SPBFCCTL); + register_mask = readl(bus->spbcap + AZX_REG_SPB_SPBFCCTL); mask |= register_mask; if (enable) - snd_hdac_updatel(ebus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask); + snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask); else - snd_hdac_updatel(ebus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0); + snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable); @@ -452,7 +452,7 @@ int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus, { struct hdac_bus *bus = &ebus->bus; - if (!ebus->spbcap) { + if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL"); return -EINVAL; } @@ -475,7 +475,7 @@ int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus, { struct hdac_bus *bus = &ebus->bus; - if (!ebus->spbcap) { + if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL"); return -EINVAL; } @@ -515,21 +515,21 @@ void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus, u32 register_mask = 0; struct hdac_bus *bus = &ebus->bus; - if (!ebus->drsmcap) { + if (!bus->drsmcap) { dev_err(bus->dev, "Address of DRSM capability is NULL"); return; } mask |= (1 << index); - register_mask = readl(ebus->drsmcap + AZX_REG_SPB_SPBFCCTL); + register_mask = readl(bus->drsmcap + AZX_REG_SPB_SPBFCCTL); mask |= register_mask; if (enable) - snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, 0, mask); + snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, 0, mask); else - snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); + snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable); @@ -544,7 +544,7 @@ int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus, { struct hdac_bus *bus = &ebus->bus; - if (!ebus->drsmcap) { + if (!bus->drsmcap) { dev_err(bus->dev, "Address of DRSM capability is NULL"); return -EINVAL; } diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index 9fee464e5d49..043065867656 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -255,6 +255,81 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, } EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response); +#define HDAC_MAX_CAPS 10 +/** + * snd_hdac_bus_parse_capabilities - parse capability structure + * @bus: the pointer to bus object + * + * Returns 0 if successful, or a negative error code. + */ +int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus) +{ + unsigned int cur_cap; + unsigned int offset; + unsigned int counter = 0; + + offset = snd_hdac_chip_readl(bus, LLCH); + + /* Lets walk the linked capabilities list */ + do { + cur_cap = _snd_hdac_chip_read(l, bus, offset); + + dev_dbg(bus->dev, "Capability version: 0x%x\n", + (cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF); + + dev_dbg(bus->dev, "HDA capability ID: 0x%x\n", + (cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF); + + switch ((cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF) { + case AZX_ML_CAP_ID: + dev_dbg(bus->dev, "Found ML capability\n"); + bus->mlcap = bus->remap_addr + offset; + break; + + case AZX_GTS_CAP_ID: + dev_dbg(bus->dev, "Found GTS capability offset=%x\n", offset); + bus->gtscap = bus->remap_addr + offset; + break; + + case AZX_PP_CAP_ID: + /* PP capability found, the Audio DSP is present */ + dev_dbg(bus->dev, "Found PP capability offset=%x\n", offset); + bus->ppcap = bus->remap_addr + offset; + break; + + case AZX_SPB_CAP_ID: + /* SPIB capability found, handler function */ + dev_dbg(bus->dev, "Found SPB capability\n"); + bus->spbcap = bus->remap_addr + offset; + break; + + case AZX_DRSM_CAP_ID: + /* DMA resume capability found, handler function */ + dev_dbg(bus->dev, "Found DRSM capability\n"); + bus->drsmcap = bus->remap_addr + offset; + break; + + default: + dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap); + break; + } + + counter++; + + if (counter > HDAC_MAX_CAPS) { + dev_err(bus->dev, "We exceeded HDAC capabilities!!!\n"); + break; + } + + /* read the offset of next capability */ + offset = cur_cap & AZX_CAP_HDR_NXT_PTR_MASK; + + } while (offset); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hdac_bus_parse_capabilities); + /* * Lowlevel interface */ diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 27de8015717d..2ad3b447483f 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -27,6 +27,12 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/slab.h> + +#ifdef CONFIG_X86 +/* for art-tsc conversion */ +#include <asm/tsc.h> +#endif + #include <sound/core.h> #include <sound/initval.h> #include "hda_controller.h" @@ -337,12 +343,173 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) azx_get_position(chip, azx_dev)); } +/* + * azx_scale64: Scale base by mult/div while not overflowing sanely + * + * Derived from scale64_check_overflow in kernel/time/timekeeping.c + * + * The tmestamps for a 48Khz stream can overflow after (2^64/10^9)/48K which + * is about 384307 ie ~4.5 days. + * + * This scales the calculation so that overflow will happen but after 2^64 / + * 48000 secs, which is pretty large! + * + * In caln below: + * base may overflow, but since there isn’t any additional division + * performed on base it’s OK + * rem can’t overflow because both are 32-bit values + */ + +#ifdef CONFIG_X86 +static u64 azx_scale64(u64 base, u32 num, u32 den) +{ + u64 rem; + + rem = do_div(base, den); + + base *= num; + rem *= num; + + do_div(rem, den); + + return base + rem; +} + +static int azx_get_sync_time(ktime_t *device, + struct system_counterval_t *system, void *ctx) +{ + struct snd_pcm_substream *substream = ctx; + struct azx_dev *azx_dev = get_azx_dev(substream); + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx *chip = apcm->chip; + struct snd_pcm_runtime *runtime; + u64 ll_counter, ll_counter_l, ll_counter_h; + u64 tsc_counter, tsc_counter_l, tsc_counter_h; + u32 wallclk_ctr, wallclk_cycles; + bool direction; + u32 dma_select; + u32 timeout = 200; + u32 retry_count = 0; + + runtime = substream->runtime; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + direction = 1; + else + direction = 0; + + /* 0th stream tag is not used, so DMA ch 0 is for 1st stream tag */ + do { + timeout = 100; + dma_select = (direction << GTSCC_CDMAS_DMA_DIR_SHIFT) | + (azx_dev->core.stream_tag - 1); + snd_hdac_chip_writel(azx_bus(chip), GTSCC, dma_select); + + /* Enable the capture */ + snd_hdac_chip_updatel(azx_bus(chip), GTSCC, 0, GTSCC_TSCCI_MASK); + + while (timeout) { + if (snd_hdac_chip_readl(azx_bus(chip), GTSCC) & + GTSCC_TSCCD_MASK) + break; + + timeout--; + } + + if (!timeout) { + dev_err(chip->card->dev, "GTSCC capture Timedout!\n"); + return -EIO; + } + + /* Read wall clock counter */ + wallclk_ctr = snd_hdac_chip_readl(azx_bus(chip), WALFCC); + + /* Read TSC counter */ + tsc_counter_l = snd_hdac_chip_readl(azx_bus(chip), TSCCL); + tsc_counter_h = snd_hdac_chip_readl(azx_bus(chip), TSCCU); + + /* Read Link counter */ + ll_counter_l = snd_hdac_chip_readl(azx_bus(chip), LLPCL); + ll_counter_h = snd_hdac_chip_readl(azx_bus(chip), LLPCU); + + /* Ack: registers read done */ + snd_hdac_chip_writel(azx_bus(chip), GTSCC, GTSCC_TSCCD_SHIFT); + + tsc_counter = (tsc_counter_h << TSCCU_CCU_SHIFT) | + tsc_counter_l; + + ll_counter = (ll_counter_h << LLPC_CCU_SHIFT) | ll_counter_l; + wallclk_cycles = wallclk_ctr & WALFCC_CIF_MASK; + + /* + * An error occurs near frame "rollover". The clocks in + * frame value indicates whether this error may have + * occurred. Here we use the value of 10 i.e., + * HDA_MAX_CYCLE_OFFSET + */ + if (wallclk_cycles < HDA_MAX_CYCLE_VALUE - HDA_MAX_CYCLE_OFFSET + && wallclk_cycles > HDA_MAX_CYCLE_OFFSET) + break; + + /* + * Sleep before we read again, else we may again get + * value near to MAX_CYCLE. Try to sleep for different + * amount of time so we dont hit the same number again + */ + udelay(retry_count++); + + } while (retry_count != HDA_MAX_CYCLE_READ_RETRY); + + if (retry_count == HDA_MAX_CYCLE_READ_RETRY) { + dev_err_ratelimited(chip->card->dev, + "Error in WALFCC cycle count\n"); + return -EIO; + } + + *device = ns_to_ktime(azx_scale64(ll_counter, + NSEC_PER_SEC, runtime->rate)); + *device = ktime_add_ns(*device, (wallclk_cycles * NSEC_PER_SEC) / + ((HDA_MAX_CYCLE_VALUE + 1) * runtime->rate)); + + *system = convert_art_to_tsc(tsc_counter); + + return 0; +} + +#else +static int azx_get_sync_time(ktime_t *device, + struct system_counterval_t *system, void *ctx) +{ + return -ENXIO; +} +#endif + +static int azx_get_crosststamp(struct snd_pcm_substream *substream, + struct system_device_crosststamp *xtstamp) +{ + return get_device_system_crosststamp(azx_get_sync_time, + substream, NULL, xtstamp); +} + +static inline bool is_link_time_supported(struct snd_pcm_runtime *runtime, + struct snd_pcm_audio_tstamp_config *ts) +{ + if (runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME) + if (ts->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED) + return true; + + return false; +} + static int azx_get_time_info(struct snd_pcm_substream *substream, struct timespec *system_ts, struct timespec *audio_ts, struct snd_pcm_audio_tstamp_config *audio_tstamp_config, struct snd_pcm_audio_tstamp_report *audio_tstamp_report) { struct azx_dev *azx_dev = get_azx_dev(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct system_device_crosststamp xtstamp; + int ret; u64 nsec; if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && @@ -361,8 +528,37 @@ static int azx_get_time_info(struct snd_pcm_substream *substream, audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */ audio_tstamp_report->accuracy = 42; /* 24 MHz WallClock == 42ns resolution */ - } else + } else if (is_link_time_supported(runtime, audio_tstamp_config)) { + + ret = azx_get_crosststamp(substream, &xtstamp); + if (ret) + return ret; + + switch (runtime->tstamp_type) { + case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC: + return -EINVAL; + + case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW: + *system_ts = ktime_to_timespec(xtstamp.sys_monoraw); + break; + + default: + *system_ts = ktime_to_timespec(xtstamp.sys_realtime); + break; + + } + + *audio_ts = ktime_to_timespec(xtstamp.device); + + audio_tstamp_report->actual_type = + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED; + audio_tstamp_report->accuracy_report = 1; + /* 24 MHz WallClock == 42ns resolution */ + audio_tstamp_report->accuracy = 42; + + } else { audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; + } return 0; } @@ -412,6 +608,11 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) goto unlock; } runtime->private_data = azx_dev; + + if (chip->gts_present) + azx_pcm_hw.info = azx_pcm_hw.info | + SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME; + runtime->hw = azx_pcm_hw; runtime->hw.channels_min = hinfo->channels_min; runtime->hw.channels_max = hinfo->channels_max; diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index ec63bbf1ec6d..a50e0532622a 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -159,6 +159,9 @@ struct azx { unsigned int region_requested:1; unsigned int disabled:1; /* disabled by vga_switcheroo */ + /* GTS present */ + unsigned int gts_present:1; + #ifdef CONFIG_SND_HDA_DSP_LOADER struct azx_dev saved_azx_dev; #endif diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 89dacf9b4e6c..c3469f756ec2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -54,6 +54,7 @@ /* for snoop control */ #include <asm/pgtable.h> #include <asm/cacheflush.h> +#include <asm/cpufeature.h> #endif #include <sound/core.h> #include <sound/initval.h> @@ -906,20 +907,23 @@ static int azx_resume(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; struct hda_intel *hda; + struct hdac_bus *bus; if (!card) return 0; chip = card->private_data; hda = container_of(chip, struct hda_intel, chip); + bus = azx_bus(chip); if (chip->disabled || hda->init_failed || !chip->running) return 0; - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL - && hda->need_i915_power) { - snd_hdac_display_power(azx_bus(chip), true); - snd_hdac_i915_set_bclk(azx_bus(chip)); + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + snd_hdac_display_power(bus, true); + if (hda->need_i915_power) + snd_hdac_i915_set_bclk(bus); } + if (chip->msi) if (pci_enable_msi(pci) < 0) chip->msi = 0; @@ -929,6 +933,11 @@ static int azx_resume(struct device *dev) hda_intel_init_chip(chip, true); + /* power down again for link-controlled chips */ + if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && + !hda->need_i915_power) + snd_hdac_display_power(bus, false); + snd_power_change_state(card, SNDRV_CTL_POWER_D0); trace_azx_resume(chip); @@ -1008,6 +1017,7 @@ static int azx_runtime_resume(struct device *dev) chip = card->private_data; hda = container_of(chip, struct hda_intel, chip); + bus = azx_bus(chip); if (chip->disabled || hda->init_failed) return 0; @@ -1015,15 +1025,9 @@ static int azx_runtime_resume(struct device *dev) return 0; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - bus = azx_bus(chip); - if (hda->need_i915_power) { - snd_hdac_display_power(bus, true); + snd_hdac_display_power(bus, true); + if (hda->need_i915_power) snd_hdac_i915_set_bclk(bus); - } else { - /* toggle codec wakeup bit for STATESTS read */ - snd_hdac_set_codec_wakeup(bus, true); - snd_hdac_set_codec_wakeup(bus, false); - } } /* Read STATESTS before controller reset */ @@ -1043,6 +1047,11 @@ static int azx_runtime_resume(struct device *dev) azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & ~STATESTS_INT_MASK); + /* power down again for link-controlled chips */ + if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && + !hda->need_i915_power) + snd_hdac_display_power(bus, false); + trace_azx_runtime_resume(chip); return 0; } @@ -1655,6 +1664,22 @@ static int azx_first_init(struct azx *chip) return -ENXIO; } + if (IS_SKL_PLUS(pci)) + snd_hdac_bus_parse_capabilities(bus); + + /* + * Some Intel CPUs has always running timer (ART) feature and + * controller may have Global time sync reporting capability, so + * check both of these before declaring synchronized time reporting + * capability SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME + */ + chip->gts_present = false; + +#ifdef CONFIG_X86 + if (bus->ppcap && boot_cpu_has(X86_FEATURE_ART)) + chip->gts_present = true; +#endif + if (chip->msi) { if (chip->driver_caps & AZX_DCAPS_NO_MSI64) { dev_dbg(card->dev, "Disabling 64bit MSI\n"); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 574b1b48996f..575cefd8cc4a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4828,7 +4828,7 @@ enum { ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, ALC292_FIXUP_TPT440_DOCK, ALC292_FIXUP_TPT440, - ALC283_FIXUP_BXBT2807_MIC, + ALC283_FIXUP_HEADSET_MIC, ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, ALC282_FIXUP_ASPIRE_V5_PINS, ALC280_FIXUP_HP_GPIO4, @@ -4855,6 +4855,7 @@ enum { ALC221_FIXUP_HP_FRONT_MIC, ALC292_FIXUP_TPT460, ALC298_FIXUP_SPK_VOLUME, + ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER, }; static const struct hda_fixup alc269_fixups[] = { @@ -5321,7 +5322,7 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC292_FIXUP_TPT440_DOCK, }, - [ALC283_FIXUP_BXBT2807_MIC] = { + [ALC283_FIXUP_HEADSET_MIC] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { { 0x19, 0x04a110f0 }, @@ -5516,6 +5517,15 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, }, + [ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x90170151 }, + { } + }, + .chained = true, + .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -5560,6 +5570,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13 9350", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), + SND_PCI_QUIRK(0x1028, 0x0706, "Dell Inspiron 7559", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER), SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE), SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME), @@ -5651,7 +5662,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN), SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC), - SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC), + SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), @@ -5894,6 +5906,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60170}, {0x14, 0x90170120}, {0x21, 0x02211030}), + SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell Inspiron 5468", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60180}, + {0x14, 0x90170120}, + {0x21, 0x02211030}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, ALC256_STANDARD_PINS), SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4, diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index d1fb035f44db..504c7cd7f58a 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -897,7 +897,7 @@ static int acp_dma_close(struct snd_pcm_substream *substream) return 0; } -static struct snd_pcm_ops acp_dma_ops = { +static const struct snd_pcm_ops acp_dma_ops = { .open = acp_dma_open, .close = acp_dma_close, .ioctl = snd_pcm_lib_ioctl, diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 6d9b8b44e2da..89ac5f5a93eb 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -308,9 +308,11 @@ static struct regmap *atmel_classd_codec_get_remap(struct device *dev) static struct snd_soc_codec_driver soc_codec_dev_classd = { .probe = atmel_classd_codec_probe, - .controls = atmel_classd_snd_controls, - .num_controls = ARRAY_SIZE(atmel_classd_snd_controls), .get_regmap = atmel_classd_codec_get_remap, + .component_driver = { + .controls = atmel_classd_snd_controls, + .num_controls = ARRAY_SIZE(atmel_classd_snd_controls), + }, }; /* codec dai component */ diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c index da861b44413f..91b7069c3499 100644 --- a/sound/soc/atmel/atmel-pcm-pdc.c +++ b/sound/soc/atmel/atmel-pcm-pdc.c @@ -381,7 +381,7 @@ static int atmel_pcm_close(struct snd_pcm_substream *substream) return 0; } -static struct snd_pcm_ops atmel_pcm_ops = { +static const struct snd_pcm_ops atmel_pcm_ops = { .open = atmel_pcm_open, .close = atmel_pcm_close, .ioctl = snd_pcm_lib_ioctl, diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c index 5f56da60c92f..c917df7715d1 100644 --- a/sound/soc/atmel/atmel-pdmic.c +++ b/sound/soc/atmel/atmel-pdmic.c @@ -80,7 +80,7 @@ static struct atmel_pdmic_pdata *atmel_pdmic_dt_init(struct device *dev) if (pdata->mic_max_freq < pdata->mic_min_freq) { dev_err(dev, - "mic-max-freq should not less than mic-min-freq\n"); + "mic-max-freq should not be less than mic-min-freq\n"); return ERR_PTR(-EINVAL); } @@ -115,8 +115,10 @@ static int atmel_pdmic_cpu_dai_startup(struct snd_pcm_substream *substream, return ret; ret = clk_prepare_enable(dd->pclk); - if (ret) + if (ret) { + clk_disable_unprepare(dd->gclk); return ret; + } /* Clear all bits in the Control Register(PDMIC_CR) */ regmap_write(dd->regmap, PDMIC_CR, 0); @@ -283,7 +285,7 @@ static const DECLARE_TLV_DB_RANGE(mic_gain_tlv, 8, ARRAY_SIZE(mic_gain_table)-1, TLV_DB_SCALE_ITEM(-6500, 100, 0), ); -int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol, +static int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); @@ -357,8 +359,10 @@ static int atmel_pdmic_codec_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_pdmic = { .probe = atmel_pdmic_codec_probe, - .controls = atmel_pdmic_snd_controls, - .num_controls = ARRAY_SIZE(atmel_pdmic_snd_controls), + .component_driver = { + .controls = atmel_pdmic_snd_controls, + .num_controls = ARRAY_SIZE(atmel_pdmic_snd_controls), + }, }; /* codec dai component */ @@ -596,7 +600,7 @@ static int atmel_pdmic_probe(struct platform_device *pdev) dd->irq = platform_get_irq(pdev, 0); if (dd->irq < 0) { ret = dd->irq; - dev_err(dev, "failed to could not get irq: %d\n", ret); + dev_err(dev, "failed to get irq: %d\n", ret); return ret; } @@ -614,7 +618,7 @@ static int atmel_pdmic_probe(struct platform_device *pdev) return ret; } - /* The gclk clock frequency must always be tree times + /* The gclk clock frequency must always be three times * lower than the pclk clock frequency */ ret = clk_set_rate(dd->gclk, clk_get_rate(dd->pclk)/3); @@ -649,7 +653,7 @@ static int atmel_pdmic_probe(struct platform_device *pdev) return ret; } - /* Get the minimal and maximal sample rate that micphone supports */ + /* Get the minimal and maximal sample rate that the microphone supports */ atmel_pdmic_get_sample_rate(dd, &rate_min, &rate_max); /* register cpu dai */ diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 54c09acd3fed..16e459aedffe 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -299,8 +299,9 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, clk_enable(ssc_p->ssc->clk); ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk); - /* Reset the SSC to keep it at a clean status */ - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); + /* Reset the SSC unless initialized to keep it in a clean state */ + if (!ssc_p->initialized) + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dir = 0; diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index e8bed6b0c9db..b013a4c62b63 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -1361,12 +1361,14 @@ static struct snd_soc_codec_driver soc_codec_dev_pm860x = { .set_bias_level = pm860x_set_bias_level, .get_regmap = pm860x_get_regmap, - .controls = pm860x_snd_controls, - .num_controls = ARRAY_SIZE(pm860x_snd_controls), - .dapm_widgets = pm860x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(pm860x_dapm_widgets), - .dapm_routes = pm860x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(pm860x_dapm_routes), + .component_driver = { + .controls = pm860x_snd_controls, + .num_controls = ARRAY_SIZE(pm860x_snd_controls), + .dapm_widgets = pm860x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pm860x_dapm_widgets), + .dapm_routes = pm860x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pm860x_dapm_routes), + }, }; static int pm860x_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 1cd6ab344d67..c67667bb970f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -92,6 +92,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX9877 if I2C select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_ML26124 if I2C + select SND_SOC_NAU8810 if I2C select SND_SOC_NAU8825 if I2C select SND_SOC_HDMI_CODEC select SND_SOC_PCM1681 if I2C @@ -112,6 +113,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_RT5645 if I2C select SND_SOC_RT5651 if I2C select SND_SOC_RT5659 if I2C + select SND_SOC_RT5660 if I2C + select SND_SOC_RT5663 if I2C select SND_SOC_RT5670 if I2C select SND_SOC_RT5677 if I2C && SPI_MASTER select SND_SOC_SGTL5000 if I2C @@ -645,6 +648,8 @@ config SND_SOC_RL6231 default y if SND_SOC_RT5645=y default y if SND_SOC_RT5651=y default y if SND_SOC_RT5659=y + default y if SND_SOC_RT5660=y + default y if SND_SOC_RT5663=y default y if SND_SOC_RT5670=y default y if SND_SOC_RT5677=y default m if SND_SOC_RT5514=m @@ -653,6 +658,8 @@ config SND_SOC_RL6231 default m if SND_SOC_RT5645=m default m if SND_SOC_RT5651=m default m if SND_SOC_RT5659=m + default m if SND_SOC_RT5660=m + default m if SND_SOC_RT5663=m default m if SND_SOC_RT5670=m default m if SND_SOC_RT5677=m @@ -665,6 +672,7 @@ config SND_SOC_RL6347A config SND_SOC_RT286 tristate + select SND_SOC_RT5663 depends on I2C config SND_SOC_RT298 @@ -697,6 +705,12 @@ config SND_SOC_RT5651 config SND_SOC_RT5659 tristate +config SND_SOC_RT5660 + tristate + +config SND_SOC_RT5663 + tristate + config SND_SOC_RT5670 tristate @@ -1064,6 +1078,10 @@ config SND_SOC_MC13783 config SND_SOC_ML26124 tristate +config SND_SOC_NAU8810 + tristate "Nuvoton Technology Corporation NAU88C10 CODEC" + depends on I2C + config SND_SOC_NAU8825 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 58036af2c7d9..958cd4912fbc 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -86,6 +86,7 @@ snd-soc-max9850-objs := max9850.o snd-soc-max9860-objs := max9860.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o +snd-soc-nau8810-objs := nau8810.o snd-soc-nau8825-objs := nau8825.o snd-soc-hdmi-codec-objs := hdmi-codec.o snd-soc-pcm1681-objs := pcm1681.o @@ -112,6 +113,8 @@ snd-soc-rt5640-objs := rt5640.o snd-soc-rt5645-objs := rt5645.o snd-soc-rt5651-objs := rt5651.o snd-soc-rt5659-objs := rt5659.o +snd-soc-rt5660-objs := rt5660.o +snd-soc-rt5663-objs := rt5663.o snd-soc-rt5670-objs := rt5670.o snd-soc-rt5677-objs := rt5677.o snd-soc-rt5677-spi-objs := rt5677-spi.o @@ -307,6 +310,7 @@ obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o +obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o @@ -333,6 +337,8 @@ obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o +obj-$(CONFIG_SND_SOC_RT5660) += snd-soc-rt5660.o +obj-$(CONFIG_SND_SOC_RT5663) += snd-soc-rt5663.o obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 2fc89155f14a..935ff7cb71c5 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2408,28 +2408,28 @@ static void ab8500_codec_of_probe(struct device *dev, struct device_node *np, { u32 value; - if (of_get_property(np, "stericsson,amic1-type-single-ended", NULL)) + if (of_property_read_bool(np, "stericsson,amic1-type-single-ended")) codec->amics.mic1_type = AMIC_TYPE_SINGLE_ENDED; else codec->amics.mic1_type = AMIC_TYPE_DIFFERENTIAL; - if (of_get_property(np, "stericsson,amic2-type-single-ended", NULL)) + if (of_property_read_bool(np, "stericsson,amic2-type-single-ended")) codec->amics.mic2_type = AMIC_TYPE_SINGLE_ENDED; else codec->amics.mic2_type = AMIC_TYPE_DIFFERENTIAL; /* Has a non-standard Vamic been requested? */ - if (of_get_property(np, "stericsson,amic1a-bias-vamic2", NULL)) + if (of_property_read_bool(np, "stericsson,amic1a-bias-vamic2")) codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC2; else codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC1; - if (of_get_property(np, "stericsson,amic1b-bias-vamic2", NULL)) + if (of_property_read_bool(np, "stericsson,amic1b-bias-vamic2")) codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC2; else codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC1; - if (of_get_property(np, "stericsson,amic2-bias-vamic1", NULL)) + if (of_property_read_bool(np, "stericsson,amic2-bias-vamic1")) codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC1; else codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC2; @@ -2525,12 +2525,14 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver ab8500_codec_driver = { .probe = ab8500_codec_probe, - .controls = ab8500_ctrls, - .num_controls = ARRAY_SIZE(ab8500_ctrls), - .dapm_widgets = ab8500_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ab8500_dapm_widgets), - .dapm_routes = ab8500_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(ab8500_dapm_routes), + .component_driver = { + .controls = ab8500_ctrls, + .num_controls = ARRAY_SIZE(ab8500_ctrls), + .dapm_widgets = ab8500_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ab8500_dapm_widgets), + .dapm_routes = ab8500_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ab8500_dapm_routes), + }, }; static int ab8500_codec_driver_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 5b3224c63943..f7f04c6be01e 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -117,10 +117,12 @@ static struct snd_soc_codec_driver soc_codec_dev_ac97 = { .suspend = ac97_soc_suspend, .resume = ac97_soc_resume, - .dapm_widgets = ac97_widgets, - .num_dapm_widgets = ARRAY_SIZE(ac97_widgets), - .dapm_routes = ac97_routes, - .num_dapm_routes = ARRAY_SIZE(ac97_routes), + .component_driver = { + .dapm_widgets = ac97_widgets, + .num_dapm_widgets = ARRAY_SIZE(ac97_widgets), + .dapm_routes = ac97_routes, + .num_dapm_routes = ARRAY_SIZE(ac97_routes), + }, }; static int ac97_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index e2ce6c4d7ece..a478239aadac 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -327,12 +327,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1836 = { .suspend = ad1836_suspend, .resume = ad1836_resume, - .controls = ad183x_controls, - .num_controls = ARRAY_SIZE(ad183x_controls), - .dapm_widgets = ad183x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ad183x_dapm_widgets), - .dapm_routes = ad183x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes), + .component_driver = { + .controls = ad183x_controls, + .num_controls = ARRAY_SIZE(ad183x_controls), + .dapm_widgets = ad183x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ad183x_dapm_widgets), + .dapm_routes = ad183x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes), + }, }; static const struct reg_default ad1836_reg_defaults[] = { diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 3a3f3f2343d7..d643557d89a7 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -410,12 +410,14 @@ static int ad193x_codec_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_ad193x = { .probe = ad193x_codec_probe, - .controls = ad193x_snd_controls, - .num_controls = ARRAY_SIZE(ad193x_snd_controls), - .dapm_widgets = ad193x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ad193x_dapm_widgets), - .dapm_routes = audio_paths, - .num_dapm_routes = ARRAY_SIZE(audio_paths), + .component_driver = { + .controls = ad193x_snd_controls, + .num_controls = ARRAY_SIZE(ad193x_snd_controls), + .dapm_widgets = ad193x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ad193x_dapm_widgets), + .dapm_routes = audio_paths, + .num_dapm_routes = ARRAY_SIZE(audio_paths), + }, }; const struct regmap_config ad193x_regmap_config = { diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 9ef20dbccbe3..b7c1b9f4bf5f 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -299,12 +299,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1980 = { .probe = ad1980_soc_probe, .remove = ad1980_soc_remove, - .controls = ad1980_snd_ac97_controls, - .num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls), - .dapm_widgets = ad1980_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets), - .dapm_routes = ad1980_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(ad1980_dapm_routes), + .component_driver = { + .controls = ad1980_snd_ac97_controls, + .num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls), + .dapm_widgets = ad1980_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets), + .dapm_routes = ad1980_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ad1980_dapm_routes), + }, }; static int ad1980_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index a9400aef60b5..3e358a49442d 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -55,10 +55,12 @@ static struct snd_soc_dai_driver ad73311_dai = { }; static struct snd_soc_codec_driver soc_codec_dev_ad73311 = { - .dapm_widgets = ad73311_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ad73311_dapm_widgets), - .dapm_routes = ad73311_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(ad73311_dapm_routes), + .component_driver = { + .dapm_widgets = ad73311_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ad73311_dapm_widgets), + .dapm_routes = ad73311_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ad73311_dapm_routes), + }, }; static int ad73311_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 1556b360fa15..8fa9045571ff 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1466,12 +1466,14 @@ static struct snd_soc_codec_driver adau1373_codec_driver = { .set_pll = adau1373_set_pll, - .controls = adau1373_controls, - .num_controls = ARRAY_SIZE(adau1373_controls), - .dapm_widgets = adau1373_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(adau1373_dapm_widgets), - .dapm_routes = adau1373_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(adau1373_dapm_routes), + .component_driver = { + .controls = adau1373_controls, + .num_controls = ARRAY_SIZE(adau1373_controls), + .dapm_widgets = adau1373_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adau1373_dapm_widgets), + .dapm_routes = adau1373_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(adau1373_dapm_routes), + }, }; static int adau1373_i2c_probe(struct i2c_client *client, diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index de53c0d7bf10..3bad1bc8c00a 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -765,13 +765,14 @@ static struct snd_soc_codec_driver adau1701_codec_drv = { .set_bias_level = adau1701_set_bias_level, .idle_bias_off = true, - .controls = adau1701_controls, - .num_controls = ARRAY_SIZE(adau1701_controls), - .dapm_widgets = adau1701_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(adau1701_dapm_widgets), - .dapm_routes = adau1701_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(adau1701_dapm_routes), - + .component_driver = { + .controls = adau1701_controls, + .num_controls = ARRAY_SIZE(adau1701_controls), + .dapm_widgets = adau1701_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adau1701_dapm_widgets), + .dapm_routes = adau1701_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(adau1701_dapm_routes), + }, .set_sysclk = adau1701_set_sysclk, }; diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index b95d29dbd13d..3bc3cc559dde 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -719,12 +719,14 @@ static const struct snd_soc_codec_driver adau1761_codec_driver = { .set_bias_level = adau1761_set_bias_level, .suspend_bias_off = true, - .controls = adau1761_controls, - .num_controls = ARRAY_SIZE(adau1761_controls), - .dapm_widgets = adau1x61_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(adau1x61_dapm_widgets), - .dapm_routes = adau1x61_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(adau1x61_dapm_routes), + .component_driver = { + .controls = adau1761_controls, + .num_controls = ARRAY_SIZE(adau1761_controls), + .dapm_widgets = adau1x61_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adau1x61_dapm_widgets), + .dapm_routes = adau1x61_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(adau1x61_dapm_routes), + }, }; #define ADAU1761_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index bc1bb56dae63..546071c6c0d0 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c @@ -432,12 +432,14 @@ static const struct snd_soc_codec_driver adau1781_codec_driver = { .set_bias_level = adau1781_set_bias_level, .suspend_bias_off = true, - .controls = adau1781_controls, - .num_controls = ARRAY_SIZE(adau1781_controls), - .dapm_widgets = adau1781_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(adau1781_dapm_widgets), - .dapm_routes = adau1781_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(adau1781_dapm_routes), + .component_driver = { + .controls = adau1781_controls, + .num_controls = ARRAY_SIZE(adau1781_controls), + .dapm_widgets = adau1781_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adau1781_dapm_widgets), + .dapm_routes = adau1781_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(adau1781_dapm_routes), + }, }; #define ADAU1781_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index 9bdd15f408c1..b319db6a69f8 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -873,12 +873,14 @@ static struct snd_soc_codec_driver adau1977_codec_driver = { .set_sysclk = adau1977_set_sysclk, .idle_bias_off = true, - .controls = adau1977_snd_controls, - .num_controls = ARRAY_SIZE(adau1977_snd_controls), - .dapm_widgets = adau1977_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(adau1977_dapm_widgets), - .dapm_routes = adau1977_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes), + .component_driver = { + .controls = adau1977_snd_controls, + .num_controls = ARRAY_SIZE(adau1977_snd_controls), + .dapm_widgets = adau1977_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adau1977_dapm_widgets), + .dapm_routes = adau1977_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes), + }, }; static int adau1977_setup_micbias(struct adau1977 *adau1977) diff --git a/sound/soc/codecs/adau7002.c b/sound/soc/codecs/adau7002.c index 9df72c6adcca..6384c5491de8 100644 --- a/sound/soc/codecs/adau7002.c +++ b/sound/soc/codecs/adau7002.c @@ -39,10 +39,12 @@ static struct snd_soc_dai_driver adau7002_dai = { }; static const struct snd_soc_codec_driver adau7002_codec_driver = { - .dapm_widgets = adau7002_widgets, - .num_dapm_widgets = ARRAY_SIZE(adau7002_widgets), - .dapm_routes = adau7002_routes, - .num_dapm_routes = ARRAY_SIZE(adau7002_routes), + .component_driver = { + .dapm_widgets = adau7002_widgets, + .num_dapm_widgets = ARRAY_SIZE(adau7002_widgets), + .dapm_routes = adau7002_routes, + .num_dapm_routes = ARRAY_SIZE(adau7002_routes), + }, }; static int adau7002_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index acff8d62059c..6e793ebb5883 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -834,12 +834,14 @@ static struct snd_soc_codec_driver adav80x_codec_driver = { .set_pll = adav80x_set_pll, .set_sysclk = adav80x_set_sysclk, - .controls = adav80x_controls, - .num_controls = ARRAY_SIZE(adav80x_controls), - .dapm_widgets = adav80x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(adav80x_dapm_widgets), - .dapm_routes = adav80x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), + .component_driver = { + .controls = adav80x_controls, + .num_controls = ARRAY_SIZE(adav80x_controls), + .dapm_widgets = adav80x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adav80x_dapm_widgets), + .dapm_routes = adav80x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), + }, }; int adav80x_bus_probe(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c index c5be1bdc2c9a..90c756d183b4 100644 --- a/sound/soc/codecs/ads117x.c +++ b/sound/soc/codecs/ads117x.c @@ -59,10 +59,12 @@ static struct snd_soc_dai_driver ads117x_dai = { }; static struct snd_soc_codec_driver soc_codec_dev_ads117x = { - .dapm_widgets = ads117x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ads117x_dapm_widgets), - .dapm_routes = ads117x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(ads117x_dapm_routes), + .component_driver = { + .dapm_widgets = ads117x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ads117x_dapm_widgets), + .dapm_routes = ads117x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ads117x_dapm_routes), + }, }; static int ads117x_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 595d02d7602c..1a9d233c94d0 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -163,7 +163,10 @@ static struct snd_soc_dai_driver ak4104_dai = { .stream_name = "Playback", .channels_min = 2, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE @@ -245,10 +248,12 @@ static struct snd_soc_codec_driver soc_codec_device_ak4104 = { .suspend = ak4104_soc_suspend, .resume = ak4104_soc_resume, - .dapm_widgets = ak4104_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets), - .dapm_routes = ak4104_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(ak4104_dapm_routes), + .component_driver = { + .dapm_widgets = ak4104_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets), + .dapm_routes = ak4104_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ak4104_dapm_routes), + } }; static const struct regmap_config ak4104_regmap = { diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 54428c64387b..66cfffde9a12 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -395,12 +395,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4535 = { .set_bias_level = ak4535_set_bias_level, .suspend_bias_off = true, - .controls = ak4535_snd_controls, - .num_controls = ARRAY_SIZE(ak4535_snd_controls), - .dapm_widgets = ak4535_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets), - .dapm_routes = ak4535_audio_map, - .num_dapm_routes = ARRAY_SIZE(ak4535_audio_map), + .component_driver = { + .controls = ak4535_snd_controls, + .num_controls = ARRAY_SIZE(ak4535_snd_controls), + .dapm_widgets = ak4535_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets), + .dapm_routes = ak4535_audio_map, + .num_dapm_routes = ARRAY_SIZE(ak4535_audio_map), + }, }; static int ak4535_i2c_probe(struct i2c_client *i2c, diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c index 298dedc05140..b92c548b9d29 100644 --- a/sound/soc/codecs/ak4554.c +++ b/sound/soc/codecs/ak4554.c @@ -65,10 +65,12 @@ static struct snd_soc_dai_driver ak4554_dai = { }; static struct snd_soc_codec_driver soc_codec_dev_ak4554 = { - .dapm_widgets = ak4554_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ak4554_dapm_widgets), - .dapm_routes = ak4554_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(ak4554_dapm_routes), + .component_driver = { + .dapm_widgets = ak4554_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4554_dapm_widgets), + .dapm_routes = ak4554_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ak4554_dapm_routes), + }, }; static int ak4554_soc_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 97798d250f08..e819dd8c82fd 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -458,12 +458,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4613 = { .suspend = ak4613_suspend, .resume = ak4613_resume, .set_bias_level = ak4613_set_bias_level, - .controls = ak4613_snd_controls, - .num_controls = ARRAY_SIZE(ak4613_snd_controls), - .dapm_widgets = ak4613_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ak4613_dapm_widgets), - .dapm_routes = ak4613_intercon, - .num_dapm_routes = ARRAY_SIZE(ak4613_intercon), + .component_driver = { + .controls = ak4613_snd_controls, + .num_controls = ARRAY_SIZE(ak4613_snd_controls), + .dapm_widgets = ak4613_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4613_dapm_widgets), + .dapm_routes = ak4613_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4613_intercon), + }, }; static void ak4613_parse_of(struct ak4613_priv *priv, diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index b14176f8d884..c91717d08513 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -505,12 +505,14 @@ static struct snd_soc_dai_driver ak4641_dai[] = { }; static struct snd_soc_codec_driver soc_codec_dev_ak4641 = { - .controls = ak4641_snd_controls, - .num_controls = ARRAY_SIZE(ak4641_snd_controls), - .dapm_widgets = ak4641_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ak4641_dapm_widgets), - .dapm_routes = ak4641_audio_map, - .num_dapm_routes = ARRAY_SIZE(ak4641_audio_map), + .component_driver = { + .controls = ak4641_snd_controls, + .num_controls = ARRAY_SIZE(ak4641_snd_controls), + .dapm_widgets = ak4641_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4641_dapm_widgets), + .dapm_routes = ak4641_audio_map, + .num_dapm_routes = ARRAY_SIZE(ak4641_audio_map), + }, .set_bias_level = ak4641_set_bias_level, .suspend_bias_off = true, }; diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index cc941d66ec3d..2609f95b7d19 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -555,12 +555,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { .suspend = ak4642_suspend, .resume = ak4642_resume, .set_bias_level = ak4642_set_bias_level, - .controls = ak4642_snd_controls, - .num_controls = ARRAY_SIZE(ak4642_snd_controls), - .dapm_widgets = ak4642_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets), - .dapm_routes = ak4642_intercon, - .num_dapm_routes = ARRAY_SIZE(ak4642_intercon), + .component_driver = { + .controls = ak4642_snd_controls, + .num_controls = ARRAY_SIZE(ak4642_snd_controls), + .dapm_widgets = ak4642_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets), + .dapm_routes = ak4642_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4642_intercon), + }, }; static const struct regmap_config ak4642_regmap = { diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index c73a9f6914b6..6088afaabf62 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -612,12 +612,14 @@ static struct snd_soc_dai_driver ak4671_dai = { static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { .set_bias_level = ak4671_set_bias_level, - .controls = ak4671_snd_controls, - .num_controls = ARRAY_SIZE(ak4671_snd_controls), - .dapm_widgets = ak4671_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets), - .dapm_routes = ak4671_intercon, - .num_dapm_routes = ARRAY_SIZE(ak4671_intercon), + .component_driver = { + .controls = ak4671_snd_controls, + .num_controls = ARRAY_SIZE(ak4671_snd_controls), + .dapm_widgets = ak4671_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets), + .dapm_routes = ak4671_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4671_intercon), + }, }; static const struct regmap_config ak4671_regmap = { diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c index afa95360826d..0ef2df223336 100644 --- a/sound/soc/codecs/ak5386.c +++ b/sound/soc/codecs/ak5386.c @@ -74,10 +74,12 @@ static struct snd_soc_codec_driver soc_codec_ak5386 = { .remove = ak5386_soc_remove, .suspend = ak5386_soc_suspend, .resume = ak5386_soc_resume, - .dapm_widgets = ak5386_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets), - .dapm_routes = ak5386_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(ak5386_dapm_routes), + .component_driver = { + .dapm_widgets = ak5386_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets), + .dapm_routes = ak5386_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ak5386_dapm_routes), + }, }; static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai, diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 4d3ba33eb6f9..adb80d8719bd 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -1072,12 +1072,14 @@ static const struct snd_soc_codec_driver soc_codec_device_alc5632 = { .set_bias_level = alc5632_set_bias_level, .suspend_bias_off = true, - .controls = alc5632_snd_controls, - .num_controls = ARRAY_SIZE(alc5632_snd_controls), - .dapm_widgets = alc5632_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(alc5632_dapm_widgets), - .dapm_routes = alc5632_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(alc5632_dapm_routes), + .component_driver = { + .controls = alc5632_snd_controls, + .num_controls = ARRAY_SIZE(alc5632_snd_controls), + .dapm_widgets = alc5632_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(alc5632_dapm_widgets), + .dapm_routes = alc5632_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(alc5632_dapm_routes), + }, }; static const struct regmap_config alc5632_regmap = { diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index ecfdbfcae366..846ca079845f 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -109,7 +109,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, break; } - return 0; + return arizona_out_ev(w, kcontrol, event); } static irqreturn_t arizona_thermal_warn(int irq, void *data) @@ -159,12 +159,14 @@ static irqreturn_t arizona_thermal_shutdown(int irq, void *data) static const struct snd_soc_dapm_widget arizona_spkl = SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM, ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD); static const struct snd_soc_dapm_widget arizona_spkr = SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM, ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD); int arizona_init_spk(struct snd_soc_codec *codec) { @@ -864,6 +866,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -877,6 +880,18 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, priv->out_up_pending++; priv->out_up_delay += 17; break; + case ARIZONA_OUT4L_ENA_SHIFT: + case ARIZONA_OUT4R_ENA_SHIFT: + priv->out_up_pending++; + switch (arizona->type) { + case WM5102: + case WM8997: + break; + default: + priv->out_up_delay += 10; + break; + } + break; default: break; } @@ -889,8 +904,12 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, case ARIZONA_OUT2R_ENA_SHIFT: case ARIZONA_OUT3L_ENA_SHIFT: case ARIZONA_OUT3R_ENA_SHIFT: + case ARIZONA_OUT4L_ENA_SHIFT: + case ARIZONA_OUT4R_ENA_SHIFT: priv->out_up_pending--; - if (!priv->out_up_pending) { + if (!priv->out_up_pending && priv->out_up_delay) { + dev_dbg(codec->dev, "Power up delay: %d\n", + priv->out_up_delay); msleep(priv->out_up_delay); priv->out_up_delay = 0; } @@ -911,6 +930,21 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, priv->out_down_pending++; priv->out_down_delay++; break; + case ARIZONA_OUT4L_ENA_SHIFT: + case ARIZONA_OUT4R_ENA_SHIFT: + priv->out_down_pending++; + switch (arizona->type) { + case WM5102: + case WM8997: + break; + case WM8998: + case WM1814: + priv->out_down_delay += 5; + break; + default: + priv->out_down_delay++; + break; + } default: break; } @@ -923,8 +957,12 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, case ARIZONA_OUT2R_ENA_SHIFT: case ARIZONA_OUT3L_ENA_SHIFT: case ARIZONA_OUT3R_ENA_SHIFT: + case ARIZONA_OUT4L_ENA_SHIFT: + case ARIZONA_OUT4R_ENA_SHIFT: priv->out_down_pending--; - if (!priv->out_down_pending) { + if (!priv->out_down_pending && priv->out_down_delay) { + dev_dbg(codec->dev, "Power down delay: %d\n", + priv->out_down_delay); msleep(priv->out_down_delay); priv->out_down_delay = 0; } @@ -1920,8 +1958,8 @@ static struct { struct arizona_fll_cfg { int n; - int theta; - int lambda; + unsigned int theta; + unsigned int lambda; int refdiv; int outdiv; int fratio; @@ -2188,13 +2226,13 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, ARIZONA_FLL1_CTRL_UPD | cfg->n); } -static int arizona_is_enabled_fll(struct arizona_fll *fll) +static int arizona_is_enabled_fll(struct arizona_fll *fll, int base) { struct arizona *arizona = fll->arizona; unsigned int reg; int ret; - ret = regmap_read(arizona->regmap, fll->base + 1, ®); + ret = regmap_read(arizona->regmap, base + 1, ®); if (ret != 0) { arizona_fll_err(fll, "Failed to read current state: %d\n", ret); @@ -2208,21 +2246,24 @@ static int arizona_enable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; bool use_sync = false; - int already_enabled = arizona_is_enabled_fll(fll); + int already_enabled = arizona_is_enabled_fll(fll, fll->base); + int sync_enabled = arizona_is_enabled_fll(fll, fll->base + 0x10); struct arizona_fll_cfg cfg; int i; unsigned int val; if (already_enabled < 0) return already_enabled; + if (sync_enabled < 0) + return sync_enabled; if (already_enabled) { /* Facilitate smooth refclk across the transition */ - regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9, - ARIZONA_FLL1_GAIN_MASK, 0); regmap_update_bits(fll->arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN); udelay(32); + regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9, + ARIZONA_FLL1_GAIN_MASK, 0); } /* @@ -2233,6 +2274,10 @@ static int arizona_enable_fll(struct arizona_fll *fll) fll->ref_src != fll->sync_src) { arizona_calc_fll(fll, &cfg, fll->ref_freq, false); + /* Ref path hardcodes lambda to 65536 when sync is on */ + if (fll->sync_src >= 0 && cfg.lambda) + cfg.theta = (cfg.theta * (1 << 16)) / cfg.lambda; + arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src, false); if (fll->sync_src >= 0) { @@ -2255,6 +2300,9 @@ static int arizona_enable_fll(struct arizona_fll *fll) return -EINVAL; } + if (already_enabled && !!sync_enabled != use_sync) + arizona_fll_warn(fll, "Synchroniser changed on active FLL\n"); + /* * Increase the bandwidth if we're not using a low frequency * sync source. @@ -2268,14 +2316,14 @@ static int arizona_enable_fll(struct arizona_fll *fll) ARIZONA_FLL1_SYNC_BW); if (!already_enabled) - pm_runtime_get(arizona->dev); + pm_runtime_get_sync(arizona->dev); - regmap_update_bits_async(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); if (use_sync) regmap_update_bits_async(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); + regmap_update_bits_async(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); if (already_enabled) regmap_update_bits_async(arizona->regmap, fll->base + 1, diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 69da1ef3a17c..850aa338ba29 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -190,20 +190,21 @@ extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; #define ARIZONA_DSP_ROUTES(name) \ { name, NULL, name " Preloader"}, \ - { name " Preloader", NULL, name " Aux 1" }, \ - { name " Preloader", NULL, name " Aux 2" }, \ - { name " Preloader", NULL, name " Aux 3" }, \ - { name " Preloader", NULL, name " Aux 4" }, \ - { name " Preloader", NULL, name " Aux 5" }, \ - { name " Preloader", NULL, name " Aux 6" }, \ + { name " Preloader", NULL, "SYSCLK" }, \ + { name, NULL, name " Aux 1" }, \ + { name, NULL, name " Aux 2" }, \ + { name, NULL, name " Aux 3" }, \ + { name, NULL, name " Aux 4" }, \ + { name, NULL, name " Aux 5" }, \ + { name, NULL, name " Aux 6" }, \ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 1"), \ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 2"), \ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 3"), \ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 4"), \ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 5"), \ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 6"), \ - ARIZONA_MIXER_ROUTES(name " Preloader", name "L"), \ - ARIZONA_MIXER_ROUTES(name " Preloader", name "R") + ARIZONA_MIXER_ROUTES(name, name "L"), \ + ARIZONA_MIXER_ROUTES(name, name "R") #define ARIZONA_EQ_CONTROL(xname, xbase) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c index 2a8d0ee141d4..8014e697d540 100644 --- a/sound/soc/codecs/bt-sco.c +++ b/sound/soc/codecs/bt-sco.c @@ -63,10 +63,12 @@ static struct snd_soc_dai_driver bt_sco_dai[] = { }; static struct snd_soc_codec_driver soc_codec_dev_bt_sco = { - .dapm_widgets = bt_sco_widgets, - .num_dapm_widgets = ARRAY_SIZE(bt_sco_widgets), - .dapm_routes = bt_sco_routes, - .num_dapm_routes = ARRAY_SIZE(bt_sco_routes), + .component_driver = { + .dapm_widgets = bt_sco_widgets, + .num_dapm_widgets = ARRAY_SIZE(bt_sco_widgets), + .dapm_routes = bt_sco_routes, + .num_dapm_routes = ARRAY_SIZE(bt_sco_routes), + }, }; static int bt_sco_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 1c895a53001d..7a2d9a2ee427 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -131,8 +131,10 @@ static struct regmap *cq93vc_get_regmap(struct device *dev) static struct snd_soc_codec_driver soc_codec_dev_cq93vc = { .set_bias_level = cq93vc_set_bias_level, .get_regmap = cq93vc_get_regmap, - .controls = cq93vc_snd_controls, - .num_controls = ARRAY_SIZE(cq93vc_snd_controls), + .component_driver = { + .controls = cq93vc_snd_controls, + .num_controls = ARRAY_SIZE(cq93vc_snd_controls), + }, }; static int cq93vc_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 287d13740be4..7e9806206648 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -231,13 +231,14 @@ static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec, static const struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { .set_sysclk = cs35l32_codec_set_sysclk, - .dapm_widgets = cs35l32_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cs35l32_dapm_widgets), - .dapm_routes = cs35l32_audio_map, - .num_dapm_routes = ARRAY_SIZE(cs35l32_audio_map), - - .controls = cs35l32_snd_controls, - .num_controls = ARRAY_SIZE(cs35l32_snd_controls), + .component_driver = { + .controls = cs35l32_snd_controls, + .num_controls = ARRAY_SIZE(cs35l32_snd_controls), + .dapm_widgets = cs35l32_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs35l32_dapm_widgets), + .dapm_routes = cs35l32_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs35l32_audio_map), + }, }; /* Current and threshold powerup sequence Pg37 in datasheet */ diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c index 6f9c1addcd7f..6df29fa30fb9 100644 --- a/sound/soc/codecs/cs35l33.c +++ b/sound/soc/codecs/cs35l33.c @@ -837,13 +837,14 @@ static struct snd_soc_codec_driver soc_codec_dev_cs35l33 = { .set_bias_level = cs35l33_set_bias_level, .set_sysclk = cs35l33_codec_set_sysclk, - .dapm_widgets = cs35l33_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cs35l33_dapm_widgets), - .dapm_routes = cs35l33_audio_map, - .num_dapm_routes = ARRAY_SIZE(cs35l33_audio_map), - .controls = cs35l33_snd_controls, - .num_controls = ARRAY_SIZE(cs35l33_snd_controls), - + .component_driver = { + .controls = cs35l33_snd_controls, + .num_controls = ARRAY_SIZE(cs35l33_snd_controls), + .dapm_widgets = cs35l33_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs35l33_dapm_widgets), + .dapm_routes = cs35l33_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs35l33_audio_map), + }, .idle_bias_off = true, }; diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 55db19ddc5ff..fd966bb851cb 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -547,13 +547,14 @@ static struct snd_soc_dai_driver cs4265_dai[] = { static const struct snd_soc_codec_driver soc_codec_cs4265 = { .set_bias_level = cs4265_set_bias_level, - .dapm_widgets = cs4265_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cs4265_dapm_widgets), - .dapm_routes = cs4265_audio_map, - .num_dapm_routes = ARRAY_SIZE(cs4265_audio_map), - - .controls = cs4265_snd_controls, - .num_controls = ARRAY_SIZE(cs4265_snd_controls), + .component_driver = { + .controls = cs4265_snd_controls, + .num_controls = ARRAY_SIZE(cs4265_snd_controls), + .dapm_widgets = cs4265_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs4265_dapm_widgets), + .dapm_routes = cs4265_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs4265_audio_map), + }, }; static const struct regmap_config cs4265_regmap = { diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index e07807d96b68..18baea2f7d65 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -617,12 +617,14 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = { .suspend = cs4270_soc_suspend, .resume = cs4270_soc_resume, - .controls = cs4270_snd_controls, - .num_controls = ARRAY_SIZE(cs4270_snd_controls), - .dapm_widgets = cs4270_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cs4270_dapm_widgets), - .dapm_routes = cs4270_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(cs4270_dapm_routes), + .component_driver = { + .controls = cs4270_snd_controls, + .num_controls = ARRAY_SIZE(cs4270_snd_controls), + .dapm_widgets = cs4270_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs4270_dapm_widgets), + .dapm_routes = cs4270_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(cs4270_dapm_routes), + }, }; /* diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 0c0010b25421..8c0f3b89b5bc 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -645,12 +645,14 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { .suspend = cs4271_soc_suspend, .resume = cs4271_soc_resume, - .controls = cs4271_snd_controls, - .num_controls = ARRAY_SIZE(cs4271_snd_controls), - .dapm_widgets = cs4271_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cs4271_dapm_widgets), - .dapm_routes = cs4271_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(cs4271_dapm_routes), + .component_driver = { + .controls = cs4271_snd_controls, + .num_controls = ARRAY_SIZE(cs4271_snd_controls), + .dapm_widgets = cs4271_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs4271_dapm_widgets), + .dapm_routes = cs4271_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(cs4271_dapm_routes), + }, }; static int cs4271_common_probe(struct device *dev, diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 35488f14e237..96cfe38943cd 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -507,12 +507,14 @@ static int cs42l51_codec_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { .probe = cs42l51_codec_probe, - .controls = cs42l51_snd_controls, - .num_controls = ARRAY_SIZE(cs42l51_snd_controls), - .dapm_widgets = cs42l51_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cs42l51_dapm_widgets), - .dapm_routes = cs42l51_routes, - .num_dapm_routes = ARRAY_SIZE(cs42l51_routes), + .component_driver = { + .controls = cs42l51_snd_controls, + .num_controls = ARRAY_SIZE(cs42l51_snd_controls), + .dapm_widgets = cs42l51_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs42l51_dapm_widgets), + .dapm_routes = cs42l51_routes, + .num_dapm_routes = ARRAY_SIZE(cs42l51_routes), + }, }; const struct regmap_config cs42l51_regmap = { diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 47b97fcefb0b..0d9c4a57301b 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1056,13 +1056,14 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs42l52 = { .set_bias_level = cs42l52_set_bias_level, .suspend_bias_off = true, - .dapm_widgets = cs42l52_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cs42l52_dapm_widgets), - .dapm_routes = cs42l52_audio_map, - .num_dapm_routes = ARRAY_SIZE(cs42l52_audio_map), - - .controls = cs42l52_snd_controls, - .num_controls = ARRAY_SIZE(cs42l52_snd_controls), + .component_driver = { + .controls = cs42l52_snd_controls, + .num_controls = ARRAY_SIZE(cs42l52_snd_controls), + .dapm_widgets = cs42l52_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs42l52_dapm_widgets), + .dapm_routes = cs42l52_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs42l52_audio_map), + }, }; /* Current and threshold powerup sequence Pg37 */ diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index eec1ff853b98..54c1768bc818 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1121,13 +1121,14 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs42l56 = { .set_bias_level = cs42l56_set_bias_level, .suspend_bias_off = true, - .dapm_widgets = cs42l56_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets), - .dapm_routes = cs42l56_audio_map, - .num_dapm_routes = ARRAY_SIZE(cs42l56_audio_map), - - .controls = cs42l56_snd_controls, - .num_controls = ARRAY_SIZE(cs42l56_snd_controls), + .component_driver = { + .controls = cs42l56_snd_controls, + .num_controls = ARRAY_SIZE(cs42l56_snd_controls), + .dapm_widgets = cs42l56_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets), + .dapm_routes = cs42l56_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs42l56_audio_map), + }, }; static const struct regmap_config cs42l56_regmap = { diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 42a8fd4e1f9b..71ba5605495f 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -794,7 +794,7 @@ struct cs42l73_mclk_div { u8 mmcc; }; -static struct cs42l73_mclk_div cs42l73_mclk_coeffs[] = { +static const struct cs42l73_mclk_div cs42l73_mclk_coeffs[] = { /* MCLK, Sample Rate, xMMCC[5:0] */ {5644800, 11025, 0x30}, {5644800, 22050, 0x20}, @@ -844,7 +844,7 @@ struct cs42l73_mclkx_div { u8 mclkdiv; }; -static struct cs42l73_mclkx_div cs42l73_mclkx_coeffs[] = { +static const struct cs42l73_mclkx_div cs42l73_mclkx_coeffs[] = { {5644800, 1, 0}, /* 5644800 */ {6000000, 1, 0}, /* 6000000 */ {6144000, 1, 0}, /* 6144000 */ @@ -1257,13 +1257,14 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs42l73 = { .set_bias_level = cs42l73_set_bias_level, .suspend_bias_off = true, - .dapm_widgets = cs42l73_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cs42l73_dapm_widgets), - .dapm_routes = cs42l73_audio_map, - .num_dapm_routes = ARRAY_SIZE(cs42l73_audio_map), - - .controls = cs42l73_snd_controls, - .num_controls = ARRAY_SIZE(cs42l73_snd_controls), + .component_driver = { + .controls = cs42l73_snd_controls, + .num_controls = ARRAY_SIZE(cs42l73_snd_controls), + .dapm_widgets = cs42l73_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs42l73_dapm_widgets), + .dapm_routes = cs42l73_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs42l73_audio_map), + }, }; static const struct regmap_config cs42l73_regmap = { diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index 1179101b2b05..b4d87379d2bc 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -411,12 +411,14 @@ static const struct snd_soc_codec_driver cs42xx8_driver = { .probe = cs42xx8_codec_probe, .idle_bias_off = true, - .controls = cs42xx8_snd_controls, - .num_controls = ARRAY_SIZE(cs42xx8_snd_controls), - .dapm_widgets = cs42xx8_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cs42xx8_dapm_widgets), - .dapm_routes = cs42xx8_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes), + .component_driver = { + .controls = cs42xx8_snd_controls, + .num_controls = ARRAY_SIZE(cs42xx8_snd_controls), + .dapm_widgets = cs42xx8_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs42xx8_dapm_widgets), + .dapm_routes = cs42xx8_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes), + }, }; const struct cs42xx8_driver_data cs42448_data = { diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 0ac8fc5ed4ae..231ca935cdf3 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -256,13 +256,14 @@ static struct snd_soc_dai_driver cs4349_dai = { }; static struct snd_soc_codec_driver soc_codec_dev_cs4349 = { - .controls = cs4349_snd_controls, - .num_controls = ARRAY_SIZE(cs4349_snd_controls), - - .dapm_widgets = cs4349_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cs4349_dapm_widgets), - .dapm_routes = cs4349_routes, - .num_dapm_routes = ARRAY_SIZE(cs4349_routes), + .component_driver = { + .controls = cs4349_snd_controls, + .num_controls = ARRAY_SIZE(cs4349_snd_controls), + .dapm_widgets = cs4349_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs4349_dapm_widgets), + .dapm_routes = cs4349_routes, + .num_dapm_routes = ARRAY_SIZE(cs4349_routes), + }, }; static const struct regmap_config cs4349_regmap = { diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 954a4f5d3338..5b22564f037c 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -746,6 +746,16 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = { { "IN2L", NULL, "SYSCLK" }, { "IN2R", NULL, "SYSCLK" }, + { "ASRC1L", NULL, "SYSCLK" }, + { "ASRC1R", NULL, "SYSCLK" }, + { "ASRC2L", NULL, "SYSCLK" }, + { "ASRC2R", NULL, "SYSCLK" }, + + { "ASRC1L", NULL, "ASYNCCLK" }, + { "ASRC1R", NULL, "ASYNCCLK" }, + { "ASRC2L", NULL, "ASYNCCLK" }, + { "ASRC2R", NULL, "ASYNCCLK" }, + { "MICBIAS1", NULL, "MICVDD" }, { "MICBIAS2", NULL, "MICVDD" }, @@ -804,7 +814,6 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = { { "AIF3 Capture", NULL, "SYSCLK" }, { "Voice Control DSP", NULL, "DSP3" }, - { "Voice Control DSP", NULL, "SYSCLK" }, { "IN1L PGA", NULL, "IN1L" }, { "IN1R PGA", NULL, "IN1R" }, @@ -813,7 +822,6 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = { { "IN2R PGA", NULL, "IN2R" }, { "Audio Trace DSP", NULL, "DSP2" }, - { "Audio Trace DSP", NULL, "SYSCLK" }, ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), @@ -1190,12 +1198,14 @@ static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = { .set_sysclk = arizona_set_sysclk, .set_pll = cs47l24_set_fll, - .controls = cs47l24_snd_controls, - .num_controls = ARRAY_SIZE(cs47l24_snd_controls), - .dapm_widgets = cs47l24_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cs47l24_dapm_widgets), - .dapm_routes = cs47l24_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes), + .component_driver = { + .controls = cs47l24_snd_controls, + .num_controls = ARRAY_SIZE(cs47l24_snd_controls), + .dapm_widgets = cs47l24_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs47l24_dapm_widgets), + .dapm_routes = cs47l24_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes), + }, }; static struct snd_compr_ops cs47l24_compr_ops = { diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index 2c0d9c430a8c..cb47fb595ff4 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -466,7 +466,7 @@ struct cs53l30_mclk_div { u8 mclk_int_scale; }; -static struct cs53l30_mclk_div cs53l30_mclk_coeffs[] = { +static const struct cs53l30_mclk_div cs53l30_mclk_coeffs[] = { /* NOTE: Enable MCLK_INT_SCALE to save power. */ /* MCLK, Sample Rate, asp_rate, internal_fs_ratio, mclk_int_scale */ @@ -511,7 +511,7 @@ struct cs53l30_mclkx_div { u8 mclkdiv; }; -static struct cs53l30_mclkx_div cs53l30_mclkx_coeffs[] = { +static const struct cs53l30_mclkx_div cs53l30_mclkx_coeffs[] = { {5644800, 1, CS53L30_MCLK_DIV_BY_1}, {6000000, 1, CS53L30_MCLK_DIV_BY_1}, {6144000, 1, CS53L30_MCLK_DIV_BY_1}, @@ -897,13 +897,14 @@ static struct snd_soc_codec_driver cs53l30_driver = { .set_bias_level = cs53l30_set_bias_level, .idle_bias_off = true, - .dapm_widgets = cs53l30_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cs53l30_dapm_widgets), - .dapm_routes = cs53l30_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(cs53l30_dapm_routes), - - .controls = cs53l30_snd_controls, - .num_controls = ARRAY_SIZE(cs53l30_snd_controls), + .component_driver = { + .controls = cs53l30_snd_controls, + .num_controls = ARRAY_SIZE(cs53l30_snd_controls), + .dapm_widgets = cs53l30_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs53l30_dapm_widgets), + .dapm_routes = cs53l30_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(cs53l30_dapm_routes), + }, }; static struct regmap_config cs53l30_regmap = { @@ -999,8 +1000,8 @@ static int cs53l30_i2c_probe(struct i2c_client *client, /* Check if MCLK provided */ cs53l30->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(cs53l30->mclk)) { - if (PTR_ERR(cs53l30->mclk) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; + if (PTR_ERR(cs53l30->mclk) != -ENOENT) { + ret = PTR_ERR(cs53l30->mclk); goto error; } /* Otherwise mark the mclk pointer to NULL */ diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index fb3885fe0afb..2c12471e42a6 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -407,10 +407,12 @@ static struct snd_soc_codec_driver cx20442_codec_dev = { .reg_word_size = sizeof(u8), .read = cx20442_read_reg_cache, .write = cx20442_write, - .dapm_widgets = cx20442_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets), - .dapm_routes = cx20442_audio_map, - .num_dapm_routes = ARRAY_SIZE(cx20442_audio_map), + .component_driver = { + .dapm_widgets = cx20442_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets), + .dapm_routes = cx20442_audio_map, + .num_dapm_routes = ARRAY_SIZE(cx20442_audio_map), + }, }; static int cx20442_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index af23a61b7b28..17053dfc94cf 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -1167,13 +1167,14 @@ static int da7210_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_da7210 = { .probe = da7210_probe, - .controls = da7210_snd_controls, - .num_controls = ARRAY_SIZE(da7210_snd_controls), - - .dapm_widgets = da7210_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(da7210_dapm_widgets), - .dapm_routes = da7210_audio_map, - .num_dapm_routes = ARRAY_SIZE(da7210_audio_map), + .component_driver = { + .controls = da7210_snd_controls, + .num_controls = ARRAY_SIZE(da7210_snd_controls), + .dapm_widgets = da7210_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(da7210_dapm_widgets), + .dapm_routes = da7210_audio_map, + .num_dapm_routes = ARRAY_SIZE(da7210_audio_map), + }, }; #if IS_ENABLED(CONFIG_I2C) diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index e5527bc570ae..12da55882c06 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -750,11 +750,18 @@ static int da7213_dai_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK, 0); - /* Slave mode, if SRM not enabled no need for status checks */ + /* If SRM not enabled then nothing more to do */ pll_ctrl = snd_soc_read(codec, DA7213_PLL_CTRL); if (!(pll_ctrl & DA7213_PLL_SRM_EN)) return 0; + /* Assist 32KHz mode PLL lock */ + if (pll_ctrl & DA7213_PLL_32K_MODE) { + snd_soc_write(codec, 0xF0, 0x8B); + snd_soc_write(codec, 0xF2, 0x03); + snd_soc_write(codec, 0xF0, 0x00); + } + /* Check SRM has locked */ do { pll_status = snd_soc_read(codec, DA7213_PLL_STATUS); @@ -771,6 +778,14 @@ static int da7213_dai_event(struct snd_soc_dapm_widget *w, return 0; case SND_SOC_DAPM_POST_PMD: + /* Revert 32KHz PLL lock udpates if applied previously */ + pll_ctrl = snd_soc_read(codec, DA7213_PLL_CTRL); + if (pll_ctrl & DA7213_PLL_32K_MODE) { + snd_soc_write(codec, 0xF0, 0x8B); + snd_soc_write(codec, 0xF2, 0x01); + snd_soc_write(codec, 0xF0, 0x00); + } + /* PC free-running */ snd_soc_update_bits(codec, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK, @@ -1247,8 +1262,8 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - /* By default only 32 BCLK per WCLK is supported */ - dai_clk_mode |= DA7213_DAI_BCLKS_PER_WCLK_32; + /* By default only 64 BCLK per WCLK is supported */ + dai_clk_mode |= DA7213_DAI_BCLKS_PER_WCLK_64; snd_soc_write(codec, DA7213_DAI_CLK_MODE, dai_clk_mode); snd_soc_update_bits(codec, DA7213_DAI_CTRL, DA7213_DAI_FORMAT_MASK, @@ -1297,10 +1312,13 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, switch (clk_id) { case DA7213_CLKSRC_MCLK: - da7213->mclk_squarer_en = false; + snd_soc_update_bits(codec, DA7213_PLL_CTRL, + DA7213_PLL_MCLK_SQR_EN, 0); break; case DA7213_CLKSRC_MCLK_SQR: - da7213->mclk_squarer_en = true; + snd_soc_update_bits(codec, DA7213_PLL_CTRL, + DA7213_PLL_MCLK_SQR_EN, + DA7213_PLL_MCLK_SQR_EN); break; default: dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); @@ -1324,7 +1342,7 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, return 0; } -/* Supported PLL input frequencies are 5MHz - 54MHz. */ +/* Supported PLL input frequencies are 32KHz, 5MHz - 54MHz. */ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, int source, unsigned int fref, unsigned int fout) { @@ -1336,22 +1354,26 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, u32 freq_ref; u64 frac_div; - /* Reset PLL configuration */ - snd_soc_write(codec, DA7213_PLL_CTRL, 0); - - pll_ctrl = 0; - /* Workout input divider based on MCLK rate */ if (da7213->mclk_rate == 32768) { + if (!da7213->master) { + dev_err(codec->dev, + "32KHz only valid if codec is clock master\n"); + return -EINVAL; + } + /* 32KHz PLL Mode */ indiv_bits = DA7213_PLL_INDIV_9_TO_18_MHZ; indiv = DA7213_PLL_INDIV_9_TO_18_MHZ_VAL; + source = DA7213_SYSCLK_PLL_32KHZ; freq_ref = 3750000; - pll_ctrl |= DA7213_PLL_32K_MODE; + } else { - /* 5 - 54MHz MCLK */ if (da7213->mclk_rate < 5000000) { - goto pll_err; + dev_err(codec->dev, + "PLL input clock %d below valid range\n", + da7213->mclk_rate); + return -EINVAL; } else if (da7213->mclk_rate <= 9000000) { indiv_bits = DA7213_PLL_INDIV_5_TO_9_MHZ; indiv = DA7213_PLL_INDIV_5_TO_9_MHZ_VAL; @@ -1365,32 +1387,44 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, indiv_bits = DA7213_PLL_INDIV_36_TO_54_MHZ; indiv = DA7213_PLL_INDIV_36_TO_54_MHZ_VAL; } else { - goto pll_err; + dev_err(codec->dev, + "PLL input clock %d above valid range\n", + da7213->mclk_rate); + return -EINVAL; } freq_ref = (da7213->mclk_rate / indiv); } - pll_ctrl |= indiv_bits; + pll_ctrl = indiv_bits; - /* PLL Bypass mode */ - if (source == DA7213_SYSCLK_MCLK) { - snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl); + /* Configure PLL */ + switch (source) { + case DA7213_SYSCLK_MCLK: + snd_soc_update_bits(codec, DA7213_PLL_CTRL, + DA7213_PLL_INDIV_MASK | + DA7213_PLL_MODE_MASK, pll_ctrl); return 0; - } + case DA7213_SYSCLK_PLL: + break; + case DA7213_SYSCLK_PLL_SRM: + pll_ctrl |= DA7213_PLL_SRM_EN; + fout = DA7213_PLL_FREQ_OUT_94310400; + break; + case DA7213_SYSCLK_PLL_32KHZ: + if (da7213->mclk_rate != 32768) { + dev_err(codec->dev, + "32KHz mode only valid with 32KHz MCLK\n"); + return -EINVAL; + } - /* - * If Codec is slave and SRM enabled, - * freq_out is (98304000 + 90316800)/2 = 94310400 - */ - if (!da7213->master && da7213->srm_en) { + pll_ctrl |= DA7213_PLL_32K_MODE | DA7213_PLL_SRM_EN; fout = DA7213_PLL_FREQ_OUT_94310400; - pll_ctrl |= DA7213_PLL_SRM_EN; + break; + default: + dev_err(codec->dev, "Invalid PLL config\n"); + return -EINVAL; } - /* Enable MCLK squarer if required */ - if (da7213->mclk_squarer_en) - pll_ctrl |= DA7213_PLL_MCLK_SQR_EN; - /* Calculate dividers for PLL */ pll_integer = fout / freq_ref; frac_div = (u64)(fout % freq_ref) * 8192ULL; @@ -1405,14 +1439,19 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, /* Enable PLL */ pll_ctrl |= DA7213_PLL_EN; - snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl); + snd_soc_update_bits(codec, DA7213_PLL_CTRL, + DA7213_PLL_INDIV_MASK | DA7213_PLL_MODE_MASK, + pll_ctrl); + + /* Assist 32KHz mode PLL lock */ + if (source == DA7213_SYSCLK_PLL_32KHZ) { + snd_soc_write(codec, 0xF0, 0x8B); + snd_soc_write(codec, 0xF1, 0x03); + snd_soc_write(codec, 0xF1, 0x01); + snd_soc_write(codec, 0xF0, 0x00); + } return 0; - -pll_err: - dev_err(codec_dai->dev, "Unsupported PLL input frequency %d\n", - da7213->mclk_rate); - return -EINVAL; } /* DAI operations */ @@ -1454,11 +1493,10 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: - case SND_SOC_BIAS_PREPARE: break; - case SND_SOC_BIAS_STANDBY: - if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { - /* MCLK */ + case SND_SOC_BIAS_PREPARE: + /* Enable MCLK for transition to ON state */ + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) { if (da7213->mclk) { ret = clk_prepare_enable(da7213->mclk); if (ret) { @@ -1467,21 +1505,24 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec, return ret; } } - + } + break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { /* Enable VMID reference & master bias */ snd_soc_update_bits(codec, DA7213_REFERENCES, DA7213_VMID_EN | DA7213_BIAS_EN, DA7213_VMID_EN | DA7213_BIAS_EN); + } else { + /* Remove MCLK */ + if (da7213->mclk) + clk_disable_unprepare(da7213->mclk); } break; case SND_SOC_BIAS_OFF: /* Disable VMID reference & master bias */ snd_soc_update_bits(codec, DA7213_REFERENCES, DA7213_VMID_EN | DA7213_BIAS_EN, 0); - - /* MCLK */ - if (da7213->mclk) - clk_disable_unprepare(da7213->mclk); break; } return 0; @@ -1605,9 +1646,6 @@ static int da7213_probe(struct snd_soc_codec *codec) DA7213_ALC_CALIB_MODE_MAN, 0); da7213->alc_calib_auto = true; - /* Default to using SRM for slave mode */ - da7213->srm_en = true; - /* Default PC counter to free-running */ snd_soc_update_bits(codec, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK, DA7213_PC_FREERUN_MASK); @@ -1740,13 +1778,14 @@ static struct snd_soc_codec_driver soc_codec_dev_da7213 = { .probe = da7213_probe, .set_bias_level = da7213_set_bias_level, - .controls = da7213_snd_controls, - .num_controls = ARRAY_SIZE(da7213_snd_controls), - - .dapm_widgets = da7213_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(da7213_dapm_widgets), - .dapm_routes = da7213_audio_map, - .num_dapm_routes = ARRAY_SIZE(da7213_audio_map), + .component_driver = { + .controls = da7213_snd_controls, + .num_controls = ARRAY_SIZE(da7213_snd_controls), + .dapm_widgets = da7213_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(da7213_dapm_widgets), + .dapm_routes = da7213_audio_map, + .num_dapm_routes = ARRAY_SIZE(da7213_audio_map), + }, }; static const struct regmap_config da7213_regmap_config = { diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h index fbb7a356a501..16ef56f77cd4 100644 --- a/sound/soc/codecs/da7213.h +++ b/sound/soc/codecs/da7213.h @@ -172,6 +172,7 @@ #define DA7213_PLL_32K_MODE (0x1 << 5) #define DA7213_PLL_SRM_EN (0x1 << 6) #define DA7213_PLL_EN (0x1 << 7) +#define DA7213_PLL_MODE_MASK (0x7 << 5) /* DA7213_DAI_CLK_MODE = 0x28 */ #define DA7213_DAI_BCLKS_PER_WCLK_32 (0x0 << 0) @@ -499,8 +500,6 @@ #define DA7213_ALC_AVG_ITERATIONS 5 /* PLL related */ -#define DA7213_SYSCLK_MCLK 0 -#define DA7213_SYSCLK_PLL 1 #define DA7213_PLL_FREQ_OUT_90316800 90316800 #define DA7213_PLL_FREQ_OUT_98304000 98304000 #define DA7213_PLL_FREQ_OUT_94310400 94310400 @@ -515,6 +514,13 @@ enum da7213_clk_src { DA7213_CLKSRC_MCLK_SQR, }; +enum da7213_sys_clk { + DA7213_SYSCLK_MCLK = 0, + DA7213_SYSCLK_PLL, + DA7213_SYSCLK_PLL_SRM, + DA7213_SYSCLK_PLL_32KHZ +}; + /* Codec private data */ struct da7213_priv { struct regmap *regmap; @@ -522,8 +528,6 @@ struct da7213_priv { unsigned int mclk_rate; int clk_src; bool master; - bool mclk_squarer_en; - bool srm_en; bool alc_calib_auto; bool alc_en; struct da7213_platform_data *pdata; diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index 99ce23e113bf..c69e97654fc6 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -1819,7 +1819,7 @@ static int da7218_set_dai_sysclk(struct snd_soc_dai *codec_dai, if (da7218->mclk_rate == freq) return 0; - if (((freq < 2000000) && (freq != 32768)) || (freq > 54000000)) { + if ((freq < 2000000) || (freq > 54000000)) { dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", freq); return -EINVAL; @@ -1866,11 +1866,8 @@ static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, u32 freq_ref; u64 frac_div; - /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */ - if (da7218->mclk_rate == 32768) { - indiv_bits = DA7218_PLL_INDIV_9_TO_18_MHZ; - indiv = DA7218_PLL_INDIV_9_TO_18_MHZ_VAL; - } else if (da7218->mclk_rate < 2000000) { + /* Verify 2MHz - 54MHz MCLK provided, and set input divider */ + if (da7218->mclk_rate < 2000000) { dev_err(codec->dev, "PLL input clock %d below valid range\n", da7218->mclk_rate); return -EINVAL; @@ -1911,9 +1908,6 @@ static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, case DA7218_SYSCLK_PLL_SRM: pll_ctrl |= DA7218_PLL_MODE_SRM; break; - case DA7218_SYSCLK_PLL_32KHZ: - pll_ctrl |= DA7218_PLL_MODE_32KHZ; - break; default: dev_err(codec->dev, "Invalid PLL config\n"); return -EINVAL; @@ -2589,20 +2583,22 @@ static int da7218_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: - case SND_SOC_BIAS_PREPARE: break; - case SND_SOC_BIAS_STANDBY: - if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { - /* MCLK */ + case SND_SOC_BIAS_PREPARE: + /* Enable MCLK for transition to ON state */ + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) { if (da7218->mclk) { ret = clk_prepare_enable(da7218->mclk); if (ret) { - dev_err(codec->dev, - "Failed to enable mclk\n"); + dev_err(codec->dev, "Failed to enable mclk\n"); return ret; } } + } + break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { /* Master bias */ snd_soc_update_bits(codec, DA7218_REFERENCES, DA7218_BIAS_EN_MASK, @@ -2612,6 +2608,10 @@ static int da7218_set_bias_level(struct snd_soc_codec *codec, snd_soc_update_bits(codec, DA7218_LDO_CTRL, DA7218_LDO_EN_MASK, DA7218_LDO_EN_MASK); + } else { + /* Remove MCLK */ + if (da7218->mclk) + clk_disable_unprepare(da7218->mclk); } break; case SND_SOC_BIAS_OFF: @@ -2625,10 +2625,6 @@ static int da7218_set_bias_level(struct snd_soc_codec *codec, snd_soc_update_bits(codec, DA7218_REFERENCES, DA7218_BIAS_EN_MASK, 0); } - - /* MCLK */ - if (da7218->mclk) - clk_disable_unprepare(da7218->mclk); break; } @@ -3045,13 +3041,14 @@ static struct snd_soc_codec_driver soc_codec_dev_da7218 = { .resume = da7218_resume, .set_bias_level = da7218_set_bias_level, - .controls = da7218_snd_controls, - .num_controls = ARRAY_SIZE(da7218_snd_controls), - - .dapm_widgets = da7218_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(da7218_dapm_widgets), - .dapm_routes = da7218_audio_map, - .num_dapm_routes = ARRAY_SIZE(da7218_audio_map), + .component_driver = { + .controls = da7218_snd_controls, + .num_controls = ARRAY_SIZE(da7218_snd_controls), + .dapm_widgets = da7218_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(da7218_dapm_widgets), + .dapm_routes = da7218_audio_map, + .num_dapm_routes = ARRAY_SIZE(da7218_audio_map), + }, }; diff --git a/sound/soc/codecs/da7218.h b/sound/soc/codecs/da7218.h index 477cd37723cf..4f7ec21069a4 100644 --- a/sound/soc/codecs/da7218.h +++ b/sound/soc/codecs/da7218.h @@ -888,7 +888,6 @@ #define DA7218_PLL_MODE_BYPASS (0x0 << 6) #define DA7218_PLL_MODE_NORMAL (0x1 << 6) #define DA7218_PLL_MODE_SRM (0x2 << 6) -#define DA7218_PLL_MODE_32KHZ (0x3 << 6) /* DA7218_PLL_FRAC_TOP = 0x92 */ #define DA7218_PLL_FBDIV_FRAC_TOP_SHIFT 0 @@ -1371,7 +1370,6 @@ enum da7218_sys_clk { DA7218_SYSCLK_MCLK = 0, DA7218_SYSCLK_PLL, DA7218_SYSCLK_PLL_SRM, - DA7218_SYSCLK_PLL_32KHZ }; enum da7218_dev_id { diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index f0057cd223a4..2b8914dd5990 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/clk.h> #include <linux/i2c.h> #include <linux/property.h> #include <linux/pm_wakeirq.h> @@ -114,13 +115,38 @@ static void da7219_aad_hptest_work(struct work_struct *work) struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); u16 tonegen_freq_hptest; - u8 accdet_cfg8; - int report = 0; + u8 pll_srm_sts, gain_ramp_ctrl, accdet_cfg8; + int report = 0, ret = 0; /* Lock DAPM and any Kcontrols that are affected by this test */ snd_soc_dapm_mutex_lock(dapm); mutex_lock(&da7219->lock); + /* Ensure MCLK is available for HP test procedure */ + if (da7219->mclk) { + ret = clk_prepare_enable(da7219->mclk); + if (ret) { + dev_err(codec->dev, "Failed to enable mclk - %d\n", ret); + mutex_unlock(&da7219->lock); + snd_soc_dapm_mutex_unlock(dapm); + return; + } + } + + /* + * If MCLK not present, then we're using the internal oscillator and + * require different frequency settings to achieve the same result. + */ + pll_srm_sts = snd_soc_read(codec, DA7219_PLL_SRM_STS); + if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) + tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ); + else + tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC); + + /* Ensure gain ramping at fastest rate */ + gain_ramp_ctrl = snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL); + snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8); + /* Bypass cache so it saves current settings */ regcache_cache_bypass(da7219->regmap, true); @@ -183,9 +209,15 @@ static void da7219_aad_hptest_work(struct work_struct *work) snd_soc_write(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK); + /* + * If we're running from the internal oscillator then give audio paths + * time to settle before running test. + */ + if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK)) + msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY); + /* Configure & start Tone Generator */ snd_soc_write(codec, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK); - tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ); regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L, &tonegen_freq_hptest, sizeof(tonegen_freq_hptest)); snd_soc_update_bits(codec, DA7219_TONE_GEN_CFG2, @@ -244,12 +276,26 @@ static void da7219_aad_hptest_work(struct work_struct *work) snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8, DA7219_HPTEST_EN_MASK, 0); + /* + * If we're running from the internal oscillator then give audio paths + * time to settle before allowing headphones to be driven as required. + */ + if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK)) + msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY); + + /* Restore gain ramping rate */ + snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, gain_ramp_ctrl); + /* Drive Headphones/lineout */ snd_soc_update_bits(codec, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK, DA7219_HP_L_AMP_OE_MASK); snd_soc_update_bits(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK, DA7219_HP_R_AMP_OE_MASK); + /* Remove MCLK, if previously enabled */ + if (da7219->mclk) + clk_disable_unprepare(da7219->mclk); + mutex_unlock(&da7219->lock); snd_soc_dapm_mutex_unlock(dapm); @@ -751,6 +797,62 @@ static void da7219_aad_handle_pdata(struct snd_soc_codec *codec) /* + * Suspend/Resume + */ + +void da7219_aad_suspend(struct snd_soc_codec *codec) +{ + struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); + struct da7219_aad_priv *da7219_aad = da7219->aad; + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + u8 micbias_ctrl; + + if (da7219_aad->jack) { + /* Disable jack detection during suspend */ + snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, + DA7219_ACCDET_EN_MASK, 0); + + /* + * If we have a 4-pole jack inserted, then micbias will be + * enabled. We can disable micbias here, and keep a note to + * re-enable it on resume. If jack removal occurred during + * suspend then this will be dealt with through the IRQ handler. + */ + if (da7219_aad->jack_inserted) { + micbias_ctrl = snd_soc_read(codec, DA7219_MICBIAS_CTRL); + if (micbias_ctrl & DA7219_MICBIAS1_EN_MASK) { + snd_soc_dapm_disable_pin(dapm, "Mic Bias"); + snd_soc_dapm_sync(dapm); + da7219_aad->micbias_resume_enable = true; + } + } + } +} + +void da7219_aad_resume(struct snd_soc_codec *codec) +{ + struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); + struct da7219_aad_priv *da7219_aad = da7219->aad; + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + + if (da7219_aad->jack) { + /* Re-enable micbias if previously enabled for 4-pole jack */ + if (da7219_aad->jack_inserted && + da7219_aad->micbias_resume_enable) { + snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); + snd_soc_dapm_sync(dapm); + da7219_aad->micbias_resume_enable = false; + } + + /* Re-enable jack detection */ + snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, + DA7219_ACCDET_EN_MASK, + DA7219_ACCDET_EN_MASK); + } +} + + +/* * Init/Exit */ diff --git a/sound/soc/codecs/da7219-aad.h b/sound/soc/codecs/da7219-aad.h index 4fccf677cd06..117a3d7ccd31 100644 --- a/sound/soc/codecs/da7219-aad.h +++ b/sound/soc/codecs/da7219-aad.h @@ -176,8 +176,10 @@ #define DA7219_AAD_MICBIAS_CHK_DELAY 10 #define DA7219_AAD_MICBIAS_CHK_RETRIES 5 -#define DA7219_AAD_HPTEST_RAMP_FREQ 0x28 -#define DA7219_AAD_HPTEST_PERIOD 65 +#define DA7219_AAD_HPTEST_RAMP_FREQ 0x28 +#define DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC 0x4D +#define DA7219_AAD_HPTEST_PERIOD 65 +#define DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY 20 enum da7219_aad_event_regs { DA7219_AAD_IRQ_REG_A = 0, @@ -199,12 +201,17 @@ struct da7219_aad_priv { struct work_struct hptest_work; struct snd_soc_jack *jack; + bool micbias_resume_enable; bool jack_inserted; }; /* AAD control */ void da7219_aad_jack_det(struct snd_soc_codec *codec, struct snd_soc_jack *jack); +/* Suspend/Resume */ +void da7219_aad_suspend(struct snd_soc_codec *codec); +void da7219_aad_resume(struct snd_soc_codec *codec); + /* Init/Exit */ int da7219_aad_init(struct snd_soc_codec *codec); void da7219_aad_exit(struct snd_soc_codec *codec); diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 50ea94317cb3..1152aa5e7c39 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -801,7 +801,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w, ++i; msleep(50); } - } while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock)); + } while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock)); if (!srm_lock) dev_warn(codec->dev, "SRM failed to lock\n"); @@ -1482,6 +1482,8 @@ static struct da7219_pdata *da7219_fw_to_pdata(struct snd_soc_codec *codec) if (!pdata) return NULL; + pdata->wakeup_source = device_property_read_bool(dev, "wakeup-source"); + if (device_property_read_u32(dev, "dlg,micbias-lvl", &of_val32) >= 0) pdata->micbias_lvl = da7219_fw_micbias_lvl(dev, of_val32); else @@ -1508,11 +1510,10 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: - case SND_SOC_BIAS_PREPARE: break; - case SND_SOC_BIAS_STANDBY: - if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { - /* MCLK */ + case SND_SOC_BIAS_PREPARE: + /* Enable MCLK for transition to ON state */ + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) { if (da7219->mclk) { ret = clk_prepare_enable(da7219->mclk); if (ret) { @@ -1521,22 +1522,28 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec, return ret; } } + } + break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) /* Master bias */ snd_soc_update_bits(codec, DA7219_REFERENCES, DA7219_BIAS_EN_MASK, DA7219_BIAS_EN_MASK); + + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) { + /* Remove MCLK */ + if (da7219->mclk) + clk_disable_unprepare(da7219->mclk); } break; case SND_SOC_BIAS_OFF: - /* Only disable master bias if jack detection not active */ - if (!da7219->aad->jack) + /* Only disable master bias if we're not a wake-up source */ + if (!da7219->wakeup_source) snd_soc_update_bits(codec, DA7219_REFERENCES, DA7219_BIAS_EN_MASK, 0); - /* MCLK */ - if (da7219->mclk) - clk_disable_unprepare(da7219->mclk); break; } @@ -1599,6 +1606,8 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec) if (pdata) { u8 micbias_lvl = 0; + da7219->wakeup_source = pdata->wakeup_source; + /* Mic Bias voltages */ switch (pdata->micbias_lvl) { case DA7219_MICBIAS_1_6V: @@ -1733,11 +1742,11 @@ static int da7219_suspend(struct snd_soc_codec *codec) { struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); - snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); + /* Suspend AAD if we're not a wake-up source */ + if (!da7219->wakeup_source) + da7219_aad_suspend(codec); - /* Put device into standby mode if jack detection disabled */ - if (!da7219->aad->jack) - snd_soc_write(codec, DA7219_SYSTEM_ACTIVE, 0); + snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } @@ -1746,13 +1755,12 @@ static int da7219_resume(struct snd_soc_codec *codec) { struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); - /* Put device into active mode if previously pushed to standby */ - if (!da7219->aad->jack) - snd_soc_write(codec, DA7219_SYSTEM_ACTIVE, - DA7219_SYSTEM_ACTIVE_MASK); - snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); + /* Resume AAD if previously suspended */ + if (!da7219->wakeup_source) + da7219_aad_resume(codec); + return 0; } #else @@ -1767,13 +1775,14 @@ static struct snd_soc_codec_driver soc_codec_dev_da7219 = { .resume = da7219_resume, .set_bias_level = da7219_set_bias_level, - .controls = da7219_snd_controls, - .num_controls = ARRAY_SIZE(da7219_snd_controls), - - .dapm_widgets = da7219_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(da7219_dapm_widgets), - .dapm_routes = da7219_audio_map, - .num_dapm_routes = ARRAY_SIZE(da7219_audio_map), + .component_driver = { + .controls = da7219_snd_controls, + .num_controls = ARRAY_SIZE(da7219_snd_controls), + .dapm_widgets = da7219_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(da7219_dapm_widgets), + .dapm_routes = da7219_audio_map, + .num_dapm_routes = ARRAY_SIZE(da7219_audio_map), + }, }; @@ -1921,7 +1930,8 @@ static int da7219_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct da7219_priv *da7219; - int ret; + unsigned int system_active, system_status; + int i, ret; da7219 = devm_kzalloc(&i2c->dev, sizeof(struct da7219_priv), GFP_KERNEL); @@ -1937,6 +1947,37 @@ static int da7219_i2c_probe(struct i2c_client *i2c, return ret; } + regcache_cache_bypass(da7219->regmap, true); + + /* Disable audio paths if still active from previous start */ + regmap_read(da7219->regmap, DA7219_SYSTEM_ACTIVE, &system_active); + if (system_active) { + regmap_write(da7219->regmap, DA7219_GAIN_RAMP_CTRL, + DA7219_GAIN_RAMP_RATE_NOMINAL); + regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_INPUT, 0x00); + regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_OUTPUT, 0x01); + + for (i = 0; i < DA7219_SYS_STAT_CHECK_RETRIES; ++i) { + regmap_read(da7219->regmap, DA7219_SYSTEM_STATUS, + &system_status); + if (!system_status) + break; + + msleep(DA7219_SYS_STAT_CHECK_DELAY); + } + } + + /* Soft reset codec */ + regmap_write_bits(da7219->regmap, DA7219_ACCDET_CONFIG_1, + DA7219_ACCDET_EN_MASK, 0); + regmap_write_bits(da7219->regmap, DA7219_CIF_CTRL, + DA7219_CIF_REG_SOFT_RESET_MASK, + DA7219_CIF_REG_SOFT_RESET_MASK); + regmap_write_bits(da7219->regmap, DA7219_SYSTEM_ACTIVE, + DA7219_SYSTEM_ACTIVE_MASK, 0); + + regcache_cache_bypass(da7219->regmap, false); + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da7219, &da7219_dai, 1); if (ret < 0) { diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index ff2a2f02ce40..66d3bad86739 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -224,6 +224,7 @@ #define DA7219_PLL_SRM_STATE_MASK (0xF << 0) #define DA7219_PLL_SRM_STATUS_SHIFT 4 #define DA7219_PLL_SRM_STATUS_MASK (0xF << 4) +#define DA7219_PLL_SRM_STS_MCLK (0x1 << 4) #define DA7219_PLL_SRM_STS_SRM_LOCK (0x1 << 7) /* DA7219_DIG_ROUTING_DAI = 0x2A */ @@ -576,6 +577,8 @@ /* DA7219_GAIN_RAMP_CTRL = 0x92 */ #define DA7219_GAIN_RAMP_RATE_SHIFT 0 #define DA7219_GAIN_RAMP_RATE_MASK (0x3 << 0) +#define DA7219_GAIN_RAMP_RATE_X8 (0x0 << 0) +#define DA7219_GAIN_RAMP_RATE_NOMINAL (0x1 << 0) #define DA7219_GAIN_RAMP_RATE_MAX 4 /* DA7219_PC_COUNT = 0x94 */ @@ -770,6 +773,10 @@ /* SRM */ #define DA7219_SRM_CHECK_RETRIES 8 +/* System Controller */ +#define DA7219_SYS_STAT_CHECK_RETRIES 6 +#define DA7219_SYS_STAT_CHECK_DELAY 50 + enum da7219_clk_src { DA7219_CLKSRC_MCLK = 0, DA7219_CLKSRC_MCLK_SQR, @@ -796,6 +803,7 @@ struct da7219_priv { struct da7219_aad_priv *aad; struct da7219_pdata *pdata; + bool wakeup_source; struct regulator_bulk_data supplies[DA7219_NUM_SUPPLIES]; struct regmap *regmap; struct mutex lock; diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 461506a4ca6a..c1cc1c1c28f2 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1501,12 +1501,14 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec, static struct snd_soc_codec_driver soc_codec_dev_da732x = { .set_bias_level = da732x_set_bias_level, - .controls = da732x_snd_controls, - .num_controls = ARRAY_SIZE(da732x_snd_controls), - .dapm_widgets = da732x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(da732x_dapm_widgets), - .dapm_routes = da732x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(da732x_dapm_routes), + .component_driver = { + .controls = da732x_snd_controls, + .num_controls = ARRAY_SIZE(da732x_snd_controls), + .dapm_widgets = da732x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(da732x_dapm_widgets), + .dapm_routes = da732x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(da732x_dapm_routes), + }, .set_pll = da732x_set_dai_pll, }; diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 0b2ede8db978..4efb5f897a0c 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -1455,13 +1455,14 @@ static struct snd_soc_codec_driver soc_codec_dev_da9055 = { .probe = da9055_probe, .set_bias_level = da9055_set_bias_level, - .controls = da9055_snd_controls, - .num_controls = ARRAY_SIZE(da9055_snd_controls), - - .dapm_widgets = da9055_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(da9055_dapm_widgets), - .dapm_routes = da9055_audio_map, - .num_dapm_routes = ARRAY_SIZE(da9055_audio_map), + .component_driver = { + .controls = da9055_snd_controls, + .num_controls = ARRAY_SIZE(da9055_snd_controls), + .dapm_widgets = da9055_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(da9055_dapm_widgets), + .dapm_routes = da9055_audio_map, + .num_dapm_routes = ARRAY_SIZE(da9055_audio_map), + }, }; static const struct regmap_config da9055_regmap_config = { diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index fde53251c047..c82b9dc41e9a 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -51,10 +51,12 @@ static const struct snd_soc_dapm_route intercon[] = { }; static struct snd_soc_codec_driver soc_dmic = { - .dapm_widgets = dmic_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets), - .dapm_routes = intercon, - .num_dapm_routes = ARRAY_SIZE(intercon), + .component_driver = { + .dapm_widgets = dmic_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets), + .dapm_routes = intercon, + .num_dapm_routes = ARRAY_SIZE(intercon), + }, }; static int dmic_dev_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 2086d7107622..37722194b107 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -823,12 +823,14 @@ static struct snd_soc_codec_driver es8328_codec_driver = { .set_bias_level = es8328_set_bias_level, .suspend_bias_off = true, - .controls = es8328_snd_controls, - .num_controls = ARRAY_SIZE(es8328_snd_controls), - .dapm_widgets = es8328_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(es8328_dapm_widgets), - .dapm_routes = es8328_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(es8328_dapm_routes), + .component_driver = { + .controls = es8328_snd_controls, + .num_controls = ARRAY_SIZE(es8328_snd_controls), + .dapm_widgets = es8328_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(es8328_dapm_widgets), + .dapm_routes = es8328_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(es8328_dapm_routes), + }, }; int es8328_probe(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c index 0b80052996d3..926b1a4e37d4 100644 --- a/sound/soc/codecs/gtm601.c +++ b/sound/soc/codecs/gtm601.c @@ -52,10 +52,12 @@ static struct snd_soc_dai_driver gtm601_dai = { }; static const struct snd_soc_codec_driver soc_codec_dev_gtm601 = { - .dapm_widgets = gtm601_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(gtm601_dapm_widgets), - .dapm_routes = gtm601_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(gtm601_dapm_routes), + .component_driver = { + .dapm_widgets = gtm601_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(gtm601_dapm_widgets), + .dapm_routes = gtm601_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(gtm601_dapm_routes), + }, }; static int gtm601_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 4e181b270d95..c602c4960924 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -614,7 +614,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, (!pin->eld.eld_valid)) { dev_warn(&hdac->hdac.dev, - "Failed: montior present? %d ELD valid?: %d for pin: %d\n", + "Failed: monitor present? %d ELD valid?: %d for pin: %d\n", pin->eld.monitor_present, pin->eld.eld_valid, pin->nid); return 0; diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index f27d115626db..b904492d7744 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -24,6 +24,15 @@ #include <drm/drm_crtc.h> /* This is only to get MAX_ELD_BYTES */ +struct hdmi_device { + struct device *dev; + struct list_head list; + int cnt; +}; +#define pos_to_hdmi_device(pos) container_of((pos), struct hdmi_device, list) +LIST_HEAD(hdmi_device_list); + +#define DAI_NAME_SIZE 16 struct hdmi_codec_priv { struct hdmi_codec_pdata hcd; struct snd_soc_dai_driver *daidrv; @@ -320,7 +329,6 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = { SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) static struct snd_soc_dai_driver hdmi_i2s_dai = { - .name = "i2s-hifi", .id = DAI_ID_I2S, .playback = { .stream_name = "Playback", @@ -334,7 +342,6 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = { }; static const struct snd_soc_dai_driver hdmi_spdif_dai = { - .name = "spdif-hifi", .id = DAI_ID_SPDIF, .playback = { .stream_name = "Playback", @@ -346,13 +353,37 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .ops = &hdmi_dai_ops, }; +static char hdmi_dai_name[][DAI_NAME_SIZE] = { + "hdmi-hifi.0", + "hdmi-hifi.1", + "hdmi-hifi.2", + "hdmi-hifi.3", +}; + +static int hdmi_of_xlate_dai_name(struct snd_soc_component *component, + struct of_phandle_args *args, + const char **dai_name) +{ + int id = args->args[0]; + + if (id < ARRAY_SIZE(hdmi_dai_name)) { + *dai_name = hdmi_dai_name[id]; + return 0; + } + + return -EAGAIN; +} + static struct snd_soc_codec_driver hdmi_codec = { - .controls = hdmi_controls, - .num_controls = ARRAY_SIZE(hdmi_controls), - .dapm_widgets = hdmi_widgets, - .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), - .dapm_routes = hdmi_routes, - .num_dapm_routes = ARRAY_SIZE(hdmi_routes), + .component_driver = { + .controls = hdmi_controls, + .num_controls = ARRAY_SIZE(hdmi_controls), + .dapm_widgets = hdmi_widgets, + .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), + .dapm_routes = hdmi_routes, + .num_dapm_routes = ARRAY_SIZE(hdmi_routes), + .of_xlate_dai_name = hdmi_of_xlate_dai_name, + }, }; static int hdmi_codec_probe(struct platform_device *pdev) @@ -360,6 +391,8 @@ static int hdmi_codec_probe(struct platform_device *pdev) struct hdmi_codec_pdata *hcd = pdev->dev.platform_data; struct device *dev = &pdev->dev; struct hdmi_codec_priv *hcp; + struct hdmi_device *hd; + struct list_head *pos; int dai_count, i = 0; int ret; @@ -381,6 +414,31 @@ static int hdmi_codec_probe(struct platform_device *pdev) if (!hcp) return -ENOMEM; + hd = NULL; + list_for_each(pos, &hdmi_device_list) { + struct hdmi_device *tmp = pos_to_hdmi_device(pos); + + if (tmp->dev == dev->parent) { + hd = tmp; + break; + } + } + + if (!hd) { + hd = devm_kzalloc(dev, sizeof(*hd), GFP_KERNEL); + if (!hd) + return -ENOMEM; + + hd->dev = dev->parent; + + list_add_tail(&hd->list, &hdmi_device_list); + } + + if (hd->cnt >= ARRAY_SIZE(hdmi_dai_name)) { + dev_err(dev, "too many hdmi codec are deteced\n"); + return -EINVAL; + } + hcp->hcd = *hcd; mutex_init(&hcp->current_stream_lock); @@ -393,11 +451,14 @@ static int hdmi_codec_probe(struct platform_device *pdev) hcp->daidrv[i] = hdmi_i2s_dai; hcp->daidrv[i].playback.channels_max = hcd->max_i2s_channels; + hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++]; i++; } - if (hcd->spdif) + if (hcd->spdif) { hcp->daidrv[i] = hdmi_spdif_dai; + hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++]; + } ret = snd_soc_register_codec(dev, &hdmi_codec, hcp->daidrv, dai_count); diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c index 9b6e8840a1b5..b918ba5c8ce5 100644 --- a/sound/soc/codecs/inno_rk3036.c +++ b/sound/soc/codecs/inno_rk3036.c @@ -380,12 +380,14 @@ static struct snd_soc_codec_driver rk3036_codec_driver = { .probe = rk3036_codec_probe, .remove = rk3036_codec_remove, .set_bias_level = rk3036_codec_set_bias_level, - .controls = rk3036_codec_dapm_controls, - .num_controls = ARRAY_SIZE(rk3036_codec_dapm_controls), - .dapm_routes = rk3036_codec_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rk3036_codec_dapm_routes), - .dapm_widgets = rk3036_codec_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rk3036_codec_dapm_widgets), + .component_driver = { + .controls = rk3036_codec_dapm_controls, + .num_controls = ARRAY_SIZE(rk3036_codec_dapm_controls), + .dapm_routes = rk3036_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rk3036_codec_dapm_routes), + .dapm_widgets = rk3036_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rk3036_codec_dapm_widgets), + }, }; static const struct regmap_config rk3036_codec_regmap_config = { diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index be448373d39a..a4b0eded984a 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -1089,12 +1089,14 @@ static struct snd_soc_dai_driver isabelle_dai[] = { static struct snd_soc_codec_driver soc_codec_dev_isabelle = { .set_bias_level = isabelle_set_bias_level, - .controls = isabelle_snd_controls, - .num_controls = ARRAY_SIZE(isabelle_snd_controls), - .dapm_widgets = isabelle_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(isabelle_dapm_widgets), - .dapm_routes = isabelle_intercon, - .num_dapm_routes = ARRAY_SIZE(isabelle_intercon), + .component_driver = { + .controls = isabelle_snd_controls, + .num_controls = ARRAY_SIZE(isabelle_snd_controls), + .dapm_widgets = isabelle_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(isabelle_dapm_widgets), + .dapm_routes = isabelle_intercon, + .num_dapm_routes = ARRAY_SIZE(isabelle_intercon), + }, .idle_bias_off = true, }; diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 1f5ab99956ed..0290fab383da 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -298,12 +298,14 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = { .set_bias_level = jz4740_codec_set_bias_level, .suspend_bias_off = true, - .controls = jz4740_codec_controls, - .num_controls = ARRAY_SIZE(jz4740_codec_controls), - .dapm_widgets = jz4740_codec_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(jz4740_codec_dapm_widgets), - .dapm_routes = jz4740_codec_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(jz4740_codec_dapm_routes), + .component_driver = { + .controls = jz4740_codec_controls, + .num_controls = ARRAY_SIZE(jz4740_codec_controls), + .dapm_widgets = jz4740_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(jz4740_codec_dapm_widgets), + .dapm_routes = jz4740_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(jz4740_codec_dapm_routes), + }, }; static const struct regmap_config jz4740_codec_regmap_config = { diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c index 5353af58862c..a10ea3c716c6 100644 --- a/sound/soc/codecs/l3.c +++ b/sound/soc/codecs/l3.c @@ -20,6 +20,8 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> +#include <linux/device.h> +#include <linux/gpio.h> #include <sound/l3.h> @@ -32,11 +34,11 @@ static void sendbyte(struct l3_pins *adap, unsigned int byte) int i; for (i = 0; i < 8; i++) { - adap->setclk(0); + adap->setclk(adap, 0); udelay(adap->data_hold); - adap->setdat(byte & 1); + adap->setdat(adap, byte & 1); udelay(adap->data_setup); - adap->setclk(1); + adap->setclk(adap, 1); udelay(adap->clock_high); byte >>= 1; } @@ -55,10 +57,10 @@ static void sendbytes(struct l3_pins *adap, const u8 *buf, for (i = 0; i < len; i++) { if (i) { udelay(adap->mode_hold); - adap->setmode(0); + adap->setmode(adap, 0); udelay(adap->mode); } - adap->setmode(1); + adap->setmode(adap, 1); udelay(adap->mode_setup); sendbyte(adap, buf[i]); } @@ -66,26 +68,71 @@ static void sendbytes(struct l3_pins *adap, const u8 *buf, int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len) { - adap->setclk(1); - adap->setdat(1); - adap->setmode(1); + adap->setclk(adap, 1); + adap->setdat(adap, 1); + adap->setmode(adap, 1); udelay(adap->mode); - adap->setmode(0); + adap->setmode(adap, 0); udelay(adap->mode_setup); sendbyte(adap, addr); udelay(adap->mode_hold); sendbytes(adap, data, len); - adap->setclk(1); - adap->setdat(1); - adap->setmode(0); + adap->setclk(adap, 1); + adap->setdat(adap, 1); + adap->setmode(adap, 0); return len; } EXPORT_SYMBOL_GPL(l3_write); + +static void l3_set_clk(struct l3_pins *adap, int val) +{ + gpio_set_value(adap->gpio_clk, val); +} + +static void l3_set_data(struct l3_pins *adap, int val) +{ + gpio_set_value(adap->gpio_data, val); +} + +static void l3_set_mode(struct l3_pins *adap, int val) +{ + gpio_set_value(adap->gpio_mode, val); +} + +int l3_set_gpio_ops(struct device *dev, struct l3_pins *adap) +{ + int ret; + + if (!adap->use_gpios) + return -EINVAL; + + ret = devm_gpio_request_one(dev, adap->gpio_data, + GPIOF_OUT_INIT_LOW, "l3_data"); + if (ret < 0) + return ret; + adap->setdat = l3_set_data; + + ret = devm_gpio_request_one(dev, adap->gpio_clk, + GPIOF_OUT_INIT_LOW, "l3_clk"); + if (ret < 0) + return ret; + adap->setclk = l3_set_clk; + + ret = devm_gpio_request_one(dev, adap->gpio_mode, + GPIOF_OUT_INIT_LOW, "l3_mode"); + if (ret < 0) + return ret; + adap->setmode = l3_set_mode; + + return 0; +} +EXPORT_SYMBOL_GPL(l3_set_gpio_ops); + MODULE_DESCRIPTION("L3 bit-banging driver"); MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 9af5640e3446..8d413c2677cc 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1391,12 +1391,14 @@ static struct snd_soc_dai_driver lm49453_dai[] = { static struct snd_soc_codec_driver soc_codec_dev_lm49453 = { .set_bias_level = lm49453_set_bias_level, - .controls = lm49453_snd_controls, - .num_controls = ARRAY_SIZE(lm49453_snd_controls), - .dapm_widgets = lm49453_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(lm49453_dapm_widgets), - .dapm_routes = lm49453_audio_map, - .num_dapm_routes = ARRAY_SIZE(lm49453_audio_map), + .component_driver = { + .controls = lm49453_snd_controls, + .num_controls = ARRAY_SIZE(lm49453_snd_controls), + .dapm_widgets = lm49453_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(lm49453_dapm_widgets), + .dapm_routes = lm49453_audio_map, + .num_dapm_routes = ARRAY_SIZE(lm49453_audio_map), + }, .idle_bias_off = true, }; diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index fc22804cabc5..72f77455582e 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1704,12 +1704,14 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = { .set_bias_level = max98088_set_bias_level, .suspend_bias_off = true, - .controls = max98088_snd_controls, - .num_controls = ARRAY_SIZE(max98088_snd_controls), - .dapm_widgets = max98088_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets), - .dapm_routes = max98088_audio_map, - .num_dapm_routes = ARRAY_SIZE(max98088_audio_map), + .component_driver = { + .controls = max98088_snd_controls, + .num_controls = ARRAY_SIZE(max98088_snd_controls), + .dapm_widgets = max98088_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets), + .dapm_routes = max98088_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98088_audio_map), + }, }; static int max98088_i2c_probe(struct i2c_client *i2c, diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 3577003f39cf..6f8a757876ed 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -2108,12 +2108,14 @@ static struct snd_soc_codec_driver soc_codec_dev_max98095 = { .suspend = max98095_suspend, .resume = max98095_resume, .set_bias_level = max98095_set_bias_level, - .controls = max98095_snd_controls, - .num_controls = ARRAY_SIZE(max98095_snd_controls), - .dapm_widgets = max98095_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(max98095_dapm_widgets), - .dapm_routes = max98095_audio_map, - .num_dapm_routes = ARRAY_SIZE(max98095_audio_map), + .component_driver = { + .controls = max98095_snd_controls, + .num_controls = ARRAY_SIZE(max98095_snd_controls), + .dapm_widgets = max98095_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98095_dapm_widgets), + .dapm_routes = max98095_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98095_audio_map), + }, }; static int max98095_i2c_probe(struct i2c_client *i2c, diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index 5b1dfb1518fb..6a6b68a4cb52 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -74,10 +74,12 @@ static int max98357a_codec_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver max98357a_codec_driver = { .probe = max98357a_codec_probe, - .dapm_widgets = max98357a_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(max98357a_dapm_widgets), - .dapm_routes = max98357a_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(max98357a_dapm_routes), + .component_driver = { + .dapm_widgets = max98357a_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98357a_dapm_widgets), + .dapm_routes = max98357a_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(max98357a_dapm_routes), + }, }; static const struct snd_soc_dai_ops max98357a_dai_ops = { diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c index cf0a39bb631a..781be9ba8dba 100644 --- a/sound/soc/codecs/max98371.c +++ b/sound/soc/codecs/max98371.c @@ -412,6 +412,7 @@ static int max98371_i2c_remove(struct i2c_client *client) static const struct i2c_device_id max98371_i2c_id[] = { { "max98371", 0 }, + { } }; MODULE_DEVICE_TABLE(i2c, max98371_i2c_id); @@ -425,7 +426,6 @@ MODULE_DEVICE_TABLE(of, max98371_of_match); static struct i2c_driver max98371_i2c_driver = { .driver = { .name = "max98371", - .owner = THIS_MODULE, .pm = NULL, .of_match_table = of_match_ptr(max98371_of_match), }, diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index c14a79d026a1..0610840733d1 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -306,12 +306,14 @@ static struct snd_soc_codec_driver soc_codec_dev_max9850 = { .set_bias_level = max9850_set_bias_level, .suspend_bias_off = true, - .controls = max9850_controls, - .num_controls = ARRAY_SIZE(max9850_controls), - .dapm_widgets = max9850_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(max9850_dapm_widgets), - .dapm_routes = max9850_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(max9850_dapm_routes), + .component_driver = { + .controls = max9850_controls, + .num_controls = ARRAY_SIZE(max9850_controls), + .dapm_widgets = max9850_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max9850_dapm_widgets), + .dapm_routes = max9850_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(max9850_dapm_routes), + }, }; static int max9850_i2c_probe(struct i2c_client *i2c, diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c index 68074c92a7c0..499bdbfd0a2d 100644 --- a/sound/soc/codecs/max9860.c +++ b/sound/soc/codecs/max9860.c @@ -538,12 +538,14 @@ static struct snd_soc_codec_driver max9860_codec_driver = { .set_bias_level = max9860_set_bias_level, .idle_bias_off = true, - .controls = max9860_controls, - .num_controls = ARRAY_SIZE(max9860_controls), - .dapm_widgets = max9860_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(max9860_dapm_widgets), - .dapm_routes = max9860_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(max9860_dapm_routes), + .component_driver = { + .controls = max9860_controls, + .num_controls = ARRAY_SIZE(max9860_controls), + .dapm_widgets = max9860_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max9860_dapm_widgets), + .dapm_routes = max9860_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(max9860_dapm_routes), + }, }; #ifdef CONFIG_PM diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 2a22fddeb6af..42e2e407e287 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -38,11 +38,10 @@ static DECLARE_TLV_DB_SCALE(max9860_capture_tlv, -600, 200, 0); static DECLARE_TLV_DB_SCALE(max9860_mic_tlv, 2000, 100, 1); static DECLARE_TLV_DB_SCALE(max9860_adc_left_tlv, -1200, 100, 1); static DECLARE_TLV_DB_SCALE(max9860_adc_right_tlv, -1200, 100, 1); -static const unsigned int max98088_micboost_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max98088_micboost_tlv, 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0), 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0), -}; +); static const struct snd_kcontrol_new max9867_snd_controls[] = { SOC_DOUBLE_R("Master Playback Volume", MAX9867_LEFTVOL, @@ -417,12 +416,14 @@ static int max9867_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver max9867_codec = { .probe = max9867_probe, - .controls = max9867_snd_controls, - .num_controls = ARRAY_SIZE(max9867_snd_controls), - .dapm_routes = max9867_audio_map, - .num_dapm_routes = ARRAY_SIZE(max9867_audio_map), - .dapm_widgets = max9867_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets), + .component_driver = { + .controls = max9867_snd_controls, + .num_controls = ARRAY_SIZE(max9867_snd_controls), + .dapm_routes = max9867_audio_map, + .num_dapm_routes = ARRAY_SIZE(max9867_audio_map), + .dapm_widgets = max9867_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets), + }, }; static bool max9867_volatile_register(struct device *dev, unsigned int reg) diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index 5990de317999..327eaa25c9bd 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -540,12 +540,14 @@ static int max98925_probe(struct snd_soc_codec *codec) static const struct snd_soc_codec_driver soc_codec_dev_max98925 = { .probe = max98925_probe, - .controls = max98925_snd_controls, - .num_controls = ARRAY_SIZE(max98925_snd_controls), - .dapm_routes = max98925_audio_map, - .num_dapm_routes = ARRAY_SIZE(max98925_audio_map), - .dapm_widgets = max98925_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(max98925_dapm_widgets), + .component_driver = { + .controls = max98925_snd_controls, + .num_controls = ARRAY_SIZE(max98925_snd_controls), + .dapm_routes = max98925_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98925_audio_map), + .dapm_widgets = max98925_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98925_dapm_widgets), + }, }; static const struct regmap_config max98925_regmap = { diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index 8d14adae5cc5..1eff7e0b092e 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -347,7 +347,7 @@ static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai, max98926_set_sense_data(max98926); break; default: - dev_err(codec->dev, "DAI clock mode unsupported"); + dev_err(codec->dev, "DAI clock mode unsupported\n"); return -EINVAL; } @@ -364,7 +364,7 @@ static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai, invert = MAX98926_DAI_BCI_MASK | MAX98926_DAI_WCI_MASK; break; default: - dev_err(codec->dev, "DAI invert mode unsupported"); + dev_err(codec->dev, "DAI invert mode unsupported\n"); return -EINVAL; } @@ -408,7 +408,7 @@ static int max98926_dai_hw_params(struct snd_pcm_substream *substream, max98926->ch_size = 32; break; default: - dev_dbg(codec->dev, "format unsupported %d", + dev_dbg(codec->dev, "format unsupported %d\n", params_format(params)); return -EINVAL; } @@ -498,12 +498,14 @@ static int max98926_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_max98926 = { .probe = max98926_probe, - .controls = max98926_snd_controls, - .num_controls = ARRAY_SIZE(max98926_snd_controls), - .dapm_routes = max98926_audio_map, - .num_dapm_routes = ARRAY_SIZE(max98926_audio_map), - .dapm_widgets = max98926_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(max98926_dapm_widgets), + .component_driver = { + .controls = max98926_snd_controls, + .num_controls = ARRAY_SIZE(max98926_snd_controls), + .dapm_routes = max98926_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98926_audio_map), + .dapm_widgets = max98926_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98926_dapm_widgets), + }, }; static const struct regmap_config max98926_regmap = { diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 3e770cbe7f0f..90562703dcfd 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -737,12 +737,14 @@ static struct snd_soc_codec_driver soc_codec_dev_mc13783 = { .probe = mc13783_probe, .remove = mc13783_remove, .get_regmap = mc13783_get_regmap, - .controls = mc13783_control_list, - .num_controls = ARRAY_SIZE(mc13783_control_list), - .dapm_widgets = mc13783_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(mc13783_dapm_widgets), - .dapm_routes = mc13783_routes, - .num_dapm_routes = ARRAY_SIZE(mc13783_routes), + .component_driver = { + .controls = mc13783_control_list, + .num_controls = ARRAY_SIZE(mc13783_control_list), + .dapm_widgets = mc13783_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mc13783_dapm_widgets), + .dapm_routes = mc13783_routes, + .num_dapm_routes = ARRAY_SIZE(mc13783_routes), + }, }; static int __init mc13783_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index f561c78b9e0e..69e5e18880c5 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -541,12 +541,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ml26124 = { .probe = ml26124_probe, .set_bias_level = ml26124_set_bias_level, .suspend_bias_off = true, - .dapm_widgets = ml26124_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ml26124_dapm_widgets), - .dapm_routes = ml26124_intercon, - .num_dapm_routes = ARRAY_SIZE(ml26124_intercon), - .controls = ml26124_snd_controls, - .num_controls = ARRAY_SIZE(ml26124_snd_controls), + .component_driver = { + .controls = ml26124_snd_controls, + .num_controls = ARRAY_SIZE(ml26124_snd_controls), + .dapm_widgets = ml26124_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ml26124_dapm_widgets), + .dapm_routes = ml26124_intercon, + .num_dapm_routes = ARRAY_SIZE(ml26124_intercon), + }, }; static const struct regmap_config ml26124_i2c_regmap = { diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c new file mode 100644 index 000000000000..e45518629968 --- /dev/null +++ b/sound/soc/codecs/nau8810.c @@ -0,0 +1,884 @@ +/* + * nau8810.c -- NAU8810 ALSA Soc Audio driver + * + * Copyright 2016 Nuvoton Technology Corp. + * + * Author: David Lin <ctlin0@nuvoton.com> + * + * Based on WM8974.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "nau8810.h" + +#define NAU_PLL_FREQ_MAX 100000000 +#define NAU_PLL_FREQ_MIN 90000000 +#define NAU_PLL_REF_MAX 33000000 +#define NAU_PLL_REF_MIN 8000000 +#define NAU_PLL_OPTOP_MIN 6 + + +static const int nau8810_mclk_scaler[] = { 10, 15, 20, 30, 40, 60, 80, 120 }; + +static const struct reg_default nau8810_reg_defaults[] = { + { NAU8810_REG_POWER1, 0x0000 }, + { NAU8810_REG_POWER2, 0x0000 }, + { NAU8810_REG_POWER3, 0x0000 }, + { NAU8810_REG_IFACE, 0x0050 }, + { NAU8810_REG_COMP, 0x0000 }, + { NAU8810_REG_CLOCK, 0x0140 }, + { NAU8810_REG_SMPLR, 0x0000 }, + { NAU8810_REG_DAC, 0x0000 }, + { NAU8810_REG_DACGAIN, 0x00FF }, + { NAU8810_REG_ADC, 0x0100 }, + { NAU8810_REG_ADCGAIN, 0x00FF }, + { NAU8810_REG_EQ1, 0x012C }, + { NAU8810_REG_EQ2, 0x002C }, + { NAU8810_REG_EQ3, 0x002C }, + { NAU8810_REG_EQ4, 0x002C }, + { NAU8810_REG_EQ5, 0x002C }, + { NAU8810_REG_DACLIM1, 0x0032 }, + { NAU8810_REG_DACLIM2, 0x0000 }, + { NAU8810_REG_NOTCH1, 0x0000 }, + { NAU8810_REG_NOTCH2, 0x0000 }, + { NAU8810_REG_NOTCH3, 0x0000 }, + { NAU8810_REG_NOTCH4, 0x0000 }, + { NAU8810_REG_ALC1, 0x0038 }, + { NAU8810_REG_ALC2, 0x000B }, + { NAU8810_REG_ALC3, 0x0032 }, + { NAU8810_REG_NOISEGATE, 0x0000 }, + { NAU8810_REG_PLLN, 0x0008 }, + { NAU8810_REG_PLLK1, 0x000C }, + { NAU8810_REG_PLLK2, 0x0093 }, + { NAU8810_REG_PLLK3, 0x00E9 }, + { NAU8810_REG_ATTEN, 0x0000 }, + { NAU8810_REG_INPUT_SIGNAL, 0x0003 }, + { NAU8810_REG_PGAGAIN, 0x0010 }, + { NAU8810_REG_ADCBOOST, 0x0100 }, + { NAU8810_REG_OUTPUT, 0x0002 }, + { NAU8810_REG_SPKMIX, 0x0001 }, + { NAU8810_REG_SPKGAIN, 0x0039 }, + { NAU8810_REG_MONOMIX, 0x0001 }, + { NAU8810_REG_POWER4, 0x0000 }, + { NAU8810_REG_TSLOTCTL1, 0x0000 }, + { NAU8810_REG_TSLOTCTL2, 0x0020 }, + { NAU8810_REG_DEVICE_REVID, 0x0000 }, + { NAU8810_REG_I2C_DEVICEID, 0x001A }, + { NAU8810_REG_ADDITIONID, 0x00CA }, + { NAU8810_REG_RESERVE, 0x0124 }, + { NAU8810_REG_OUTCTL, 0x0001 }, + { NAU8810_REG_ALC1ENHAN1, 0x0010 }, + { NAU8810_REG_ALC1ENHAN2, 0x0000 }, + { NAU8810_REG_MISCCTL, 0x0000 }, + { NAU8810_REG_OUTTIEOFF, 0x0000 }, + { NAU8810_REG_AGCP2POUT, 0x0000 }, + { NAU8810_REG_AGCPOUT, 0x0000 }, + { NAU8810_REG_AMTCTL, 0x0000 }, + { NAU8810_REG_OUTTIEOFFMAN, 0x0000 }, +}; + +static bool nau8810_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NAU8810_REG_RESET ... NAU8810_REG_SMPLR: + case NAU8810_REG_DAC ... NAU8810_REG_DACGAIN: + case NAU8810_REG_ADC ... NAU8810_REG_ADCGAIN: + case NAU8810_REG_EQ1 ... NAU8810_REG_EQ5: + case NAU8810_REG_DACLIM1 ... NAU8810_REG_DACLIM2: + case NAU8810_REG_NOTCH1 ... NAU8810_REG_NOTCH4: + case NAU8810_REG_ALC1 ... NAU8810_REG_ATTEN: + case NAU8810_REG_INPUT_SIGNAL ... NAU8810_REG_PGAGAIN: + case NAU8810_REG_ADCBOOST: + case NAU8810_REG_OUTPUT ... NAU8810_REG_SPKMIX: + case NAU8810_REG_SPKGAIN: + case NAU8810_REG_MONOMIX: + case NAU8810_REG_POWER4 ... NAU8810_REG_TSLOTCTL2: + case NAU8810_REG_DEVICE_REVID ... NAU8810_REG_RESERVE: + case NAU8810_REG_OUTCTL ... NAU8810_REG_ALC1ENHAN2: + case NAU8810_REG_MISCCTL: + case NAU8810_REG_OUTTIEOFF ... NAU8810_REG_OUTTIEOFFMAN: + return true; + default: + return false; + } +} + +static bool nau8810_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NAU8810_REG_RESET ... NAU8810_REG_SMPLR: + case NAU8810_REG_DAC ... NAU8810_REG_DACGAIN: + case NAU8810_REG_ADC ... NAU8810_REG_ADCGAIN: + case NAU8810_REG_EQ1 ... NAU8810_REG_EQ5: + case NAU8810_REG_DACLIM1 ... NAU8810_REG_DACLIM2: + case NAU8810_REG_NOTCH1 ... NAU8810_REG_NOTCH4: + case NAU8810_REG_ALC1 ... NAU8810_REG_ATTEN: + case NAU8810_REG_INPUT_SIGNAL ... NAU8810_REG_PGAGAIN: + case NAU8810_REG_ADCBOOST: + case NAU8810_REG_OUTPUT ... NAU8810_REG_SPKMIX: + case NAU8810_REG_SPKGAIN: + case NAU8810_REG_MONOMIX: + case NAU8810_REG_POWER4 ... NAU8810_REG_TSLOTCTL2: + case NAU8810_REG_OUTCTL ... NAU8810_REG_ALC1ENHAN2: + case NAU8810_REG_MISCCTL: + case NAU8810_REG_OUTTIEOFF ... NAU8810_REG_OUTTIEOFFMAN: + return true; + default: + return false; + } +} + +static bool nau8810_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NAU8810_REG_RESET: + case NAU8810_REG_DEVICE_REVID ... NAU8810_REG_RESERVE: + return true; + default: + return false; + } +} + +/* The EQ parameters get function is to get the 5 band equalizer control. + * The regmap raw read can't work here because regmap doesn't provide + * value format for value width of 9 bits. Therefore, the driver reads data + * from cache and makes value format according to the endianness of + * bytes type control element. + */ +static int nau8810_eq_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + struct soc_bytes_ext *params = (void *)kcontrol->private_value; + int i, reg, reg_val; + u16 *val; + + val = (u16 *)ucontrol->value.bytes.data; + reg = NAU8810_REG_EQ1; + for (i = 0; i < params->max / sizeof(u16); i++) { + regmap_read(nau8810->regmap, reg + i, ®_val); + /* conversion of 16-bit integers between native CPU format + * and big endian format + */ + reg_val = cpu_to_be16(reg_val); + memcpy(val + i, ®_val, sizeof(reg_val)); + } + + return 0; +} + +/* The EQ parameters put function is to make configuration of 5 band equalizer + * control. These configuration includes central frequency, equalizer gain, + * cut-off frequency, bandwidth control, and equalizer path. + * The regmap raw write can't work here because regmap doesn't provide + * register and value format for register with address 7 bits and value 9 bits. + * Therefore, the driver makes value format according to the endianness of + * bytes type control element and writes data to codec. + */ +static int nau8810_eq_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + struct soc_bytes_ext *params = (void *)kcontrol->private_value; + void *data; + u16 *val, value; + int i, reg, ret; + + data = kmemdup(ucontrol->value.bytes.data, + params->max, GFP_KERNEL | GFP_DMA); + if (!data) + return -ENOMEM; + + val = (u16 *)data; + reg = NAU8810_REG_EQ1; + for (i = 0; i < params->max / sizeof(u16); i++) { + /* conversion of 16-bit integers between native CPU format + * and big endian format + */ + value = be16_to_cpu(*(val + i)); + ret = regmap_write(nau8810->regmap, reg + i, value); + if (ret) { + dev_err(codec->dev, "EQ configuration fail, register: %x ret: %d\n", + reg + i, ret); + kfree(data); + return ret; + } + } + kfree(data); + + return 0; +} + +static const char * const nau8810_companding[] = { + "Off", "NC", "u-law", "A-law" }; + +static const struct soc_enum nau8810_companding_adc_enum = + SOC_ENUM_SINGLE(NAU8810_REG_COMP, NAU8810_ADCCM_SFT, + ARRAY_SIZE(nau8810_companding), nau8810_companding); + +static const struct soc_enum nau8810_companding_dac_enum = + SOC_ENUM_SINGLE(NAU8810_REG_COMP, NAU8810_DACCM_SFT, + ARRAY_SIZE(nau8810_companding), nau8810_companding); + +static const char * const nau8810_deemp[] = { + "None", "32kHz", "44.1kHz", "48kHz" }; + +static const struct soc_enum nau8810_deemp_enum = + SOC_ENUM_SINGLE(NAU8810_REG_DAC, NAU8810_DEEMP_SFT, + ARRAY_SIZE(nau8810_deemp), nau8810_deemp); + +static const char * const nau8810_eqmode[] = {"Capture", "Playback" }; + +static const struct soc_enum nau8810_eqmode_enum = + SOC_ENUM_SINGLE(NAU8810_REG_EQ1, NAU8810_EQM_SFT, + ARRAY_SIZE(nau8810_eqmode), nau8810_eqmode); + +static const char * const nau8810_alc[] = {"Normal", "Limiter" }; + +static const struct soc_enum nau8810_alc_enum = + SOC_ENUM_SINGLE(NAU8810_REG_ALC3, NAU8810_ALCM_SFT, + ARRAY_SIZE(nau8810_alc), nau8810_alc); + +static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); +static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0); +static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0); + +static const struct snd_kcontrol_new nau8810_snd_controls[] = { + SOC_ENUM("ADC Companding", nau8810_companding_adc_enum), + SOC_ENUM("DAC Companding", nau8810_companding_dac_enum), + SOC_ENUM("DAC De-emphasis", nau8810_deemp_enum), + + SOC_ENUM("EQ Function", nau8810_eqmode_enum), + SND_SOC_BYTES_EXT("EQ Parameters", 10, + nau8810_eq_get, nau8810_eq_put), + + SOC_SINGLE("DAC Inversion Switch", NAU8810_REG_DAC, + NAU8810_DACPL_SFT, 1, 0), + SOC_SINGLE_TLV("Playback Volume", NAU8810_REG_DACGAIN, + NAU8810_DACGAIN_SFT, 0xff, 0, digital_tlv), + + SOC_SINGLE("High Pass Filter Switch", NAU8810_REG_ADC, + NAU8810_HPFEN_SFT, 1, 0), + SOC_SINGLE("High Pass Cut Off", NAU8810_REG_ADC, + NAU8810_HPF_SFT, 0x7, 0), + + SOC_SINGLE("ADC Inversion Switch", NAU8810_REG_ADC, + NAU8810_ADCPL_SFT, 1, 0), + SOC_SINGLE_TLV("Capture Volume", NAU8810_REG_ADCGAIN, + NAU8810_ADCGAIN_SFT, 0xff, 0, digital_tlv), + + SOC_SINGLE_TLV("EQ1 Volume", NAU8810_REG_EQ1, + NAU8810_EQ1GC_SFT, 0x18, 1, eq_tlv), + SOC_SINGLE_TLV("EQ2 Volume", NAU8810_REG_EQ2, + NAU8810_EQ2GC_SFT, 0x18, 1, eq_tlv), + SOC_SINGLE_TLV("EQ3 Volume", NAU8810_REG_EQ3, + NAU8810_EQ3GC_SFT, 0x18, 1, eq_tlv), + SOC_SINGLE_TLV("EQ4 Volume", NAU8810_REG_EQ4, + NAU8810_EQ4GC_SFT, 0x18, 1, eq_tlv), + SOC_SINGLE_TLV("EQ5 Volume", NAU8810_REG_EQ5, + NAU8810_EQ5GC_SFT, 0x18, 1, eq_tlv), + + SOC_SINGLE("DAC Limiter Switch", NAU8810_REG_DACLIM1, + NAU8810_DACLIMEN_SFT, 1, 0), + SOC_SINGLE("DAC Limiter Decay", NAU8810_REG_DACLIM1, + NAU8810_DACLIMDCY_SFT, 0xf, 0), + SOC_SINGLE("DAC Limiter Attack", NAU8810_REG_DACLIM1, + NAU8810_DACLIMATK_SFT, 0xf, 0), + SOC_SINGLE("DAC Limiter Threshold", NAU8810_REG_DACLIM2, + NAU8810_DACLIMTHL_SFT, 0x7, 0), + SOC_SINGLE("DAC Limiter Boost", NAU8810_REG_DACLIM2, + NAU8810_DACLIMBST_SFT, 0xf, 0), + + SOC_ENUM("ALC Mode", nau8810_alc_enum), + SOC_SINGLE("ALC Enable Switch", NAU8810_REG_ALC1, + NAU8810_ALCEN_SFT, 1, 0), + SOC_SINGLE("ALC Max Volume", NAU8810_REG_ALC1, + NAU8810_ALCMXGAIN_SFT, 0x7, 0), + SOC_SINGLE("ALC Min Volume", NAU8810_REG_ALC1, + NAU8810_ALCMINGAIN_SFT, 0x7, 0), + SOC_SINGLE("ALC ZC Switch", NAU8810_REG_ALC2, + NAU8810_ALCZC_SFT, 1, 0), + SOC_SINGLE("ALC Hold", NAU8810_REG_ALC2, + NAU8810_ALCHT_SFT, 0xf, 0), + SOC_SINGLE("ALC Target", NAU8810_REG_ALC2, + NAU8810_ALCSL_SFT, 0xf, 0), + SOC_SINGLE("ALC Decay", NAU8810_REG_ALC3, + NAU8810_ALCDCY_SFT, 0xf, 0), + SOC_SINGLE("ALC Attack", NAU8810_REG_ALC3, + NAU8810_ALCATK_SFT, 0xf, 0), + SOC_SINGLE("ALC Noise Gate Switch", NAU8810_REG_NOISEGATE, + NAU8810_ALCNEN_SFT, 1, 0), + SOC_SINGLE("ALC Noise Gate Threshold", NAU8810_REG_NOISEGATE, + NAU8810_ALCNTH_SFT, 0x7, 0), + + SOC_SINGLE("PGA ZC Switch", NAU8810_REG_PGAGAIN, + NAU8810_PGAZC_SFT, 1, 0), + SOC_SINGLE_TLV("PGA Volume", NAU8810_REG_PGAGAIN, + NAU8810_PGAGAIN_SFT, 0x3f, 0, inpga_tlv), + + SOC_SINGLE("Speaker ZC Switch", NAU8810_REG_SPKGAIN, + NAU8810_SPKZC_SFT, 1, 0), + SOC_SINGLE("Speaker Mute Switch", NAU8810_REG_SPKGAIN, + NAU8810_SPKMT_SFT, 1, 0), + SOC_SINGLE_TLV("Speaker Volume", NAU8810_REG_SPKGAIN, + NAU8810_SPKGAIN_SFT, 0x3f, 0, spk_tlv), + + SOC_SINGLE("Capture Boost(+20dB)", NAU8810_REG_ADCBOOST, + NAU8810_PGABST_SFT, 1, 0), + SOC_SINGLE("Mono Mute Switch", NAU8810_REG_MONOMIX, + NAU8810_MOUTMXMT_SFT, 1, 0), + + SOC_SINGLE("DAC Oversampling Rate(128x) Switch", NAU8810_REG_DAC, + NAU8810_DACOS_SFT, 1, 0), + SOC_SINGLE("ADC Oversampling Rate(128x) Switch", NAU8810_REG_ADC, + NAU8810_ADCOS_SFT, 1, 0), +}; + +/* Speaker Output Mixer */ +static const struct snd_kcontrol_new nau8810_speaker_mixer_controls[] = { + SOC_DAPM_SINGLE("Line Bypass Switch", NAU8810_REG_SPKMIX, + NAU8810_BYPSPK_SFT, 1, 0), + SOC_DAPM_SINGLE("PCM Playback Switch", NAU8810_REG_SPKMIX, + NAU8810_DACSPK_SFT, 1, 0), +}; + +/* Mono Output Mixer */ +static const struct snd_kcontrol_new nau8810_mono_mixer_controls[] = { + SOC_DAPM_SINGLE("Line Bypass Switch", NAU8810_REG_MONOMIX, + NAU8810_BYPMOUT_SFT, 1, 0), + SOC_DAPM_SINGLE("PCM Playback Switch", NAU8810_REG_MONOMIX, + NAU8810_DACMOUT_SFT, 1, 0), +}; + +/* PGA Mute */ +static const struct snd_kcontrol_new nau8810_inpga_mute[] = { + SOC_DAPM_SINGLE("PGA Mute Switch", NAU8810_REG_PGAGAIN, + NAU8810_PGAMT_SFT, 1, 0), +}; + +/* Input PGA */ +static const struct snd_kcontrol_new nau8810_inpga[] = { + SOC_DAPM_SINGLE("MicN Switch", NAU8810_REG_INPUT_SIGNAL, + NAU8810_NMICPGA_SFT, 1, 0), + SOC_DAPM_SINGLE("MicP Switch", NAU8810_REG_INPUT_SIGNAL, + NAU8810_PMICPGA_SFT, 1, 0), +}; + +/* Mic Input boost vol */ +static const struct snd_kcontrol_new nau8810_mic_boost_controls = + SOC_DAPM_SINGLE("Mic Volume", NAU8810_REG_ADCBOOST, + NAU8810_PMICBSTGAIN_SFT, 0x7, 0); + +/* Loopback Switch */ +static const struct snd_kcontrol_new nau8810_loopback = + SOC_DAPM_SINGLE("Switch", NAU8810_REG_COMP, + NAU8810_ADDAP_SFT, 1, 0); + +static int check_mclk_select_pll(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + unsigned int value; + + regmap_read(nau8810->regmap, NAU8810_REG_CLOCK, &value); + return (value & NAU8810_CLKM_MASK); +} + +static const struct snd_soc_dapm_widget nau8810_dapm_widgets[] = { + SND_SOC_DAPM_MIXER("Speaker Mixer", NAU8810_REG_POWER3, + NAU8810_SPKMX_EN_SFT, 0, &nau8810_speaker_mixer_controls[0], + ARRAY_SIZE(nau8810_speaker_mixer_controls)), + SND_SOC_DAPM_MIXER("Mono Mixer", NAU8810_REG_POWER3, + NAU8810_MOUTMX_EN_SFT, 0, &nau8810_mono_mixer_controls[0], + ARRAY_SIZE(nau8810_mono_mixer_controls)), + SND_SOC_DAPM_DAC("DAC", "HiFi Playback", NAU8810_REG_POWER3, + NAU8810_DAC_EN_SFT, 0), + SND_SOC_DAPM_ADC("ADC", "HiFi Capture", NAU8810_REG_POWER2, + NAU8810_ADC_EN_SFT, 0), + SND_SOC_DAPM_PGA("SpkN Out", NAU8810_REG_POWER3, + NAU8810_NSPK_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("SpkP Out", NAU8810_REG_POWER3, + NAU8810_PSPK_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mono Out", NAU8810_REG_POWER3, + NAU8810_MOUT_EN_SFT, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("Input PGA", NAU8810_REG_POWER2, + NAU8810_PGA_EN_SFT, 0, nau8810_inpga, + ARRAY_SIZE(nau8810_inpga)), + SND_SOC_DAPM_MIXER("Input Boost Stage", NAU8810_REG_POWER2, + NAU8810_BST_EN_SFT, 0, nau8810_inpga_mute, + ARRAY_SIZE(nau8810_inpga_mute)), + + SND_SOC_DAPM_SUPPLY("Mic Bias", NAU8810_REG_POWER1, + NAU8810_MICBIAS_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL", NAU8810_REG_POWER1, + NAU8810_PLL_EN_SFT, 0, NULL, 0), + + SND_SOC_DAPM_SWITCH("Digital Loopback", SND_SOC_NOPM, 0, 0, + &nau8810_loopback), + + SND_SOC_DAPM_INPUT("MICN"), + SND_SOC_DAPM_INPUT("MICP"), + SND_SOC_DAPM_OUTPUT("MONOOUT"), + SND_SOC_DAPM_OUTPUT("SPKOUTP"), + SND_SOC_DAPM_OUTPUT("SPKOUTN"), +}; + +static const struct snd_soc_dapm_route nau8810_dapm_routes[] = { + {"DAC", NULL, "PLL", check_mclk_select_pll}, + + /* Mono output mixer */ + {"Mono Mixer", "PCM Playback Switch", "DAC"}, + {"Mono Mixer", "Line Bypass Switch", "Input Boost Stage"}, + + /* Speaker output mixer */ + {"Speaker Mixer", "PCM Playback Switch", "DAC"}, + {"Speaker Mixer", "Line Bypass Switch", "Input Boost Stage"}, + + /* Outputs */ + {"Mono Out", NULL, "Mono Mixer"}, + {"MONOOUT", NULL, "Mono Out"}, + {"SpkN Out", NULL, "Speaker Mixer"}, + {"SpkP Out", NULL, "Speaker Mixer"}, + {"SPKOUTN", NULL, "SpkN Out"}, + {"SPKOUTP", NULL, "SpkP Out"}, + + /* Input Boost Stage */ + {"ADC", NULL, "Input Boost Stage"}, + {"ADC", NULL, "PLL", check_mclk_select_pll}, + {"Input Boost Stage", NULL, "Input PGA"}, + {"Input Boost Stage", NULL, "MICP"}, + + /* Input PGA */ + {"Input PGA", NULL, "Mic Bias"}, + {"Input PGA", "MicN Switch", "MICN"}, + {"Input PGA", "MicP Switch", "MICP"}, + + /* Digital Looptack */ + {"Digital Loopback", "Switch", "ADC"}, + {"DAC", NULL, "Digital Loopback"}, +}; + +static int nau8810_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + + nau8810->clk_id = clk_id; + nau8810->sysclk = freq; + dev_dbg(nau8810->dev, "master sysclk %dHz, source %s\n", + freq, clk_id == NAU8810_SCLK_PLL ? "PLL" : "MCLK"); + + return 0; +} + +static int nau88l0_calc_pll(unsigned int pll_in, + unsigned int fs, struct nau8810_pll *pll_param) +{ + u64 f2, f2_max, pll_ratio; + int i, scal_sel; + + if (pll_in > NAU_PLL_REF_MAX || pll_in < NAU_PLL_REF_MIN) + return -EINVAL; + + f2_max = 0; + scal_sel = ARRAY_SIZE(nau8810_mclk_scaler); + for (i = 0; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) { + f2 = 256 * fs * 4 * nau8810_mclk_scaler[i] / 10; + if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX && + f2_max < f2) { + f2_max = f2; + scal_sel = i; + } + } + if (ARRAY_SIZE(nau8810_mclk_scaler) == scal_sel) + return -EINVAL; + pll_param->mclk_scaler = scal_sel; + f2 = f2_max; + + /* Calculate the PLL 4-bit integer input and the PLL 24-bit fractional + * input; round up the 24+4bit. + */ + pll_ratio = div_u64(f2 << 28, pll_in); + pll_param->pre_factor = 0; + if (((pll_ratio >> 28) & 0xF) < NAU_PLL_OPTOP_MIN) { + pll_ratio <<= 1; + pll_param->pre_factor = 1; + } + pll_param->pll_int = (pll_ratio >> 28) & 0xF; + pll_param->pll_frac = ((pll_ratio & 0xFFFFFFF) >> 4); + + return 0; +} + +static int nau8810_set_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + struct regmap *map = nau8810->regmap; + struct nau8810_pll *pll_param = &nau8810->pll; + int ret, fs; + + fs = freq_out / 256; + ret = nau88l0_calc_pll(freq_in, fs, pll_param); + if (ret < 0) { + dev_err(nau8810->dev, "Unsupported input clock %d\n", freq_in); + return ret; + } + dev_info(nau8810->dev, "pll_int=%x pll_frac=%x mclk_scaler=%x pre_factor=%x\n", + pll_param->pll_int, pll_param->pll_frac, pll_param->mclk_scaler, + pll_param->pre_factor); + + regmap_update_bits(map, NAU8810_REG_PLLN, + NAU8810_PLLMCLK_DIV2 | NAU8810_PLLN_MASK, + (pll_param->pre_factor ? NAU8810_PLLMCLK_DIV2 : 0) | + pll_param->pll_int); + regmap_write(map, NAU8810_REG_PLLK1, + (pll_param->pll_frac >> NAU8810_PLLK1_SFT) & + NAU8810_PLLK1_MASK); + regmap_write(map, NAU8810_REG_PLLK2, + (pll_param->pll_frac >> NAU8810_PLLK2_SFT) & + NAU8810_PLLK2_MASK); + regmap_write(map, NAU8810_REG_PLLK3, + pll_param->pll_frac & NAU8810_PLLK3_MASK); + regmap_update_bits(map, NAU8810_REG_CLOCK, NAU8810_MCLKSEL_MASK, + pll_param->mclk_scaler << NAU8810_MCLKSEL_SFT); + regmap_update_bits(map, NAU8810_REG_CLOCK, + NAU8810_CLKM_MASK, NAU8810_CLKM_PLL); + + return 0; +} + +static int nau8810_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + u16 ctrl1_val = 0, ctrl2_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + ctrl2_val |= NAU8810_CLKIO_MASTER; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + ctrl1_val |= NAU8810_AIFMT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + ctrl1_val |= NAU8810_AIFMT_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + ctrl1_val |= NAU8810_AIFMT_PCM_A; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + ctrl1_val |= NAU8810_BCLKP_IB | NAU8810_FSP_IF; + break; + case SND_SOC_DAIFMT_IB_NF: + ctrl1_val |= NAU8810_BCLKP_IB; + break; + case SND_SOC_DAIFMT_NB_IF: + ctrl1_val |= NAU8810_FSP_IF; + break; + default: + return -EINVAL; + } + + regmap_update_bits(nau8810->regmap, NAU8810_REG_IFACE, + NAU8810_AIFMT_MASK | NAU8810_FSP_IF | + NAU8810_BCLKP_IB, ctrl1_val); + regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK, + NAU8810_CLKIO_MASK, ctrl2_val); + + return 0; +} + +static int nau8810_mclk_clkdiv(struct nau8810 *nau8810, int rate) +{ + int i, sclk, imclk = rate * 256, div = 0; + + if (!nau8810->sysclk) { + dev_err(nau8810->dev, "Make mclk div configuration fail because of invalid system clock\n"); + return -EINVAL; + } + + /* Configure the master clock prescaler div to make system + * clock to approximate the internal master clock (IMCLK); + * and large or equal to IMCLK. + */ + for (i = 1; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) { + sclk = (nau8810->sysclk * 10) / + nau8810_mclk_scaler[i]; + if (sclk < imclk) + break; + div = i; + } + dev_dbg(nau8810->dev, + "master clock prescaler %x for fs %d\n", div, rate); + + /* master clock from MCLK and disable PLL */ + regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK, + NAU8810_MCLKSEL_MASK, (div << NAU8810_MCLKSEL_SFT)); + regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK, + NAU8810_CLKM_MASK, NAU8810_CLKM_MCLK); + + return 0; +} + +static int nau8810_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + int val_len = 0, val_rate = 0, ret = 0; + + switch (params_width(params)) { + case 16: + break; + case 20: + val_len |= NAU8810_WLEN_20; + break; + case 24: + val_len |= NAU8810_WLEN_24; + break; + case 32: + val_len |= NAU8810_WLEN_32; + break; + } + + switch (params_rate(params)) { + case 8000: + val_rate |= NAU8810_SMPLR_8K; + break; + case 11025: + val_rate |= NAU8810_SMPLR_12K; + break; + case 16000: + val_rate |= NAU8810_SMPLR_16K; + break; + case 22050: + val_rate |= NAU8810_SMPLR_24K; + break; + case 32000: + val_rate |= NAU8810_SMPLR_32K; + break; + case 44100: + case 48000: + break; + } + + regmap_update_bits(nau8810->regmap, NAU8810_REG_IFACE, + NAU8810_WLEN_MASK, val_len); + regmap_update_bits(nau8810->regmap, NAU8810_REG_SMPLR, + NAU8810_SMPLR_MASK, val_rate); + + /* If the master clock is from MCLK, provide the runtime FS for driver + * to get the master clock prescaler configuration. + */ + if (nau8810->clk_id == NAU8810_SCLK_MCLK) { + ret = nau8810_mclk_clkdiv(nau8810, params_rate(params)); + if (ret < 0) + dev_err(nau8810->dev, "MCLK div configuration fail\n"); + } + + return ret; +} + +static int nau8810_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + struct regmap *map = nau8810->regmap; + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + regmap_update_bits(map, NAU8810_REG_POWER1, + NAU8810_REFIMP_MASK, NAU8810_REFIMP_80K); + break; + + case SND_SOC_BIAS_STANDBY: + regmap_update_bits(map, NAU8810_REG_POWER1, + NAU8810_IOBUF_EN | NAU8810_ABIAS_EN, + NAU8810_IOBUF_EN | NAU8810_ABIAS_EN); + + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { + regcache_sync(map); + regmap_update_bits(map, NAU8810_REG_POWER1, + NAU8810_REFIMP_MASK, NAU8810_REFIMP_3K); + mdelay(100); + } + regmap_update_bits(map, NAU8810_REG_POWER1, + NAU8810_REFIMP_MASK, NAU8810_REFIMP_300K); + break; + + case SND_SOC_BIAS_OFF: + regmap_write(map, NAU8810_REG_POWER1, 0); + regmap_write(map, NAU8810_REG_POWER2, 0); + regmap_write(map, NAU8810_REG_POWER3, 0); + break; + } + + return 0; +} + + +#define NAU8810_RATES (SNDRV_PCM_RATE_8000_48000) + +#define NAU8810_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static const struct snd_soc_dai_ops nau8810_ops = { + .hw_params = nau8810_pcm_hw_params, + .set_fmt = nau8810_set_dai_fmt, + .set_sysclk = nau8810_set_sysclk, + .set_pll = nau8810_set_pll, +}; + +static struct snd_soc_dai_driver nau8810_dai = { + .name = "nau8810-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, /* Only 1 channel of data */ + .rates = NAU8810_RATES, + .formats = NAU8810_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, /* Only 1 channel of data */ + .rates = NAU8810_RATES, + .formats = NAU8810_FORMATS, + }, + .ops = &nau8810_ops, + .symmetric_rates = 1, +}; + +static const struct regmap_config nau8810_regmap_config = { + .reg_bits = 7, + .val_bits = 9, + + .max_register = NAU8810_REG_MAX, + .readable_reg = nau8810_readable_reg, + .writeable_reg = nau8810_writeable_reg, + .volatile_reg = nau8810_volatile_reg, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = nau8810_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(nau8810_reg_defaults), +}; + +static struct snd_soc_codec_driver nau8810_codec_driver = { + .set_bias_level = nau8810_set_bias_level, + .suspend_bias_off = true, + + .component_driver = { + .controls = nau8810_snd_controls, + .num_controls = ARRAY_SIZE(nau8810_snd_controls), + .dapm_widgets = nau8810_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(nau8810_dapm_widgets), + .dapm_routes = nau8810_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(nau8810_dapm_routes), + }, +}; + +static int nau8810_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct device *dev = &i2c->dev; + struct nau8810 *nau8810 = dev_get_platdata(dev); + + if (!nau8810) { + nau8810 = devm_kzalloc(dev, sizeof(*nau8810), GFP_KERNEL); + if (!nau8810) + return -ENOMEM; + } + i2c_set_clientdata(i2c, nau8810); + + nau8810->regmap = devm_regmap_init_i2c(i2c, &nau8810_regmap_config); + if (IS_ERR(nau8810->regmap)) + return PTR_ERR(nau8810->regmap); + nau8810->dev = dev; + + regmap_write(nau8810->regmap, NAU8810_REG_RESET, 0x00); + + return snd_soc_register_codec(dev, + &nau8810_codec_driver, &nau8810_dai, 1); +} + +static int nau8810_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + + return 0; +} + +static const struct i2c_device_id nau8810_i2c_id[] = { + { "nau8810", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, nau8810_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id nau8810_of_match[] = { + { .compatible = "nuvoton,nau8810", }, + { } +}; +MODULE_DEVICE_TABLE(of, nau8810_of_match); +#endif + +static struct i2c_driver nau8810_i2c_driver = { + .driver = { + .name = "nau8810", + .of_match_table = of_match_ptr(nau8810_of_match), + }, + .probe = nau8810_i2c_probe, + .remove = nau8810_i2c_remove, + .id_table = nau8810_i2c_id, +}; + +module_i2c_driver(nau8810_i2c_driver); + +MODULE_DESCRIPTION("ASoC NAU8810 driver"); +MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/nau8810.h b/sound/soc/codecs/nau8810.h new file mode 100644 index 000000000000..df882658ca91 --- /dev/null +++ b/sound/soc/codecs/nau8810.h @@ -0,0 +1,281 @@ +/* + * NAU8810 ALSA SoC audio driver + * + * Copyright 2016 Nuvoton Technology Corp. + * Author: David Lin <ctlin0@nuvoton.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __NAU8810_H__ +#define __NAU8810_H__ + +#define NAU8810_REG_RESET 0x00 +#define NAU8810_REG_POWER1 0x01 +#define NAU8810_REG_POWER2 0x02 +#define NAU8810_REG_POWER3 0x03 +#define NAU8810_REG_IFACE 0x04 +#define NAU8810_REG_COMP 0x05 +#define NAU8810_REG_CLOCK 0x06 +#define NAU8810_REG_SMPLR 0x07 +#define NAU8810_REG_DAC 0x0A +#define NAU8810_REG_DACGAIN 0x0B +#define NAU8810_REG_ADC 0x0E +#define NAU8810_REG_ADCGAIN 0x0F +#define NAU8810_REG_EQ1 0x12 +#define NAU8810_REG_EQ2 0x13 +#define NAU8810_REG_EQ3 0x14 +#define NAU8810_REG_EQ4 0x15 +#define NAU8810_REG_EQ5 0x16 +#define NAU8810_REG_DACLIM1 0x18 +#define NAU8810_REG_DACLIM2 0x19 +#define NAU8810_REG_NOTCH1 0x1B +#define NAU8810_REG_NOTCH2 0x1C +#define NAU8810_REG_NOTCH3 0x1D +#define NAU8810_REG_NOTCH4 0x1E +#define NAU8810_REG_ALC1 0x20 +#define NAU8810_REG_ALC2 0x21 +#define NAU8810_REG_ALC3 0x22 +#define NAU8810_REG_NOISEGATE 0x23 +#define NAU8810_REG_PLLN 0x24 +#define NAU8810_REG_PLLK1 0x25 +#define NAU8810_REG_PLLK2 0x26 +#define NAU8810_REG_PLLK3 0x27 +#define NAU8810_REG_ATTEN 0x28 +#define NAU8810_REG_INPUT_SIGNAL 0x2C +#define NAU8810_REG_PGAGAIN 0x2D +#define NAU8810_REG_ADCBOOST 0x2F +#define NAU8810_REG_OUTPUT 0x31 +#define NAU8810_REG_SPKMIX 0x32 +#define NAU8810_REG_SPKGAIN 0x36 +#define NAU8810_REG_MONOMIX 0x38 +#define NAU8810_REG_POWER4 0x3A +#define NAU8810_REG_TSLOTCTL1 0x3B +#define NAU8810_REG_TSLOTCTL2 0x3C +#define NAU8810_REG_DEVICE_REVID 0x3E +#define NAU8810_REG_I2C_DEVICEID 0x3F +#define NAU8810_REG_ADDITIONID 0x40 +#define NAU8810_REG_RESERVE 0x41 +#define NAU8810_REG_OUTCTL 0x45 +#define NAU8810_REG_ALC1ENHAN1 0x46 +#define NAU8810_REG_ALC1ENHAN2 0x47 +#define NAU8810_REG_MISCCTL 0x49 +#define NAU8810_REG_OUTTIEOFF 0x4B +#define NAU8810_REG_AGCP2POUT 0x4C +#define NAU8810_REG_AGCPOUT 0x4D +#define NAU8810_REG_AMTCTL 0x4E +#define NAU8810_REG_OUTTIEOFFMAN 0x4F +#define NAU8810_REG_MAX NAU8810_REG_OUTTIEOFFMAN + + +/* NAU8810_REG_POWER1 (0x1) */ +#define NAU8810_DCBUF_EN (0x1 << 8) +#define NAU8810_PLL_EN_SFT 5 +#define NAU8810_MICBIAS_EN_SFT 4 +#define NAU8810_ABIAS_EN (0x1 << 3) +#define NAU8810_IOBUF_EN (0x1 << 2) +#define NAU8810_REFIMP_MASK 0x3 +#define NAU8810_REFIMP_DIS 0x0 +#define NAU8810_REFIMP_80K 0x1 +#define NAU8810_REFIMP_300K 0x2 +#define NAU8810_REFIMP_3K 0x3 + +/* NAU8810_REG_POWER2 (0x2) */ +#define NAU8810_BST_EN_SFT 4 +#define NAU8810_PGA_EN_SFT 2 +#define NAU8810_ADC_EN_SFT 0 + +/* NAU8810_REG_POWER3 (0x3) */ +#define NAU8810_DAC_EN_SFT 0 +#define NAU8810_SPKMX_EN_SFT 2 +#define NAU8810_MOUTMX_EN_SFT 3 +#define NAU8810_PSPK_EN_SFT 5 +#define NAU8810_NSPK_EN_SFT 6 +#define NAU8810_MOUT_EN_SFT 7 + +/* NAU8810_REG_IFACE (0x4) */ +#define NAU8810_AIFMT_SFT 3 +#define NAU8810_AIFMT_MASK (0x3 << NAU8810_AIFMT_SFT) +#define NAU8810_AIFMT_RIGHT (0x0 << NAU8810_AIFMT_SFT) +#define NAU8810_AIFMT_LEFT (0x1 << NAU8810_AIFMT_SFT) +#define NAU8810_AIFMT_I2S (0x2 << NAU8810_AIFMT_SFT) +#define NAU8810_AIFMT_PCM_A (0x3 << NAU8810_AIFMT_SFT) +#define NAU8810_WLEN_SFT 5 +#define NAU8810_WLEN_MASK (0x3 << NAU8810_WLEN_SFT) +#define NAU8810_WLEN_16 (0x0 << NAU8810_WLEN_SFT) +#define NAU8810_WLEN_20 (0x1 << NAU8810_WLEN_SFT) +#define NAU8810_WLEN_24 (0x2 << NAU8810_WLEN_SFT) +#define NAU8810_WLEN_32 (0x3 << NAU8810_WLEN_SFT) +#define NAU8810_FSP_IF (0x1 << 7) +#define NAU8810_BCLKP_IB (0x1 << 8) + +/* NAU8810_REG_COMP (0x5) */ +#define NAU8810_ADDAP_SFT 0 +#define NAU8810_ADCCM_SFT 1 +#define NAU8810_DACCM_SFT 3 + +/* NAU8810_REG_CLOCK (0x6) */ +#define NAU8810_CLKIO_MASK 0x1 +#define NAU8810_CLKIO_SLAVE 0x0 +#define NAU8810_CLKIO_MASTER 0x1 +#define NAU8810_BCLKSEL_SFT 2 +#define NAU8810_BCLKSEL_MASK (0x7 << NAU8810_BCLKSEL_SFT) +#define NAU8810_BCLKDIV_1 (0x0 << NAU8810_BCLKSEL_SFT) +#define NAU8810_BCLKDIV_2 (0x1 << NAU8810_BCLKSEL_SFT) +#define NAU8810_BCLKDIV_4 (0x2 << NAU8810_BCLKSEL_SFT) +#define NAU8810_BCLKDIV_8 (0x3 << NAU8810_BCLKSEL_SFT) +#define NAU8810_BCLKDIV_16 (0x4 << NAU8810_BCLKSEL_SFT) +#define NAU8810_BCLKDIV_32 (0x5 << NAU8810_BCLKSEL_SFT) +#define NAU8810_MCLKSEL_SFT 5 +#define NAU8810_MCLKSEL_MASK (0x7 << NAU8810_MCLKSEL_SFT) +#define NAU8810_CLKM_SFT 8 +#define NAU8810_CLKM_MASK (0x1 << NAU8810_CLKM_SFT) +#define NAU8810_CLKM_MCLK (0x0 << NAU8810_CLKM_SFT) +#define NAU8810_CLKM_PLL (0x1 << NAU8810_CLKM_SFT) + +/* NAU8810_REG_SMPLR (0x7) */ +#define NAU8810_SMPLR_SFT 1 +#define NAU8810_SMPLR_MASK (0x7 << NAU8810_SMPLR_SFT) +#define NAU8810_SMPLR_48K (0x0 << NAU8810_SMPLR_SFT) +#define NAU8810_SMPLR_32K (0x1 << NAU8810_SMPLR_SFT) +#define NAU8810_SMPLR_24K (0x2 << NAU8810_SMPLR_SFT) +#define NAU8810_SMPLR_16K (0x3 << NAU8810_SMPLR_SFT) +#define NAU8810_SMPLR_12K (0x4 << NAU8810_SMPLR_SFT) +#define NAU8810_SMPLR_8K (0x5 << NAU8810_SMPLR_SFT) + +/* NAU8810_REG_DAC (0xA) */ +#define NAU8810_DACPL_SFT 0 +#define NAU8810_DACOS_SFT 3 +#define NAU8810_DEEMP_SFT 4 + +/* NAU8810_REG_DACGAIN (0xB) */ +#define NAU8810_DACGAIN_SFT 0 + +/* NAU8810_REG_ADC (0xE) */ +#define NAU8810_ADCPL_SFT 0 +#define NAU8810_ADCOS_SFT 3 +#define NAU8810_HPF_SFT 4 +#define NAU8810_HPFEN_SFT 8 + +/* NAU8810_REG_ADCGAIN (0xF) */ +#define NAU8810_ADCGAIN_SFT 0 + +/* NAU8810_REG_EQ1 (0x12) */ +#define NAU8810_EQ1GC_SFT 0 +#define NAU8810_EQ1CF_SFT 5 +#define NAU8810_EQM_SFT 8 + +/* NAU8810_REG_EQ2 (0x13) */ +#define NAU8810_EQ2GC_SFT 0 +#define NAU8810_EQ2CF_SFT 5 +#define NAU8810_EQ2BW_SFT 8 + +/* NAU8810_REG_EQ3 (0x14) */ +#define NAU8810_EQ3GC_SFT 0 +#define NAU8810_EQ3CF_SFT 5 +#define NAU8810_EQ3BW_SFT 8 + +/* NAU8810_REG_EQ4 (0x15) */ +#define NAU8810_EQ4GC_SFT 0 +#define NAU8810_EQ4CF_SFT 5 +#define NAU8810_EQ4BW_SFT 8 + +/* NAU8810_REG_EQ5 (0x16) */ +#define NAU8810_EQ5GC_SFT 0 +#define NAU8810_EQ5CF_SFT 5 + +/* NAU8810_REG_DACLIM1 (0x18) */ +#define NAU8810_DACLIMATK_SFT 0 +#define NAU8810_DACLIMDCY_SFT 4 +#define NAU8810_DACLIMEN_SFT 8 + +/* NAU8810_REG_DACLIM2 (0x19) */ +#define NAU8810_DACLIMBST_SFT 0 +#define NAU8810_DACLIMTHL_SFT 4 + +/* NAU8810_REG_ALC1 (0x20) */ +#define NAU8810_ALCMINGAIN_SFT 0 +#define NAU8810_ALCMXGAIN_SFT 3 +#define NAU8810_ALCEN_SFT 8 + +/* NAU8810_REG_ALC2 (0x21) */ +#define NAU8810_ALCSL_SFT 0 +#define NAU8810_ALCHT_SFT 4 +#define NAU8810_ALCZC_SFT 8 + +/* NAU8810_REG_ALC3 (0x22) */ +#define NAU8810_ALCATK_SFT 0 +#define NAU8810_ALCDCY_SFT 4 +#define NAU8810_ALCM_SFT 8 + +/* NAU8810_REG_NOISEGATE (0x23) */ +#define NAU8810_ALCNTH_SFT 0 +#define NAU8810_ALCNEN_SFT 3 + +/* NAU8810_REG_PLLN (0x24) */ +#define NAU8810_PLLN_MASK 0xF +#define NAU8810_PLLMCLK_DIV2 (0x1 << 4) + +/* NAU8810_REG_PLLK1 (0x25) */ +#define NAU8810_PLLK1_SFT 18 +#define NAU8810_PLLK1_MASK 0x3F + +/* NAU8810_REG_PLLK2 (0x26) */ +#define NAU8810_PLLK2_SFT 9 +#define NAU8810_PLLK2_MASK 0x1FF + +/* NAU8810_REG_PLLK3 (0x27) */ +#define NAU8810_PLLK3_MASK 0x1FF + +/* NAU8810_REG_INPUT_SIGNAL (0x2C) */ +#define NAU8810_PMICPGA_SFT 0 +#define NAU8810_NMICPGA_SFT 1 + +/* NAU8810_REG_PGAGAIN (0x2D) */ +#define NAU8810_PGAGAIN_SFT 0 +#define NAU8810_PGAMT_SFT 6 +#define NAU8810_PGAZC_SFT 7 + +/* NAU8810_REG_ADCBOOST (0x2F) */ +#define NAU8810_PMICBSTGAIN_SFT 4 +#define NAU8810_PGABST_SFT 8 + +/* NAU8810_REG_SPKMIX (0x32) */ +#define NAU8810_DACSPK_SFT 0 +#define NAU8810_BYPSPK_SFT 1 + +/* NAU8810_REG_SPKGAIN (0x36) */ +#define NAU8810_SPKGAIN_SFT 0 +#define NAU8810_SPKMT_SFT 6 +#define NAU8810_SPKZC_SFT 7 + +/* NAU8810_REG_MONOMIX (0x38) */ +#define NAU8810_DACMOUT_SFT 0 +#define NAU8810_BYPMOUT_SFT 1 +#define NAU8810_MOUTMXMT_SFT 6 + + +/* System Clock Source */ +enum { + NAU8810_SCLK_MCLK, + NAU8810_SCLK_PLL, +}; + +struct nau8810_pll { + int pre_factor; + int mclk_scaler; + int pll_frac; + int pll_int; +}; + +struct nau8810 { + struct device *dev; + struct regmap *regmap; + struct nau8810_pll pll; + int sysclk; + int clk_id; +}; + +#endif diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 5c9707ac4bbf..e643be91d762 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -212,31 +212,6 @@ static const unsigned short logtable[256] = { 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47 }; -static struct snd_soc_dai *nau8825_get_codec_dai(struct nau8825 *nau8825) -{ - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(nau8825->dapm); - struct snd_soc_component *component = &codec->component; - struct snd_soc_dai *codec_dai, *_dai; - - list_for_each_entry_safe(codec_dai, _dai, &component->dai_list, list) { - if (!strncmp(codec_dai->name, NUVOTON_CODEC_DAI, - strlen(NUVOTON_CODEC_DAI))) - return codec_dai; - } - return NULL; -} - -static bool nau8825_dai_is_active(struct nau8825 *nau8825) -{ - struct snd_soc_dai *codec_dai = nau8825_get_codec_dai(nau8825); - - if (codec_dai) { - if (codec_dai->playback_active || codec_dai->capture_active) - return true; - } - return false; -} - /** * nau8825_sema_acquire - acquire the semaphore of nau88l25 * @nau8825: component to register the codec private data with @@ -250,19 +225,26 @@ static bool nau8825_dai_is_active(struct nau8825 *nau8825) * Acquires the semaphore without jiffies. If no more tasks are allowed * to acquire the semaphore, calling this function will put the task to * sleep until the semaphore is released. - * It returns if the semaphore was acquired. + * If the semaphore is not released within the specified number of jiffies, + * this function returns -ETIME. + * If the sleep is interrupted by a signal, this function will return -EINTR. + * It returns 0 if the semaphore was acquired successfully. */ -static void nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) +static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) { int ret; - if (timeout) + if (timeout) { ret = down_timeout(&nau8825->xtalk_sem, timeout); - else + if (ret < 0) + dev_warn(nau8825->dev, "Acquire semaphone timeout\n"); + } else { ret = down_interruptible(&nau8825->xtalk_sem); + if (ret < 0) + dev_warn(nau8825->dev, "Acquire semaphone fail\n"); + } - if (ret < 0) - dev_warn(nau8825->dev, "Acquire semaphone fail\n"); + return ret; } /** @@ -1205,6 +1187,8 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); unsigned int val_len = 0; + nau8825_sema_acquire(nau8825, 2 * HZ); + switch (params_width(params)) { case 16: val_len |= NAU8825_I2S_DL_16; @@ -1225,6 +1209,9 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1, NAU8825_I2S_DL_MASK, val_len); + /* Release the semaphone. */ + nau8825_sema_release(nau8825); + return 0; } @@ -1234,6 +1221,8 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); unsigned int ctrl1_val = 0, ctrl2_val = 0; + nau8825_sema_acquire(nau8825, 2 * HZ); + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: ctrl2_val |= NAU8825_I2S_MS_MASTER; @@ -1282,6 +1271,9 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, NAU8825_I2S_MS_MASK, ctrl2_val); + /* Release the semaphone. */ + nau8825_sema_release(nau8825); + return 0; } @@ -1611,8 +1603,11 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) * cess and restore changes if process * is ongoing when ejection. */ + int ret; nau8825->xtalk_protect = true; - nau8825_sema_acquire(nau8825, 0); + ret = nau8825_sema_acquire(nau8825, 0); + if (ret < 0) + nau8825->xtalk_protect = false; } /* Startup cross talk detection process */ nau8825->xtalk_state = NAU8825_XTALK_PREPARE; @@ -1912,7 +1907,7 @@ static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs, /* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional * input based on FDCO, FREF and FLL ratio. */ - fvco = div_u64(fvco << 16, fref * fll_param->ratio); + fvco = div_u64(fvco_max << 16, fref * fll_param->ratio); fll_param->fll_int = (fvco >> 16) & 0x3FF; fll_param->fll_frac = fvco & 0xFFFF; return 0; @@ -2238,23 +2233,14 @@ static int __maybe_unused nau8825_suspend(struct snd_soc_codec *codec) static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec) { struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); + int ret; regcache_cache_only(nau8825->regmap, false); regcache_sync(nau8825->regmap); - if (nau8825_is_jack_inserted(nau8825->regmap)) { - /* If the jack is inserted, we need to check whether the play- - * back is active before suspend. If active, the driver has to - * raise the protection for cross talk function to avoid the - * playback recovers before cross talk process finish. Other- - * wise, the playback will be interfered by cross talk func- - * tion. It is better to apply hardware related parameters - * before starting playback or record. - */ - if (nau8825_dai_is_active(nau8825)) { - nau8825->xtalk_protect = true; - nau8825_sema_acquire(nau8825, 0); - } - } + nau8825->xtalk_protect = true; + ret = nau8825_sema_acquire(nau8825, 0); + if (ret < 0) + nau8825->xtalk_protect = false; enable_irq(nau8825->irq); return 0; @@ -2270,12 +2256,14 @@ static struct snd_soc_codec_driver nau8825_codec_driver = { .suspend = nau8825_suspend, .resume = nau8825_resume, - .controls = nau8825_controls, - .num_controls = ARRAY_SIZE(nau8825_controls), - .dapm_widgets = nau8825_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(nau8825_dapm_widgets), - .dapm_routes = nau8825_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(nau8825_dapm_routes), + .component_driver = { + .controls = nau8825_controls, + .num_controls = ARRAY_SIZE(nau8825_controls), + .dapm_widgets = nau8825_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(nau8825_dapm_widgets), + .dapm_routes = nau8825_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(nau8825_dapm_routes), + }, }; static void nau8825_reset_chip(struct regmap *regmap) diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 33e1fc2d1598..0b14efab6280 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -289,12 +289,14 @@ static const struct regmap_config pcm1681_regmap = { }; static struct snd_soc_codec_driver soc_codec_dev_pcm1681 = { - .controls = pcm1681_controls, - .num_controls = ARRAY_SIZE(pcm1681_controls), - .dapm_widgets = pcm1681_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(pcm1681_dapm_widgets), - .dapm_routes = pcm1681_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(pcm1681_dapm_routes), + .component_driver = { + .controls = pcm1681_controls, + .num_controls = ARRAY_SIZE(pcm1681_controls), + .dapm_widgets = pcm1681_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm1681_dapm_widgets), + .dapm_routes = pcm1681_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pcm1681_dapm_routes), + }, }; static const struct i2c_device_id pcm1681_i2c_id[] = { diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c index 88fbdd184aa0..b813a154ddd9 100644 --- a/sound/soc/codecs/pcm179x.c +++ b/sound/soc/codecs/pcm179x.c @@ -206,12 +206,14 @@ const struct regmap_config pcm179x_regmap_config = { EXPORT_SYMBOL_GPL(pcm179x_regmap_config); static struct snd_soc_codec_driver soc_codec_dev_pcm179x = { - .controls = pcm179x_controls, - .num_controls = ARRAY_SIZE(pcm179x_controls), - .dapm_widgets = pcm179x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(pcm179x_dapm_widgets), - .dapm_routes = pcm179x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(pcm179x_dapm_routes), + .component_driver = { + .controls = pcm179x_controls, + .num_controls = ARRAY_SIZE(pcm179x_controls), + .dapm_widgets = pcm179x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm179x_dapm_widgets), + .dapm_routes = pcm179x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pcm179x_dapm_routes), + }, }; int pcm179x_common_init(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index 8fb445f33f6f..708af05486f6 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -99,10 +99,12 @@ static struct snd_soc_dai_driver pcm3008_dai = { }; static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = { - .dapm_widgets = pcm3008_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(pcm3008_dapm_widgets), - .dapm_routes = pcm3008_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(pcm3008_dapm_routes), + .component_driver = { + .dapm_widgets = pcm3008_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm3008_dapm_widgets), + .dapm_routes = pcm3008_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pcm3008_dapm_routes), + }, }; static int pcm3008_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 992a77edcd5d..39bc02d5bc5d 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -599,12 +599,14 @@ EXPORT_SYMBOL_GPL(pcm3168a_regmap); static const struct snd_soc_codec_driver pcm3168a_driver = { .idle_bias_off = true, - .controls = pcm3168a_snd_controls, - .num_controls = ARRAY_SIZE(pcm3168a_snd_controls), - .dapm_widgets = pcm3168a_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(pcm3168a_dapm_widgets), - .dapm_routes = pcm3168a_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(pcm3168a_dapm_routes) + .component_driver = { + .controls = pcm3168a_snd_controls, + .num_controls = ARRAY_SIZE(pcm3168a_snd_controls), + .dapm_widgets = pcm3168a_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm3168a_dapm_widgets), + .dapm_routes = pcm3168a_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pcm3168a_dapm_routes) + }, }; int pcm3168a_probe(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 047c48953a20..72b19e62f626 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1348,12 +1348,14 @@ static struct snd_soc_codec_driver pcm512x_codec_driver = { .set_bias_level = pcm512x_set_bias_level, .idle_bias_off = true, - .controls = pcm512x_controls, - .num_controls = ARRAY_SIZE(pcm512x_controls), - .dapm_widgets = pcm512x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets), - .dapm_routes = pcm512x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), + .component_driver = { + .controls = pcm512x_controls, + .num_controls = ARRAY_SIZE(pcm512x_controls), + .dapm_widgets = pcm512x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets), + .dapm_routes = pcm512x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), + }, }; static const struct regmap_range_cfg pcm512x_range = { diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 74c0e4eb3788..9c365a7f758d 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1053,12 +1053,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt286 = { .resume = rt286_resume, .set_bias_level = rt286_set_bias_level, .idle_bias_off = true, - .controls = rt286_snd_controls, - .num_controls = ARRAY_SIZE(rt286_snd_controls), - .dapm_widgets = rt286_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rt286_dapm_widgets), - .dapm_routes = rt286_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rt286_dapm_routes), + .component_driver = { + .controls = rt286_snd_controls, + .num_controls = ARRAY_SIZE(rt286_snd_controls), + .dapm_widgets = rt286_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt286_dapm_widgets), + .dapm_routes = rt286_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt286_dapm_routes), + }, }; static const struct regmap_config rt286_regmap = { diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index f80cfe4d2ef2..55558643166f 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -1095,12 +1095,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt298 = { .resume = rt298_resume, .set_bias_level = rt298_set_bias_level, .idle_bias_off = true, - .controls = rt298_snd_controls, - .num_controls = ARRAY_SIZE(rt298_snd_controls), - .dapm_widgets = rt298_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rt298_dapm_widgets), - .dapm_routes = rt298_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rt298_dapm_routes), + .component_driver = { + .controls = rt298_snd_controls, + .num_controls = ARRAY_SIZE(rt298_snd_controls), + .dapm_widgets = rt298_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt298_dapm_widgets), + .dapm_routes = rt298_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt298_dapm_routes), + }, }; static const struct regmap_config rt298_regmap = { diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 77ff8ebe6dfb..09103aab0cb2 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -236,7 +236,7 @@ static snd_pcm_uframes_t rt5514_spi_pcm_pointer( return bytes_to_frames(runtime, rt5514_dsp->dma_offset); } -static struct snd_pcm_ops rt5514_spi_pcm_ops = { +static const struct snd_pcm_ops rt5514_spi_pcm_ops = { .open = rt5514_spi_pcm_open, .hw_params = rt5514_spi_hw_params, .hw_free = rt5514_spi_hw_free, diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 7162f05101d9..f24b7cfd3a89 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -278,7 +278,7 @@ static const DECLARE_TLV_DB_RANGE(bst_tlv, 8, 8, TLV_DB_SCALE_ITEM(1700, 0, 0) ); -static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); static int rt5514_dsp_voice_wake_up_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -352,10 +352,10 @@ static const struct snd_kcontrol_new rt5514_snd_controls[] = { SOC_DOUBLE_TLV("MIC Boost Volume", RT5514_ANA_CTRL_MICBST, RT5514_SEL_BSTL_SFT, RT5514_SEL_BSTR_SFT, 8, 0, bst_tlv), SOC_DOUBLE_R_TLV("ADC1 Capture Volume", RT5514_DOWNFILTER0_CTRL1, - RT5514_DOWNFILTER0_CTRL2, RT5514_AD_GAIN_SFT, 127, 0, + RT5514_DOWNFILTER0_CTRL2, RT5514_AD_GAIN_SFT, 63, 0, adc_vol_tlv), SOC_DOUBLE_R_TLV("ADC2 Capture Volume", RT5514_DOWNFILTER1_CTRL1, - RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 127, 0, + RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 63, 0, adc_vol_tlv), SOC_SINGLE_EXT("DSP Voice Wake Up", SND_SOC_NOPM, 0, 1, 0, rt5514_dsp_voice_wake_up_get, rt5514_dsp_voice_wake_up_put), @@ -1023,12 +1023,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5514 = { .probe = rt5514_probe, .idle_bias_off = true, .set_bias_level = rt5514_set_bias_level, - .controls = rt5514_snd_controls, - .num_controls = ARRAY_SIZE(rt5514_snd_controls), - .dapm_widgets = rt5514_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rt5514_dapm_widgets), - .dapm_routes = rt5514_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rt5514_dapm_routes), + .component_driver = { + .controls = rt5514_snd_controls, + .num_controls = ARRAY_SIZE(rt5514_snd_controls), + .dapm_widgets = rt5514_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5514_dapm_widgets), + .dapm_routes = rt5514_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5514_dapm_routes), + }, }; static const struct regmap_config rt5514_i2c_regmap = { diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h index 68883c68e999..229de0e2c88c 100644 --- a/sound/soc/codecs/rt5514.h +++ b/sound/soc/codecs/rt5514.h @@ -196,8 +196,8 @@ #define RT5514_AD_AD_MIX_BIT 10 #define RT5514_AD_AD_MUTE (0x1 << 7) #define RT5514_AD_AD_MUTE_BIT 7 -#define RT5514_AD_GAIN_MASK (0x7f << 0) -#define RT5514_AD_GAIN_SFT 0 +#define RT5514_AD_GAIN_MASK (0x3f << 1) +#define RT5514_AD_GAIN_SFT 1 /* RT5514_ANA_CTRL_MICBST (0x2220) */ #define RT5514_SEL_BSTL_MASK (0xf << 4) diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index f527b5b2817b..d1f273b24991 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -294,8 +294,7 @@ static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ -static unsigned int bst_tlv[] = { - TLV_DB_RANGE_HEAD(7), +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(bst_tlv, 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), @@ -303,7 +302,7 @@ static unsigned int bst_tlv[] = { 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), -}; +); static const struct snd_kcontrol_new rt5616_snd_controls[] = { /* Headphone Output Volume */ @@ -1267,14 +1266,14 @@ static int rt5616_resume(struct snd_soc_codec *codec) #define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -struct snd_soc_dai_ops rt5616_aif_dai_ops = { +static struct snd_soc_dai_ops rt5616_aif_dai_ops = { .hw_params = rt5616_hw_params, .set_fmt = rt5616_set_dai_fmt, .set_sysclk = rt5616_set_dai_sysclk, .set_pll = rt5616_set_dai_pll, }; -struct snd_soc_dai_driver rt5616_dai[] = { +static struct snd_soc_dai_driver rt5616_dai[] = { { .name = "rt5616-aif1", .id = RT5616_AIF1, @@ -1302,12 +1301,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5616 = { .resume = rt5616_resume, .set_bias_level = rt5616_set_bias_level, .idle_bias_off = true, - .controls = rt5616_snd_controls, - .num_controls = ARRAY_SIZE(rt5616_snd_controls), - .dapm_widgets = rt5616_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rt5616_dapm_widgets), - .dapm_routes = rt5616_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rt5616_dapm_routes), + .component_driver = { + .controls = rt5616_snd_controls, + .num_controls = ARRAY_SIZE(rt5616_snd_controls), + .dapm_widgets = rt5616_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5616_dapm_widgets), + .dapm_routes = rt5616_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5616_dapm_routes), + }, }; static const struct regmap_config rt5616_regmap = { diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 1be2bab7dee3..0e418089c053 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1657,12 +1657,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5631 = { .probe = rt5631_probe, .set_bias_level = rt5631_set_bias_level, .suspend_bias_off = true, - .controls = rt5631_snd_controls, - .num_controls = ARRAY_SIZE(rt5631_snd_controls), - .dapm_widgets = rt5631_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rt5631_dapm_widgets), - .dapm_routes = rt5631_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rt5631_dapm_routes), + .component_driver = { + .controls = rt5631_snd_controls, + .num_controls = ARRAY_SIZE(rt5631_snd_controls), + .dapm_widgets = rt5631_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5631_dapm_widgets), + .dapm_routes = rt5631_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5631_dapm_routes), + }, }; static const struct i2c_device_id rt5631_i2c_id[] = { diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 09e8988bbb2d..3cc1135fc2cd 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1870,6 +1870,9 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, case RT5640_SCLK_S_PLL1: reg_val |= RT5640_SCLK_SRC_PLL1; break; + case RT5640_SCLK_S_RCCLK: + reg_val |= RT5640_SCLK_SRC_RCCLK; + break; default: dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); return -EINVAL; @@ -2261,12 +2264,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5640 = { .resume = rt5640_resume, .set_bias_level = rt5640_set_bias_level, .idle_bias_off = true, - .controls = rt5640_snd_controls, - .num_controls = ARRAY_SIZE(rt5640_snd_controls), - .dapm_widgets = rt5640_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rt5640_dapm_widgets), - .dapm_routes = rt5640_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rt5640_dapm_routes), + .component_driver = { + .controls = rt5640_snd_controls, + .num_controls = ARRAY_SIZE(rt5640_snd_controls), + .dapm_widgets = rt5640_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5640_dapm_widgets), + .dapm_routes = rt5640_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5640_dapm_routes), + }, }; static const struct regmap_config rt5640_regmap = { diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 58b664b06c16..90c88711c72a 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -984,6 +984,7 @@ #define RT5640_SCLK_SRC_SFT 14 #define RT5640_SCLK_SRC_MCLK (0x0 << 14) #define RT5640_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5640_SCLK_SRC_RCCLK (0x2 << 14) #define RT5640_PLL1_SRC_MASK (0x3 << 12) #define RT5640_PLL1_SRC_SFT 12 #define RT5640_PLL1_SRC_MCLK (0x0 << 12) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 490bfe661346..10c2a564a715 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3484,12 +3484,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5645 = { .resume = rt5645_resume, .set_bias_level = rt5645_set_bias_level, .idle_bias_off = true, - .controls = rt5645_snd_controls, - .num_controls = ARRAY_SIZE(rt5645_snd_controls), - .dapm_widgets = rt5645_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rt5645_dapm_widgets), - .dapm_routes = rt5645_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rt5645_dapm_routes), + .component_driver = { + .controls = rt5645_snd_controls, + .num_controls = ARRAY_SIZE(rt5645_snd_controls), + .dapm_widgets = rt5645_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5645_dapm_widgets), + .dapm_routes = rt5645_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5645_dapm_routes), + }, }; static const struct regmap_config rt5645_regmap = { diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 7a6197042423..f5d34153e21f 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1712,12 +1712,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5651 = { .resume = rt5651_resume, .set_bias_level = rt5651_set_bias_level, .idle_bias_off = true, - .controls = rt5651_snd_controls, - .num_controls = ARRAY_SIZE(rt5651_snd_controls), - .dapm_widgets = rt5651_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rt5651_dapm_widgets), - .dapm_routes = rt5651_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes), + .component_driver = { + .controls = rt5651_snd_controls, + .num_controls = ARRAY_SIZE(rt5651_snd_controls), + .dapm_widgets = rt5651_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5651_dapm_widgets), + .dapm_routes = rt5651_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes), + }, }; static const struct regmap_config rt5651_regmap = { diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index 1b30914c2d91..db54550aed60 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include <linux/clk.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -3565,7 +3566,9 @@ static int rt5659_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) static int rt5659_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + int ret; switch (level) { case SND_SOC_BIAS_PREPARE: @@ -3582,6 +3585,17 @@ static int rt5659_set_bias_level(struct snd_soc_codec *codec, RT5659_PWR_FV1 | RT5659_PWR_FV2); break; + case SND_SOC_BIAS_STANDBY: + if (dapm->bias_level == SND_SOC_BIAS_OFF) { + ret = clk_prepare_enable(rt5659->mclk); + if (ret) { + dev_err(codec->dev, + "failed to enable MCLK: %d\n", ret); + return ret; + } + } + break; + case SND_SOC_BIAS_OFF: regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1, RT5659_PWR_LDO, 0); @@ -3591,6 +3605,7 @@ static int rt5659_set_bias_level(struct snd_soc_codec *codec, RT5659_PWR_MB | RT5659_PWR_VREF2); regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC, RT5659_DIG_GATE_CTRL, 0); + clk_disable_unprepare(rt5659->mclk); break; default: @@ -3722,12 +3737,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5659 = { .resume = rt5659_resume, .set_bias_level = rt5659_set_bias_level, .idle_bias_off = true, - .controls = rt5659_snd_controls, - .num_controls = ARRAY_SIZE(rt5659_snd_controls), - .dapm_widgets = rt5659_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rt5659_dapm_widgets), - .dapm_routes = rt5659_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rt5659_dapm_routes), + .component_driver = { + .controls = rt5659_snd_controls, + .num_controls = ARRAY_SIZE(rt5659_snd_controls), + .dapm_widgets = rt5659_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5659_dapm_widgets), + .dapm_routes = rt5659_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5659_dapm_routes), + }, }; @@ -4020,6 +4037,15 @@ static int rt5659_i2c_probe(struct i2c_client *i2c, regmap_write(rt5659->regmap, RT5659_RESET, 0); + /* Check if MCLK provided */ + rt5659->mclk = devm_clk_get(&i2c->dev, "mclk"); + if (IS_ERR(rt5659->mclk)) { + if (PTR_ERR(rt5659->mclk) != -ENOENT) + return PTR_ERR(rt5659->mclk); + /* Otherwise mark the mclk pointer to NULL */ + rt5659->mclk = NULL; + } + rt5659_calibrate(rt5659); /* line in diff mode*/ @@ -4163,6 +4189,9 @@ static int rt5659_i2c_probe(struct i2c_client *i2c, if (ret) dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); + /* Enable IRQ output for GPIO1 pin any way */ + regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1, + RT5659_GP1_PIN_MASK, RT5659_GP1_PIN_IRQ); } return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659, diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h index d31c9e5bcec8..8f1aeef08489 100644 --- a/sound/soc/codecs/rt5659.h +++ b/sound/soc/codecs/rt5659.h @@ -180,9 +180,9 @@ #define RT5659_IRQ_CTRL_1 0x00b6 #define RT5659_IRQ_CTRL_2 0x00b7 #define RT5659_IRQ_CTRL_3 0x00b8 -#define RT5659_IRQ_CTRL_4 0x00b9 -#define RT5659_IRQ_CTRL_5 0x00ba -#define RT5659_IRQ_CTRL_6 0x00bb +#define RT5659_IRQ_CTRL_4 0x00ba +#define RT5659_IRQ_CTRL_5 0x00bb +#define RT5659_IRQ_CTRL_6 0x00bc #define RT5659_INT_ST_1 0x00be #define RT5659_INT_ST_2 0x00bf #define RT5659_GPIO_CTRL_1 0x00c0 @@ -1796,6 +1796,7 @@ struct rt5659_priv { struct gpio_desc *gpiod_reset; struct snd_soc_jack *hs_jack; struct delayed_work jack_detect_work; + struct clk *mclk; int sysclk; int sysclk_src; diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c new file mode 100644 index 000000000000..9f0933ced804 --- /dev/null +++ b/sound/soc/codecs/rt5660.c @@ -0,0 +1,1353 @@ +/* + * rt5660.c -- RT5660 ALSA SoC audio codec driver + * + * Copyright 2016 Realtek Semiconductor Corp. + * Author: Oder Chiou <oder_chiou@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/acpi.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "rl6231.h" +#include "rt5660.h" + +#define RT5660_DEVICE_ID 0x6338 + +#define RT5660_PR_RANGE_BASE (0xff + 1) +#define RT5660_PR_SPACING 0x100 + +#define RT5660_PR_BASE (RT5660_PR_RANGE_BASE + (0 * RT5660_PR_SPACING)) + +static const struct regmap_range_cfg rt5660_ranges[] = { + { .name = "PR", .range_min = RT5660_PR_BASE, + .range_max = RT5660_PR_BASE + 0xf3, + .selector_reg = RT5660_PRIV_INDEX, + .selector_mask = 0xff, + .selector_shift = 0x0, + .window_start = RT5660_PRIV_DATA, + .window_len = 0x1, }, +}; + +static const struct reg_sequence rt5660_patch[] = { + { RT5660_ALC_PGA_CTRL2, 0x44c3 }, + { RT5660_PR_BASE + 0x3d, 0x2600 }, +}; + +static const struct reg_default rt5660_reg[] = { + { 0x00, 0x0000 }, + { 0x01, 0xc800 }, + { 0x02, 0xc8c8 }, + { 0x0d, 0x1010 }, + { 0x0e, 0x1010 }, + { 0x19, 0xafaf }, + { 0x1c, 0x2f2f }, + { 0x1e, 0x0000 }, + { 0x27, 0x6060 }, + { 0x29, 0x8080 }, + { 0x2a, 0x4242 }, + { 0x2f, 0x0000 }, + { 0x3b, 0x0000 }, + { 0x3c, 0x007f }, + { 0x3d, 0x0000 }, + { 0x3e, 0x007f }, + { 0x45, 0xe000 }, + { 0x46, 0x003e }, + { 0x48, 0xf800 }, + { 0x4a, 0x0004 }, + { 0x4d, 0x0000 }, + { 0x4e, 0x0000 }, + { 0x4f, 0x01ff }, + { 0x50, 0x0000 }, + { 0x51, 0x0000 }, + { 0x52, 0x01ff }, + { 0x61, 0x0000 }, + { 0x62, 0x0000 }, + { 0x63, 0x00c0 }, + { 0x64, 0x0000 }, + { 0x65, 0x0000 }, + { 0x66, 0x0000 }, + { 0x70, 0x8000 }, + { 0x73, 0x7000 }, + { 0x74, 0x3c00 }, + { 0x75, 0x2800 }, + { 0x80, 0x0000 }, + { 0x81, 0x0000 }, + { 0x82, 0x0000 }, + { 0x8c, 0x0228 }, + { 0x8d, 0xa000 }, + { 0x8e, 0x0000 }, + { 0x92, 0x0000 }, + { 0x93, 0x3000 }, + { 0xa1, 0x0059 }, + { 0xa2, 0x0001 }, + { 0xa3, 0x5c80 }, + { 0xa4, 0x0146 }, + { 0xa5, 0x1f1f }, + { 0xa6, 0x78c6 }, + { 0xa7, 0xe5ec }, + { 0xa8, 0xba61 }, + { 0xa9, 0x3c78 }, + { 0xaa, 0x8ae2 }, + { 0xab, 0xe5ec }, + { 0xac, 0xc600 }, + { 0xad, 0xba61 }, + { 0xae, 0x17ed }, + { 0xb0, 0x2080 }, + { 0xb1, 0x0000 }, + { 0xb3, 0x001f }, + { 0xb4, 0x020c }, + { 0xb5, 0x1f00 }, + { 0xb6, 0x0000 }, + { 0xb7, 0x4000 }, + { 0xbb, 0x0000 }, + { 0xbd, 0x0000 }, + { 0xbe, 0x0000 }, + { 0xbf, 0x0100 }, + { 0xc0, 0x0000 }, + { 0xc2, 0x0000 }, + { 0xd3, 0xa220 }, + { 0xd9, 0x0809 }, + { 0xda, 0x0000 }, + { 0xe0, 0x8000 }, + { 0xe1, 0x0200 }, + { 0xe2, 0x8000 }, + { 0xe3, 0x0200 }, + { 0xe4, 0x0f20 }, + { 0xe5, 0x001f }, + { 0xe6, 0x020c }, + { 0xe7, 0x1f00 }, + { 0xe8, 0x0000 }, + { 0xe9, 0x4000 }, + { 0xea, 0x00a6 }, + { 0xeb, 0x04c3 }, + { 0xec, 0x27c8 }, + { 0xed, 0x7418 }, + { 0xee, 0xbf50 }, + { 0xef, 0x0045 }, + { 0xf0, 0x0007 }, + { 0xfa, 0x0000 }, + { 0xfd, 0x0000 }, + { 0xfe, 0x10ec }, + { 0xff, 0x6338 }, +}; + +static bool rt5660_volatile_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5660_ranges); i++) + if ((reg >= rt5660_ranges[i].window_start && + reg <= rt5660_ranges[i].window_start + + rt5660_ranges[i].window_len) || + (reg >= rt5660_ranges[i].range_min && + reg <= rt5660_ranges[i].range_max)) + return true; + + switch (reg) { + case RT5660_RESET: + case RT5660_PRIV_DATA: + case RT5660_EQ_CTRL1: + case RT5660_IRQ_CTRL2: + case RT5660_INT_IRQ_ST: + case RT5660_VENDOR_ID: + case RT5660_VENDOR_ID1: + case RT5660_VENDOR_ID2: + return true; + default: + return false; + } +} + +static bool rt5660_readable_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5660_ranges); i++) + if ((reg >= rt5660_ranges[i].window_start && + reg <= rt5660_ranges[i].window_start + + rt5660_ranges[i].window_len) || + (reg >= rt5660_ranges[i].range_min && + reg <= rt5660_ranges[i].range_max)) + return true; + + switch (reg) { + case RT5660_RESET: + case RT5660_SPK_VOL: + case RT5660_LOUT_VOL: + case RT5660_IN1_IN2: + case RT5660_IN3_IN4: + case RT5660_DAC1_DIG_VOL: + case RT5660_STO1_ADC_DIG_VOL: + case RT5660_ADC_BST_VOL1: + case RT5660_STO1_ADC_MIXER: + case RT5660_AD_DA_MIXER: + case RT5660_STO_DAC_MIXER: + case RT5660_DIG_INF1_DATA: + case RT5660_REC_L1_MIXER: + case RT5660_REC_L2_MIXER: + case RT5660_REC_R1_MIXER: + case RT5660_REC_R2_MIXER: + case RT5660_LOUT_MIXER: + case RT5660_SPK_MIXER: + case RT5660_SPO_MIXER: + case RT5660_SPO_CLSD_RATIO: + case RT5660_OUT_L_GAIN1: + case RT5660_OUT_L_GAIN2: + case RT5660_OUT_L1_MIXER: + case RT5660_OUT_R_GAIN1: + case RT5660_OUT_R_GAIN2: + case RT5660_OUT_R1_MIXER: + case RT5660_PWR_DIG1: + case RT5660_PWR_DIG2: + case RT5660_PWR_ANLG1: + case RT5660_PWR_ANLG2: + case RT5660_PWR_MIXER: + case RT5660_PWR_VOL: + case RT5660_PRIV_INDEX: + case RT5660_PRIV_DATA: + case RT5660_I2S1_SDP: + case RT5660_ADDA_CLK1: + case RT5660_ADDA_CLK2: + case RT5660_DMIC_CTRL1: + case RT5660_GLB_CLK: + case RT5660_PLL_CTRL1: + case RT5660_PLL_CTRL2: + case RT5660_CLSD_AMP_OC_CTRL: + case RT5660_CLSD_AMP_CTRL: + case RT5660_LOUT_AMP_CTRL: + case RT5660_SPK_AMP_SPKVDD: + case RT5660_MICBIAS: + case RT5660_CLSD_OUT_CTRL1: + case RT5660_CLSD_OUT_CTRL2: + case RT5660_DIPOLE_MIC_CTRL1: + case RT5660_DIPOLE_MIC_CTRL2: + case RT5660_DIPOLE_MIC_CTRL3: + case RT5660_DIPOLE_MIC_CTRL4: + case RT5660_DIPOLE_MIC_CTRL5: + case RT5660_DIPOLE_MIC_CTRL6: + case RT5660_DIPOLE_MIC_CTRL7: + case RT5660_DIPOLE_MIC_CTRL8: + case RT5660_DIPOLE_MIC_CTRL9: + case RT5660_DIPOLE_MIC_CTRL10: + case RT5660_DIPOLE_MIC_CTRL11: + case RT5660_DIPOLE_MIC_CTRL12: + case RT5660_EQ_CTRL1: + case RT5660_EQ_CTRL2: + case RT5660_DRC_AGC_CTRL1: + case RT5660_DRC_AGC_CTRL2: + case RT5660_DRC_AGC_CTRL3: + case RT5660_DRC_AGC_CTRL4: + case RT5660_DRC_AGC_CTRL5: + case RT5660_JD_CTRL: + case RT5660_IRQ_CTRL1: + case RT5660_IRQ_CTRL2: + case RT5660_INT_IRQ_ST: + case RT5660_GPIO_CTRL1: + case RT5660_GPIO_CTRL2: + case RT5660_WIND_FILTER_CTRL1: + case RT5660_SV_ZCD1: + case RT5660_SV_ZCD2: + case RT5660_DRC1_LM_CTRL1: + case RT5660_DRC1_LM_CTRL2: + case RT5660_DRC2_LM_CTRL1: + case RT5660_DRC2_LM_CTRL2: + case RT5660_MULTI_DRC_CTRL: + case RT5660_DRC2_CTRL1: + case RT5660_DRC2_CTRL2: + case RT5660_DRC2_CTRL3: + case RT5660_DRC2_CTRL4: + case RT5660_DRC2_CTRL5: + case RT5660_ALC_PGA_CTRL1: + case RT5660_ALC_PGA_CTRL2: + case RT5660_ALC_PGA_CTRL3: + case RT5660_ALC_PGA_CTRL4: + case RT5660_ALC_PGA_CTRL5: + case RT5660_ALC_PGA_CTRL6: + case RT5660_ALC_PGA_CTRL7: + case RT5660_GEN_CTRL1: + case RT5660_GEN_CTRL2: + case RT5660_GEN_CTRL3: + case RT5660_VENDOR_ID: + case RT5660_VENDOR_ID1: + case RT5660_VENDOR_ID2: + return true; + default: + return false; + } +} + +static const DECLARE_TLV_DB_SCALE(rt5660_out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(rt5660_dac_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(rt5660_adc_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(rt5660_adc_bst_tlv, 0, 1200, 0); +static const DECLARE_TLV_DB_SCALE(rt5660_bst_tlv, -1200, 75, 0); + +static const struct snd_kcontrol_new rt5660_snd_controls[] = { + /* Speaker Output Volume */ + SOC_SINGLE("Speaker Playback Switch", RT5660_SPK_VOL, RT5660_L_MUTE_SFT, + 1, 1), + SOC_SINGLE_TLV("Speaker Playback Volume", RT5660_SPK_VOL, + RT5660_L_VOL_SFT, 39, 1, rt5660_out_vol_tlv), + + /* OUTPUT Control */ + SOC_DOUBLE("OUT Playback Switch", RT5660_LOUT_VOL, RT5660_L_MUTE_SFT, + RT5660_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("OUT Playback Volume", RT5660_LOUT_VOL, RT5660_L_VOL_SFT, + RT5660_R_VOL_SFT, 39, 1, rt5660_out_vol_tlv), + + /* DAC Digital Volume */ + SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5660_DAC1_DIG_VOL, + RT5660_DAC_L1_VOL_SFT, RT5660_DAC_R1_VOL_SFT, 87, 0, + rt5660_dac_vol_tlv), + + /* IN1/IN2/IN3 Control */ + SOC_SINGLE_TLV("IN1 Boost Volume", RT5660_IN1_IN2, RT5660_BST_SFT1, 69, + 0, rt5660_bst_tlv), + SOC_SINGLE_TLV("IN2 Boost Volume", RT5660_IN1_IN2, RT5660_BST_SFT2, 69, + 0, rt5660_bst_tlv), + SOC_SINGLE_TLV("IN3 Boost Volume", RT5660_IN3_IN4, RT5660_BST_SFT3, 69, + 0, rt5660_bst_tlv), + + /* ADC Digital Volume Control */ + SOC_DOUBLE("ADC Capture Switch", RT5660_STO1_ADC_DIG_VOL, + RT5660_L_MUTE_SFT, RT5660_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("ADC Capture Volume", RT5660_STO1_ADC_DIG_VOL, + RT5660_ADC_L_VOL_SFT, RT5660_ADC_R_VOL_SFT, 63, 0, + rt5660_adc_vol_tlv), + + /* ADC Boost Volume Control */ + SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5660_ADC_BST_VOL1, + RT5660_STO1_ADC_L_BST_SFT, RT5660_STO1_ADC_R_BST_SFT, 3, 0, + rt5660_adc_bst_tlv), +}; + +/** + * rt5660_set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + */ +static int rt5660_set_dmic_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + int idx, rate; + + rate = rt5660->sysclk / rl6231_get_pre_div(rt5660->regmap, + RT5660_ADDA_CLK1, RT5660_I2S_PD1_SFT); + idx = rl6231_calc_dmic_clk(rate); + if (idx < 0) + dev_err(codec->dev, "Failed to set DMIC clock\n"); + else + snd_soc_update_bits(codec, RT5660_DMIC_CTRL1, + RT5660_DMIC_CLK_MASK, idx << RT5660_DMIC_CLK_SFT); + + return idx; +} + +static int rt5660_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + unsigned int val; + + val = snd_soc_read(codec, RT5660_GLB_CLK); + val &= RT5660_SCLK_SRC_MASK; + if (val == RT5660_SCLK_SRC_PLL1) + return 1; + else + return 0; +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5660_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5660_STO1_ADC_MIXER, + RT5660_M_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5660_STO1_ADC_MIXER, + RT5660_M_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5660_STO1_ADC_MIXER, + RT5660_M_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5660_STO1_ADC_MIXER, + RT5660_M_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_dac_l_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5660_AD_DA_MIXER, + RT5660_M_ADCMIX_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5660_AD_DA_MIXER, + RT5660_M_DAC1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_dac_r_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5660_AD_DA_MIXER, + RT5660_M_ADCMIX_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5660_AD_DA_MIXER, + RT5660_M_DAC1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_sto_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5660_STO_DAC_MIXER, + RT5660_M_DAC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5660_STO_DAC_MIXER, + RT5660_M_DAC_R1_STO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_sto_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5660_STO_DAC_MIXER, + RT5660_M_DAC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5660_STO_DAC_MIXER, + RT5660_M_DAC_L1_STO_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5660_rec_l_mix[] = { + SOC_DAPM_SINGLE("BST3 Switch", RT5660_REC_L2_MIXER, + RT5660_M_BST3_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5660_REC_L2_MIXER, + RT5660_M_BST2_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5660_REC_L2_MIXER, + RT5660_M_BST1_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("OUT MIXL Switch", RT5660_REC_L2_MIXER, + RT5660_M_OM_L_RM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_rec_r_mix[] = { + SOC_DAPM_SINGLE("BST3 Switch", RT5660_REC_R2_MIXER, + RT5660_M_BST3_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5660_REC_R2_MIXER, + RT5660_M_BST2_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5660_REC_R2_MIXER, + RT5660_M_BST1_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("OUT MIXR Switch", RT5660_REC_R2_MIXER, + RT5660_M_OM_R_RM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_spk_mix[] = { + SOC_DAPM_SINGLE("BST3 Switch", RT5660_SPK_MIXER, + RT5660_M_BST3_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5660_SPK_MIXER, + RT5660_M_BST1_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("DACL Switch", RT5660_SPK_MIXER, + RT5660_M_DACL_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("DACR Switch", RT5660_SPK_MIXER, + RT5660_M_DACR_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTMIXL Switch", RT5660_SPK_MIXER, + RT5660_M_OM_L_SM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_out_l_mix[] = { + SOC_DAPM_SINGLE("BST3 Switch", RT5660_OUT_L1_MIXER, + RT5660_M_BST3_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5660_OUT_L1_MIXER, + RT5660_M_BST2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5660_OUT_L1_MIXER, + RT5660_M_BST1_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("RECMIXL Switch", RT5660_OUT_L1_MIXER, + RT5660_M_RM_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DACR Switch", RT5660_OUT_L1_MIXER, + RT5660_M_DAC_R_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DACL Switch", RT5660_OUT_L1_MIXER, + RT5660_M_DAC_L_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_out_r_mix[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5660_OUT_R1_MIXER, + RT5660_M_BST2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5660_OUT_R1_MIXER, + RT5660_M_BST1_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("RECMIXR Switch", RT5660_OUT_R1_MIXER, + RT5660_M_RM_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DACR Switch", RT5660_OUT_R1_MIXER, + RT5660_M_DAC_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DACL Switch", RT5660_OUT_R1_MIXER, + RT5660_M_DAC_L_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_spo_mix[] = { + SOC_DAPM_SINGLE("DACR Switch", RT5660_SPO_MIXER, + RT5660_M_DAC_R_SPM_SFT, 1, 1), + SOC_DAPM_SINGLE("DACL Switch", RT5660_SPO_MIXER, + RT5660_M_DAC_L_SPM_SFT, 1, 1), + SOC_DAPM_SINGLE("SPKVOL Switch", RT5660_SPO_MIXER, + RT5660_M_SV_SPM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5660_SPO_MIXER, + RT5660_M_BST1_SPM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_lout_mix[] = { + SOC_DAPM_SINGLE("DAC Switch", RT5660_LOUT_MIXER, + RT5660_M_DAC1_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTMIX Switch", RT5660_LOUT_MIXER, + RT5660_M_LOVOL_LM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new spk_vol_control = + SOC_DAPM_SINGLE("Switch", RT5660_SPK_VOL, + RT5660_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_l_vol_control = + SOC_DAPM_SINGLE("Switch", RT5660_LOUT_VOL, + RT5660_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_r_vol_control = + SOC_DAPM_SINGLE("Switch", RT5660_LOUT_VOL, + RT5660_VOL_R_SFT, 1, 1); + +/* Interface data select */ +static const char * const rt5660_data_select[] = { + "L/R", "R/L", "L/L", "R/R" +}; + +static const SOC_ENUM_SINGLE_DECL(rt5660_if1_dac_enum, + RT5660_DIG_INF1_DATA, RT5660_IF1_DAC_IN_SFT, rt5660_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5660_if1_adc_enum, + RT5660_DIG_INF1_DATA, RT5660_IF1_ADC_IN_SFT, rt5660_data_select); + +static const struct snd_kcontrol_new rt5660_if1_dac_swap_mux = + SOC_DAPM_ENUM("IF1 DAC Swap Source", rt5660_if1_dac_enum); + +static const struct snd_kcontrol_new rt5660_if1_adc_swap_mux = + SOC_DAPM_ENUM("IF1 ADC Swap Source", rt5660_if1_adc_enum); + +static int rt5660_lout_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5660_LOUT_AMP_CTRL, + RT5660_LOUT_CO_MASK | RT5660_LOUT_CB_MASK, + RT5660_LOUT_CO_EN | RT5660_LOUT_CB_PU); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5660_LOUT_AMP_CTRL, + RT5660_LOUT_CO_MASK | RT5660_LOUT_CB_MASK, + RT5660_LOUT_CO_DIS | RT5660_LOUT_CB_PD); + break; + + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt5660_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("LDO2", RT5660_PWR_ANLG1, + RT5660_PWR_LDO2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL1", RT5660_PWR_ANLG2, + RT5660_PWR_PLL_BIT, 0, NULL, 0), + + /* MICBIAS */ + SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5660_PWR_ANLG2, + RT5660_PWR_MB1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5660_PWR_ANLG2, + RT5660_PWR_MB2_BIT, 0, NULL, 0), + + /* Input Side */ + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC L1"), + SND_SOC_DAPM_INPUT("DMIC R1"), + + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN1N"), + SND_SOC_DAPM_INPUT("IN2P"), + SND_SOC_DAPM_INPUT("IN3P"), + SND_SOC_DAPM_INPUT("IN3N"), + + SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, + rt5660_set_dmic_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("DMIC Power", RT5660_DMIC_CTRL1, + RT5660_DMIC_1_EN_SFT, 0, NULL, 0), + + /* Boost */ + SND_SOC_DAPM_PGA("BST1", RT5660_PWR_ANLG2, RT5660_PWR_BST1_BIT, 0, + NULL, 0), + SND_SOC_DAPM_PGA("BST2", RT5660_PWR_ANLG2, RT5660_PWR_BST2_BIT, 0, + NULL, 0), + SND_SOC_DAPM_PGA("BST3", RT5660_PWR_ANLG2, RT5660_PWR_BST3_BIT, 0, + NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIXL", RT5660_PWR_MIXER, RT5660_PWR_RM_L_BIT, + 0, rt5660_rec_l_mix, ARRAY_SIZE(rt5660_rec_l_mix)), + SND_SOC_DAPM_MIXER("RECMIXR", RT5660_PWR_MIXER, RT5660_PWR_RM_R_BIT, + 0, rt5660_rec_r_mix, ARRAY_SIZE(rt5660_rec_r_mix)), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("ADC L power", RT5660_PWR_DIG1, + RT5660_PWR_ADC_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC R power", RT5660_PWR_DIG1, + RT5660_PWR_ADC_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC clock", RT5660_PR_BASE + RT5660_CHOP_DAC_ADC, + 12, 0, NULL, 0), + + /* ADC Mixer */ + SND_SOC_DAPM_SUPPLY("adc stereo1 filter", RT5660_PWR_DIG2, + RT5660_PWR_ADC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5660_sto1_adc_l_mix, ARRAY_SIZE(rt5660_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5660_sto1_adc_r_mix, ARRAY_SIZE(rt5660_sto1_adc_r_mix)), + + /* ADC */ + SND_SOC_DAPM_ADC("Stereo1 ADC MIXL", NULL, RT5660_STO1_ADC_DIG_VOL, + RT5660_L_MUTE_SFT, 1), + SND_SOC_DAPM_ADC("Stereo1 ADC MIXR", NULL, RT5660_STO1_ADC_DIG_VOL, + RT5660_R_MUTE_SFT, 1), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S1", RT5660_PWR_DIG1, RT5660_PWR_I2S1_BIT, 0, + NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX("IF1 DAC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5660_if1_dac_swap_mux), + SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX("IF1 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5660_if1_adc_swap_mux), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Output Side */ + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, rt5660_dac_l_mix, + ARRAY_SIZE(rt5660_dac_l_mix)), + SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, rt5660_dac_r_mix, + ARRAY_SIZE(rt5660_dac_r_mix)), + + /* DAC Mixer */ + SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5660_PWR_DIG2, + RT5660_PWR_DAC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5660_sto_dac_l_mix, ARRAY_SIZE(rt5660_sto_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5660_sto_dac_r_mix, ARRAY_SIZE(rt5660_sto_dac_r_mix)), + + /* DACs */ + SND_SOC_DAPM_DAC("DAC L1", NULL, RT5660_PWR_DIG1, + RT5660_PWR_DAC_L1_BIT, 0), + SND_SOC_DAPM_DAC("DAC R1", NULL, RT5660_PWR_DIG1, + RT5660_PWR_DAC_R1_BIT, 0), + + /* OUT Mixer */ + SND_SOC_DAPM_MIXER("SPK MIX", RT5660_PWR_MIXER, RT5660_PWR_SM_BIT, + 0, rt5660_spk_mix, ARRAY_SIZE(rt5660_spk_mix)), + SND_SOC_DAPM_MIXER("OUT MIXL", RT5660_PWR_MIXER, RT5660_PWR_OM_L_BIT, + 0, rt5660_out_l_mix, ARRAY_SIZE(rt5660_out_l_mix)), + SND_SOC_DAPM_MIXER("OUT MIXR", RT5660_PWR_MIXER, RT5660_PWR_OM_R_BIT, + 0, rt5660_out_r_mix, ARRAY_SIZE(rt5660_out_r_mix)), + + /* Output Volume */ + SND_SOC_DAPM_SWITCH("SPKVOL", RT5660_PWR_VOL, + RT5660_PWR_SV_BIT, 0, &spk_vol_control), + SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("LOUTVOL", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_SWITCH("LOUTVOL L", SND_SOC_NOPM, + RT5660_PWR_LV_L_BIT, 0, &lout_l_vol_control), + SND_SOC_DAPM_SWITCH("LOUTVOL R", SND_SOC_NOPM, + RT5660_PWR_LV_R_BIT, 0, &lout_r_vol_control), + + /* HPO/LOUT/Mono Mixer */ + SND_SOC_DAPM_MIXER("SPO MIX", SND_SOC_NOPM, 0, + 0, rt5660_spo_mix, ARRAY_SIZE(rt5660_spo_mix)), + SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0, + rt5660_lout_mix, ARRAY_SIZE(rt5660_lout_mix)), + SND_SOC_DAPM_SUPPLY("VREF HP", RT5660_GEN_CTRL1, + RT5660_PWR_VREF_HP_SFT, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("LOUT amp", 1, RT5660_PWR_ANLG1, + RT5660_PWR_HA_BIT, 0, rt5660_lout_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("SPK amp", 1, RT5660_PWR_DIG1, + RT5660_PWR_CLS_D_BIT, 0, NULL, 0), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("LOUTL"), + SND_SOC_DAPM_OUTPUT("LOUTR"), + SND_SOC_DAPM_OUTPUT("SPO"), +}; + +static const struct snd_soc_dapm_route rt5660_dapm_routes[] = { + { "MICBIAS1", NULL, "LDO2" }, + { "MICBIAS2", NULL, "LDO2" }, + + { "BST1", NULL, "IN1P" }, + { "BST1", NULL, "IN1N" }, + { "BST2", NULL, "IN2P" }, + { "BST3", NULL, "IN3P" }, + { "BST3", NULL, "IN3N" }, + + { "RECMIXL", "BST3 Switch", "BST3" }, + { "RECMIXL", "BST2 Switch", "BST2" }, + { "RECMIXL", "BST1 Switch", "BST1" }, + { "RECMIXL", "OUT MIXL Switch", "OUT MIXL" }, + + { "RECMIXR", "BST3 Switch", "BST3" }, + { "RECMIXR", "BST2 Switch", "BST2" }, + { "RECMIXR", "BST1 Switch", "BST1" }, + { "RECMIXR", "OUT MIXR Switch", "OUT MIXR" }, + + { "ADC L", NULL, "RECMIXL" }, + { "ADC L", NULL, "ADC L power" }, + { "ADC L", NULL, "ADC clock" }, + { "ADC R", NULL, "RECMIXR" }, + { "ADC R", NULL, "ADC R power" }, + { "ADC R", NULL, "ADC clock" }, + + {"DMIC L1", NULL, "DMIC CLK"}, + {"DMIC L1", NULL, "DMIC Power"}, + {"DMIC R1", NULL, "DMIC CLK"}, + {"DMIC R1", NULL, "DMIC Power"}, + + { "Sto1 ADC MIXL", "ADC1 Switch", "ADC L" }, + { "Sto1 ADC MIXL", "ADC2 Switch", "DMIC L1" }, + { "Sto1 ADC MIXR", "ADC1 Switch", "ADC R" }, + { "Sto1 ADC MIXR", "ADC2 Switch", "DMIC R1" }, + + { "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" }, + { "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" }, + { "adc stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll }, + + { "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" }, + { "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" }, + { "adc stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll }, + + { "IF1 ADC", NULL, "Stereo1 ADC MIXL" }, + { "IF1 ADC", NULL, "Stereo1 ADC MIXR" }, + { "IF1 ADC", NULL, "I2S1" }, + + { "IF1 ADC Swap Mux", "L/R", "IF1 ADC" }, + { "IF1 ADC Swap Mux", "R/L", "IF1 ADC" }, + { "IF1 ADC Swap Mux", "L/L", "IF1 ADC" }, + { "IF1 ADC Swap Mux", "R/R", "IF1 ADC" }, + { "AIF1TX", NULL, "IF1 ADC Swap Mux" }, + + { "IF1 DAC", NULL, "AIF1RX" }, + { "IF1 DAC", NULL, "I2S1" }, + + { "IF1 DAC Swap Mux", "L/R", "IF1 DAC" }, + { "IF1 DAC Swap Mux", "R/L", "IF1 DAC" }, + { "IF1 DAC Swap Mux", "L/L", "IF1 DAC" }, + { "IF1 DAC Swap Mux", "R/R", "IF1 DAC" }, + + { "IF1 DAC L", NULL, "IF1 DAC Swap Mux" }, + { "IF1 DAC R", NULL, "IF1 DAC Swap Mux" }, + + { "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" }, + { "DAC1 MIXL", "DAC1 Switch", "IF1 DAC L" }, + { "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR" }, + { "DAC1 MIXR", "DAC1 Switch", "IF1 DAC R" }, + + { "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" }, + { "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" }, + { "Stereo DAC MIXL", NULL, "dac stereo1 filter" }, + { "dac stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll }, + { "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" }, + { "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" }, + { "Stereo DAC MIXR", NULL, "dac stereo1 filter" }, + { "dac stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll }, + + { "DAC L1", NULL, "Stereo DAC MIXL" }, + { "DAC R1", NULL, "Stereo DAC MIXR" }, + + { "SPK MIX", "BST3 Switch", "BST3" }, + { "SPK MIX", "BST1 Switch", "BST1" }, + { "SPK MIX", "DACL Switch", "DAC L1" }, + { "SPK MIX", "DACR Switch", "DAC R1" }, + { "SPK MIX", "OUTMIXL Switch", "OUT MIXL" }, + + { "OUT MIXL", "BST3 Switch", "BST3" }, + { "OUT MIXL", "BST2 Switch", "BST2" }, + { "OUT MIXL", "BST1 Switch", "BST1" }, + { "OUT MIXL", "RECMIXL Switch", "RECMIXL" }, + { "OUT MIXL", "DACR Switch", "DAC R1" }, + { "OUT MIXL", "DACL Switch", "DAC L1" }, + + { "OUT MIXR", "BST2 Switch", "BST2" }, + { "OUT MIXR", "BST1 Switch", "BST1" }, + { "OUT MIXR", "RECMIXR Switch", "RECMIXR" }, + { "OUT MIXR", "DACR Switch", "DAC R1" }, + { "OUT MIXR", "DACL Switch", "DAC L1" }, + + { "SPO MIX", "DACR Switch", "DAC R1" }, + { "SPO MIX", "DACL Switch", "DAC L1" }, + { "SPO MIX", "SPKVOL Switch", "SPKVOL" }, + { "SPO MIX", "BST1 Switch", "BST1" }, + + { "SPKVOL", "Switch", "SPK MIX" }, + { "LOUTVOL L", "Switch", "OUT MIXL" }, + { "LOUTVOL R", "Switch", "OUT MIXR" }, + + { "LOUTVOL", NULL, "LOUTVOL L" }, + { "LOUTVOL", NULL, "LOUTVOL R" }, + + { "DAC 1", NULL, "DAC L1" }, + { "DAC 1", NULL, "DAC R1" }, + + { "LOUT MIX", "DAC Switch", "DAC 1" }, + { "LOUT MIX", "OUTMIX Switch", "LOUTVOL" }, + + { "LOUT amp", NULL, "LOUT MIX" }, + { "LOUT amp", NULL, "VREF HP" }, + { "LOUTL", NULL, "LOUT amp" }, + { "LOUTR", NULL, "LOUT amp" }, + + { "SPK amp", NULL, "SPO MIX" }, + { "SPO", NULL, "SPK amp" }, +}; + +static int rt5660_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + unsigned int val_len = 0, val_clk, mask_clk; + int pre_div, bclk_ms, frame_size; + + rt5660->lrck[dai->id] = params_rate(params); + pre_div = rl6231_get_clk_info(rt5660->sysclk, rt5660->lrck[dai->id]); + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", + rt5660->lrck[dai->id], dai->id); + return -EINVAL; + } + + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); + return frame_size; + } + + if (frame_size > 32) + bclk_ms = 1; + else + bclk_ms = 0; + + rt5660->bclk[dai->id] = rt5660->lrck[dai->id] * (32 << bclk_ms); + + dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n", + rt5660->bclk[dai->id], rt5660->lrck[dai->id]); + dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", + bclk_ms, pre_div, dai->id); + + switch (params_width(params)) { + case 16: + break; + case 20: + val_len |= RT5660_I2S_DL_20; + break; + case 24: + val_len |= RT5660_I2S_DL_24; + break; + case 8: + val_len |= RT5660_I2S_DL_8; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5660_AIF1: + mask_clk = RT5660_I2S_BCLK_MS1_MASK | RT5660_I2S_PD1_MASK; + val_clk = bclk_ms << RT5660_I2S_BCLK_MS1_SFT | + pre_div << RT5660_I2S_PD1_SFT; + snd_soc_update_bits(codec, RT5660_I2S1_SDP, RT5660_I2S_DL_MASK, + val_len); + snd_soc_update_bits(codec, RT5660_ADDA_CLK1, mask_clk, val_clk); + break; + + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + + return 0; +} + +static int rt5660_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + rt5660->master[dai->id] = 1; + break; + + case SND_SOC_DAIFMT_CBS_CFS: + reg_val |= RT5660_I2S_MS_S; + rt5660->master[dai->id] = 0; + break; + + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5660_I2S_BP_INV; + break; + + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5660_I2S_DF_LEFT; + break; + + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5660_I2S_DF_PCM_A; + break; + + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5660_I2S_DF_PCM_B; + break; + + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5660_AIF1: + snd_soc_update_bits(codec, RT5660_I2S1_SDP, + RT5660_I2S_MS_MASK | RT5660_I2S_BP_MASK | + RT5660_I2S_DF_MASK, reg_val); + break; + + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + + return 0; +} + +static int rt5660_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5660->sysclk && clk_id == rt5660->sysclk_src) + return 0; + + switch (clk_id) { + case RT5660_SCLK_S_MCLK: + reg_val |= RT5660_SCLK_SRC_MCLK; + break; + + case RT5660_SCLK_S_PLL1: + reg_val |= RT5660_SCLK_SRC_PLL1; + break; + + case RT5660_SCLK_S_RCCLK: + reg_val |= RT5660_SCLK_SRC_RCCLK; + break; + + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5660_GLB_CLK, RT5660_SCLK_SRC_MASK, + reg_val); + + rt5660->sysclk = freq; + rt5660->sysclk_src = clk_id; + + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + + return 0; +} + +static int rt5660_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + struct rl6231_pll_code pll_code; + int ret; + + if (source == rt5660->pll_src && freq_in == rt5660->pll_in && + freq_out == rt5660->pll_out) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5660->pll_in = 0; + rt5660->pll_out = 0; + snd_soc_update_bits(codec, RT5660_GLB_CLK, + RT5660_SCLK_SRC_MASK, RT5660_SCLK_SRC_MCLK); + return 0; + } + + switch (source) { + case RT5660_PLL1_S_MCLK: + snd_soc_update_bits(codec, RT5660_GLB_CLK, + RT5660_PLL1_SRC_MASK, RT5660_PLL1_SRC_MCLK); + break; + + case RT5660_PLL1_S_BCLK: + snd_soc_update_bits(codec, RT5660_GLB_CLK, + RT5660_PLL1_SRC_MASK, RT5660_PLL1_SRC_BCLK1); + break; + + default: + dev_err(codec->dev, "Unknown PLL source %d\n", source); + return -EINVAL; + } + + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), + pll_code.n_code, pll_code.k_code); + + snd_soc_write(codec, RT5660_PLL_CTRL1, + pll_code.n_code << RT5660_PLL_N_SFT | pll_code.k_code); + snd_soc_write(codec, RT5660_PLL_CTRL2, + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5660_PLL_M_SFT | + pll_code.m_bp << RT5660_PLL_M_BP_SFT); + + rt5660->pll_in = freq_in; + rt5660->pll_out = freq_out; + rt5660->pll_src = source; + + return 0; +} + +static int rt5660_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + snd_soc_update_bits(codec, RT5660_GEN_CTRL1, + RT5660_DIG_GATE_CTRL, RT5660_DIG_GATE_CTRL); + + if (IS_ERR(rt5660->mclk)) + break; + + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) { + clk_disable_unprepare(rt5660->mclk); + } else { + ret = clk_prepare_enable(rt5660->mclk); + if (ret) + return ret; + } + break; + + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { + snd_soc_update_bits(codec, RT5660_PWR_ANLG1, + RT5660_PWR_VREF1 | RT5660_PWR_MB | + RT5660_PWR_BG | RT5660_PWR_VREF2, + RT5660_PWR_VREF1 | RT5660_PWR_MB | + RT5660_PWR_BG | RT5660_PWR_VREF2); + usleep_range(10000, 15000); + snd_soc_update_bits(codec, RT5660_PWR_ANLG1, + RT5660_PWR_FV1 | RT5660_PWR_FV2, + RT5660_PWR_FV1 | RT5660_PWR_FV2); + } + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, RT5660_GEN_CTRL1, + RT5660_DIG_GATE_CTRL, 0); + break; + + default: + break; + } + + return 0; +} + +static int rt5660_probe(struct snd_soc_codec *codec) +{ + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + + rt5660->codec = codec; + + return 0; +} + +static int rt5660_remove(struct snd_soc_codec *codec) +{ + return snd_soc_write(codec, RT5660_RESET, 0); +} + +#ifdef CONFIG_PM +static int rt5660_suspend(struct snd_soc_codec *codec) +{ + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5660->regmap, true); + regcache_mark_dirty(rt5660->regmap); + + return 0; +} + +static int rt5660_resume(struct snd_soc_codec *codec) +{ + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + + if (rt5660->pdata.poweroff_codec_in_suspend) + usleep_range(350000, 400000); + + regcache_cache_only(rt5660->regmap, false); + regcache_sync(rt5660->regmap); + + return 0; +} +#else +#define rt5660_suspend NULL +#define rt5660_resume NULL +#endif + +#define RT5660_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT5660_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt5660_aif_dai_ops = { + .hw_params = rt5660_hw_params, + .set_fmt = rt5660_set_dai_fmt, + .set_sysclk = rt5660_set_dai_sysclk, + .set_pll = rt5660_set_dai_pll, +}; + +static struct snd_soc_dai_driver rt5660_dai[] = { + { + .name = "rt5660-aif1", + .id = RT5660_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5660_STEREO_RATES, + .formats = RT5660_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5660_STEREO_RATES, + .formats = RT5660_FORMATS, + }, + .ops = &rt5660_aif_dai_ops, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5660 = { + .probe = rt5660_probe, + .remove = rt5660_remove, + .suspend = rt5660_suspend, + .resume = rt5660_resume, + .set_bias_level = rt5660_set_bias_level, + .idle_bias_off = true, + .component_driver = { + .controls = rt5660_snd_controls, + .num_controls = ARRAY_SIZE(rt5660_snd_controls), + .dapm_widgets = rt5660_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5660_dapm_widgets), + .dapm_routes = rt5660_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5660_dapm_routes), + }, +}; + +static const struct regmap_config rt5660_regmap = { + .reg_bits = 8, + .val_bits = 16, + .use_single_rw = true, + + .max_register = RT5660_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5660_ranges) * + RT5660_PR_SPACING), + .volatile_reg = rt5660_volatile_register, + .readable_reg = rt5660_readable_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5660_reg, + .num_reg_defaults = ARRAY_SIZE(rt5660_reg), + .ranges = rt5660_ranges, + .num_ranges = ARRAY_SIZE(rt5660_ranges), +}; + +static const struct i2c_device_id rt5660_i2c_id[] = { + { "rt5660", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt5660_i2c_id); + +static const struct of_device_id rt5660_of_match[] = { + { .compatible = "realtek,rt5660", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt5660_of_match); + +static const struct acpi_device_id rt5660_acpi_match[] = { + { "10EC5660", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, rt5660_acpi_match); + +static int rt5660_parse_dt(struct rt5660_priv *rt5660, struct device *dev) +{ + rt5660->pdata.in1_diff = device_property_read_bool(dev, + "realtek,in1-differential"); + rt5660->pdata.in3_diff = device_property_read_bool(dev, + "realtek,in3-differential"); + rt5660->pdata.poweroff_codec_in_suspend = device_property_read_bool(dev, + "realtek,poweroff-in-suspend"); + device_property_read_u32(dev, "realtek,dmic1-data-pin", + &rt5660->pdata.dmic1_data_pin); + + return 0; +} + +static int rt5660_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5660_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt5660_priv *rt5660; + int ret; + unsigned int val; + + rt5660 = devm_kzalloc(&i2c->dev, sizeof(struct rt5660_priv), + GFP_KERNEL); + + if (rt5660 == NULL) + return -ENOMEM; + + /* Check if MCLK provided */ + rt5660->mclk = devm_clk_get(&i2c->dev, "mclk"); + if (PTR_ERR(rt5660->mclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + i2c_set_clientdata(i2c, rt5660); + + if (pdata) + rt5660->pdata = *pdata; + else if (i2c->dev.of_node) + rt5660_parse_dt(rt5660, &i2c->dev); + + rt5660->regmap = devm_regmap_init_i2c(i2c, &rt5660_regmap); + if (IS_ERR(rt5660->regmap)) { + ret = PTR_ERR(rt5660->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt5660->regmap, RT5660_VENDOR_ID2, &val); + if (val != RT5660_DEVICE_ID) { + dev_err(&i2c->dev, + "Device with ID register %#x is not rt5660\n", val); + return -ENODEV; + } + + regmap_write(rt5660->regmap, RT5660_RESET, 0); + + ret = regmap_register_patch(rt5660->regmap, rt5660_patch, + ARRAY_SIZE(rt5660_patch)); + if (ret != 0) + dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + + if (rt5660->pdata.dmic1_data_pin) { + regmap_update_bits(rt5660->regmap, RT5660_GPIO_CTRL1, + RT5660_GP1_PIN_MASK, RT5660_GP1_PIN_DMIC1_SCL); + + if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_GPIO2) + regmap_update_bits(rt5660->regmap, RT5660_DMIC_CTRL1, + RT5660_SEL_DMIC_DATA_MASK, + RT5660_SEL_DMIC_DATA_GPIO2); + else if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_IN1P) + regmap_update_bits(rt5660->regmap, RT5660_DMIC_CTRL1, + RT5660_SEL_DMIC_DATA_MASK, + RT5660_SEL_DMIC_DATA_IN1P); + } + + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5660, + rt5660_dai, ARRAY_SIZE(rt5660_dai)); +} + +static int rt5660_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static struct i2c_driver rt5660_i2c_driver = { + .driver = { + .name = "rt5660", + .acpi_match_table = ACPI_PTR(rt5660_acpi_match), + .of_match_table = of_match_ptr(rt5660_of_match), + }, + .probe = rt5660_i2c_probe, + .remove = rt5660_i2c_remove, + .id_table = rt5660_i2c_id, +}; +module_i2c_driver(rt5660_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5660 driver"); +MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5660.h b/sound/soc/codecs/rt5660.h new file mode 100644 index 000000000000..6cdb9269ec9e --- /dev/null +++ b/sound/soc/codecs/rt5660.h @@ -0,0 +1,847 @@ +/* + * rt5660.h -- RT5660 ALSA SoC audio driver + * + * Copyright 2016 Realtek Semiconductor Corp. + * Author: Oder Chiou <oder_chiou@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _RT5660_H +#define _RT5660_H + +#include <linux/clk.h> +#include <sound/rt5660.h> + +/* Info */ +#define RT5660_RESET 0x00 +#define RT5660_VENDOR_ID 0xfd +#define RT5660_VENDOR_ID1 0xfe +#define RT5660_VENDOR_ID2 0xff +/* I/O - Output */ +#define RT5660_SPK_VOL 0x01 +#define RT5660_LOUT_VOL 0x02 +/* I/O - Input */ +#define RT5660_IN1_IN2 0x0d +#define RT5660_IN3_IN4 0x0e +/* I/O - ADC/DAC/DMIC */ +#define RT5660_DAC1_DIG_VOL 0x19 +#define RT5660_STO1_ADC_DIG_VOL 0x1c +#define RT5660_ADC_BST_VOL1 0x1e +/* Mixer - D-D */ +#define RT5660_STO1_ADC_MIXER 0x27 +#define RT5660_AD_DA_MIXER 0x29 +#define RT5660_STO_DAC_MIXER 0x2a +#define RT5660_DIG_INF1_DATA 0x2f +/* Mixer - ADC */ +#define RT5660_REC_L1_MIXER 0x3b +#define RT5660_REC_L2_MIXER 0x3c +#define RT5660_REC_R1_MIXER 0x3d +#define RT5660_REC_R2_MIXER 0x3e +/* Mixer - DAC */ +#define RT5660_LOUT_MIXER 0x45 +#define RT5660_SPK_MIXER 0x46 +#define RT5660_SPO_MIXER 0x48 +#define RT5660_SPO_CLSD_RATIO 0x4a +#define RT5660_OUT_L_GAIN1 0x4d +#define RT5660_OUT_L_GAIN2 0x4e +#define RT5660_OUT_L1_MIXER 0x4f +#define RT5660_OUT_R_GAIN1 0x50 +#define RT5660_OUT_R_GAIN2 0x51 +#define RT5660_OUT_R1_MIXER 0x52 +/* Power */ +#define RT5660_PWR_DIG1 0x61 +#define RT5660_PWR_DIG2 0x62 +#define RT5660_PWR_ANLG1 0x63 +#define RT5660_PWR_ANLG2 0x64 +#define RT5660_PWR_MIXER 0x65 +#define RT5660_PWR_VOL 0x66 +/* Private Register Control */ +#define RT5660_PRIV_INDEX 0x6a +#define RT5660_PRIV_DATA 0x6c +/* Format - ADC/DAC */ +#define RT5660_I2S1_SDP 0x70 +#define RT5660_ADDA_CLK1 0x73 +#define RT5660_ADDA_CLK2 0x74 +#define RT5660_DMIC_CTRL1 0x75 +/* Function - Analog */ +#define RT5660_GLB_CLK 0x80 +#define RT5660_PLL_CTRL1 0x81 +#define RT5660_PLL_CTRL2 0x82 +#define RT5660_CLSD_AMP_OC_CTRL 0x8c +#define RT5660_CLSD_AMP_CTRL 0x8d +#define RT5660_LOUT_AMP_CTRL 0x8e +#define RT5660_SPK_AMP_SPKVDD 0x92 +#define RT5660_MICBIAS 0x93 +#define RT5660_CLSD_OUT_CTRL1 0xa1 +#define RT5660_CLSD_OUT_CTRL2 0xa2 +#define RT5660_DIPOLE_MIC_CTRL1 0xa3 +#define RT5660_DIPOLE_MIC_CTRL2 0xa4 +#define RT5660_DIPOLE_MIC_CTRL3 0xa5 +#define RT5660_DIPOLE_MIC_CTRL4 0xa6 +#define RT5660_DIPOLE_MIC_CTRL5 0xa7 +#define RT5660_DIPOLE_MIC_CTRL6 0xa8 +#define RT5660_DIPOLE_MIC_CTRL7 0xa9 +#define RT5660_DIPOLE_MIC_CTRL8 0xaa +#define RT5660_DIPOLE_MIC_CTRL9 0xab +#define RT5660_DIPOLE_MIC_CTRL10 0xac +#define RT5660_DIPOLE_MIC_CTRL11 0xad +#define RT5660_DIPOLE_MIC_CTRL12 0xae +/* Function - Digital */ +#define RT5660_EQ_CTRL1 0xb0 +#define RT5660_EQ_CTRL2 0xb1 +#define RT5660_DRC_AGC_CTRL1 0xb3 +#define RT5660_DRC_AGC_CTRL2 0xb4 +#define RT5660_DRC_AGC_CTRL3 0xb5 +#define RT5660_DRC_AGC_CTRL4 0xb6 +#define RT5660_DRC_AGC_CTRL5 0xb7 +#define RT5660_JD_CTRL 0xbb +#define RT5660_IRQ_CTRL1 0xbd +#define RT5660_IRQ_CTRL2 0xbe +#define RT5660_INT_IRQ_ST 0xbf +#define RT5660_GPIO_CTRL1 0xc0 +#define RT5660_GPIO_CTRL2 0xc2 +#define RT5660_WIND_FILTER_CTRL1 0xd3 +#define RT5660_SV_ZCD1 0xd9 +#define RT5660_SV_ZCD2 0xda +#define RT5660_DRC1_LM_CTRL1 0xe0 +#define RT5660_DRC1_LM_CTRL2 0xe1 +#define RT5660_DRC2_LM_CTRL1 0xe2 +#define RT5660_DRC2_LM_CTRL2 0xe3 +#define RT5660_MULTI_DRC_CTRL 0xe4 +#define RT5660_DRC2_CTRL1 0xe5 +#define RT5660_DRC2_CTRL2 0xe6 +#define RT5660_DRC2_CTRL3 0xe7 +#define RT5660_DRC2_CTRL4 0xe8 +#define RT5660_DRC2_CTRL5 0xe9 +#define RT5660_ALC_PGA_CTRL1 0xea +#define RT5660_ALC_PGA_CTRL2 0xeb +#define RT5660_ALC_PGA_CTRL3 0xec +#define RT5660_ALC_PGA_CTRL4 0xed +#define RT5660_ALC_PGA_CTRL5 0xee +#define RT5660_ALC_PGA_CTRL6 0xef +#define RT5660_ALC_PGA_CTRL7 0xf0 + +/* General Control */ +#define RT5660_GEN_CTRL1 0xfa +#define RT5660_GEN_CTRL2 0xfb +#define RT5660_GEN_CTRL3 0xfc + +/* Index of Codec Private Register definition */ +#define RT5660_CHOP_DAC_ADC 0x3d + +/* Global Definition */ +#define RT5660_L_MUTE (0x1 << 15) +#define RT5660_L_MUTE_SFT 15 +#define RT5660_VOL_L_MUTE (0x1 << 14) +#define RT5660_VOL_L_SFT 14 +#define RT5660_R_MUTE (0x1 << 7) +#define RT5660_R_MUTE_SFT 7 +#define RT5660_VOL_R_MUTE (0x1 << 6) +#define RT5660_VOL_R_SFT 6 +#define RT5660_L_VOL_MASK (0x3f << 8) +#define RT5660_L_VOL_SFT 8 +#define RT5660_R_VOL_MASK (0x3f) +#define RT5660_R_VOL_SFT 0 + +/* IN1 and IN2 Control (0x0d) */ +#define RT5660_IN_DF1 (0x1 << 15) +#define RT5660_IN_SFT1 15 +#define RT5660_BST_MASK1 (0x7f << 8) +#define RT5660_BST_SFT1 8 +#define RT5660_IN_DF2 (0x1 << 7) +#define RT5660_IN_SFT2 7 +#define RT5660_BST_MASK2 (0x7f << 0) +#define RT5660_BST_SFT2 0 + +/* IN3 and IN4 Control (0x0e) */ +#define RT5660_IN_DF3 (0x1 << 15) +#define RT5660_IN_SFT3 15 +#define RT5660_BST_MASK3 (0x7f << 8) +#define RT5660_BST_SFT3 8 +#define RT5660_IN_DF4 (0x1 << 7) +#define RT5660_IN_SFT4 7 +#define RT5660_BST_MASK4 (0x7f << 0) +#define RT5660_BST_SFT4 0 + +/* DAC1 Digital Volume (0x19) */ +#define RT5660_DAC_L1_VOL_MASK (0x7f << 9) +#define RT5660_DAC_L1_VOL_SFT 9 +#define RT5660_DAC_R1_VOL_MASK (0x7f << 1) +#define RT5660_DAC_R1_VOL_SFT 1 + +/* ADC Digital Volume Control (0x1c) */ +#define RT5660_ADC_L_VOL_MASK (0x3f << 9) +#define RT5660_ADC_L_VOL_SFT 9 +#define RT5660_ADC_R_VOL_MASK (0x3f << 1) +#define RT5660_ADC_R_VOL_SFT 1 + +/* ADC Boost Volume Control (0x1e) */ +#define RT5660_STO1_ADC_L_BST_MASK (0x3 << 14) +#define RT5660_STO1_ADC_L_BST_SFT 14 +#define RT5660_STO1_ADC_R_BST_MASK (0x3 << 12) +#define RT5660_STO1_ADC_R_BST_SFT 12 + +/* Stereo ADC Mixer Control (0x27) */ +#define RT5660_M_ADC_L1 (0x1 << 14) +#define RT5660_M_ADC_L1_SFT 14 +#define RT5660_M_ADC_L2 (0x1 << 13) +#define RT5660_M_ADC_L2_SFT 13 +#define RT5660_M_ADC_R1 (0x1 << 6) +#define RT5660_M_ADC_R1_SFT 6 +#define RT5660_M_ADC_R2 (0x1 << 5) +#define RT5660_M_ADC_R2_SFT 5 + +/* ADC Mixer to DAC Mixer Control (0x29) */ +#define RT5660_M_ADCMIX_L (0x1 << 15) +#define RT5660_M_ADCMIX_L_SFT 15 +#define RT5660_M_DAC1_L (0x1 << 14) +#define RT5660_M_DAC1_L_SFT 14 +#define RT5660_M_ADCMIX_R (0x1 << 7) +#define RT5660_M_ADCMIX_R_SFT 7 +#define RT5660_M_DAC1_R (0x1 << 6) +#define RT5660_M_DAC1_R_SFT 6 + +/* Stereo DAC Mixer Control (0x2a) */ +#define RT5660_M_DAC_L1 (0x1 << 14) +#define RT5660_M_DAC_L1_SFT 14 +#define RT5660_DAC_L1_STO_L_VOL_MASK (0x1 << 13) +#define RT5660_DAC_L1_STO_L_VOL_SFT 13 +#define RT5660_M_DAC_R1_STO_L (0x1 << 9) +#define RT5660_M_DAC_R1_STO_L_SFT 9 +#define RT5660_DAC_R1_STO_L_VOL_MASK (0x1 << 8) +#define RT5660_DAC_R1_STO_L_VOL_SFT 8 +#define RT5660_M_DAC_R1 (0x1 << 6) +#define RT5660_M_DAC_R1_SFT 6 +#define RT5660_DAC_R1_STO_R_VOL_MASK (0x1 << 5) +#define RT5660_DAC_R1_STO_R_VOL_SFT 5 +#define RT5660_M_DAC_L1_STO_R (0x1 << 1) +#define RT5660_M_DAC_L1_STO_R_SFT 1 +#define RT5660_DAC_L1_STO_R_VOL_MASK (0x1) +#define RT5660_DAC_L1_STO_R_VOL_SFT 0 + +/* Digital Interface Data Control (0x2f) */ +#define RT5660_IF1_DAC_IN_SEL (0x3 << 14) +#define RT5660_IF1_DAC_IN_SFT 14 +#define RT5660_IF1_ADC_IN_SEL (0x3 << 12) +#define RT5660_IF1_ADC_IN_SFT 12 + +/* REC Left Mixer Control 1 (0x3b) */ +#define RT5660_G_BST3_RM_L_MASK (0x7 << 4) +#define RT5660_G_BST3_RM_L_SFT 4 +#define RT5660_G_BST2_RM_L_MASK (0x7 << 1) +#define RT5660_G_BST2_RM_L_SFT 1 + +/* REC Left Mixer Control 2 (0x3c) */ +#define RT5660_G_BST1_RM_L_MASK (0x7 << 13) +#define RT5660_G_BST1_RM_L_SFT 13 +#define RT5660_G_OM_L_RM_L_MASK (0x7 << 10) +#define RT5660_G_OM_L_RM_L_SFT 10 +#define RT5660_M_BST3_RM_L (0x1 << 3) +#define RT5660_M_BST3_RM_L_SFT 3 +#define RT5660_M_BST2_RM_L (0x1 << 2) +#define RT5660_M_BST2_RM_L_SFT 2 +#define RT5660_M_BST1_RM_L (0x1 << 1) +#define RT5660_M_BST1_RM_L_SFT 1 +#define RT5660_M_OM_L_RM_L (0x1) +#define RT5660_M_OM_L_RM_L_SFT 0 + +/* REC Right Mixer Control 1 (0x3d) */ +#define RT5660_G_BST3_RM_R_MASK (0x7 << 4) +#define RT5660_G_BST3_RM_R_SFT 4 +#define RT5660_G_BST2_RM_R_MASK (0x7 << 1) +#define RT5660_G_BST2_RM_R_SFT 1 + +/* REC Right Mixer Control 2 (0x3e) */ +#define RT5660_G_BST1_RM_R_MASK (0x7 << 13) +#define RT5660_G_BST1_RM_R_SFT 13 +#define RT5660_G_OM_R_RM_R_MASK (0x7 << 10) +#define RT5660_G_OM_R_RM_R_SFT 10 +#define RT5660_M_BST3_RM_R (0x1 << 3) +#define RT5660_M_BST3_RM_R_SFT 3 +#define RT5660_M_BST2_RM_R (0x1 << 2) +#define RT5660_M_BST2_RM_R_SFT 2 +#define RT5660_M_BST1_RM_R (0x1 << 1) +#define RT5660_M_BST1_RM_R_SFT 1 +#define RT5660_M_OM_R_RM_R (0x1) +#define RT5660_M_OM_R_RM_R_SFT 0 + +/* LOUTMIX Control (0x45) */ +#define RT5660_M_DAC1_LM (0x1 << 14) +#define RT5660_M_DAC1_LM_SFT 14 +#define RT5660_M_LOVOL_M (0x1 << 13) +#define RT5660_M_LOVOL_LM_SFT 13 + +/* SPK Mixer Control (0x46) */ +#define RT5660_G_BST3_SM_MASK (0x3 << 14) +#define RT5660_G_BST3_SM_SFT 14 +#define RT5660_G_BST1_SM_MASK (0x3 << 12) +#define RT5660_G_BST1_SM_SFT 12 +#define RT5660_G_DACl_SM_MASK (0x3 << 10) +#define RT5660_G_DACl_SM_SFT 10 +#define RT5660_G_DACR_SM_MASK (0x3 << 8) +#define RT5660_G_DACR_SM_SFT 8 +#define RT5660_G_OM_L_SM_MASK (0x3 << 6) +#define RT5660_G_OM_L_SM_SFT 6 +#define RT5660_M_DACR_SM (0x1 << 5) +#define RT5660_M_DACR_SM_SFT 5 +#define RT5660_M_BST1_SM (0x1 << 4) +#define RT5660_M_BST1_SM_SFT 4 +#define RT5660_M_BST3_SM (0x1 << 3) +#define RT5660_M_BST3_SM_SFT 3 +#define RT5660_M_DACL_SM (0x1 << 2) +#define RT5660_M_DACL_SM_SFT 2 +#define RT5660_M_OM_L_SM (0x1 << 1) +#define RT5660_M_OM_L_SM_SFT 1 + +/* SPOMIX Control (0x48) */ +#define RT5660_M_DAC_R_SPM (0x1 << 14) +#define RT5660_M_DAC_R_SPM_SFT 14 +#define RT5660_M_DAC_L_SPM (0x1 << 13) +#define RT5660_M_DAC_L_SPM_SFT 13 +#define RT5660_M_SV_SPM (0x1 << 12) +#define RT5660_M_SV_SPM_SFT 12 +#define RT5660_M_BST1_SPM (0x1 << 11) +#define RT5660_M_BST1_SPM_SFT 11 + +/* Output Left Mixer Control 1 (0x4d) */ +#define RT5660_G_BST3_OM_L_MASK (0x7 << 13) +#define RT5660_G_BST3_OM_L_SFT 13 +#define RT5660_G_BST2_OM_L_MASK (0x7 << 10) +#define RT5660_G_BST2_OM_L_SFT 10 +#define RT5660_G_BST1_OM_L_MASK (0x7 << 7) +#define RT5660_G_BST1_OM_L_SFT 7 +#define RT5660_G_RM_L_OM_L_MASK (0x7 << 1) +#define RT5660_G_RM_L_OM_L_SFT 1 + +/* Output Left Mixer Control 2 (0x4e) */ +#define RT5660_G_DAC_R1_OM_L_MASK (0x7 << 10) +#define RT5660_G_DAC_R1_OM_L_SFT 10 +#define RT5660_G_DAC_L1_OM_L_MASK (0x7 << 7) +#define RT5660_G_DAC_L1_OM_L_SFT 7 + +/* Output Left Mixer Control 3 (0x4f) */ +#define RT5660_M_BST3_OM_L (0x1 << 5) +#define RT5660_M_BST3_OM_L_SFT 5 +#define RT5660_M_BST2_OM_L (0x1 << 4) +#define RT5660_M_BST2_OM_L_SFT 4 +#define RT5660_M_BST1_OM_L (0x1 << 3) +#define RT5660_M_BST1_OM_L_SFT 3 +#define RT5660_M_RM_L_OM_L (0x1 << 2) +#define RT5660_M_RM_L_OM_L_SFT 2 +#define RT5660_M_DAC_R_OM_L (0x1 << 1) +#define RT5660_M_DAC_R_OM_L_SFT 1 +#define RT5660_M_DAC_L_OM_L (0x1) +#define RT5660_M_DAC_L_OM_L_SFT 0 + +/* Output Right Mixer Control 1 (0x50) */ +#define RT5660_G_BST2_OM_R_MASK (0x7 << 10) +#define RT5660_G_BST2_OM_R_SFT 10 +#define RT5660_G_BST1_OM_R_MASK (0x7 << 7) +#define RT5660_G_BST1_OM_R_SFT 7 +#define RT5660_G_RM_R_OM_R_MASK (0x7 << 1) +#define RT5660_G_RM_R_OM_R_SFT 1 + +/* Output Right Mixer Control 2 (0x51) */ +#define RT5660_G_DAC_L_OM_R_MASK (0x7 << 10) +#define RT5660_G_DAC_L_OM_R_SFT 10 +#define RT5660_G_DAC_R_OM_R_MASK (0x7 << 7) +#define RT5660_G_DAC_R_OM_R_SFT 7 + +/* Output Right Mixer Control 3 (0x52) */ +#define RT5660_M_BST2_OM_R (0x1 << 4) +#define RT5660_M_BST2_OM_R_SFT 4 +#define RT5660_M_BST1_OM_R (0x1 << 3) +#define RT5660_M_BST1_OM_R_SFT 3 +#define RT5660_M_RM_R_OM_R (0x1 << 2) +#define RT5660_M_RM_R_OM_R_SFT 2 +#define RT5660_M_DAC_L_OM_R (0x1 << 1) +#define RT5660_M_DAC_L_OM_R_SFT 1 +#define RT5660_M_DAC_R_OM_R (0x1) +#define RT5660_M_DAC_R_OM_R_SFT 0 + +/* Power Management for Digital 1 (0x61) */ +#define RT5660_PWR_I2S1 (0x1 << 15) +#define RT5660_PWR_I2S1_BIT 15 +#define RT5660_PWR_DAC_L1 (0x1 << 12) +#define RT5660_PWR_DAC_L1_BIT 12 +#define RT5660_PWR_DAC_R1 (0x1 << 11) +#define RT5660_PWR_DAC_R1_BIT 11 +#define RT5660_PWR_ADC_L (0x1 << 2) +#define RT5660_PWR_ADC_L_BIT 2 +#define RT5660_PWR_ADC_R (0x1 << 1) +#define RT5660_PWR_ADC_R_BIT 1 +#define RT5660_PWR_CLS_D (0x1) +#define RT5660_PWR_CLS_D_BIT 0 + +/* Power Management for Digital 2 (0x62) */ +#define RT5660_PWR_ADC_S1F (0x1 << 15) +#define RT5660_PWR_ADC_S1F_BIT 15 +#define RT5660_PWR_DAC_S1F (0x1 << 11) +#define RT5660_PWR_DAC_S1F_BIT 11 + +/* Power Management for Analog 1 (0x63) */ +#define RT5660_PWR_VREF1 (0x1 << 15) +#define RT5660_PWR_VREF1_BIT 15 +#define RT5660_PWR_FV1 (0x1 << 14) +#define RT5660_PWR_FV1_BIT 14 +#define RT5660_PWR_MB (0x1 << 13) +#define RT5660_PWR_MB_BIT 13 +#define RT5660_PWR_BG (0x1 << 11) +#define RT5660_PWR_BG_BIT 11 +#define RT5660_PWR_HP_L (0x1 << 7) +#define RT5660_PWR_HP_L_BIT 7 +#define RT5660_PWR_HP_R (0x1 << 6) +#define RT5660_PWR_HP_R_BIT 6 +#define RT5660_PWR_HA (0x1 << 5) +#define RT5660_PWR_HA_BIT 5 +#define RT5660_PWR_VREF2 (0x1 << 4) +#define RT5660_PWR_VREF2_BIT 4 +#define RT5660_PWR_FV2 (0x1 << 3) +#define RT5660_PWR_FV2_BIT 3 +#define RT5660_PWR_LDO2 (0x1 << 2) +#define RT5660_PWR_LDO2_BIT 2 + +/* Power Management for Analog 2 (0x64) */ +#define RT5660_PWR_BST1 (0x1 << 15) +#define RT5660_PWR_BST1_BIT 15 +#define RT5660_PWR_BST2 (0x1 << 14) +#define RT5660_PWR_BST2_BIT 14 +#define RT5660_PWR_BST3 (0x1 << 13) +#define RT5660_PWR_BST3_BIT 13 +#define RT5660_PWR_MB1 (0x1 << 11) +#define RT5660_PWR_MB1_BIT 11 +#define RT5660_PWR_MB2 (0x1 << 10) +#define RT5660_PWR_MB2_BIT 10 +#define RT5660_PWR_PLL (0x1 << 9) +#define RT5660_PWR_PLL_BIT 9 + +/* Power Management for Mixer (0x65) */ +#define RT5660_PWR_OM_L (0x1 << 15) +#define RT5660_PWR_OM_L_BIT 15 +#define RT5660_PWR_OM_R (0x1 << 14) +#define RT5660_PWR_OM_R_BIT 14 +#define RT5660_PWR_SM (0x1 << 13) +#define RT5660_PWR_SM_BIT 13 +#define RT5660_PWR_RM_L (0x1 << 11) +#define RT5660_PWR_RM_L_BIT 11 +#define RT5660_PWR_RM_R (0x1 << 10) +#define RT5660_PWR_RM_R_BIT 10 + +/* Power Management for Volume (0x66) */ +#define RT5660_PWR_SV (0x1 << 15) +#define RT5660_PWR_SV_BIT 15 +#define RT5660_PWR_LV_L (0x1 << 11) +#define RT5660_PWR_LV_L_BIT 11 +#define RT5660_PWR_LV_R (0x1 << 10) +#define RT5660_PWR_LV_R_BIT 10 + +/* I2S1 Audio Serial Data Port Control (0x70) */ +#define RT5660_I2S_MS_MASK (0x1 << 15) +#define RT5660_I2S_MS_SFT 15 +#define RT5660_I2S_MS_M (0x0 << 15) +#define RT5660_I2S_MS_S (0x1 << 15) +#define RT5660_I2S_O_CP_MASK (0x3 << 10) +#define RT5660_I2S_O_CP_SFT 10 +#define RT5660_I2S_O_CP_OFF (0x0 << 10) +#define RT5660_I2S_O_CP_U_LAW (0x1 << 10) +#define RT5660_I2S_O_CP_A_LAW (0x2 << 10) +#define RT5660_I2S_I_CP_MASK (0x3 << 8) +#define RT5660_I2S_I_CP_SFT 8 +#define RT5660_I2S_I_CP_OFF (0x0 << 8) +#define RT5660_I2S_I_CP_U_LAW (0x1 << 8) +#define RT5660_I2S_I_CP_A_LAW (0x2 << 8) +#define RT5660_I2S_BP_MASK (0x1 << 7) +#define RT5660_I2S_BP_SFT 7 +#define RT5660_I2S_BP_NOR (0x0 << 7) +#define RT5660_I2S_BP_INV (0x1 << 7) +#define RT5660_I2S_DL_MASK (0x3 << 2) +#define RT5660_I2S_DL_SFT 2 +#define RT5660_I2S_DL_16 (0x0 << 2) +#define RT5660_I2S_DL_20 (0x1 << 2) +#define RT5660_I2S_DL_24 (0x2 << 2) +#define RT5660_I2S_DL_8 (0x3 << 2) +#define RT5660_I2S_DF_MASK (0x3) +#define RT5660_I2S_DF_SFT 0 +#define RT5660_I2S_DF_I2S (0x0) +#define RT5660_I2S_DF_LEFT (0x1) +#define RT5660_I2S_DF_PCM_A (0x2) +#define RT5660_I2S_DF_PCM_B (0x3) + +/* ADC/DAC Clock Control 1 (0x73) */ +#define RT5660_I2S_BCLK_MS1_MASK (0x1 << 15) +#define RT5660_I2S_BCLK_MS1_SFT 15 +#define RT5660_I2S_BCLK_MS1_32 (0x0 << 15) +#define RT5660_I2S_BCLK_MS1_64 (0x1 << 15) +#define RT5660_I2S_PD1_MASK (0x7 << 12) +#define RT5660_I2S_PD1_SFT 12 +#define RT5660_I2S_PD1_1 (0x0 << 12) +#define RT5660_I2S_PD1_2 (0x1 << 12) +#define RT5660_I2S_PD1_3 (0x2 << 12) +#define RT5660_I2S_PD1_4 (0x3 << 12) +#define RT5660_I2S_PD1_6 (0x4 << 12) +#define RT5660_I2S_PD1_8 (0x5 << 12) +#define RT5660_I2S_PD1_12 (0x6 << 12) +#define RT5660_I2S_PD1_16 (0x7 << 12) +#define RT5660_DAC_OSR_MASK (0x3 << 2) +#define RT5660_DAC_OSR_SFT 2 +#define RT5660_DAC_OSR_128 (0x0 << 2) +#define RT5660_DAC_OSR_64 (0x1 << 2) +#define RT5660_DAC_OSR_32 (0x2 << 2) +#define RT5660_DAC_OSR_16 (0x3 << 2) +#define RT5660_ADC_OSR_MASK (0x3) +#define RT5660_ADC_OSR_SFT 0 +#define RT5660_ADC_OSR_128 (0x0) +#define RT5660_ADC_OSR_64 (0x1) +#define RT5660_ADC_OSR_32 (0x2) +#define RT5660_ADC_OSR_16 (0x3) + +/* ADC/DAC Clock Control 2 (0x74) */ +#define RT5660_RESET_ADF (0x1 << 13) +#define RT5660_RESET_ADF_SFT 13 +#define RT5660_RESET_DAF (0x1 << 12) +#define RT5660_RESET_DAF_SFT 12 +#define RT5660_DAHPF_EN (0x1 << 11) +#define RT5660_DAHPF_EN_SFT 11 +#define RT5660_ADHPF_EN (0x1 << 10) +#define RT5660_ADHPF_EN_SFT 10 + +/* Digital Microphone Control (0x75) */ +#define RT5660_DMIC_1_EN_MASK (0x1 << 15) +#define RT5660_DMIC_1_EN_SFT 15 +#define RT5660_DMIC_1_DIS (0x0 << 15) +#define RT5660_DMIC_1_EN (0x1 << 15) +#define RT5660_DMIC_1L_LH_MASK (0x1 << 13) +#define RT5660_DMIC_1L_LH_SFT 13 +#define RT5660_DMIC_1L_LH_RISING (0x0 << 13) +#define RT5660_DMIC_1L_LH_FALLING (0x1 << 13) +#define RT5660_DMIC_1R_LH_MASK (0x1 << 12) +#define RT5660_DMIC_1R_LH_SFT 12 +#define RT5660_DMIC_1R_LH_RISING (0x0 << 12) +#define RT5660_DMIC_1R_LH_FALLING (0x1 << 12) +#define RT5660_SEL_DMIC_DATA_MASK (0x1 << 11) +#define RT5660_SEL_DMIC_DATA_SFT 11 +#define RT5660_SEL_DMIC_DATA_GPIO2 (0x0 << 11) +#define RT5660_SEL_DMIC_DATA_IN1P (0x1 << 11) +#define RT5660_DMIC_CLK_MASK (0x7 << 5) +#define RT5660_DMIC_CLK_SFT 5 + +/* Global Clock Control (0x80) */ +#define RT5660_SCLK_SRC_MASK (0x3 << 14) +#define RT5660_SCLK_SRC_SFT 14 +#define RT5660_SCLK_SRC_MCLK (0x0 << 14) +#define RT5660_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5660_SCLK_SRC_RCCLK (0x2 << 14) +#define RT5660_PLL1_SRC_MASK (0x3 << 12) +#define RT5660_PLL1_SRC_SFT 12 +#define RT5660_PLL1_SRC_MCLK (0x0 << 12) +#define RT5660_PLL1_SRC_BCLK1 (0x1 << 12) +#define RT5660_PLL1_SRC_RCCLK (0x2 << 12) +#define RT5660_PLL1_PD_MASK (0x1 << 3) +#define RT5660_PLL1_PD_SFT 3 +#define RT5660_PLL1_PD_1 (0x0 << 3) +#define RT5660_PLL1_PD_2 (0x1 << 3) + +#define RT5660_PLL_INP_MAX 40000000 +#define RT5660_PLL_INP_MIN 256000 +/* PLL M/N/K Code Control 1 (0x81) */ +#define RT5660_PLL_N_MAX 0x1ff +#define RT5660_PLL_N_MASK (RT5660_PLL_N_MAX << 7) +#define RT5660_PLL_N_SFT 7 +#define RT5660_PLL_K_MAX 0x1f +#define RT5660_PLL_K_MASK (RT5660_PLL_K_MAX) +#define RT5660_PLL_K_SFT 0 + +/* PLL M/N/K Code Control 2 (0x82) */ +#define RT5660_PLL_M_MAX 0xf +#define RT5660_PLL_M_MASK (RT5660_PLL_M_MAX << 12) +#define RT5660_PLL_M_SFT 12 +#define RT5660_PLL_M_BP (0x1 << 11) +#define RT5660_PLL_M_BP_SFT 11 + +/* Class D Over Current Control (0x8c) */ +#define RT5660_CLSD_OC_MASK (0x1 << 9) +#define RT5660_CLSD_OC_SFT 9 +#define RT5660_CLSD_OC_PU (0x0 << 9) +#define RT5660_CLSD_OC_PD (0x1 << 9) +#define RT5660_AUTO_PD_MASK (0x1 << 8) +#define RT5660_AUTO_PD_SFT 8 +#define RT5660_AUTO_PD_DIS (0x0 << 8) +#define RT5660_AUTO_PD_EN (0x1 << 8) +#define RT5660_CLSD_OC_TH_MASK (0x3f) +#define RT5660_CLSD_OC_TH_SFT 0 + +/* Class D Output Control (0x8d) */ +#define RT5660_CLSD_RATIO_MASK (0xf << 12) +#define RT5660_CLSD_RATIO_SFT 12 + +/* Lout Amp Control 1 (0x8e) */ +#define RT5660_LOUT_CO_MASK (0x1 << 4) +#define RT5660_LOUT_CO_SFT 4 +#define RT5660_LOUT_CO_DIS (0x0 << 4) +#define RT5660_LOUT_CO_EN (0x1 << 4) +#define RT5660_LOUT_CB_MASK (0x1) +#define RT5660_LOUT_CB_SFT 0 +#define RT5660_LOUT_CB_PD (0x0) +#define RT5660_LOUT_CB_PU (0x1) + +/* SPKVDD detection control (0x92) */ +#define RT5660_SPKVDD_DET_MASK (0x1 << 15) +#define RT5660_SPKVDD_DET_SFT 15 +#define RT5660_SPKVDD_DET_DIS (0x0 << 15) +#define RT5660_SPKVDD_DET_EN (0x1 << 15) +#define RT5660_SPK_AG_MASK (0x1 << 14) +#define RT5660_SPK_AG_SFT 14 +#define RT5660_SPK_AG_DIS (0x0 << 14) +#define RT5660_SPK_AG_EN (0x1 << 14) + +/* Micbias Control (0x93) */ +#define RT5660_MIC1_BS_MASK (0x1 << 15) +#define RT5660_MIC1_BS_SFT 15 +#define RT5660_MIC1_BS_9AV (0x0 << 15) +#define RT5660_MIC1_BS_75AV (0x1 << 15) +#define RT5660_MIC2_BS_MASK (0x1 << 14) +#define RT5660_MIC2_BS_SFT 14 +#define RT5660_MIC2_BS_9AV (0x0 << 14) +#define RT5660_MIC2_BS_75AV (0x1 << 14) +#define RT5660_MIC1_OVCD_MASK (0x1 << 11) +#define RT5660_MIC1_OVCD_SFT 11 +#define RT5660_MIC1_OVCD_DIS (0x0 << 11) +#define RT5660_MIC1_OVCD_EN (0x1 << 11) +#define RT5660_MIC1_OVTH_MASK (0x3 << 9) +#define RT5660_MIC1_OVTH_SFT 9 +#define RT5660_MIC1_OVTH_600UA (0x0 << 9) +#define RT5660_MIC1_OVTH_1500UA (0x1 << 9) +#define RT5660_MIC1_OVTH_2000UA (0x2 << 9) +#define RT5660_MIC2_OVCD_MASK (0x1 << 8) +#define RT5660_MIC2_OVCD_SFT 8 +#define RT5660_MIC2_OVCD_DIS (0x0 << 8) +#define RT5660_MIC2_OVCD_EN (0x1 << 8) +#define RT5660_MIC2_OVTH_MASK (0x3 << 6) +#define RT5660_MIC2_OVTH_SFT 6 +#define RT5660_MIC2_OVTH_600UA (0x0 << 6) +#define RT5660_MIC2_OVTH_1500UA (0x1 << 6) +#define RT5660_MIC2_OVTH_2000UA (0x2 << 6) +#define RT5660_PWR_CLK25M_MASK (0x1 << 4) +#define RT5660_PWR_CLK25M_SFT 4 +#define RT5660_PWR_CLK25M_PD (0x0 << 4) +#define RT5660_PWR_CLK25M_PU (0x1 << 4) + +/* EQ Control 1 (0xb0) */ +#define RT5660_EQ_SRC_MASK (0x1 << 15) +#define RT5660_EQ_SRC_SFT 15 +#define RT5660_EQ_SRC_DAC (0x0 << 15) +#define RT5660_EQ_SRC_ADC (0x1 << 15) +#define RT5660_EQ_UPD (0x1 << 14) +#define RT5660_EQ_UPD_BIT 14 + +/* Jack Detect Control (0xbb) */ +#define RT5660_JD_MASK (0x3 << 14) +#define RT5660_JD_SFT 14 +#define RT5660_JD_DIS (0x0 << 14) +#define RT5660_JD_GPIO1 (0x1 << 14) +#define RT5660_JD_GPIO2 (0x2 << 14) +#define RT5660_JD_LOUT_MASK (0x1 << 11) +#define RT5660_JD_LOUT_SFT 11 +#define RT5660_JD_LOUT_DIS (0x0 << 11) +#define RT5660_JD_LOUT_EN (0x1 << 11) +#define RT5660_JD_LOUT_TRG_MASK (0x1 << 10) +#define RT5660_JD_LOUT_TRG_SFT 10 +#define RT5660_JD_LOUT_TRG_LO (0x0 << 10) +#define RT5660_JD_LOUT_TRG_HI (0x1 << 10) +#define RT5660_JD_SPO_MASK (0x1 << 9) +#define RT5660_JD_SPO_SFT 9 +#define RT5660_JD_SPO_DIS (0x0 << 9) +#define RT5660_JD_SPO_EN (0x1 << 9) +#define RT5660_JD_SPO_TRG_MASK (0x1 << 8) +#define RT5660_JD_SPO_TRG_SFT 8 +#define RT5660_JD_SPO_TRG_LO (0x0 << 8) +#define RT5660_JD_SPO_TRG_HI (0x1 << 8) + +/* IRQ Control 1 (0xbd) */ +#define RT5660_IRQ_JD_MASK (0x1 << 15) +#define RT5660_IRQ_JD_SFT 15 +#define RT5660_IRQ_JD_BP (0x0 << 15) +#define RT5660_IRQ_JD_NOR (0x1 << 15) +#define RT5660_IRQ_OT_MASK (0x1 << 14) +#define RT5660_IRQ_OT_SFT 14 +#define RT5660_IRQ_OT_BP (0x0 << 14) +#define RT5660_IRQ_OT_NOR (0x1 << 14) +#define RT5660_JD_STKY_MASK (0x1 << 13) +#define RT5660_JD_STKY_SFT 13 +#define RT5660_JD_STKY_DIS (0x0 << 13) +#define RT5660_JD_STKY_EN (0x1 << 13) +#define RT5660_OT_STKY_MASK (0x1 << 12) +#define RT5660_OT_STKY_SFT 12 +#define RT5660_OT_STKY_DIS (0x0 << 12) +#define RT5660_OT_STKY_EN (0x1 << 12) +#define RT5660_JD_P_MASK (0x1 << 11) +#define RT5660_JD_P_SFT 11 +#define RT5660_JD_P_NOR (0x0 << 11) +#define RT5660_JD_P_INV (0x1 << 11) +#define RT5660_OT_P_MASK (0x1 << 10) +#define RT5660_OT_P_SFT 10 +#define RT5660_OT_P_NOR (0x0 << 10) +#define RT5660_OT_P_INV (0x1 << 10) + +/* IRQ Control 2 (0xbe) */ +#define RT5660_IRQ_MB1_OC_MASK (0x1 << 15) +#define RT5660_IRQ_MB1_OC_SFT 15 +#define RT5660_IRQ_MB1_OC_BP (0x0 << 15) +#define RT5660_IRQ_MB1_OC_NOR (0x1 << 15) +#define RT5660_IRQ_MB2_OC_MASK (0x1 << 14) +#define RT5660_IRQ_MB2_OC_SFT 14 +#define RT5660_IRQ_MB2_OC_BP (0x0 << 14) +#define RT5660_IRQ_MB2_OC_NOR (0x1 << 14) +#define RT5660_MB1_OC_STKY_MASK (0x1 << 11) +#define RT5660_MB1_OC_STKY_SFT 11 +#define RT5660_MB1_OC_STKY_DIS (0x0 << 11) +#define RT5660_MB1_OC_STKY_EN (0x1 << 11) +#define RT5660_MB2_OC_STKY_MASK (0x1 << 10) +#define RT5660_MB2_OC_STKY_SFT 10 +#define RT5660_MB2_OC_STKY_DIS (0x0 << 10) +#define RT5660_MB2_OC_STKY_EN (0x1 << 10) +#define RT5660_MB1_OC_P_MASK (0x1 << 7) +#define RT5660_MB1_OC_P_SFT 7 +#define RT5660_MB1_OC_P_NOR (0x0 << 7) +#define RT5660_MB1_OC_P_INV (0x1 << 7) +#define RT5660_MB2_OC_P_MASK (0x1 << 6) +#define RT5660_MB2_OC_P_SFT 6 +#define RT5660_MB2_OC_P_NOR (0x0 << 6) +#define RT5660_MB2_OC_P_INV (0x1 << 6) +#define RT5660_MB1_OC_CLR (0x1 << 3) +#define RT5660_MB1_OC_CLR_SFT 3 +#define RT5660_MB2_OC_CLR (0x1 << 2) +#define RT5660_MB2_OC_CLR_SFT 2 + +/* GPIO Control 1 (0xc0) */ +#define RT5660_GP2_PIN_MASK (0x1 << 14) +#define RT5660_GP2_PIN_SFT 14 +#define RT5660_GP2_PIN_GPIO2 (0x0 << 14) +#define RT5660_GP2_PIN_DMIC1_SDA (0x1 << 14) +#define RT5660_GP1_PIN_MASK (0x3 << 12) +#define RT5660_GP1_PIN_SFT 12 +#define RT5660_GP1_PIN_GPIO1 (0x0 << 12) +#define RT5660_GP1_PIN_DMIC1_SCL (0x1 << 12) +#define RT5660_GP1_PIN_IRQ (0x2 << 12) +#define RT5660_GPIO_M_MASK (0x1 << 9) +#define RT5660_GPIO_M_SFT 9 +#define RT5660_GPIO_M_FLT (0x0 << 9) +#define RT5660_GPIO_M_PH (0x1 << 9) + +/* GPIO Control 3 (0xc2) */ +#define RT5660_GP2_PF_MASK (0x1 << 5) +#define RT5660_GP2_PF_SFT 5 +#define RT5660_GP2_PF_IN (0x0 << 5) +#define RT5660_GP2_PF_OUT (0x1 << 5) +#define RT5660_GP2_OUT_MASK (0x1 << 4) +#define RT5660_GP2_OUT_SFT 4 +#define RT5660_GP2_OUT_LO (0x0 << 4) +#define RT5660_GP2_OUT_HI (0x1 << 4) +#define RT5660_GP2_P_MASK (0x1 << 3) +#define RT5660_GP2_P_SFT 3 +#define RT5660_GP2_P_NOR (0x0 << 3) +#define RT5660_GP2_P_INV (0x1 << 3) +#define RT5660_GP1_PF_MASK (0x1 << 2) +#define RT5660_GP1_PF_SFT 2 +#define RT5660_GP1_PF_IN (0x0 << 2) +#define RT5660_GP1_PF_OUT (0x1 << 2) +#define RT5660_GP1_OUT_MASK (0x1 << 1) +#define RT5660_GP1_OUT_SFT 1 +#define RT5660_GP1_OUT_LO (0x0 << 1) +#define RT5660_GP1_OUT_HI (0x1 << 1) +#define RT5660_GP1_P_MASK (0x1) +#define RT5660_GP1_P_SFT 0 +#define RT5660_GP1_P_NOR (0x0) +#define RT5660_GP1_P_INV (0x1) + +/* Soft volume and zero cross control 1 (0xd9) */ +#define RT5660_SV_MASK (0x1 << 15) +#define RT5660_SV_SFT 15 +#define RT5660_SV_DIS (0x0 << 15) +#define RT5660_SV_EN (0x1 << 15) +#define RT5660_SPO_SV_MASK (0x1 << 14) +#define RT5660_SPO_SV_SFT 14 +#define RT5660_SPO_SV_DIS (0x0 << 14) +#define RT5660_SPO_SV_EN (0x1 << 14) +#define RT5660_OUT_SV_MASK (0x1 << 12) +#define RT5660_OUT_SV_SFT 12 +#define RT5660_OUT_SV_DIS (0x0 << 12) +#define RT5660_OUT_SV_EN (0x1 << 12) +#define RT5660_ZCD_DIG_MASK (0x1 << 11) +#define RT5660_ZCD_DIG_SFT 11 +#define RT5660_ZCD_DIG_DIS (0x0 << 11) +#define RT5660_ZCD_DIG_EN (0x1 << 11) +#define RT5660_ZCD_MASK (0x1 << 10) +#define RT5660_ZCD_SFT 10 +#define RT5660_ZCD_PD (0x0 << 10) +#define RT5660_ZCD_PU (0x1 << 10) +#define RT5660_SV_DLY_MASK (0xf) +#define RT5660_SV_DLY_SFT 0 + +/* Soft volume and zero cross control 2 (0xda) */ +#define RT5660_ZCD_SPO_MASK (0x1 << 15) +#define RT5660_ZCD_SPO_SFT 15 +#define RT5660_ZCD_SPO_DIS (0x0 << 15) +#define RT5660_ZCD_SPO_EN (0x1 << 15) +#define RT5660_ZCD_OMR_MASK (0x1 << 8) +#define RT5660_ZCD_OMR_SFT 8 +#define RT5660_ZCD_OMR_DIS (0x0 << 8) +#define RT5660_ZCD_OMR_EN (0x1 << 8) +#define RT5660_ZCD_OML_MASK (0x1 << 7) +#define RT5660_ZCD_OML_SFT 7 +#define RT5660_ZCD_OML_DIS (0x0 << 7) +#define RT5660_ZCD_OML_EN (0x1 << 7) +#define RT5660_ZCD_SPM_MASK (0x1 << 6) +#define RT5660_ZCD_SPM_SFT 6 +#define RT5660_ZCD_SPM_DIS (0x0 << 6) +#define RT5660_ZCD_SPM_EN (0x1 << 6) +#define RT5660_ZCD_RMR_MASK (0x1 << 5) +#define RT5660_ZCD_RMR_SFT 5 +#define RT5660_ZCD_RMR_DIS (0x0 << 5) +#define RT5660_ZCD_RMR_EN (0x1 << 5) +#define RT5660_ZCD_RML_MASK (0x1 << 4) +#define RT5660_ZCD_RML_SFT 4 +#define RT5660_ZCD_RML_DIS (0x0 << 4) +#define RT5660_ZCD_RML_EN (0x1 << 4) + +/* General Control 1 (0xfa) */ +#define RT5660_PWR_VREF_HP (0x1 << 11) +#define RT5660_PWR_VREF_HP_SFT 11 +#define RT5660_DIG_GATE_CTRL (0x1) +#define RT5660_DIG_GATE_CTRL_SFT 0 + +/* System Clock Source */ +#define RT5660_SCLK_S_MCLK 0 +#define RT5660_SCLK_S_PLL1 1 +#define RT5660_SCLK_S_RCCLK 2 + +/* PLL1 Source */ +#define RT5660_PLL1_S_MCLK 0 +#define RT5660_PLL1_S_BCLK 1 + +enum { + RT5660_AIF1, + RT5660_AIFS, +}; + +struct rt5660_priv { + struct snd_soc_codec *codec; + struct rt5660_platform_data pdata; + struct regmap *regmap; + struct clk *mclk; + + int sysclk; + int sysclk_src; + int lrck[RT5660_AIFS]; + int bclk[RT5660_AIFS]; + int master[RT5660_AIFS]; + + int pll_src; + int pll_in; + int pll_out; +}; + +#endif diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c new file mode 100644 index 000000000000..01a18d88f1eb --- /dev/null +++ b/sound/soc/codecs/rt5663.c @@ -0,0 +1,3218 @@ +/* + * rt5663.c -- RT5668/RT5663 ALSA SoC audio codec driver + * + * Copyright 2016 Realtek Semiconductor Corp. + * Author: Jack Yu <jack.yu@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/acpi.h> +#include <linux/workqueue.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/jack.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "rt5663.h" +#include "rl6231.h" + +#define RT5668_DEVICE_ID 0x6451 +#define RT5663_DEVICE_ID 0x6406 + +enum { + CODEC_TYPE_RT5668, + CODEC_TYPE_RT5663, +}; + +struct rt5663_priv { + struct snd_soc_codec *codec; + struct regmap *regmap; + struct delayed_work jack_detect_work; + struct snd_soc_jack *hs_jack; + struct timer_list btn_check_timer; + + int codec_type; + int sysclk; + int sysclk_src; + int lrck; + + int pll_src; + int pll_in; + int pll_out; + + int jack_type; +}; + +static const struct reg_default rt5668_reg[] = { + { 0x0000, 0x0000 }, + { 0x0001, 0xc8c8 }, + { 0x0002, 0x8080 }, + { 0x0003, 0x8000 }, + { 0x0004, 0xc80a }, + { 0x0005, 0x0000 }, + { 0x0006, 0x0000 }, + { 0x0007, 0x0000 }, + { 0x000a, 0x0000 }, + { 0x000b, 0x0000 }, + { 0x000c, 0x0000 }, + { 0x000d, 0x0000 }, + { 0x000f, 0x0808 }, + { 0x0010, 0x4000 }, + { 0x0011, 0x0000 }, + { 0x0012, 0x1404 }, + { 0x0013, 0x1000 }, + { 0x0014, 0xa00a }, + { 0x0015, 0x0404 }, + { 0x0016, 0x0404 }, + { 0x0017, 0x0011 }, + { 0x0018, 0xafaf }, + { 0x0019, 0xafaf }, + { 0x001a, 0xafaf }, + { 0x001b, 0x0011 }, + { 0x001c, 0x2f2f }, + { 0x001d, 0x2f2f }, + { 0x001e, 0x2f2f }, + { 0x001f, 0x0000 }, + { 0x0020, 0x0000 }, + { 0x0021, 0x0000 }, + { 0x0022, 0x5757 }, + { 0x0023, 0x0039 }, + { 0x0024, 0x000b }, + { 0x0026, 0xc0c0 }, + { 0x0027, 0xc0c0 }, + { 0x0028, 0xc0c0 }, + { 0x0029, 0x8080 }, + { 0x002a, 0xaaaa }, + { 0x002b, 0xaaaa }, + { 0x002c, 0xaba8 }, + { 0x002d, 0x0000 }, + { 0x002e, 0x0000 }, + { 0x002f, 0x0000 }, + { 0x0030, 0x0000 }, + { 0x0031, 0x5000 }, + { 0x0032, 0x0000 }, + { 0x0033, 0x0000 }, + { 0x0034, 0x0000 }, + { 0x0035, 0x0000 }, + { 0x003a, 0x0000 }, + { 0x003b, 0x0000 }, + { 0x003c, 0x00ff }, + { 0x003d, 0x0000 }, + { 0x003e, 0x00ff }, + { 0x003f, 0x0000 }, + { 0x0040, 0x0000 }, + { 0x0041, 0x00ff }, + { 0x0042, 0x0000 }, + { 0x0043, 0x00ff }, + { 0x0044, 0x0c0c }, + { 0x0049, 0xc00b }, + { 0x004a, 0x0000 }, + { 0x004b, 0x031f }, + { 0x004d, 0x0000 }, + { 0x004e, 0x001f }, + { 0x004f, 0x0000 }, + { 0x0050, 0x001f }, + { 0x0052, 0xf000 }, + { 0x0061, 0x0000 }, + { 0x0062, 0x0000 }, + { 0x0063, 0x003e }, + { 0x0064, 0x0000 }, + { 0x0065, 0x0000 }, + { 0x0066, 0x003f }, + { 0x0067, 0x0000 }, + { 0x006b, 0x0000 }, + { 0x006d, 0xff00 }, + { 0x006e, 0x2808 }, + { 0x006f, 0x000a }, + { 0x0070, 0x8000 }, + { 0x0071, 0x8000 }, + { 0x0072, 0x8000 }, + { 0x0073, 0x7000 }, + { 0x0074, 0x7770 }, + { 0x0075, 0x0002 }, + { 0x0076, 0x0001 }, + { 0x0078, 0x00f0 }, + { 0x0079, 0x0000 }, + { 0x007a, 0x0000 }, + { 0x007b, 0x0000 }, + { 0x007c, 0x0000 }, + { 0x007d, 0x0123 }, + { 0x007e, 0x4500 }, + { 0x007f, 0x8003 }, + { 0x0080, 0x0000 }, + { 0x0081, 0x0000 }, + { 0x0082, 0x0000 }, + { 0x0083, 0x0000 }, + { 0x0084, 0x0000 }, + { 0x0085, 0x0000 }, + { 0x0086, 0x0008 }, + { 0x0087, 0x0000 }, + { 0x0088, 0x0000 }, + { 0x0089, 0x0000 }, + { 0x008a, 0x0000 }, + { 0x008b, 0x0000 }, + { 0x008c, 0x0003 }, + { 0x008e, 0x0060 }, + { 0x008f, 0x1000 }, + { 0x0091, 0x0c26 }, + { 0x0092, 0x0073 }, + { 0x0093, 0x0000 }, + { 0x0094, 0x0080 }, + { 0x0098, 0x0000 }, + { 0x0099, 0x0000 }, + { 0x009a, 0x0007 }, + { 0x009f, 0x0000 }, + { 0x00a0, 0x0000 }, + { 0x00a1, 0x0002 }, + { 0x00a2, 0x0001 }, + { 0x00a3, 0x0002 }, + { 0x00a4, 0x0001 }, + { 0x00ae, 0x2040 }, + { 0x00af, 0x0000 }, + { 0x00b6, 0x0000 }, + { 0x00b7, 0x0000 }, + { 0x00b8, 0x0000 }, + { 0x00b9, 0x0000 }, + { 0x00ba, 0x0002 }, + { 0x00bb, 0x0000 }, + { 0x00be, 0x0000 }, + { 0x00c0, 0x0000 }, + { 0x00c1, 0x0aaa }, + { 0x00c2, 0xaa80 }, + { 0x00c3, 0x0003 }, + { 0x00c4, 0x0000 }, + { 0x00d0, 0x0000 }, + { 0x00d1, 0x2244 }, + { 0x00d2, 0x0000 }, + { 0x00d3, 0x3300 }, + { 0x00d4, 0x2200 }, + { 0x00d9, 0x0809 }, + { 0x00da, 0x0000 }, + { 0x00db, 0x0008 }, + { 0x00dc, 0x00c0 }, + { 0x00dd, 0x6724 }, + { 0x00de, 0x3131 }, + { 0x00df, 0x0008 }, + { 0x00e0, 0x4000 }, + { 0x00e1, 0x3131 }, + { 0x00e2, 0x600c }, + { 0x00ea, 0xb320 }, + { 0x00eb, 0x0000 }, + { 0x00ec, 0xb300 }, + { 0x00ed, 0x0000 }, + { 0x00ee, 0xb320 }, + { 0x00ef, 0x0000 }, + { 0x00f0, 0x0201 }, + { 0x00f1, 0x0ddd }, + { 0x00f2, 0x0ddd }, + { 0x00f6, 0x0000 }, + { 0x00f7, 0x0000 }, + { 0x00f8, 0x0000 }, + { 0x00fa, 0x0000 }, + { 0x00fb, 0x0000 }, + { 0x00fc, 0x0000 }, + { 0x00fd, 0x0000 }, + { 0x00fe, 0x10ec }, + { 0x00ff, 0x6451 }, + { 0x0100, 0xaaaa }, + { 0x0101, 0x000a }, + { 0x010a, 0xaaaa }, + { 0x010b, 0xa0a0 }, + { 0x010c, 0xaeae }, + { 0x010d, 0xaaaa }, + { 0x010e, 0xaaaa }, + { 0x010f, 0xaaaa }, + { 0x0110, 0xe002 }, + { 0x0111, 0xa602 }, + { 0x0112, 0xaaaa }, + { 0x0113, 0x2000 }, + { 0x0117, 0x0f00 }, + { 0x0125, 0x0420 }, + { 0x0132, 0x0000 }, + { 0x0133, 0x0000 }, + { 0x0136, 0x5555 }, + { 0x0137, 0x5540 }, + { 0x0138, 0x3700 }, + { 0x0139, 0x79a1 }, + { 0x013a, 0x2020 }, + { 0x013b, 0x2020 }, + { 0x013c, 0x2005 }, + { 0x013f, 0x0000 }, + { 0x0145, 0x0002 }, + { 0x0146, 0x0000 }, + { 0x0147, 0x0000 }, + { 0x0148, 0x0000 }, + { 0x0160, 0x4ec0 }, + { 0x0161, 0x0080 }, + { 0x0162, 0x0200 }, + { 0x0163, 0x0800 }, + { 0x0164, 0x0000 }, + { 0x0165, 0x0000 }, + { 0x0166, 0x0000 }, + { 0x0167, 0x000f }, + { 0x0168, 0x000f }, + { 0x0170, 0x4e80 }, + { 0x0171, 0x0080 }, + { 0x0172, 0x0200 }, + { 0x0173, 0x0800 }, + { 0x0174, 0x00ff }, + { 0x0175, 0x0000 }, + { 0x0190, 0x4131 }, + { 0x0191, 0x4131 }, + { 0x0192, 0x4131 }, + { 0x0193, 0x4131 }, + { 0x0194, 0x0000 }, + { 0x0195, 0x0000 }, + { 0x0196, 0x0000 }, + { 0x0197, 0x0000 }, + { 0x0198, 0x0000 }, + { 0x0199, 0x0000 }, + { 0x01a0, 0x1e64 }, + { 0x01a1, 0x06a3 }, + { 0x01a2, 0x0000 }, + { 0x01a3, 0x0000 }, + { 0x01a4, 0x0000 }, + { 0x01a5, 0x0000 }, + { 0x01a6, 0x0000 }, + { 0x01a7, 0x0000 }, + { 0x01a8, 0x0000 }, + { 0x01a9, 0x0000 }, + { 0x01aa, 0x0000 }, + { 0x01ab, 0x0000 }, + { 0x01b5, 0x0000 }, + { 0x01b6, 0x01c3 }, + { 0x01b7, 0x02a0 }, + { 0x01b8, 0x03e9 }, + { 0x01b9, 0x1389 }, + { 0x01ba, 0xc351 }, + { 0x01bb, 0x0009 }, + { 0x01bc, 0x0018 }, + { 0x01bd, 0x002a }, + { 0x01be, 0x004c }, + { 0x01bf, 0x0097 }, + { 0x01c0, 0x433d }, + { 0x01c1, 0x0000 }, + { 0x01c2, 0x0000 }, + { 0x01c3, 0x0000 }, + { 0x01c4, 0x0000 }, + { 0x01c5, 0x0000 }, + { 0x01c6, 0x0000 }, + { 0x01c7, 0x0000 }, + { 0x01c8, 0x40af }, + { 0x01c9, 0x0702 }, + { 0x01ca, 0x0000 }, + { 0x01cb, 0x0000 }, + { 0x01cc, 0x5757 }, + { 0x01cd, 0x5757 }, + { 0x01ce, 0x5757 }, + { 0x01cf, 0x5757 }, + { 0x01d0, 0x5757 }, + { 0x01d1, 0x5757 }, + { 0x01d2, 0x5757 }, + { 0x01d3, 0x5757 }, + { 0x01d4, 0x5757 }, + { 0x01d5, 0x5757 }, + { 0x01d6, 0x003c }, + { 0x01da, 0x0000 }, + { 0x01db, 0x0000 }, + { 0x01dc, 0x0000 }, + { 0x01de, 0x7c00 }, + { 0x01df, 0x0320 }, + { 0x01e0, 0x06a1 }, + { 0x01e1, 0x0000 }, + { 0x01e2, 0x0000 }, + { 0x01e3, 0x0000 }, + { 0x01e4, 0x0000 }, + { 0x01e5, 0x0000 }, + { 0x01e6, 0x0001 }, + { 0x01e7, 0x0000 }, + { 0x01e8, 0x0000 }, + { 0x01ea, 0x0000 }, + { 0x01eb, 0x0000 }, + { 0x01ec, 0x0000 }, + { 0x01ed, 0x0000 }, + { 0x01ee, 0x0000 }, + { 0x01ef, 0x0000 }, + { 0x01f0, 0x0000 }, + { 0x01f1, 0x0000 }, + { 0x01f2, 0x0000 }, + { 0x01f3, 0x0000 }, + { 0x01f4, 0x0000 }, + { 0x0200, 0x0000 }, + { 0x0201, 0x0000 }, + { 0x0202, 0x0000 }, + { 0x0203, 0x0000 }, + { 0x0204, 0x0000 }, + { 0x0205, 0x0000 }, + { 0x0206, 0x0000 }, + { 0x0207, 0x0000 }, + { 0x0208, 0x0000 }, + { 0x0210, 0x60b1 }, + { 0x0211, 0xa000 }, + { 0x0212, 0x024c }, + { 0x0213, 0xf7ff }, + { 0x0214, 0x024c }, + { 0x0215, 0x0102 }, + { 0x0216, 0x00a3 }, + { 0x0217, 0x0048 }, + { 0x0218, 0x92c0 }, + { 0x0219, 0x0000 }, + { 0x021a, 0x00c8 }, + { 0x021b, 0x0020 }, + { 0x02fa, 0x0000 }, + { 0x02fb, 0x0000 }, + { 0x02fc, 0x0000 }, + { 0x02ff, 0x0110 }, + { 0x0300, 0x001f }, + { 0x0301, 0x032c }, + { 0x0302, 0x5f21 }, + { 0x0303, 0x4000 }, + { 0x0304, 0x4000 }, + { 0x0305, 0x06d5 }, + { 0x0306, 0x8000 }, + { 0x0307, 0x0700 }, + { 0x0310, 0x4560 }, + { 0x0311, 0xa4a8 }, + { 0x0312, 0x7418 }, + { 0x0313, 0x0000 }, + { 0x0314, 0x0006 }, + { 0x0315, 0xffff }, + { 0x0316, 0xc400 }, + { 0x0317, 0x0000 }, + { 0x0330, 0x00a6 }, + { 0x0331, 0x04c3 }, + { 0x0332, 0x27c8 }, + { 0x0333, 0xbf50 }, + { 0x0334, 0x0045 }, + { 0x0335, 0x0007 }, + { 0x0336, 0x7418 }, + { 0x0337, 0x0501 }, + { 0x0338, 0x0000 }, + { 0x0339, 0x0010 }, + { 0x033a, 0x1010 }, + { 0x03c0, 0x7e00 }, + { 0x03c1, 0x8000 }, + { 0x03c2, 0x8000 }, + { 0x03c3, 0x8000 }, + { 0x03c4, 0x8000 }, + { 0x03c5, 0x8000 }, + { 0x03c6, 0x8000 }, + { 0x03c7, 0x8000 }, + { 0x03c8, 0x8000 }, + { 0x03c9, 0x8000 }, + { 0x03ca, 0x8000 }, + { 0x03cb, 0x8000 }, + { 0x03cc, 0x8000 }, + { 0x03d0, 0x0000 }, + { 0x03d1, 0x0000 }, + { 0x03d2, 0x0000 }, + { 0x03d3, 0x0000 }, + { 0x03d4, 0x2000 }, + { 0x03d5, 0x2000 }, + { 0x03d6, 0x0000 }, + { 0x03d7, 0x0000 }, + { 0x03d8, 0x2000 }, + { 0x03d9, 0x2000 }, + { 0x03da, 0x2000 }, + { 0x03db, 0x2000 }, + { 0x03dc, 0x0000 }, + { 0x03dd, 0x0000 }, + { 0x03de, 0x0000 }, + { 0x03df, 0x2000 }, + { 0x03e0, 0x0000 }, + { 0x03e1, 0x0000 }, + { 0x03e2, 0x0000 }, + { 0x03e3, 0x0000 }, + { 0x03e4, 0x0000 }, + { 0x03e5, 0x0000 }, + { 0x03e6, 0x0000 }, + { 0x03e7, 0x0000 }, + { 0x03e8, 0x0000 }, + { 0x03e9, 0x0000 }, + { 0x03ea, 0x0000 }, + { 0x03eb, 0x0000 }, + { 0x03ec, 0x0000 }, + { 0x03ed, 0x0000 }, + { 0x03ee, 0x0000 }, + { 0x03ef, 0x0000 }, + { 0x03f0, 0x0800 }, + { 0x03f1, 0x0800 }, + { 0x03f2, 0x0800 }, + { 0x03f3, 0x0800 }, + { 0x03fe, 0x0000 }, + { 0x03ff, 0x0000 }, + { 0x07f0, 0x0000 }, + { 0x07fa, 0x0000 }, +}; + +static const struct reg_default rt5663_reg[] = { + { 0x0000, 0x0000 }, + { 0x0002, 0x0008 }, + { 0x0005, 0x1000 }, + { 0x0006, 0x1000 }, + { 0x000a, 0x0000 }, + { 0x0010, 0x000f }, + { 0x0015, 0x42c1 }, + { 0x0016, 0x0000 }, + { 0x0018, 0x000b }, + { 0x0019, 0xafaf }, + { 0x001c, 0x2f2f }, + { 0x001f, 0x0000 }, + { 0x0022, 0x5757 }, + { 0x0023, 0x0039 }, + { 0x0026, 0xc0c0 }, + { 0x0029, 0x8080 }, + { 0x002a, 0xa0a0 }, + { 0x002c, 0x000c }, + { 0x002d, 0x0000 }, + { 0x0040, 0x0808 }, + { 0x0061, 0x0000 }, + { 0x0062, 0x0000 }, + { 0x0063, 0x003e }, + { 0x0064, 0x0000 }, + { 0x0065, 0x0000 }, + { 0x0066, 0x0000 }, + { 0x006b, 0x0000 }, + { 0x006e, 0x0000 }, + { 0x006f, 0x0000 }, + { 0x0070, 0x8020 }, + { 0x0073, 0x1000 }, + { 0x0074, 0xe400 }, + { 0x0075, 0x0002 }, + { 0x0076, 0x0001 }, + { 0x0077, 0x00f0 }, + { 0x0078, 0x0000 }, + { 0x0079, 0x0000 }, + { 0x007a, 0x0123 }, + { 0x007b, 0x8003 }, + { 0x0080, 0x0000 }, + { 0x0081, 0x0000 }, + { 0x0082, 0x0000 }, + { 0x0083, 0x0000 }, + { 0x0084, 0x0000 }, + { 0x0086, 0x0008 }, + { 0x0087, 0x0000 }, + { 0x008a, 0x0000 }, + { 0x008b, 0x0000 }, + { 0x008c, 0x0003 }, + { 0x008e, 0x0004 }, + { 0x008f, 0x1000 }, + { 0x0090, 0x0646 }, + { 0x0091, 0x0e3e }, + { 0x0092, 0x1071 }, + { 0x0093, 0x0000 }, + { 0x0094, 0x0080 }, + { 0x0097, 0x0000 }, + { 0x0098, 0x0000 }, + { 0x009a, 0x0000 }, + { 0x009f, 0x0000 }, + { 0x00ae, 0x2000 }, + { 0x00af, 0x0000 }, + { 0x00b6, 0x0000 }, + { 0x00b7, 0x0000 }, + { 0x00b8, 0x0000 }, + { 0x00ba, 0x0000 }, + { 0x00bb, 0x0000 }, + { 0x00be, 0x0000 }, + { 0x00bf, 0x0000 }, + { 0x00c0, 0x0000 }, + { 0x00c1, 0x0000 }, + { 0x00c5, 0x0000 }, + { 0x00cb, 0xa02f }, + { 0x00cc, 0x0000 }, + { 0x00cd, 0x0e02 }, + { 0x00d9, 0x08f9 }, + { 0x00db, 0x0008 }, + { 0x00dc, 0x00c0 }, + { 0x00dd, 0x6724 }, + { 0x00de, 0x3131 }, + { 0x00df, 0x0008 }, + { 0x00e0, 0x4000 }, + { 0x00e1, 0x3131 }, + { 0x00e2, 0x0043 }, + { 0x00e4, 0x400b }, + { 0x00e5, 0x8031 }, + { 0x00e6, 0x3080 }, + { 0x00e7, 0x4100 }, + { 0x00e8, 0x1400 }, + { 0x00e9, 0xe00a }, + { 0x00ea, 0x0404 }, + { 0x00eb, 0x0404 }, + { 0x00ec, 0xb320 }, + { 0x00ed, 0x0000 }, + { 0x00f4, 0x0000 }, + { 0x00f6, 0x0000 }, + { 0x00f8, 0x0000 }, + { 0x00fa, 0x8000 }, + { 0x00fd, 0x0001 }, + { 0x00fe, 0x10ec }, + { 0x00ff, 0x6406 }, + { 0x0100, 0xa0a0 }, + { 0x0108, 0x4444 }, + { 0x0109, 0x4444 }, + { 0x010a, 0xaaaa }, + { 0x010b, 0x00a0 }, + { 0x010c, 0x8aaa }, + { 0x010d, 0xaaaa }, + { 0x010e, 0x2aaa }, + { 0x010f, 0x002a }, + { 0x0110, 0xa0a4 }, + { 0x0111, 0x4602 }, + { 0x0112, 0x0101 }, + { 0x0113, 0x2000 }, + { 0x0114, 0x0000 }, + { 0x0116, 0x0000 }, + { 0x0117, 0x0f00 }, + { 0x0118, 0x0006 }, + { 0x0125, 0x2224 }, + { 0x0126, 0x5550 }, + { 0x0127, 0x0400 }, + { 0x0128, 0x7711 }, + { 0x0132, 0x0004 }, + { 0x0137, 0x5441 }, + { 0x0139, 0x79a1 }, + { 0x013a, 0x30c0 }, + { 0x013b, 0x2000 }, + { 0x013c, 0x2005 }, + { 0x013d, 0x30c0 }, + { 0x013e, 0x0000 }, + { 0x0140, 0x3700 }, + { 0x0141, 0x1f00 }, + { 0x0144, 0x0000 }, + { 0x0145, 0x0002 }, + { 0x0146, 0x0000 }, + { 0x0160, 0x0e80 }, + { 0x0161, 0x0020 }, + { 0x0162, 0x0080 }, + { 0x0163, 0x0800 }, + { 0x0164, 0x0000 }, + { 0x0165, 0x0000 }, + { 0x0166, 0x0000 }, + { 0x0167, 0x1417 }, + { 0x0168, 0x0017 }, + { 0x0169, 0x0017 }, + { 0x0180, 0x2000 }, + { 0x0181, 0x0000 }, + { 0x0182, 0x0000 }, + { 0x0183, 0x2000 }, + { 0x0184, 0x0000 }, + { 0x0185, 0x0000 }, + { 0x01b0, 0x4b30 }, + { 0x01b1, 0x0000 }, + { 0x01b2, 0xd870 }, + { 0x01b3, 0x0000 }, + { 0x01b4, 0x0030 }, + { 0x01b5, 0x5757 }, + { 0x01b6, 0x5757 }, + { 0x01b7, 0x5757 }, + { 0x01b8, 0x5757 }, + { 0x01c0, 0x433d }, + { 0x01c1, 0x0540 }, + { 0x01c2, 0x0000 }, + { 0x01c3, 0x0000 }, + { 0x01c4, 0x0000 }, + { 0x01c5, 0x0009 }, + { 0x01c6, 0x0018 }, + { 0x01c7, 0x002a }, + { 0x01c8, 0x004c }, + { 0x01c9, 0x0097 }, + { 0x01ca, 0x01c3 }, + { 0x01cb, 0x03e9 }, + { 0x01cc, 0x1389 }, + { 0x01cd, 0xc351 }, + { 0x01ce, 0x0000 }, + { 0x01cf, 0x0000 }, + { 0x01d0, 0x0000 }, + { 0x01d1, 0x0000 }, + { 0x01d2, 0x0000 }, + { 0x01d3, 0x003c }, + { 0x01d4, 0x5757 }, + { 0x01d5, 0x5757 }, + { 0x01d6, 0x5757 }, + { 0x01d7, 0x5757 }, + { 0x01d8, 0x5757 }, + { 0x01d9, 0x5757 }, + { 0x01da, 0x0000 }, + { 0x01db, 0x0000 }, + { 0x01dd, 0x0009 }, + { 0x01de, 0x7f00 }, + { 0x01df, 0x00c8 }, + { 0x01e0, 0x0691 }, + { 0x01e1, 0x0000 }, + { 0x01e2, 0x0000 }, + { 0x01e3, 0x0000 }, + { 0x01e4, 0x0000 }, + { 0x01e5, 0x0040 }, + { 0x01e6, 0x0000 }, + { 0x01e7, 0x0000 }, + { 0x01e8, 0x0000 }, + { 0x01ea, 0x0000 }, + { 0x01eb, 0x0000 }, + { 0x01ec, 0x0000 }, + { 0x01ed, 0x0000 }, + { 0x01ee, 0x0000 }, + { 0x01ef, 0x0000 }, + { 0x01f0, 0x0000 }, + { 0x01f1, 0x0000 }, + { 0x01f2, 0x0000 }, + { 0x0200, 0x0000 }, + { 0x0201, 0x2244 }, + { 0x0202, 0xaaaa }, + { 0x0250, 0x8010 }, + { 0x0251, 0x0000 }, + { 0x0252, 0x028a }, + { 0x02fa, 0x0000 }, + { 0x02fb, 0x0000 }, + { 0x02fc, 0x0000 }, + { 0x0300, 0x0000 }, + { 0x03d0, 0x0000 }, + { 0x03d1, 0x0000 }, + { 0x03d2, 0x0000 }, + { 0x03d3, 0x0000 }, + { 0x03d4, 0x2000 }, + { 0x03d5, 0x2000 }, + { 0x03d6, 0x0000 }, + { 0x03d7, 0x0000 }, + { 0x03d8, 0x2000 }, + { 0x03d9, 0x2000 }, + { 0x03da, 0x2000 }, + { 0x03db, 0x2000 }, + { 0x03dc, 0x0000 }, + { 0x03dd, 0x0000 }, + { 0x03de, 0x0000 }, + { 0x03df, 0x2000 }, + { 0x03e0, 0x0000 }, + { 0x03e1, 0x0000 }, + { 0x03e2, 0x0000 }, + { 0x03e3, 0x0000 }, + { 0x03e4, 0x0000 }, + { 0x03e5, 0x0000 }, + { 0x03e6, 0x0000 }, + { 0x03e7, 0x0000 }, + { 0x03e8, 0x0000 }, + { 0x03e9, 0x0000 }, + { 0x03ea, 0x0000 }, + { 0x03eb, 0x0000 }, + { 0x03ec, 0x0000 }, + { 0x03ed, 0x0000 }, + { 0x03ee, 0x0000 }, + { 0x03ef, 0x0000 }, + { 0x03f0, 0x0800 }, + { 0x03f1, 0x0800 }, + { 0x03f2, 0x0800 }, + { 0x03f3, 0x0800 }, +}; + +static bool rt5663_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5663_RESET: + case RT5663_SIL_DET_CTL: + case RT5663_HP_IMP_GAIN_2: + case RT5663_AD_DA_MIXER: + case RT5663_FRAC_DIV_2: + case RT5663_MICBIAS_1: + case RT5663_ASRC_11_2: + case RT5663_ADC_EQ_1: + case RT5663_INT_ST_1: + case RT5663_INT_ST_2: + case RT5663_GPIO_STA: + case RT5663_SIN_GEN_1: + case RT5663_IL_CMD_1: + case RT5663_IL_CMD_5: + case RT5663_IL_CMD_PWRSAV1: + case RT5663_EM_JACK_TYPE_1: + case RT5663_EM_JACK_TYPE_2: + case RT5663_EM_JACK_TYPE_3: + case RT5663_JD_CTRL2: + case RT5663_VENDOR_ID: + case RT5663_VENDOR_ID_1: + case RT5663_VENDOR_ID_2: + case RT5663_PLL_INT_REG: + case RT5663_SOFT_RAMP: + case RT5663_STO_DRE_1: + case RT5663_STO_DRE_5: + case RT5663_STO_DRE_6: + case RT5663_STO_DRE_7: + case RT5663_MIC_DECRO_1: + case RT5663_MIC_DECRO_4: + case RT5663_HP_IMP_SEN_1: + case RT5663_HP_IMP_SEN_3: + case RT5663_HP_IMP_SEN_4: + case RT5663_HP_IMP_SEN_5: + case RT5663_HP_CALIB_1_1: + case RT5663_HP_CALIB_9: + case RT5663_HP_CALIB_ST1: + case RT5663_HP_CALIB_ST2: + case RT5663_HP_CALIB_ST3: + case RT5663_HP_CALIB_ST4: + case RT5663_HP_CALIB_ST5: + case RT5663_HP_CALIB_ST6: + case RT5663_HP_CALIB_ST7: + case RT5663_HP_CALIB_ST8: + case RT5663_HP_CALIB_ST9: + case RT5663_ANA_JD: + return true; + default: + return false; + } +} + +static bool rt5663_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5663_RESET: + case RT5663_HP_OUT_EN: + case RT5663_HP_LCH_DRE: + case RT5663_HP_RCH_DRE: + case RT5663_CALIB_BST: + case RT5663_RECMIX: + case RT5663_SIL_DET_CTL: + case RT5663_PWR_SAV_SILDET: + case RT5663_SIDETONE_CTL: + case RT5663_STO1_DAC_DIG_VOL: + case RT5663_STO1_ADC_DIG_VOL: + case RT5663_STO1_BOOST: + case RT5663_HP_IMP_GAIN_1: + case RT5663_HP_IMP_GAIN_2: + case RT5663_STO1_ADC_MIXER: + case RT5663_AD_DA_MIXER: + case RT5663_STO_DAC_MIXER: + case RT5663_DIG_SIDE_MIXER: + case RT5663_BYPASS_STO_DAC: + case RT5663_CALIB_REC_MIX: + case RT5663_PWR_DIG_1: + case RT5663_PWR_DIG_2: + case RT5663_PWR_ANLG_1: + case RT5663_PWR_ANLG_2: + case RT5663_PWR_ANLG_3: + case RT5663_PWR_MIXER: + case RT5663_SIG_CLK_DET: + case RT5663_PRE_DIV_GATING_1: + case RT5663_PRE_DIV_GATING_2: + case RT5663_I2S1_SDP: + case RT5663_ADDA_CLK_1: + case RT5663_ADDA_RST: + case RT5663_FRAC_DIV_1: + case RT5663_FRAC_DIV_2: + case RT5663_TDM_1: + case RT5663_TDM_2: + case RT5663_TDM_3: + case RT5663_TDM_4: + case RT5663_TDM_5: + case RT5663_GLB_CLK: + case RT5663_PLL_1: + case RT5663_PLL_2: + case RT5663_ASRC_1: + case RT5663_ASRC_2: + case RT5663_ASRC_4: + case RT5663_DUMMY_REG: + case RT5663_ASRC_8: + case RT5663_ASRC_9: + case RT5663_ASRC_11: + case RT5663_DEPOP_1: + case RT5663_DEPOP_2: + case RT5663_DEPOP_3: + case RT5663_HP_CHARGE_PUMP_1: + case RT5663_HP_CHARGE_PUMP_2: + case RT5663_MICBIAS_1: + case RT5663_RC_CLK: + case RT5663_ASRC_11_2: + case RT5663_DUMMY_REG_2: + case RT5663_REC_PATH_GAIN: + case RT5663_AUTO_1MRC_CLK: + case RT5663_ADC_EQ_1: + case RT5663_ADC_EQ_2: + case RT5663_IRQ_1: + case RT5663_IRQ_2: + case RT5663_IRQ_3: + case RT5663_IRQ_4: + case RT5663_IRQ_5: + case RT5663_INT_ST_1: + case RT5663_INT_ST_2: + case RT5663_GPIO_1: + case RT5663_GPIO_2: + case RT5663_GPIO_STA: + case RT5663_SIN_GEN_1: + case RT5663_SIN_GEN_2: + case RT5663_SIN_GEN_3: + case RT5663_SOF_VOL_ZC1: + case RT5663_IL_CMD_1: + case RT5663_IL_CMD_2: + case RT5663_IL_CMD_3: + case RT5663_IL_CMD_4: + case RT5663_IL_CMD_5: + case RT5663_IL_CMD_6: + case RT5663_IL_CMD_7: + case RT5663_IL_CMD_8: + case RT5663_IL_CMD_PWRSAV1: + case RT5663_IL_CMD_PWRSAV2: + case RT5663_EM_JACK_TYPE_1: + case RT5663_EM_JACK_TYPE_2: + case RT5663_EM_JACK_TYPE_3: + case RT5663_EM_JACK_TYPE_4: + case RT5663_EM_JACK_TYPE_5: + case RT5663_EM_JACK_TYPE_6: + case RT5663_STO1_HPF_ADJ1: + case RT5663_STO1_HPF_ADJ2: + case RT5663_FAST_OFF_MICBIAS: + case RT5663_JD_CTRL1: + case RT5663_JD_CTRL2: + case RT5663_DIG_MISC: + case RT5663_VENDOR_ID: + case RT5663_VENDOR_ID_1: + case RT5663_VENDOR_ID_2: + case RT5663_DIG_VOL_ZCD: + case RT5663_ANA_BIAS_CUR_1: + case RT5663_ANA_BIAS_CUR_2: + case RT5663_ANA_BIAS_CUR_3: + case RT5663_ANA_BIAS_CUR_4: + case RT5663_ANA_BIAS_CUR_5: + case RT5663_ANA_BIAS_CUR_6: + case RT5663_BIAS_CUR_5: + case RT5663_BIAS_CUR_6: + case RT5663_BIAS_CUR_7: + case RT5663_BIAS_CUR_8: + case RT5663_DACREF_LDO: + case RT5663_DUMMY_REG_3: + case RT5663_BIAS_CUR_9: + case RT5663_DUMMY_REG_4: + case RT5663_VREFADJ_OP: + case RT5663_VREF_RECMIX: + case RT5663_CHARGE_PUMP_1: + case RT5663_CHARGE_PUMP_1_2: + case RT5663_CHARGE_PUMP_1_3: + case RT5663_CHARGE_PUMP_2: + case RT5663_DIG_IN_PIN1: + case RT5663_PAD_DRV_CTL: + case RT5663_PLL_INT_REG: + case RT5663_CHOP_DAC_L: + case RT5663_CHOP_ADC: + case RT5663_CALIB_ADC: + case RT5663_CHOP_DAC_R: + case RT5663_DUMMY_CTL_DACLR: + case RT5663_DUMMY_REG_5: + case RT5663_SOFT_RAMP: + case RT5663_TEST_MODE_1: + case RT5663_TEST_MODE_2: + case RT5663_TEST_MODE_3: + case RT5663_STO_DRE_1: + case RT5663_STO_DRE_2: + case RT5663_STO_DRE_3: + case RT5663_STO_DRE_4: + case RT5663_STO_DRE_5: + case RT5663_STO_DRE_6: + case RT5663_STO_DRE_7: + case RT5663_STO_DRE_8: + case RT5663_STO_DRE_9: + case RT5663_STO_DRE_10: + case RT5663_MIC_DECRO_1: + case RT5663_MIC_DECRO_2: + case RT5663_MIC_DECRO_3: + case RT5663_MIC_DECRO_4: + case RT5663_MIC_DECRO_5: + case RT5663_MIC_DECRO_6: + case RT5663_HP_DECRO_1: + case RT5663_HP_DECRO_2: + case RT5663_HP_DECRO_3: + case RT5663_HP_DECRO_4: + case RT5663_HP_DECOUP: + case RT5663_HP_IMP_SEN_MAP8: + case RT5663_HP_IMP_SEN_MAP9: + case RT5663_HP_IMP_SEN_MAP10: + case RT5663_HP_IMP_SEN_MAP11: + case RT5663_HP_IMP_SEN_1: + case RT5663_HP_IMP_SEN_2: + case RT5663_HP_IMP_SEN_3: + case RT5663_HP_IMP_SEN_4: + case RT5663_HP_IMP_SEN_5: + case RT5663_HP_IMP_SEN_6: + case RT5663_HP_IMP_SEN_7: + case RT5663_HP_IMP_SEN_8: + case RT5663_HP_IMP_SEN_9: + case RT5663_HP_IMP_SEN_10: + case RT5663_HP_IMP_SEN_11: + case RT5663_HP_IMP_SEN_12: + case RT5663_HP_IMP_SEN_13: + case RT5663_HP_IMP_SEN_14: + case RT5663_HP_IMP_SEN_15: + case RT5663_HP_IMP_SEN_16: + case RT5663_HP_IMP_SEN_17: + case RT5663_HP_IMP_SEN_18: + case RT5663_HP_IMP_SEN_19: + case RT5663_HP_IMPSEN_DIG5: + case RT5663_HP_IMPSEN_MAP1: + case RT5663_HP_IMPSEN_MAP2: + case RT5663_HP_IMPSEN_MAP3: + case RT5663_HP_IMPSEN_MAP4: + case RT5663_HP_IMPSEN_MAP5: + case RT5663_HP_IMPSEN_MAP7: + case RT5663_HP_LOGIC_1: + case RT5663_HP_LOGIC_2: + case RT5663_HP_CALIB_1: + case RT5663_HP_CALIB_1_1: + case RT5663_HP_CALIB_2: + case RT5663_HP_CALIB_3: + case RT5663_HP_CALIB_4: + case RT5663_HP_CALIB_5: + case RT5663_HP_CALIB_5_1: + case RT5663_HP_CALIB_6: + case RT5663_HP_CALIB_7: + case RT5663_HP_CALIB_9: + case RT5663_HP_CALIB_10: + case RT5663_HP_CALIB_11: + case RT5663_HP_CALIB_ST1: + case RT5663_HP_CALIB_ST2: + case RT5663_HP_CALIB_ST3: + case RT5663_HP_CALIB_ST4: + case RT5663_HP_CALIB_ST5: + case RT5663_HP_CALIB_ST6: + case RT5663_HP_CALIB_ST7: + case RT5663_HP_CALIB_ST8: + case RT5663_HP_CALIB_ST9: + case RT5663_HP_AMP_DET: + case RT5663_DUMMY_REG_6: + case RT5663_HP_BIAS: + case RT5663_CBJ_1: + case RT5663_CBJ_2: + case RT5663_CBJ_3: + case RT5663_DUMMY_1: + case RT5663_DUMMY_2: + case RT5663_DUMMY_3: + case RT5663_ANA_JD: + case RT5663_ADC_LCH_LPF1_A1: + case RT5663_ADC_RCH_LPF1_A1: + case RT5663_ADC_LCH_LPF1_H0: + case RT5663_ADC_RCH_LPF1_H0: + case RT5663_ADC_LCH_BPF1_A1: + case RT5663_ADC_RCH_BPF1_A1: + case RT5663_ADC_LCH_BPF1_A2: + case RT5663_ADC_RCH_BPF1_A2: + case RT5663_ADC_LCH_BPF1_H0: + case RT5663_ADC_RCH_BPF1_H0: + case RT5663_ADC_LCH_BPF2_A1: + case RT5663_ADC_RCH_BPF2_A1: + case RT5663_ADC_LCH_BPF2_A2: + case RT5663_ADC_RCH_BPF2_A2: + case RT5663_ADC_LCH_BPF2_H0: + case RT5663_ADC_RCH_BPF2_H0: + case RT5663_ADC_LCH_BPF3_A1: + case RT5663_ADC_RCH_BPF3_A1: + case RT5663_ADC_LCH_BPF3_A2: + case RT5663_ADC_RCH_BPF3_A2: + case RT5663_ADC_LCH_BPF3_H0: + case RT5663_ADC_RCH_BPF3_H0: + case RT5663_ADC_LCH_BPF4_A1: + case RT5663_ADC_RCH_BPF4_A1: + case RT5663_ADC_LCH_BPF4_A2: + case RT5663_ADC_RCH_BPF4_A2: + case RT5663_ADC_LCH_BPF4_H0: + case RT5663_ADC_RCH_BPF4_H0: + case RT5663_ADC_LCH_HPF1_A1: + case RT5663_ADC_RCH_HPF1_A1: + case RT5663_ADC_LCH_HPF1_H0: + case RT5663_ADC_RCH_HPF1_H0: + case RT5663_ADC_EQ_PRE_VOL_L: + case RT5663_ADC_EQ_PRE_VOL_R: + case RT5663_ADC_EQ_POST_VOL_L: + case RT5663_ADC_EQ_POST_VOL_R: + return true; + default: + return false; + } +} + +static bool rt5668_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5663_RESET: + case RT5668_CBJ_TYPE_2: + case RT5668_PDM_OUT_CTL: + case RT5668_PDM_I2C_DATA_CTL1: + case RT5668_PDM_I2C_DATA_CTL4: + case RT5668_ALC_BK_GAIN: + case RT5663_PLL_2: + case RT5663_MICBIAS_1: + case RT5663_ADC_EQ_1: + case RT5663_INT_ST_1: + case RT5668_GPIO_STA: + case RT5663_IL_CMD_1: + case RT5663_IL_CMD_5: + case RT5668_A_JD_CTRL: + case RT5663_JD_CTRL2: + case RT5663_VENDOR_ID: + case RT5663_VENDOR_ID_1: + case RT5663_VENDOR_ID_2: + case RT5663_STO_DRE_1: + case RT5663_STO_DRE_5: + case RT5663_STO_DRE_6: + case RT5663_STO_DRE_7: + case RT5668_MONO_DYNA_6: + case RT5668_STO1_SIL_DET: + case RT5668_MONOL_SIL_DET: + case RT5668_MONOR_SIL_DET: + case RT5668_STO2_DAC_SIL: + case RT5668_MONO_AMP_CAL_ST1: + case RT5668_MONO_AMP_CAL_ST2: + case RT5668_MONO_AMP_CAL_ST3: + case RT5668_MONO_AMP_CAL_ST4: + case RT5663_HP_IMP_SEN_2: + case RT5663_HP_IMP_SEN_3: + case RT5663_HP_IMP_SEN_4: + case RT5663_HP_IMP_SEN_10: + case RT5663_HP_CALIB_1: + case RT5663_HP_CALIB_10: + case RT5663_HP_CALIB_ST1: + case RT5663_HP_CALIB_ST4: + case RT5663_HP_CALIB_ST5: + case RT5663_HP_CALIB_ST6: + case RT5663_HP_CALIB_ST7: + case RT5663_HP_CALIB_ST8: + case RT5663_HP_CALIB_ST9: + case RT5668_HP_CALIB_ST10: + case RT5668_HP_CALIB_ST11: + return true; + default: + return false; + } +} + +static bool rt5668_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5668_LOUT_CTRL: + case RT5668_HP_AMP_2: + case RT5668_MONO_OUT: + case RT5668_MONO_GAIN: + case RT5668_AEC_BST: + case RT5668_IN1_IN2: + case RT5668_IN3_IN4: + case RT5668_INL1_INR1: + case RT5668_CBJ_TYPE_2: + case RT5668_CBJ_TYPE_3: + case RT5668_CBJ_TYPE_4: + case RT5668_CBJ_TYPE_5: + case RT5668_CBJ_TYPE_8: + case RT5668_DAC3_DIG_VOL: + case RT5668_DAC3_CTRL: + case RT5668_MONO_ADC_DIG_VOL: + case RT5668_STO2_ADC_DIG_VOL: + case RT5668_MONO_ADC_BST_GAIN: + case RT5668_STO2_ADC_BST_GAIN: + case RT5668_SIDETONE_CTRL: + case RT5668_MONO1_ADC_MIXER: + case RT5668_STO2_ADC_MIXER: + case RT5668_MONO_DAC_MIXER: + case RT5668_DAC2_SRC_CTRL: + case RT5668_IF_3_4_DATA_CTL: + case RT5668_IF_5_DATA_CTL: + case RT5668_PDM_OUT_CTL: + case RT5668_PDM_I2C_DATA_CTL1: + case RT5668_PDM_I2C_DATA_CTL2: + case RT5668_PDM_I2C_DATA_CTL3: + case RT5668_PDM_I2C_DATA_CTL4: + case RT5668_RECMIX1_NEW: + case RT5668_RECMIX1L_0: + case RT5668_RECMIX1L: + case RT5668_RECMIX1R_0: + case RT5668_RECMIX1R: + case RT5668_RECMIX2_NEW: + case RT5668_RECMIX2_L_2: + case RT5668_RECMIX2_R: + case RT5668_RECMIX2_R_2: + case RT5668_CALIB_REC_LR: + case RT5668_ALC_BK_GAIN: + case RT5668_MONOMIX_GAIN: + case RT5668_MONOMIX_IN_GAIN: + case RT5668_OUT_MIXL_GAIN: + case RT5668_OUT_LMIX_IN_GAIN: + case RT5668_OUT_RMIX_IN_GAIN: + case RT5668_OUT_RMIX_IN_GAIN1: + case RT5668_LOUT_MIXER_CTRL: + case RT5668_PWR_VOL: + case RT5668_ADCDAC_RST: + case RT5668_I2S34_SDP: + case RT5668_I2S5_SDP: + case RT5668_TDM_5: + case RT5668_TDM_6: + case RT5668_TDM_7: + case RT5668_TDM_8: + case RT5668_ASRC_3: + case RT5668_ASRC_6: + case RT5668_ASRC_7: + case RT5668_PLL_TRK_13: + case RT5668_I2S_M_CLK_CTL: + case RT5668_FDIV_I2S34_M_CLK: + case RT5668_FDIV_I2S34_M_CLK2: + case RT5668_FDIV_I2S5_M_CLK: + case RT5668_FDIV_I2S5_M_CLK2: + case RT5668_IRQ_4: + case RT5668_GPIO_3: + case RT5668_GPIO_4: + case RT5668_GPIO_STA: + case RT5668_HP_AMP_DET1: + case RT5668_HP_AMP_DET2: + case RT5668_HP_AMP_DET3: + case RT5668_MID_BD_HP_AMP: + case RT5668_LOW_BD_HP_AMP: + case RT5668_SOF_VOL_ZC2: + case RT5668_ADC_STO2_ADJ1: + case RT5668_ADC_STO2_ADJ2: + case RT5668_A_JD_CTRL: + case RT5668_JD1_TRES_CTRL: + case RT5668_JD2_TRES_CTRL: + case RT5668_JD_CTRL2: + case RT5668_DUM_REG_2: + case RT5668_DUM_REG_3: + case RT5663_VENDOR_ID: + case RT5663_VENDOR_ID_1: + case RT5663_VENDOR_ID_2: + case RT5668_DACADC_DIG_VOL2: + case RT5668_DIG_IN_PIN2: + case RT5668_PAD_DRV_CTL1: + case RT5668_SOF_RAM_DEPOP: + case RT5668_VOL_TEST: + case RT5668_TEST_MODE_3: + case RT5668_TEST_MODE_4: + case RT5663_STO_DRE_9: + case RT5668_MONO_DYNA_1: + case RT5668_MONO_DYNA_2: + case RT5668_MONO_DYNA_3: + case RT5668_MONO_DYNA_4: + case RT5668_MONO_DYNA_5: + case RT5668_MONO_DYNA_6: + case RT5668_STO1_SIL_DET: + case RT5668_MONOL_SIL_DET: + case RT5668_MONOR_SIL_DET: + case RT5668_STO2_DAC_SIL: + case RT5668_PWR_SAV_CTL1: + case RT5668_PWR_SAV_CTL2: + case RT5668_PWR_SAV_CTL3: + case RT5668_PWR_SAV_CTL4: + case RT5668_PWR_SAV_CTL5: + case RT5668_PWR_SAV_CTL6: + case RT5668_MONO_AMP_CAL1: + case RT5668_MONO_AMP_CAL2: + case RT5668_MONO_AMP_CAL3: + case RT5668_MONO_AMP_CAL4: + case RT5668_MONO_AMP_CAL5: + case RT5668_MONO_AMP_CAL6: + case RT5668_MONO_AMP_CAL7: + case RT5668_MONO_AMP_CAL_ST1: + case RT5668_MONO_AMP_CAL_ST2: + case RT5668_MONO_AMP_CAL_ST3: + case RT5668_MONO_AMP_CAL_ST4: + case RT5668_MONO_AMP_CAL_ST5: + case RT5668_HP_IMP_SEN_13: + case RT5668_HP_IMP_SEN_14: + case RT5668_HP_IMP_SEN_6: + case RT5668_HP_IMP_SEN_7: + case RT5668_HP_IMP_SEN_8: + case RT5668_HP_IMP_SEN_9: + case RT5668_HP_IMP_SEN_10: + case RT5668_HP_LOGIC_3: + case RT5668_HP_CALIB_ST10: + case RT5668_HP_CALIB_ST11: + case RT5668_PRO_REG_TBL_4: + case RT5668_PRO_REG_TBL_5: + case RT5668_PRO_REG_TBL_6: + case RT5668_PRO_REG_TBL_7: + case RT5668_PRO_REG_TBL_8: + case RT5668_PRO_REG_TBL_9: + case RT5668_SAR_ADC_INL_1: + case RT5668_SAR_ADC_INL_2: + case RT5668_SAR_ADC_INL_3: + case RT5668_SAR_ADC_INL_4: + case RT5668_SAR_ADC_INL_5: + case RT5668_SAR_ADC_INL_6: + case RT5668_SAR_ADC_INL_7: + case RT5668_SAR_ADC_INL_8: + case RT5668_SAR_ADC_INL_9: + case RT5668_SAR_ADC_INL_10: + case RT5668_SAR_ADC_INL_11: + case RT5668_SAR_ADC_INL_12: + case RT5668_DRC_CTRL_1: + case RT5668_DRC1_CTRL_2: + case RT5668_DRC1_CTRL_3: + case RT5668_DRC1_CTRL_4: + case RT5668_DRC1_CTRL_5: + case RT5668_DRC1_CTRL_6: + case RT5668_DRC1_HD_CTRL_1: + case RT5668_DRC1_HD_CTRL_2: + case RT5668_DRC1_PRI_REG_1: + case RT5668_DRC1_PRI_REG_2: + case RT5668_DRC1_PRI_REG_3: + case RT5668_DRC1_PRI_REG_4: + case RT5668_DRC1_PRI_REG_5: + case RT5668_DRC1_PRI_REG_6: + case RT5668_DRC1_PRI_REG_7: + case RT5668_DRC1_PRI_REG_8: + case RT5668_ALC_PGA_CTL_1: + case RT5668_ALC_PGA_CTL_2: + case RT5668_ALC_PGA_CTL_3: + case RT5668_ALC_PGA_CTL_4: + case RT5668_ALC_PGA_CTL_5: + case RT5668_ALC_PGA_CTL_6: + case RT5668_ALC_PGA_CTL_7: + case RT5668_ALC_PGA_CTL_8: + case RT5668_ALC_PGA_REG_1: + case RT5668_ALC_PGA_REG_2: + case RT5668_ALC_PGA_REG_3: + case RT5668_ADC_EQ_RECOV_1: + case RT5668_ADC_EQ_RECOV_2: + case RT5668_ADC_EQ_RECOV_3: + case RT5668_ADC_EQ_RECOV_4: + case RT5668_ADC_EQ_RECOV_5: + case RT5668_ADC_EQ_RECOV_6: + case RT5668_ADC_EQ_RECOV_7: + case RT5668_ADC_EQ_RECOV_8: + case RT5668_ADC_EQ_RECOV_9: + case RT5668_ADC_EQ_RECOV_10: + case RT5668_ADC_EQ_RECOV_11: + case RT5668_ADC_EQ_RECOV_12: + case RT5668_ADC_EQ_RECOV_13: + case RT5668_VID_HIDDEN: + case RT5668_VID_CUSTOMER: + case RT5668_SCAN_MODE: + case RT5668_I2C_BYPA: + return true; + case RT5663_TDM_1: + case RT5663_DEPOP_3: + case RT5663_ASRC_11_2: + case RT5663_INT_ST_2: + case RT5663_GPIO_STA: + case RT5663_SIN_GEN_1: + case RT5663_SIN_GEN_2: + case RT5663_SIN_GEN_3: + case RT5663_IL_CMD_PWRSAV1: + case RT5663_IL_CMD_PWRSAV2: + case RT5663_EM_JACK_TYPE_1: + case RT5663_EM_JACK_TYPE_2: + case RT5663_EM_JACK_TYPE_3: + case RT5663_EM_JACK_TYPE_4: + case RT5663_FAST_OFF_MICBIAS: + case RT5663_ANA_BIAS_CUR_1: + case RT5663_ANA_BIAS_CUR_2: + case RT5663_BIAS_CUR_9: + case RT5663_DUMMY_REG_4: + case RT5663_VREF_RECMIX: + case RT5663_CHARGE_PUMP_1_2: + case RT5663_CHARGE_PUMP_1_3: + case RT5663_CHARGE_PUMP_2: + case RT5663_CHOP_DAC_R: + case RT5663_DUMMY_CTL_DACLR: + case RT5663_DUMMY_REG_5: + case RT5663_SOFT_RAMP: + case RT5663_TEST_MODE_1: + case RT5663_STO_DRE_10: + case RT5663_MIC_DECRO_1: + case RT5663_MIC_DECRO_2: + case RT5663_MIC_DECRO_3: + case RT5663_MIC_DECRO_4: + case RT5663_MIC_DECRO_5: + case RT5663_MIC_DECRO_6: + case RT5663_HP_DECRO_1: + case RT5663_HP_DECRO_2: + case RT5663_HP_DECRO_3: + case RT5663_HP_DECRO_4: + case RT5663_HP_DECOUP: + case RT5663_HP_IMPSEN_MAP4: + case RT5663_HP_IMPSEN_MAP5: + case RT5663_HP_IMPSEN_MAP7: + case RT5663_HP_CALIB_1: + case RT5663_CBJ_1: + case RT5663_CBJ_2: + case RT5663_CBJ_3: + return false; + default: + return rt5663_readable_register(dev, reg); + } +} + +static const DECLARE_TLV_DB_SCALE(rt5663_hp_vol_tlv, -2400, 150, 0); +static const DECLARE_TLV_DB_SCALE(rt5668_hp_vol_tlv, -2250, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); + +/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ +static const DECLARE_TLV_DB_RANGE(in_bst_tlv, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), + 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), + 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), + 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0) +); + +/* Interface data select */ +static const char * const rt5663_if1_adc_data_select[] = { + "L/R", "R/L", "L/L", "R/R" +}; + +static SOC_ENUM_SINGLE_DECL(rt5663_if1_adc_enum, RT5663_TDM_2, + RT5663_DATA_SWAP_ADCDAT1_SHIFT, rt5663_if1_adc_data_select); + +static void rt5663_enable_push_button_irq(struct snd_soc_codec *codec, + bool enable) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + if (enable) { + snd_soc_update_bits(codec, RT5663_IL_CMD_6, + RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_EN); + /* reset in-line command */ + snd_soc_update_bits(codec, RT5663_IL_CMD_6, + RT5668_RESET_4BTN_INL_MASK, + RT5668_RESET_4BTN_INL_RESET); + snd_soc_update_bits(codec, RT5663_IL_CMD_6, + RT5668_RESET_4BTN_INL_MASK, + RT5668_RESET_4BTN_INL_NOR); + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + snd_soc_update_bits(codec, RT5663_IRQ_3, + RT5668_EN_IRQ_INLINE_MASK, + RT5668_EN_IRQ_INLINE_NOR); + break; + case CODEC_TYPE_RT5663: + snd_soc_update_bits(codec, RT5663_IRQ_2, + RT5663_EN_IRQ_INLINE_MASK, + RT5663_EN_IRQ_INLINE_NOR); + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + } + } else { + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + snd_soc_update_bits(codec, RT5663_IRQ_3, + RT5668_EN_IRQ_INLINE_MASK, + RT5668_EN_IRQ_INLINE_BYP); + break; + case CODEC_TYPE_RT5663: + snd_soc_update_bits(codec, RT5663_IRQ_2, + RT5663_EN_IRQ_INLINE_MASK, + RT5663_EN_IRQ_INLINE_BYP); + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + } + snd_soc_update_bits(codec, RT5663_IL_CMD_6, + RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_DIS); + /* reset in-line command */ + snd_soc_update_bits(codec, RT5663_IL_CMD_6, + RT5668_RESET_4BTN_INL_MASK, + RT5668_RESET_4BTN_INL_RESET); + snd_soc_update_bits(codec, RT5663_IL_CMD_6, + RT5668_RESET_4BTN_INL_MASK, + RT5668_RESET_4BTN_INL_NOR); + } +} + +/** + * rt5668_jack_detect - Detect headset. + * @codec: SoC audio codec device. + * @jack_insert: Jack insert or not. + * + * Detect whether is headset or not when jack inserted. + * + * Returns detect status. + */ + +static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec); + int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30}; + + dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert); + if (jack_insert) { + snd_soc_write(codec, RT5668_CBJ_TYPE_2, 0x8040); + snd_soc_write(codec, RT5668_CBJ_TYPE_3, 0x1484); + + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2"); + snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_force_enable_pin(dapm, "CBJ Power"); + snd_soc_dapm_sync(dapm); + snd_soc_update_bits(codec, RT5663_RC_CLK, + RT5668_DIG_1M_CLK_MASK, RT5668_DIG_1M_CLK_EN); + snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x8); + + while (i < 5) { + msleep(sleep_time[i]); + val = snd_soc_read(codec, RT5668_CBJ_TYPE_2) & 0x0003; + if (val == 0x1 || val == 0x2 || val == 0x3) + break; + dev_dbg(codec->dev, "%s: MX-0011 val=%x sleep %d\n", + __func__, val, sleep_time[i]); + i++; + } + dev_dbg(codec->dev, "%s val = %d\n", __func__, val); + switch (val) { + case 1: + case 2: + rt5668->jack_type = SND_JACK_HEADSET; + rt5663_enable_push_button_irq(codec, true); + break; + default: + snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_disable_pin(dapm, "MICBIAS2"); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_disable_pin(dapm, "CBJ Power"); + snd_soc_dapm_sync(dapm); + rt5668->jack_type = SND_JACK_HEADPHONE; + break; + } + } else { + snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x0); + + if (rt5668->jack_type == SND_JACK_HEADSET) { + rt5663_enable_push_button_irq(codec, false); + snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_disable_pin(dapm, "MICBIAS2"); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_disable_pin(dapm, "CBJ Power"); + snd_soc_dapm_sync(dapm); + } + rt5668->jack_type = 0; + } + + dev_dbg(codec->dev, "jack_type = %d\n", rt5668->jack_type); + return rt5668->jack_type; +} + +/** + * rt5663_jack_detect - Detect headset. + * @codec: SoC audio codec device. + * @jack_insert: Jack insert or not. + * + * Detect whether is headset or not when jack inserted. + * + * Returns detect status. + */ +static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30}; + + dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert); + + if (jack_insert) { + snd_soc_update_bits(codec, RT5663_DIG_MISC, + RT5668_DIG_GATE_CTRL_MASK, RT5668_DIG_GATE_CTRL_EN); + snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, + RT5663_SI_HP_MASK | RT5668_OSW_HP_L_MASK | + RT5668_OSW_HP_R_MASK, RT5663_SI_HP_EN | + RT5668_OSW_HP_L_DIS | RT5668_OSW_HP_R_DIS); + snd_soc_update_bits(codec, RT5663_DUMMY_1, + RT5663_EMB_CLK_MASK | RT5663_HPA_CPL_BIAS_MASK | + RT5663_HPA_CPR_BIAS_MASK, RT5663_EMB_CLK_EN | + RT5663_HPA_CPL_BIAS_1 | RT5663_HPA_CPR_BIAS_1); + snd_soc_update_bits(codec, RT5663_CBJ_1, + RT5663_INBUF_CBJ_BST1_MASK | RT5663_CBJ_SENSE_BST1_MASK, + RT5663_INBUF_CBJ_BST1_ON | RT5663_CBJ_SENSE_BST1_L); + snd_soc_update_bits(codec, RT5663_IL_CMD_2, + RT5663_PWR_MIC_DET_MASK, RT5663_PWR_MIC_DET_ON); + /* BST1 power on for JD */ + snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, + RT5668_PWR_BST1_MASK, RT5668_PWR_BST1_ON); + snd_soc_update_bits(codec, RT5663_EM_JACK_TYPE_1, + RT5663_CBJ_DET_MASK | RT5663_EXT_JD_MASK | + RT5663_POL_EXT_JD_MASK, RT5663_CBJ_DET_EN | + RT5663_EXT_JD_EN | RT5663_POL_EXT_JD_EN); + snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, + RT5668_PWR_MB_MASK | RT5668_LDO1_DVO_MASK | + RT5668_AMP_HP_MASK, RT5668_PWR_MB | + RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X); + snd_soc_update_bits(codec, RT5663_AUTO_1MRC_CLK, + RT5668_IRQ_POW_SAV_MASK, RT5668_IRQ_POW_SAV_EN); + snd_soc_update_bits(codec, RT5663_IRQ_1, + RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN); + while (i < 5) { + msleep(sleep_time[i]); + val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) & + 0x0003; + i++; + if (val == 0x1 || val == 0x2 || val == 0x3) + break; + dev_dbg(codec->dev, "%s: MX-00e7 val=%x sleep %d\n", + __func__, val, sleep_time[i]); + } + dev_dbg(codec->dev, "%s val = %d\n", __func__, val); + switch (val) { + case 1: + case 2: + rt5663->jack_type = SND_JACK_HEADSET; + rt5663_enable_push_button_irq(codec, true); + break; + default: + rt5663->jack_type = SND_JACK_HEADPHONE; + break; + } + } else { + if (rt5663->jack_type == SND_JACK_HEADSET) + rt5663_enable_push_button_irq(codec, false); + rt5663->jack_type = 0; + } + + dev_dbg(codec->dev, "jack_type = %d\n", rt5663->jack_type); + return rt5663->jack_type; +} + +static int rt5663_button_detect(struct snd_soc_codec *codec) +{ + int btn_type, val; + + val = snd_soc_read(codec, RT5663_IL_CMD_5); + dev_dbg(codec->dev, "%s: val=0x%x\n", __func__, val); + btn_type = val & 0xfff0; + snd_soc_write(codec, RT5663_IL_CMD_5, val); + + return btn_type; +} + +static irqreturn_t rt5663_irq(int irq, void *data) +{ + struct rt5663_priv *rt5663 = data; + + dev_dbg(rt5663->codec->dev, "%s IRQ queue work\n", __func__); + + queue_delayed_work(system_wq, &rt5663->jack_detect_work, + msecs_to_jiffies(250)); + + return IRQ_HANDLED; +} + +int rt5663_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hs_jack) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + rt5663->hs_jack = hs_jack; + + rt5663_irq(0, rt5663); + + return 0; +} +EXPORT_SYMBOL_GPL(rt5663_set_jack_detect); + +static bool rt5663_check_jd_status(struct snd_soc_codec *codec) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + int val = snd_soc_read(codec, RT5663_INT_ST_1); + + dev_dbg(codec->dev, "%s val=%x\n", __func__, val); + + /* JD1 */ + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + return !(val & 0x2000); + case CODEC_TYPE_RT5663: + return !(val & 0x1000); + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + } + + return false; +} + +static void rt5663_jack_detect_work(struct work_struct *work) +{ + struct rt5663_priv *rt5663 = + container_of(work, struct rt5663_priv, jack_detect_work.work); + struct snd_soc_codec *codec = rt5663->codec; + int btn_type, report = 0; + + if (!codec) + return; + + if (rt5663_check_jd_status(codec)) { + /* jack in */ + if (rt5663->jack_type == 0) { + /* jack was out, report jack type */ + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + report = rt5668_jack_detect(rt5663->codec, 1); + break; + case CODEC_TYPE_RT5663: + report = rt5663_jack_detect(rt5663->codec, 1); + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + } + } else { + /* jack is already in, report button event */ + report = SND_JACK_HEADSET; + btn_type = rt5663_button_detect(rt5663->codec); + /** + * rt5663 can report three kinds of button behavior, + * one click, double click and hold. However, + * currently we will report button pressed/released + * event. So all the three button behaviors are + * treated as button pressed. + */ + switch (btn_type) { + case 0x8000: + case 0x4000: + case 0x2000: + report |= SND_JACK_BTN_0; + break; + case 0x1000: + case 0x0800: + case 0x0400: + report |= SND_JACK_BTN_1; + break; + case 0x0200: + case 0x0100: + case 0x0080: + report |= SND_JACK_BTN_2; + break; + case 0x0040: + case 0x0020: + case 0x0010: + report |= SND_JACK_BTN_3; + break; + case 0x0000: /* unpressed */ + break; + default: + btn_type = 0; + dev_err(rt5663->codec->dev, + "Unexpected button code 0x%04x\n", + btn_type); + break; + } + /* button release or spurious interrput*/ + if (btn_type == 0) + report = rt5663->jack_type; + } + } else { + /* jack out */ + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + report = rt5668_jack_detect(rt5663->codec, 0); + break; + case CODEC_TYPE_RT5663: + report = rt5663_jack_detect(rt5663->codec, 0); + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + } + } + dev_dbg(codec->dev, "%s jack report: 0x%04x\n", __func__, report); + snd_soc_jack_report(rt5663->hs_jack, report, SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); +} + +static const struct snd_kcontrol_new rt5663_snd_controls[] = { + /* DAC Digital Volume */ + SOC_DOUBLE_TLV("DAC Playback Volume", RT5663_STO1_DAC_DIG_VOL, + RT5668_DAC_L1_VOL_SHIFT + 1, RT5668_DAC_R1_VOL_SHIFT + 1, + 87, 0, dac_vol_tlv), + /* ADC Digital Volume Control */ + SOC_DOUBLE("ADC Capture Switch", RT5663_STO1_ADC_DIG_VOL, + RT5668_ADC_L_MUTE_SHIFT, RT5668_ADC_R_MUTE_SHIFT, 1, 1), + SOC_DOUBLE_TLV("ADC Capture Volume", RT5663_STO1_ADC_DIG_VOL, + RT5668_ADC_L_VOL_SHIFT + 1, RT5668_ADC_R_VOL_SHIFT + 1, + 63, 0, adc_vol_tlv), +}; + +static const struct snd_kcontrol_new rt5668_specific_controls[] = { + /* Headphone Output Volume */ + SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_HP_LCH_DRE, + RT5663_HP_RCH_DRE, RT5668_GAIN_HP_SHIFT, 15, 1, + rt5668_hp_vol_tlv), + /* Mic Boost Volume */ + SOC_SINGLE_TLV("IN1 Capture Volume", RT5668_AEC_BST, + RT5668_GAIN_CBJ_SHIFT, 8, 0, in_bst_tlv), +}; + +static const struct snd_kcontrol_new rt5663_specific_controls[] = { + /* Headphone Output Volume */ + SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_STO_DRE_9, + RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_SHIFT, 23, 1, + rt5663_hp_vol_tlv), + /* Mic Boost Volume*/ + SOC_SINGLE_TLV("IN1 Capture Volume", RT5663_CBJ_2, + RT5663_GAIN_BST1_SHIFT, 8, 0, in_bst_tlv), + /* Data Swap for Slot0/1 in ADCDAT1 */ + SOC_ENUM("IF1 ADC Data Swap", rt5663_if1_adc_enum), +}; + +static int rt5663_is_sys_clk_from_pll(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int val; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + val = snd_soc_read(codec, RT5663_GLB_CLK); + val &= RT5663_SCLK_SRC_MASK; + if (val == RT5663_SCLK_SRC_PLL1) + return 1; + else + return 0; +} + +static int rt5663_is_using_asrc(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg, shift, val; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + if (rt5663->codec_type == CODEC_TYPE_RT5668) { + switch (w->shift) { + case RT5668_ADC_STO1_ASRC_SHIFT: + reg = RT5668_ASRC_3; + shift = RT5668_AD_STO1_TRACK_SHIFT; + break; + case RT5668_DAC_STO1_ASRC_SHIFT: + reg = RT5663_ASRC_2; + shift = RT5668_DA_STO1_TRACK_SHIFT; + break; + default: + return 0; + } + } else { + switch (w->shift) { + case RT5663_ADC_STO1_ASRC_SHIFT: + reg = RT5663_ASRC_2; + shift = RT5663_AD_STO1_TRACK_SHIFT; + break; + case RT5663_DAC_STO1_ASRC_SHIFT: + reg = RT5663_ASRC_2; + shift = RT5663_DA_STO1_TRACK_SHIFT; + break; + default: + return 0; + } + } + + val = (snd_soc_read(codec, reg) >> shift) & 0x7; + + if (val) + return 1; + + return 0; +} + +static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + int da_asrc_en, ad_asrc_en; + + da_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) & + RT5663_DA_STO1_TRACK_MASK) ? 1 : 0; + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + ad_asrc_en = (snd_soc_read(codec, RT5668_ASRC_3) & + RT5668_AD_STO1_TRACK_MASK) ? 1 : 0; + break; + case CODEC_TYPE_RT5663: + ad_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) & + RT5663_AD_STO1_TRACK_MASK) ? 1 : 0; + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + return 1; + } + + if (da_asrc_en || ad_asrc_en) + if (rt5663->sysclk > rt5663->lrck * 384) + return 1; + + dev_err(codec->dev, "sysclk < 384 x fs, disable i2s asrc\n"); + + return 0; +} + +/** + * rt5663_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @codec: SoC audio codec device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5668 can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the codec driver will turn on ASRC + * for these filters if ASRC is selected as their clock source. + */ +int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec); + unsigned int asrc2_mask = 0; + unsigned int asrc2_value = 0; + unsigned int asrc3_mask = 0; + unsigned int asrc3_value = 0; + + switch (clk_src) { + case RT5663_CLK_SEL_SYS: + case RT5663_CLK_SEL_I2S1_ASRC: + break; + + default: + return -EINVAL; + } + + if (filter_mask & RT5663_DA_STEREO_FILTER) { + asrc2_mask |= RT5668_DA_STO1_TRACK_MASK; + asrc2_value |= clk_src << RT5668_DA_STO1_TRACK_SHIFT; + } + + if (filter_mask & RT5663_AD_STEREO_FILTER) { + switch (rt5668->codec_type) { + case CODEC_TYPE_RT5668: + asrc3_mask |= RT5668_AD_STO1_TRACK_MASK; + asrc3_value |= clk_src << RT5668_AD_STO1_TRACK_SHIFT; + break; + case CODEC_TYPE_RT5663: + asrc2_mask |= RT5663_AD_STO1_TRACK_MASK; + asrc2_value |= clk_src << RT5663_AD_STO1_TRACK_SHIFT; + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + } + } + + if (asrc2_mask) + snd_soc_update_bits(codec, RT5663_ASRC_2, asrc2_mask, + asrc2_value); + + if (asrc3_mask) + snd_soc_update_bits(codec, RT5668_ASRC_3, asrc3_mask, + asrc3_value); + + return 0; +} +EXPORT_SYMBOL_GPL(rt5663_sel_asrc_clk_src); + +/* Analog Mixer */ +static const struct snd_kcontrol_new rt5668_recmix1l[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1L, + RT5668_RECMIX1L_BST2_SHIFT, 1, 1), + SOC_DAPM_SINGLE("BST1 CBJ Switch", RT5668_RECMIX1L, + RT5668_RECMIX1L_BST1_CBJ_SHIFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5668_recmix1r[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1R, + RT5668_RECMIX1R_BST2_SHIFT, 1, 1), +}; + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5663_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER, + RT5668_M_STO1_ADC_L1_SHIFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER, + RT5668_M_STO1_ADC_L2_SHIFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5668_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER, + RT5668_M_STO1_ADC_R1_SHIFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER, + RT5668_M_STO1_ADC_R2_SHIFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5663_adda_l_mix[] = { + SOC_DAPM_SINGLE("ADC L Switch", RT5663_AD_DA_MIXER, + RT5668_M_ADCMIX_L_SHIFT, 1, 1), + SOC_DAPM_SINGLE("DAC L Switch", RT5663_AD_DA_MIXER, + RT5668_M_DAC1_L_SHIFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5663_adda_r_mix[] = { + SOC_DAPM_SINGLE("ADC R Switch", RT5663_AD_DA_MIXER, + RT5668_M_ADCMIX_R_SHIFT, 1, 1), + SOC_DAPM_SINGLE("DAC R Switch", RT5663_AD_DA_MIXER, + RT5668_M_DAC1_R_SHIFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5663_sto1_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER, + RT5668_M_DAC_L1_STO_L_SHIFT, 1, 1), + SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER, + RT5668_M_DAC_R1_STO_L_SHIFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5663_sto1_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER, + RT5668_M_DAC_L1_STO_R_SHIFT, 1, 1), + SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER, + RT5668_M_DAC_R1_STO_R_SHIFT, 1, 1), +}; + +/* Out Switch */ +static const struct snd_kcontrol_new rt5668_hpo_switch = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5668_HP_AMP_2, + RT5668_EN_DAC_HPO_SHIFT, 1, 0); + +/* Stereo ADC source */ +static const char * const rt5668_sto1_adc_src[] = { + "ADC L", "ADC R" +}; + +static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcl_enum, RT5663_STO1_ADC_MIXER, + RT5668_STO1_ADC_L_SRC_SHIFT, rt5668_sto1_adc_src); + +static const struct snd_kcontrol_new rt5668_sto1_adcl_mux = + SOC_DAPM_ENUM("STO1 ADC L Mux", rt5668_sto1_adcl_enum); + +static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcr_enum, RT5663_STO1_ADC_MIXER, + RT5668_STO1_ADC_R_SRC_SHIFT, rt5668_sto1_adc_src); + +static const struct snd_kcontrol_new rt5668_sto1_adcr_mux = + SOC_DAPM_ENUM("STO1 ADC R Mux", rt5668_sto1_adcr_enum); + +/* RT5663: Analog DACL1 input source */ +static const char * const rt5663_alg_dacl_src[] = { + "DAC L", "STO DAC MIXL" +}; + +static SOC_ENUM_SINGLE_DECL(rt5663_alg_dacl_enum, RT5663_BYPASS_STO_DAC, + RT5663_DACL1_SRC_SHIFT, rt5663_alg_dacl_src); + +static const struct snd_kcontrol_new rt5663_alg_dacl_mux = + SOC_DAPM_ENUM("DAC L Mux", rt5663_alg_dacl_enum); + +/* RT5663: Analog DACR1 input source */ +static const char * const rt5663_alg_dacr_src[] = { + "DAC R", "STO DAC MIXR" +}; + +static SOC_ENUM_SINGLE_DECL(rt5663_alg_dacr_enum, RT5663_BYPASS_STO_DAC, + RT5663_DACR1_SRC_SHIFT, rt5663_alg_dacr_src); + +static const struct snd_kcontrol_new rt5663_alg_dacr_mux = + SOC_DAPM_ENUM("DAC R Mux", rt5663_alg_dacr_enum); + +static int rt5663_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (rt5663->codec_type == CODEC_TYPE_RT5668) { + snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, + RT5668_SEL_PM_HP_SHIFT, RT5668_SEL_PM_HP_HIGH); + snd_soc_update_bits(codec, RT5663_HP_LOGIC_2, + RT5668_HP_SIG_SRC1_MASK, + RT5668_HP_SIG_SRC1_SILENCE); + } else { + snd_soc_write(codec, RT5663_DEPOP_2, 0x3003); + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b, + 0x000b); + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, + 0x0030); + snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, + RT5668_OVCD_HP_MASK, RT5668_OVCD_HP_DIS); + snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371); + snd_soc_write(codec, RT5663_HP_BIAS, 0xabba); + snd_soc_write(codec, RT5663_CHARGE_PUMP_1, 0x2224); + snd_soc_write(codec, RT5663_ANA_BIAS_CUR_1, 0x7766); + snd_soc_write(codec, RT5663_HP_BIAS, 0xafaa); + snd_soc_write(codec, RT5663_CHARGE_PUMP_2, 0x7777); + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, + 0x3000); + } + break; + + case SND_SOC_DAPM_PRE_PMD: + if (rt5663->codec_type == CODEC_TYPE_RT5668) { + snd_soc_update_bits(codec, RT5663_HP_LOGIC_2, + RT5668_HP_SIG_SRC1_MASK, + RT5668_HP_SIG_SRC1_REG); + } else { + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x0); + snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, + RT5668_OVCD_HP_MASK, RT5668_OVCD_HP_EN); + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0); + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b, + 0x000b); + } + break; + + default: + return 0; + } + + return 0; +} + +static int rt5668_bst2_power(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, + RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK, + RT5668_PWR_BST2 | RT5668_PWR_BST2_OP); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, + RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK, 0); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5663_pre_div_power(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_write(codec, RT5663_PRE_DIV_GATING_1, 0xff00); + snd_soc_write(codec, RT5663_PRE_DIV_GATING_2, 0xfffc); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_write(codec, RT5663_PRE_DIV_GATING_1, 0x0000); + snd_soc_write(codec, RT5663_PRE_DIV_GATING_2, 0x0000); + break; + + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("PLL", RT5663_PWR_ANLG_3, RT5668_PWR_PLL_SHIFT, 0, + NULL, 0), + + /* micbias */ + SND_SOC_DAPM_MICBIAS("MICBIAS1", RT5663_PWR_ANLG_2, + RT5668_PWR_MB1_SHIFT, 0), + SND_SOC_DAPM_MICBIAS("MICBIAS2", RT5663_PWR_ANLG_2, + RT5668_PWR_MB2_SHIFT, 0), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN1N"), + + /* REC Mixer Power */ + SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5663_PWR_ANLG_2, + RT5668_PWR_RECMIX1_SHIFT, 0, NULL, 0), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_SUPPLY("ADC L Power", RT5663_PWR_DIG_1, + RT5668_PWR_ADC_L1_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Clock", RT5663_CHOP_ADC, + RT5668_CKGEN_ADCC_SHIFT, 0, NULL, 0), + + /* ADC Mixer */ + SND_SOC_DAPM_MIXER("STO1 ADC MIXL", SND_SOC_NOPM, + 0, 0, rt5663_sto1_adc_l_mix, + ARRAY_SIZE(rt5663_sto1_adc_l_mix)), + + /* ADC Filter Power */ + SND_SOC_DAPM_SUPPLY("STO1 ADC Filter", RT5663_PWR_DIG_2, + RT5668_PWR_ADC_S1F_SHIFT, 0, NULL, 0), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S", RT5663_PWR_DIG_1, RT5668_PWR_I2S1_SHIFT, 0, + NULL, 0), + SND_SOC_DAPM_PGA("IF DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIFTX", "AIF Capture", 0, SND_SOC_NOPM, 0, 0), + + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("ADDA MIXL", SND_SOC_NOPM, 0, 0, rt5663_adda_l_mix, + ARRAY_SIZE(rt5663_adda_l_mix)), + SND_SOC_DAPM_MIXER("ADDA MIXR", SND_SOC_NOPM, 0, 0, rt5663_adda_r_mix, + ARRAY_SIZE(rt5663_adda_r_mix)), + SND_SOC_DAPM_PGA("DAC L1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DAC R1", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* DAC Mixer */ + SND_SOC_DAPM_SUPPLY("STO1 DAC Filter", RT5663_PWR_DIG_2, + RT5668_PWR_DAC_S1F_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("STO1 DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5663_sto1_dac_l_mix, ARRAY_SIZE(rt5663_sto1_dac_l_mix)), + SND_SOC_DAPM_MIXER("STO1 DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5663_sto1_dac_r_mix, ARRAY_SIZE(rt5663_sto1_dac_r_mix)), + + /* DACs */ + SND_SOC_DAPM_SUPPLY("STO1 DAC L Power", RT5663_PWR_DIG_1, + RT5668_PWR_DAC_L1_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("STO1 DAC R Power", RT5663_PWR_DIG_1, + RT5668_PWR_DAC_R1_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_DAC("DAC L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC R", NULL, SND_SOC_NOPM, 0, 0), + + /* Headphone*/ + SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5663_hp_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), +}; + +static const struct snd_soc_dapm_widget rt5668_specific_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("LDO2", RT5663_PWR_ANLG_3, + RT5668_PWR_LDO2_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5668_PWR_VOL, + RT5668_PWR_MIC_DET_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("LDO DAC", RT5663_PWR_DIG_1, + RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1, + RT5668_I2S1_ASRC_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC ASRC", RT5663_ASRC_1, + RT5668_DAC_STO1_ASRC_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC ASRC", RT5663_ASRC_1, + RT5668_ADC_STO1_ASRC_SHIFT, 0, NULL, 0), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("IN2P"), + SND_SOC_DAPM_INPUT("IN2N"), + + /* Boost */ + SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CBJ Power", RT5663_PWR_ANLG_3, + RT5668_PWR_CBJ_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST2 Power", SND_SOC_NOPM, 0, 0, + rt5668_bst2_power, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5668_recmix1l, + ARRAY_SIZE(rt5668_recmix1l)), + SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5668_recmix1r, + ARRAY_SIZE(rt5668_recmix1r)), + SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5663_PWR_ANLG_2, + RT5668_PWR_RECMIX2_SHIFT, 0, NULL, 0), + + /* ADC */ + SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_SUPPLY("ADC R Power", RT5663_PWR_DIG_1, + RT5668_PWR_ADC_R1_SHIFT, 0, NULL, 0), + + /* ADC Mux */ + SND_SOC_DAPM_PGA("STO1 ADC L1", RT5663_STO1_ADC_MIXER, + RT5668_STO1_ADC_L1_SRC_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("STO1 ADC R1", RT5663_STO1_ADC_MIXER, + RT5668_STO1_ADC_R1_SRC_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("STO1 ADC L2", RT5663_STO1_ADC_MIXER, + RT5668_STO1_ADC_L2_SRC_SHIFT, 1, NULL, 0), + SND_SOC_DAPM_PGA("STO1 ADC R2", RT5663_STO1_ADC_MIXER, + RT5668_STO1_ADC_R2_SRC_SHIFT, 1, NULL, 0), + + SND_SOC_DAPM_MUX("STO1 ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5668_sto1_adcl_mux), + SND_SOC_DAPM_MUX("STO1 ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5668_sto1_adcr_mux), + + /* ADC Mix */ + SND_SOC_DAPM_MIXER("STO1 ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5668_sto1_adc_r_mix, ARRAY_SIZE(rt5668_sto1_adc_r_mix)), + + /* Analog DAC Clock */ + SND_SOC_DAPM_SUPPLY("DAC Clock", RT5663_CHOP_DAC_L, + RT5668_CKGEN_DAC1_SHIFT, 0, NULL, 0), + + /* Headphone out */ + SND_SOC_DAPM_SWITCH("HPO Playback", SND_SOC_NOPM, 0, 0, + &rt5668_hpo_switch), +}; + +static const struct snd_soc_dapm_widget rt5663_specific_dapm_widgets[] = { + /* System Clock Pre Divider Gating */ + SND_SOC_DAPM_SUPPLY("Pre Div Power", SND_SOC_NOPM, 0, 0, + rt5663_pre_div_power, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + /* LDO */ + SND_SOC_DAPM_SUPPLY("LDO ADC", RT5663_PWR_DIG_1, + RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1, + RT5663_I2S1_ASRC_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC ASRC", RT5663_ASRC_1, + RT5663_DAC_STO1_ASRC_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC ASRC", RT5663_ASRC_1, + RT5663_ADC_STO1_ASRC_SHIFT, 0, NULL, 0), + + /* Boost */ + SND_SOC_DAPM_PGA("BST1", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* STO ADC */ + SND_SOC_DAPM_PGA("STO1 ADC L1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("STO1 ADC L2", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Analog DAC source */ + SND_SOC_DAPM_MUX("DAC L Mux", SND_SOC_NOPM, 0, 0, &rt5663_alg_dacl_mux), + SND_SOC_DAPM_MUX("DAC R Mux", SND_SOC_NOPM, 0, 0, &rt5663_alg_dacr_mux), +}; + +static const struct snd_soc_dapm_route rt5663_dapm_routes[] = { + /* PLL */ + { "I2S", NULL, "PLL", rt5663_is_sys_clk_from_pll }, + + /* ASRC */ + { "STO1 ADC Filter", NULL, "ADC ASRC", rt5663_is_using_asrc }, + { "STO1 DAC Filter", NULL, "DAC ASRC", rt5663_is_using_asrc }, + { "I2S", NULL, "I2S ASRC", rt5663_i2s_use_asrc }, + + { "ADC L", NULL, "ADC L Power" }, + { "ADC L", NULL, "ADC Clock" }, + + { "STO1 ADC L2", NULL, "STO1 DAC MIXL" }, + + { "STO1 ADC MIXL", "ADC1 Switch", "STO1 ADC L1" }, + { "STO1 ADC MIXL", "ADC2 Switch", "STO1 ADC L2" }, + { "STO1 ADC MIXL", NULL, "STO1 ADC Filter" }, + + { "IF1 ADC1", NULL, "STO1 ADC MIXL" }, + { "IF ADC", NULL, "IF1 ADC1" }, + { "AIFTX", NULL, "IF ADC" }, + { "AIFTX", NULL, "I2S" }, + + { "AIFRX", NULL, "I2S" }, + { "IF DAC", NULL, "AIFRX" }, + { "IF1 DAC1 L", NULL, "IF DAC" }, + { "IF1 DAC1 R", NULL, "IF DAC" }, + + { "ADDA MIXL", "ADC L Switch", "STO1 ADC MIXL" }, + { "ADDA MIXL", "DAC L Switch", "IF1 DAC1 L" }, + { "ADDA MIXL", NULL, "STO1 DAC Filter" }, + { "ADDA MIXL", NULL, "STO1 DAC L Power" }, + { "ADDA MIXR", "DAC R Switch", "IF1 DAC1 R" }, + { "ADDA MIXR", NULL, "STO1 DAC Filter" }, + { "ADDA MIXR", NULL, "STO1 DAC R Power" }, + + { "DAC L1", NULL, "ADDA MIXL" }, + { "DAC R1", NULL, "ADDA MIXR" }, + + { "STO1 DAC MIXL", "DAC L Switch", "DAC L1" }, + { "STO1 DAC MIXL", "DAC R Switch", "DAC R1" }, + { "STO1 DAC MIXL", NULL, "STO1 DAC L Power" }, + { "STO1 DAC MIXL", NULL, "STO1 DAC Filter" }, + { "STO1 DAC MIXR", "DAC R Switch", "DAC R1" }, + { "STO1 DAC MIXR", "DAC L Switch", "DAC L1" }, + { "STO1 DAC MIXR", NULL, "STO1 DAC R Power" }, + { "STO1 DAC MIXR", NULL, "STO1 DAC Filter" }, + + { "HP Amp", NULL, "DAC L" }, + { "HP Amp", NULL, "DAC R" }, +}; + +static const struct snd_soc_dapm_route rt5668_specific_dapm_routes[] = { + { "MICBIAS1", NULL, "LDO2" }, + { "MICBIAS2", NULL, "LDO2" }, + + { "BST1 CBJ", NULL, "IN1P" }, + { "BST1 CBJ", NULL, "IN1N" }, + { "BST1 CBJ", NULL, "CBJ Power" }, + + { "BST2", NULL, "IN2P" }, + { "BST2", NULL, "IN2N" }, + { "BST2", NULL, "BST2 Power" }, + + { "RECMIX1L", "BST2 Switch", "BST2" }, + { "RECMIX1L", "BST1 CBJ Switch", "BST1 CBJ" }, + { "RECMIX1L", NULL, "RECMIX1L Power" }, + { "RECMIX1R", "BST2 Switch", "BST2" }, + { "RECMIX1R", NULL, "RECMIX1R Power" }, + + { "ADC L", NULL, "RECMIX1L" }, + { "ADC R", NULL, "RECMIX1R" }, + { "ADC R", NULL, "ADC R Power" }, + { "ADC R", NULL, "ADC Clock" }, + + { "STO1 ADC L Mux", "ADC L", "ADC L" }, + { "STO1 ADC L Mux", "ADC R", "ADC R" }, + { "STO1 ADC L1", NULL, "STO1 ADC L Mux" }, + + { "STO1 ADC R Mux", "ADC L", "ADC L" }, + { "STO1 ADC R Mux", "ADC R", "ADC R" }, + { "STO1 ADC R1", NULL, "STO1 ADC R Mux" }, + { "STO1 ADC R2", NULL, "STO1 DAC MIXR" }, + + { "STO1 ADC MIXR", "ADC1 Switch", "STO1 ADC R1" }, + { "STO1 ADC MIXR", "ADC2 Switch", "STO1 ADC R2" }, + { "STO1 ADC MIXR", NULL, "STO1 ADC Filter" }, + + { "IF1 ADC1", NULL, "STO1 ADC MIXR" }, + + { "ADDA MIXR", "ADC R Switch", "STO1 ADC MIXR" }, + + { "DAC L", NULL, "STO1 DAC MIXL" }, + { "DAC L", NULL, "LDO DAC" }, + { "DAC L", NULL, "DAC Clock" }, + { "DAC R", NULL, "STO1 DAC MIXR" }, + { "DAC R", NULL, "LDO DAC" }, + { "DAC R", NULL, "DAC Clock" }, + + { "HPO Playback", "Switch", "HP Amp" }, + { "HPOL", NULL, "HPO Playback" }, + { "HPOR", NULL, "HPO Playback" }, +}; + +static const struct snd_soc_dapm_route rt5663_specific_dapm_routes[] = { + { "I2S", NULL, "Pre Div Power" }, + + { "BST1", NULL, "IN1P" }, + { "BST1", NULL, "IN1N" }, + { "BST1", NULL, "RECMIX1L Power" }, + + { "ADC L", NULL, "BST1" }, + + { "STO1 ADC L1", NULL, "ADC L" }, + + { "DAC L Mux", "DAC L", "DAC L1" }, + { "DAC L Mux", "STO DAC MIXL", "STO1 DAC MIXL" }, + { "DAC R Mux", "DAC R", "DAC R1"}, + { "DAC R Mux", "STO DAC MIXR", "STO1 DAC MIXR" }, + + { "DAC L", NULL, "DAC L Mux" }, + { "DAC R", NULL, "DAC R Mux" }, + + { "HPOL", NULL, "HP Amp" }, + { "HPOR", NULL, "HP Amp" }, +}; + +static int rt5663_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + unsigned int val_len = 0; + int pre_div; + + rt5663->lrck = params_rate(params); + + dev_dbg(dai->dev, "bclk is %dHz and sysclk is %dHz\n", + rt5663->lrck, rt5663->sysclk); + + pre_div = rl6231_get_clk_info(rt5663->sysclk, rt5663->lrck); + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", + rt5663->lrck, dai->id); + return -EINVAL; + } + + dev_dbg(dai->dev, "pre_div is %d for iis %d\n", pre_div, dai->id); + + switch (params_width(params)) { + case 8: + val_len = RT5668_I2S_DL_8; + break; + case 16: + val_len = RT5668_I2S_DL_16; + break; + case 20: + val_len = RT5668_I2S_DL_20; + break; + case 24: + val_len = RT5668_I2S_DL_24; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5663_I2S1_SDP, + RT5668_I2S_DL_MASK, val_len); + + snd_soc_update_bits(codec, RT5663_ADDA_CLK_1, + RT5668_I2S_PD1_MASK, pre_div << RT5668_I2S_PD1_SHIFT); + + return 0; +} + +static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + break; + case SND_SOC_DAIFMT_CBS_CFS: + reg_val |= RT5668_I2S_MS_S; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5668_I2S_BP_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5668_I2S_DF_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5668_I2S_DF_PCM_A; + break; + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5668_I2S_DF_PCM_B; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5663_I2S1_SDP, RT5668_I2S_MS_MASK | + RT5668_I2S_BP_MASK | RT5668_I2S_DF_MASK, reg_val); + + return 0; +} + +static int rt5663_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5663->sysclk && clk_id == rt5663->sysclk_src) + return 0; + + switch (clk_id) { + case RT5663_SCLK_S_MCLK: + reg_val |= RT5663_SCLK_SRC_MCLK; + break; + case RT5663_SCLK_S_PLL1: + reg_val |= RT5663_SCLK_SRC_PLL1; + break; + case RT5663_SCLK_S_RCCLK: + reg_val |= RT5663_SCLK_SRC_RCCLK; + break; + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5663_GLB_CLK, RT5668_SCLK_SRC_MASK, + reg_val); + rt5663->sysclk = freq; + rt5663->sysclk_src = clk_id; + + dev_dbg(codec->dev, "Sysclk is %dHz and clock id is %d\n", + freq, clk_id); + + return 0; +} + +static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + struct rl6231_pll_code pll_code; + int ret; + int mask, shift, val; + + if (source == rt5663->pll_src && freq_in == rt5663->pll_in && + freq_out == rt5663->pll_out) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5663->pll_in = 0; + rt5663->pll_out = 0; + snd_soc_update_bits(codec, RT5663_GLB_CLK, + RT5663_SCLK_SRC_MASK, RT5663_SCLK_SRC_MCLK); + return 0; + } + + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + mask = RT5668_PLL1_SRC_MASK; + shift = RT5668_PLL1_SRC_SHIFT; + break; + case CODEC_TYPE_RT5663: + mask = RT5663_PLL1_SRC_MASK; + shift = RT5663_PLL1_SRC_SHIFT; + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + return -EINVAL; + } + + switch (source) { + case RT5663_PLL1_S_MCLK: + val = 0x0; + break; + case RT5663_PLL1_S_BCLK1: + val = 0x1; + break; + default: + dev_err(codec->dev, "Unknown PLL source %d\n", source); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5663_GLB_CLK, mask, (val << shift)); + + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", pll_code.m_bp, + (pll_code.m_bp ? 0 : pll_code.m_code), pll_code.n_code, + pll_code.k_code); + + snd_soc_write(codec, RT5663_PLL_1, + pll_code.n_code << RT5668_PLL_N_SHIFT | pll_code.k_code); + snd_soc_write(codec, RT5663_PLL_2, + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5668_PLL_M_SHIFT | + pll_code.m_bp << RT5668_PLL_M_BP_SHIFT); + + rt5663->pll_in = freq_in; + rt5663->pll_out = freq_out; + rt5663->pll_src = source; + + return 0; +} + +static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + unsigned int val = 0, reg; + + if (rx_mask || tx_mask) + val |= RT5668_TDM_MODE_TDM; + + switch (slots) { + case 4: + val |= RT5668_TDM_IN_CH_4; + val |= RT5668_TDM_OUT_CH_4; + break; + case 6: + val |= RT5668_TDM_IN_CH_6; + val |= RT5668_TDM_OUT_CH_6; + break; + case 8: + val |= RT5668_TDM_IN_CH_8; + val |= RT5668_TDM_OUT_CH_8; + break; + case 2: + break; + default: + return -EINVAL; + } + + switch (slot_width) { + case 20: + val |= RT5668_TDM_IN_LEN_20; + val |= RT5668_TDM_OUT_LEN_20; + break; + case 24: + val |= RT5668_TDM_IN_LEN_24; + val |= RT5668_TDM_OUT_LEN_24; + break; + case 32: + val |= RT5668_TDM_IN_LEN_32; + val |= RT5668_TDM_OUT_LEN_32; + break; + case 16: + break; + default: + return -EINVAL; + } + + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + reg = RT5663_TDM_2; + break; + case CODEC_TYPE_RT5663: + reg = RT5663_TDM_1; + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + return -EINVAL; + } + + snd_soc_update_bits(codec, reg, RT5668_TDM_MODE_MASK | + RT5668_TDM_IN_CH_MASK | RT5668_TDM_OUT_CH_MASK | + RT5668_TDM_IN_LEN_MASK | RT5668_TDM_OUT_LEN_MASK, val); + + return 0; +} + +static int rt5663_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + unsigned int reg; + + dev_dbg(codec->dev, "%s ratio = %d\n", __func__, ratio); + + if (rt5663->codec_type == CODEC_TYPE_RT5668) + reg = RT5668_TDM_8; + else + reg = RT5663_TDM_5; + + switch (ratio) { + case 32: + snd_soc_update_bits(codec, reg, + RT5663_TDM_LENGTN_MASK, + RT5663_TDM_LENGTN_16); + break; + case 40: + snd_soc_update_bits(codec, reg, + RT5663_TDM_LENGTN_MASK, + RT5663_TDM_LENGTN_20); + break; + case 48: + snd_soc_update_bits(codec, reg, + RT5663_TDM_LENGTN_MASK, + RT5663_TDM_LENGTN_24); + break; + case 64: + snd_soc_update_bits(codec, reg, + RT5663_TDM_LENGTN_MASK, + RT5663_TDM_LENGTN_32); + break; + default: + dev_err(codec->dev, "Invalid ratio!\n"); + return -EINVAL; + } + + return 0; +} + +static int rt5663_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + switch (level) { + case SND_SOC_BIAS_ON: + snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, + RT5668_PWR_FV1_MASK | RT5668_PWR_FV2_MASK, + RT5668_PWR_FV1 | RT5668_PWR_FV2); + break; + + case SND_SOC_BIAS_PREPARE: + if (rt5663->codec_type == CODEC_TYPE_RT5668) { + snd_soc_update_bits(codec, RT5663_DIG_MISC, + RT5668_DIG_GATE_CTRL_MASK, + RT5668_DIG_GATE_CTRL_EN); + snd_soc_update_bits(codec, RT5663_SIG_CLK_DET, + RT5668_EN_ANA_CLK_DET_MASK | + RT5668_PWR_CLK_DET_MASK, + RT5668_EN_ANA_CLK_DET_AUTO | + RT5668_PWR_CLK_DET_EN); + } + break; + + case SND_SOC_BIAS_STANDBY: + if (rt5663->codec_type == CODEC_TYPE_RT5668) + snd_soc_update_bits(codec, RT5663_DIG_MISC, + RT5668_DIG_GATE_CTRL_MASK, + RT5668_DIG_GATE_CTRL_DIS); + snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, + RT5668_PWR_VREF1_MASK | RT5668_PWR_VREF2_MASK | + RT5668_PWR_FV1_MASK | RT5668_PWR_FV2_MASK | + RT5668_PWR_MB_MASK, RT5668_PWR_VREF1 | + RT5668_PWR_VREF2 | RT5668_PWR_MB); + usleep_range(10000, 10005); + if (rt5663->codec_type == CODEC_TYPE_RT5668) { + snd_soc_update_bits(codec, RT5663_SIG_CLK_DET, + RT5668_EN_ANA_CLK_DET_MASK | + RT5668_PWR_CLK_DET_MASK, + RT5668_EN_ANA_CLK_DET_DIS | + RT5668_PWR_CLK_DET_DIS); + } + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, + RT5668_PWR_VREF1_MASK | RT5668_PWR_VREF2_MASK | + RT5668_PWR_FV1 | RT5668_PWR_FV2, 0x0); + break; + + default: + break; + } + + return 0; +} + +static int rt5663_probe(struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + rt5663->codec = codec; + + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + snd_soc_dapm_new_controls(dapm, + rt5668_specific_dapm_widgets, + ARRAY_SIZE(rt5668_specific_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, + rt5668_specific_dapm_routes, + ARRAY_SIZE(rt5668_specific_dapm_routes)); + snd_soc_add_codec_controls(codec, rt5668_specific_controls, + ARRAY_SIZE(rt5668_specific_controls)); + break; + case CODEC_TYPE_RT5663: + snd_soc_dapm_new_controls(dapm, + rt5663_specific_dapm_widgets, + ARRAY_SIZE(rt5663_specific_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, + rt5663_specific_dapm_routes, + ARRAY_SIZE(rt5663_specific_dapm_routes)); + snd_soc_add_codec_controls(codec, rt5663_specific_controls, + ARRAY_SIZE(rt5663_specific_controls)); + break; + } + + return 0; +} + +static int rt5663_remove(struct snd_soc_codec *codec) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + regmap_write(rt5663->regmap, RT5663_RESET, 0); + + return 0; +} + +#ifdef CONFIG_PM +static int rt5663_suspend(struct snd_soc_codec *codec) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5663->regmap, true); + regcache_mark_dirty(rt5663->regmap); + + return 0; +} + +static int rt5663_resume(struct snd_soc_codec *codec) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5663->regmap, false); + regcache_sync(rt5663->regmap); + + return 0; +} +#else +#define rt5663_suspend NULL +#define rt5663_resume NULL +#endif + +#define RT5663_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT5663_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static struct snd_soc_dai_ops rt5663_aif_dai_ops = { + .hw_params = rt5663_hw_params, + .set_fmt = rt5663_set_dai_fmt, + .set_sysclk = rt5663_set_dai_sysclk, + .set_pll = rt5663_set_dai_pll, + .set_tdm_slot = rt5663_set_tdm_slot, + .set_bclk_ratio = rt5663_set_bclk_ratio, +}; + +static struct snd_soc_dai_driver rt5663_dai[] = { + { + .name = "rt5663-aif", + .id = RT5663_AIF, + .playback = { + .stream_name = "AIF Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5663_STEREO_RATES, + .formats = RT5663_FORMATS, + }, + .capture = { + .stream_name = "AIF Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5663_STEREO_RATES, + .formats = RT5663_FORMATS, + }, + .ops = &rt5663_aif_dai_ops, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5663 = { + .probe = rt5663_probe, + .remove = rt5663_remove, + .suspend = rt5663_suspend, + .resume = rt5663_resume, + .set_bias_level = rt5663_set_bias_level, + .idle_bias_off = true, + .component_driver = { + .controls = rt5663_snd_controls, + .num_controls = ARRAY_SIZE(rt5663_snd_controls), + .dapm_widgets = rt5663_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5663_dapm_widgets), + .dapm_routes = rt5663_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5663_dapm_routes), + } +}; + +static const struct regmap_config rt5668_regmap = { + .reg_bits = 16, + .val_bits = 16, + .use_single_rw = true, + .max_register = 0x07fa, + .volatile_reg = rt5668_volatile_register, + .readable_reg = rt5668_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5668_reg, + .num_reg_defaults = ARRAY_SIZE(rt5668_reg), +}; + +static const struct regmap_config rt5663_regmap = { + .reg_bits = 16, + .val_bits = 16, + .use_single_rw = true, + .max_register = 0x03f3, + .volatile_reg = rt5663_volatile_register, + .readable_reg = rt5663_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5663_reg, + .num_reg_defaults = ARRAY_SIZE(rt5663_reg), +}; + +static const struct regmap_config temp_regmap = { + .name = "nocache", + .reg_bits = 16, + .val_bits = 16, + .use_single_rw = true, + .max_register = 0x03f3, + .cache_type = REGCACHE_NONE, +}; + +static const struct i2c_device_id rt5663_i2c_id[] = { + { "rt5668", 0 }, + { "rt5663", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, rt5663_i2c_id); + +#if defined(CONFIG_OF) +static const struct of_device_id rt5663_of_match[] = { + { .compatible = "realtek,rt5668", }, + { .compatible = "realtek,rt5663", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt5663_of_match); +#endif + +#ifdef CONFIG_ACPI +static struct acpi_device_id rt5663_acpi_match[] = { + { "10EC5668", 0}, + { "10EC5663", 0}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, rt5663_acpi_match); +#endif + +static void rt5668_calibrate(struct rt5663_priv *rt5668) +{ + regmap_write(rt5668->regmap, RT5663_BIAS_CUR_8, 0xa402); + regmap_write(rt5668->regmap, RT5663_PWR_DIG_1, 0x0100); + regmap_write(rt5668->regmap, RT5663_RECMIX, 0x4040); + regmap_write(rt5668->regmap, RT5663_DIG_MISC, 0x0001); + regmap_write(rt5668->regmap, RT5663_RC_CLK, 0x0380); + regmap_write(rt5668->regmap, RT5663_GLB_CLK, 0x8000); + regmap_write(rt5668->regmap, RT5663_ADDA_CLK_1, 0x1000); + regmap_write(rt5668->regmap, RT5663_CHOP_DAC_L, 0x3030); + regmap_write(rt5668->regmap, RT5663_CALIB_ADC, 0x3c05); + regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xa23e); + msleep(40); + regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xf23e); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_2, 0x0321); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_1, 0xfc00); + msleep(500); +} + +static void rt5663_calibrate(struct rt5663_priv *rt5668) +{ + int value, count; + + regmap_write(rt5668->regmap, RT5663_RC_CLK, 0x0280); + regmap_write(rt5668->regmap, RT5663_GLB_CLK, 0x8000); + regmap_write(rt5668->regmap, RT5663_DIG_MISC, 0x8001); + regmap_write(rt5668->regmap, RT5663_VREF_RECMIX, 0x0032); + regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xa2be); + msleep(20); + regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xf2be); + regmap_write(rt5668->regmap, RT5663_PWR_DIG_2, 0x8400); + regmap_write(rt5668->regmap, RT5663_CHOP_ADC, 0x3000); + regmap_write(rt5668->regmap, RT5663_DEPOP_1, 0x003b); + regmap_write(rt5668->regmap, RT5663_PWR_DIG_1, 0x8df8); + regmap_write(rt5668->regmap, RT5663_PWR_ANLG_2, 0x0003); + regmap_write(rt5668->regmap, RT5663_PWR_ANLG_3, 0x018c); + regmap_write(rt5668->regmap, RT5663_ADDA_CLK_1, 0x1111); + regmap_write(rt5668->regmap, RT5663_PRE_DIV_GATING_1, 0xffff); + regmap_write(rt5668->regmap, RT5663_PRE_DIV_GATING_2, 0xffff); + regmap_write(rt5668->regmap, RT5663_DEPOP_2, 0x3003); + regmap_write(rt5668->regmap, RT5663_DEPOP_1, 0x003b); + regmap_write(rt5668->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32); + regmap_write(rt5668->regmap, RT5663_HP_CHARGE_PUMP_2, 0x1371); + regmap_write(rt5668->regmap, RT5663_DACREF_LDO, 0x3b0b); + regmap_write(rt5668->regmap, RT5663_STO_DAC_MIXER, 0x2080); + regmap_write(rt5668->regmap, RT5663_BYPASS_STO_DAC, 0x000c); + regmap_write(rt5668->regmap, RT5663_HP_BIAS, 0xabba); + regmap_write(rt5668->regmap, RT5663_CHARGE_PUMP_1, 0x2224); + regmap_write(rt5668->regmap, RT5663_HP_OUT_EN, 0x8088); + regmap_write(rt5668->regmap, RT5663_STO_DRE_9, 0x0017); + regmap_write(rt5668->regmap, RT5663_STO_DRE_10, 0x0017); + regmap_write(rt5668->regmap, RT5663_STO1_ADC_MIXER, 0x4040); + regmap_write(rt5668->regmap, RT5663_RECMIX, 0x0005); + regmap_write(rt5668->regmap, RT5663_ADDA_RST, 0xc000); + regmap_write(rt5668->regmap, RT5663_STO1_HPF_ADJ1, 0x3320); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_2, 0x00c9); + regmap_write(rt5668->regmap, RT5663_DUMMY_1, 0x004c); + regmap_write(rt5668->regmap, RT5663_ANA_BIAS_CUR_1, 0x7766); + regmap_write(rt5668->regmap, RT5663_BIAS_CUR_8, 0x4702); + msleep(200); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_1, 0x0069); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_3, 0x06c2); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_1_1, 0x7b00); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_1_1, 0xfb00); + count = 0; + while (true) { + regmap_read(rt5668->regmap, RT5663_HP_CALIB_1_1, &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 200) + return; + count++; + } +} + +static int rt5663_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5663_priv *rt5663; + int ret; + unsigned int val; + struct regmap *regmap; + + rt5663 = devm_kzalloc(&i2c->dev, sizeof(struct rt5663_priv), + GFP_KERNEL); + + if (rt5663 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt5663); + + regmap = devm_regmap_init_i2c(i2c, &temp_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n", + ret); + return ret; + } + regmap_read(regmap, RT5663_VENDOR_ID_2, &val); + switch (val) { + case RT5668_DEVICE_ID: + rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5668_regmap); + rt5663->codec_type = CODEC_TYPE_RT5668; + break; + case RT5663_DEVICE_ID: + rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5663_regmap); + rt5663->codec_type = CODEC_TYPE_RT5663; + break; + default: + dev_err(&i2c->dev, + "Device with ID register %#x is not rt5663 or rt5668\n", + val); + return -ENODEV; + } + + if (IS_ERR(rt5663->regmap)) { + ret = PTR_ERR(rt5663->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + /* reset and calibrate */ + regmap_write(rt5663->regmap, RT5663_RESET, 0); + regcache_cache_bypass(rt5663->regmap, true); + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + rt5668_calibrate(rt5663); + break; + case CODEC_TYPE_RT5663: + rt5663_calibrate(rt5663); + break; + default: + dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__); + } + regcache_cache_bypass(rt5663->regmap, false); + regmap_write(rt5663->regmap, RT5663_RESET, 0); + dev_dbg(&i2c->dev, "calibrate done\n"); + + /* GPIO1 as IRQ */ + regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5668_GP1_PIN_MASK, + RT5668_GP1_PIN_IRQ); + /* 4btn inline command debounce */ + regmap_update_bits(rt5663->regmap, RT5663_IL_CMD_5, + RT5668_4BTN_CLK_DEB_MASK, RT5668_4BTN_CLK_DEB_65MS); + + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0xa402); + /* JD1 */ + regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK, + RT5668_IRQ_POW_SAV_MASK | RT5668_IRQ_POW_SAV_JD1_MASK, + RT5668_IRQ_POW_SAV_EN | RT5668_IRQ_POW_SAV_JD1_EN); + regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_2, + RT5668_PWR_JD1_MASK, RT5668_PWR_JD1); + regmap_update_bits(rt5663->regmap, RT5663_IRQ_1, + RT5668_EN_CB_JD_MASK, RT5668_EN_CB_JD_EN); + + regmap_update_bits(rt5663->regmap, RT5663_HP_LOGIC_2, + RT5668_HP_SIG_SRC1_MASK, RT5668_HP_SIG_SRC1_REG); + regmap_update_bits(rt5663->regmap, RT5663_RECMIX, + RT5668_VREF_BIAS_MASK | RT5668_CBJ_DET_MASK | + RT5668_DET_TYPE_MASK, RT5668_VREF_BIAS_REG | + RT5668_CBJ_DET_EN | RT5668_DET_TYPE_QFN); + /* Set GPIO4 and GPIO8 as input for combo jack */ + regmap_update_bits(rt5663->regmap, RT5663_GPIO_2, + RT5668_GP4_PIN_CONF_MASK, RT5668_GP4_PIN_CONF_INPUT); + regmap_update_bits(rt5663->regmap, RT5668_GPIO_3, + RT5668_GP8_PIN_CONF_MASK, RT5668_GP8_PIN_CONF_INPUT); + regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_1, + RT5668_LDO1_DVO_MASK | RT5668_AMP_HP_MASK, + RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X); + break; + case CODEC_TYPE_RT5663: + regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa2be); + msleep(20); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf2be); + regmap_update_bits(rt5663->regmap, RT5663_GPIO_2, + RT5663_GP1_PIN_CONF_MASK, RT5663_GP1_PIN_CONF_OUTPUT); + /* DACREF LDO control */ + regmap_update_bits(rt5663->regmap, RT5663_DACREF_LDO, 0x3e0e, + 0x3a0a); + regmap_update_bits(rt5663->regmap, RT5663_RECMIX, + RT5663_RECMIX1_BST1_MASK, RT5663_RECMIX1_BST1_ON); + regmap_update_bits(rt5663->regmap, RT5663_TDM_2, + RT5663_DATA_SWAP_ADCDAT1_MASK, + RT5663_DATA_SWAP_ADCDAT1_LL); + break; + default: + dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__); + } + + INIT_DELAYED_WORK(&rt5663->jack_detect_work, rt5663_jack_detect_work); + + if (i2c->irq) { + ret = request_irq(i2c->irq, rt5663_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, "rt5663", rt5663); + if (ret) + dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n", + __func__, ret); + } + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5663, + rt5663_dai, ARRAY_SIZE(rt5663_dai)); + + if (ret) { + if (i2c->irq) + free_irq(i2c->irq, rt5663); + } + + return ret; +} + +static int rt5663_i2c_remove(struct i2c_client *i2c) +{ + struct rt5663_priv *rt5663 = i2c_get_clientdata(i2c); + + if (i2c->irq) + free_irq(i2c->irq, rt5663); + + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static void rt5663_i2c_shutdown(struct i2c_client *client) +{ + struct rt5663_priv *rt5663 = i2c_get_clientdata(client); + + regmap_write(rt5663->regmap, RT5663_RESET, 0); +} + +static struct i2c_driver rt5663_i2c_driver = { + .driver = { + .name = "rt5663", + .acpi_match_table = ACPI_PTR(rt5663_acpi_match), + .of_match_table = of_match_ptr(rt5663_of_match), + }, + .probe = rt5663_i2c_probe, + .remove = rt5663_i2c_remove, + .shutdown = rt5663_i2c_shutdown, + .id_table = rt5663_i2c_id, +}; +module_i2c_driver(rt5663_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5663 driver"); +MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h new file mode 100644 index 000000000000..2cc8f28080f6 --- /dev/null +++ b/sound/soc/codecs/rt5663.h @@ -0,0 +1,1121 @@ +/* + * rt5663.h -- RT5663 ALSA SoC audio driver + * + * Copyright 2016 Realtek Microelectronics + * Author: Jack Yu <jack.yu@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5663_H__ +#define __RT5663_H__ + +/* Info */ +#define RT5663_RESET 0x0000 +#define RT5663_VENDOR_ID 0x00fd +#define RT5663_VENDOR_ID_1 0x00fe +#define RT5663_VENDOR_ID_2 0x00ff + +#define RT5668_LOUT_CTRL 0x0001 +#define RT5668_HP_AMP_2 0x0003 +#define RT5668_MONO_OUT 0x0004 +#define RT5668_MONO_GAIN 0x0007 + +#define RT5668_AEC_BST 0x000b +#define RT5668_IN1_IN2 0x000c +#define RT5668_IN3_IN4 0x000d +#define RT5668_INL1_INR1 0x000f +#define RT5668_CBJ_TYPE_2 0x0011 +#define RT5668_CBJ_TYPE_3 0x0012 +#define RT5668_CBJ_TYPE_4 0x0013 +#define RT5668_CBJ_TYPE_5 0x0014 +#define RT5668_CBJ_TYPE_8 0x0017 + +/* I/O - ADC/DAC/DMIC */ +#define RT5668_DAC3_DIG_VOL 0x001a +#define RT5668_DAC3_CTRL 0x001b +#define RT5668_MONO_ADC_DIG_VOL 0x001d +#define RT5668_STO2_ADC_DIG_VOL 0x001e +#define RT5668_MONO_ADC_BST_GAIN 0x0020 +#define RT5668_STO2_ADC_BST_GAIN 0x0021 +#define RT5668_SIDETONE_CTRL 0x0024 +/* Mixer - D-D */ +#define RT5668_MONO1_ADC_MIXER 0x0027 +#define RT5668_STO2_ADC_MIXER 0x0028 +#define RT5668_MONO_DAC_MIXER 0x002b +#define RT5668_DAC2_SRC_CTRL 0x002e +#define RT5668_IF_3_4_DATA_CTL 0x002f +#define RT5668_IF_5_DATA_CTL 0x0030 +#define RT5668_PDM_OUT_CTL 0x0031 +#define RT5668_PDM_I2C_DATA_CTL1 0x0032 +#define RT5668_PDM_I2C_DATA_CTL2 0x0033 +#define RT5668_PDM_I2C_DATA_CTL3 0x0034 +#define RT5668_PDM_I2C_DATA_CTL4 0x0035 + +/*Mixer - Analog*/ +#define RT5668_RECMIX1_NEW 0x003a +#define RT5668_RECMIX1L_0 0x003b +#define RT5668_RECMIX1L 0x003c +#define RT5668_RECMIX1R_0 0x003d +#define RT5668_RECMIX1R 0x003e +#define RT5668_RECMIX2_NEW 0x003f +#define RT5668_RECMIX2_L_2 0x0041 +#define RT5668_RECMIX2_R 0x0042 +#define RT5668_RECMIX2_R_2 0x0043 +#define RT5668_CALIB_REC_LR 0x0044 +#define RT5668_ALC_BK_GAIN 0x0049 +#define RT5668_MONOMIX_GAIN 0x004a +#define RT5668_MONOMIX_IN_GAIN 0x004b +#define RT5668_OUT_MIXL_GAIN 0x004d +#define RT5668_OUT_LMIX_IN_GAIN 0x004e +#define RT5668_OUT_RMIX_IN_GAIN 0x004f +#define RT5668_OUT_RMIX_IN_GAIN1 0x0050 +#define RT5668_LOUT_MIXER_CTRL 0x0052 +/* Power */ +#define RT5668_PWR_VOL 0x0067 + +#define RT5668_ADCDAC_RST 0x006d +/* Format - ADC/DAC */ +#define RT5668_I2S34_SDP 0x0071 +#define RT5668_I2S5_SDP 0x0072 +/* Format - TDM Control */ +#define RT5668_TDM_5 0x007c +#define RT5668_TDM_6 0x007d +#define RT5668_TDM_7 0x007e +#define RT5668_TDM_8 0x007f + +/* Function - Analog */ +#define RT5668_ASRC_3 0x0085 +#define RT5668_ASRC_6 0x0088 +#define RT5668_ASRC_7 0x0089 +#define RT5668_PLL_TRK_13 0x0099 +#define RT5668_I2S_M_CLK_CTL 0x00a0 +#define RT5668_FDIV_I2S34_M_CLK 0x00a1 +#define RT5668_FDIV_I2S34_M_CLK2 0x00a2 +#define RT5668_FDIV_I2S5_M_CLK 0x00a3 +#define RT5668_FDIV_I2S5_M_CLK2 0x00a4 + +/* Function - Digital */ +#define RT5668_IRQ_4 0x00b9 +#define RT5668_GPIO_3 0x00c2 +#define RT5668_GPIO_4 0x00c3 +#define RT5668_GPIO_STA 0x00c4 +#define RT5668_HP_AMP_DET1 0x00d0 +#define RT5668_HP_AMP_DET2 0x00d1 +#define RT5668_HP_AMP_DET3 0x00d2 +#define RT5668_MID_BD_HP_AMP 0x00d3 +#define RT5668_LOW_BD_HP_AMP 0x00d4 +#define RT5668_SOF_VOL_ZC2 0x00da +#define RT5668_ADC_STO2_ADJ1 0x00ee +#define RT5668_ADC_STO2_ADJ2 0x00ef +/* General Control */ +#define RT5668_A_JD_CTRL 0x00f0 +#define RT5668_JD1_TRES_CTRL 0x00f1 +#define RT5668_JD2_TRES_CTRL 0x00f2 +#define RT5668_JD_CTRL2 0x00f7 +#define RT5668_DUM_REG_2 0x00fb +#define RT5668_DUM_REG_3 0x00fc + + +#define RT5668_DACADC_DIG_VOL2 0x0101 +#define RT5668_DIG_IN_PIN2 0x0133 +#define RT5668_PAD_DRV_CTL1 0x0136 +#define RT5668_SOF_RAM_DEPOP 0x0138 +#define RT5668_VOL_TEST 0x013f +#define RT5668_TEST_MODE_3 0x0147 +#define RT5668_TEST_MODE_4 0x0148 +#define RT5668_MONO_DYNA_1 0x0170 +#define RT5668_MONO_DYNA_2 0x0171 +#define RT5668_MONO_DYNA_3 0x0172 +#define RT5668_MONO_DYNA_4 0x0173 +#define RT5668_MONO_DYNA_5 0x0174 +#define RT5668_MONO_DYNA_6 0x0175 +#define RT5668_STO1_SIL_DET 0x0190 +#define RT5668_MONOL_SIL_DET 0x0191 +#define RT5668_MONOR_SIL_DET 0x0192 +#define RT5668_STO2_DAC_SIL 0x0193 +#define RT5668_PWR_SAV_CTL1 0x0194 +#define RT5668_PWR_SAV_CTL2 0x0195 +#define RT5668_PWR_SAV_CTL3 0x0196 +#define RT5668_PWR_SAV_CTL4 0x0197 +#define RT5668_PWR_SAV_CTL5 0x0198 +#define RT5668_PWR_SAV_CTL6 0x0199 +#define RT5668_MONO_AMP_CAL1 0x01a0 +#define RT5668_MONO_AMP_CAL2 0x01a1 +#define RT5668_MONO_AMP_CAL3 0x01a2 +#define RT5668_MONO_AMP_CAL4 0x01a3 +#define RT5668_MONO_AMP_CAL5 0x01a4 +#define RT5668_MONO_AMP_CAL6 0x01a5 +#define RT5668_MONO_AMP_CAL7 0x01a6 +#define RT5668_MONO_AMP_CAL_ST1 0x01a7 +#define RT5668_MONO_AMP_CAL_ST2 0x01a8 +#define RT5668_MONO_AMP_CAL_ST3 0x01a9 +#define RT5668_MONO_AMP_CAL_ST4 0x01aa +#define RT5668_MONO_AMP_CAL_ST5 0x01ab +#define RT5668_HP_IMP_SEN_13 0x01b9 +#define RT5668_HP_IMP_SEN_14 0x01ba +#define RT5668_HP_IMP_SEN_6 0x01bb +#define RT5668_HP_IMP_SEN_7 0x01bc +#define RT5668_HP_IMP_SEN_8 0x01bd +#define RT5668_HP_IMP_SEN_9 0x01be +#define RT5668_HP_IMP_SEN_10 0x01bf +#define RT5668_HP_LOGIC_3 0x01dc +#define RT5668_HP_CALIB_ST10 0x01f3 +#define RT5668_HP_CALIB_ST11 0x01f4 +#define RT5668_PRO_REG_TBL_4 0x0203 +#define RT5668_PRO_REG_TBL_5 0x0204 +#define RT5668_PRO_REG_TBL_6 0x0205 +#define RT5668_PRO_REG_TBL_7 0x0206 +#define RT5668_PRO_REG_TBL_8 0x0207 +#define RT5668_PRO_REG_TBL_9 0x0208 +#define RT5668_SAR_ADC_INL_1 0x0210 +#define RT5668_SAR_ADC_INL_2 0x0211 +#define RT5668_SAR_ADC_INL_3 0x0212 +#define RT5668_SAR_ADC_INL_4 0x0213 +#define RT5668_SAR_ADC_INL_5 0x0214 +#define RT5668_SAR_ADC_INL_6 0x0215 +#define RT5668_SAR_ADC_INL_7 0x0216 +#define RT5668_SAR_ADC_INL_8 0x0217 +#define RT5668_SAR_ADC_INL_9 0x0218 +#define RT5668_SAR_ADC_INL_10 0x0219 +#define RT5668_SAR_ADC_INL_11 0x021a +#define RT5668_SAR_ADC_INL_12 0x021b +#define RT5668_DRC_CTRL_1 0x02ff +#define RT5668_DRC1_CTRL_2 0x0301 +#define RT5668_DRC1_CTRL_3 0x0302 +#define RT5668_DRC1_CTRL_4 0x0303 +#define RT5668_DRC1_CTRL_5 0x0304 +#define RT5668_DRC1_CTRL_6 0x0305 +#define RT5668_DRC1_HD_CTRL_1 0x0306 +#define RT5668_DRC1_HD_CTRL_2 0x0307 +#define RT5668_DRC1_PRI_REG_1 0x0310 +#define RT5668_DRC1_PRI_REG_2 0x0311 +#define RT5668_DRC1_PRI_REG_3 0x0312 +#define RT5668_DRC1_PRI_REG_4 0x0313 +#define RT5668_DRC1_PRI_REG_5 0x0314 +#define RT5668_DRC1_PRI_REG_6 0x0315 +#define RT5668_DRC1_PRI_REG_7 0x0316 +#define RT5668_DRC1_PRI_REG_8 0x0317 +#define RT5668_ALC_PGA_CTL_1 0x0330 +#define RT5668_ALC_PGA_CTL_2 0x0331 +#define RT5668_ALC_PGA_CTL_3 0x0332 +#define RT5668_ALC_PGA_CTL_4 0x0333 +#define RT5668_ALC_PGA_CTL_5 0x0334 +#define RT5668_ALC_PGA_CTL_6 0x0335 +#define RT5668_ALC_PGA_CTL_7 0x0336 +#define RT5668_ALC_PGA_CTL_8 0x0337 +#define RT5668_ALC_PGA_REG_1 0x0338 +#define RT5668_ALC_PGA_REG_2 0x0339 +#define RT5668_ALC_PGA_REG_3 0x033a +#define RT5668_ADC_EQ_RECOV_1 0x03c0 +#define RT5668_ADC_EQ_RECOV_2 0x03c1 +#define RT5668_ADC_EQ_RECOV_3 0x03c2 +#define RT5668_ADC_EQ_RECOV_4 0x03c3 +#define RT5668_ADC_EQ_RECOV_5 0x03c4 +#define RT5668_ADC_EQ_RECOV_6 0x03c5 +#define RT5668_ADC_EQ_RECOV_7 0x03c6 +#define RT5668_ADC_EQ_RECOV_8 0x03c7 +#define RT5668_ADC_EQ_RECOV_9 0x03c8 +#define RT5668_ADC_EQ_RECOV_10 0x03c9 +#define RT5668_ADC_EQ_RECOV_11 0x03ca +#define RT5668_ADC_EQ_RECOV_12 0x03cb +#define RT5668_ADC_EQ_RECOV_13 0x03cc +#define RT5668_VID_HIDDEN 0x03fe +#define RT5668_VID_CUSTOMER 0x03ff +#define RT5668_SCAN_MODE 0x07f0 +#define RT5668_I2C_BYPA 0x07fa + +/* Headphone Amp Control 2 (0x0003) */ +#define RT5668_EN_DAC_HPO_MASK (0x1 << 14) +#define RT5668_EN_DAC_HPO_SHIFT 14 +#define RT5668_EN_DAC_HPO_DIS (0x0 << 14) +#define RT5668_EN_DAC_HPO_EN (0x1 << 14) + +/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/ +#define RT5668_GAIN_HP (0x1f << 8) +#define RT5668_GAIN_HP_SHIFT 8 + +/* AEC BST Control (0x000b) */ +#define RT5668_GAIN_CBJ_MASK (0xf << 8) +#define RT5668_GAIN_CBJ_SHIFT 8 + +/* IN1 Control / MIC GND REF (0x000c) */ +#define RT5668_IN1_DF_MASK (0x1 << 15) +#define RT5668_IN1_DF_SHIFT 15 + +/* Combo Jack and Type Detection Control 1 (0x0010) */ +#define RT5668_CBJ_DET_MASK (0x1 << 15) +#define RT5668_CBJ_DET_SHIFT 15 +#define RT5668_CBJ_DET_DIS (0x0 << 15) +#define RT5668_CBJ_DET_EN (0x1 << 15) +#define RT5668_DET_TYPE_MASK (0x1 << 12) +#define RT5668_DET_TYPE_SHIFT 12 +#define RT5668_DET_TYPE_WLCSP (0x0 << 12) +#define RT5668_DET_TYPE_QFN (0x1 << 12) +#define RT5668_VREF_BIAS_MASK (0x1 << 6) +#define RT5668_VREF_BIAS_SHIFT 6 +#define RT5668_VREF_BIAS_FSM (0x0 << 6) +#define RT5668_VREF_BIAS_REG (0x1 << 6) + +/* REC Left Mixer Control 2 (0x003c) */ +#define RT5668_RECMIX1L_BST1_CBJ (0x1 << 7) +#define RT5668_RECMIX1L_BST1_CBJ_SHIFT 7 +#define RT5668_RECMIX1L_BST2 (0x1 << 4) +#define RT5668_RECMIX1L_BST2_SHIFT 4 + +/* REC Right Mixer Control 2 (0x003e) */ +#define RT5668_RECMIX1R_BST2 (0x1 << 4) +#define RT5668_RECMIX1R_BST2_SHIFT 4 + +/* DAC1 Digital Volume (0x0019) */ +#define RT5668_DAC_L1_VOL_MASK (0xff << 8) +#define RT5668_DAC_L1_VOL_SHIFT 8 +#define RT5668_DAC_R1_VOL_MASK (0xff) +#define RT5668_DAC_R1_VOL_SHIFT 0 + +/* ADC Digital Volume Control (0x001c) */ +#define RT5668_ADC_L_MUTE_MASK (0x1 << 15) +#define RT5668_ADC_L_MUTE_SHIFT 15 +#define RT5668_ADC_L_VOL_MASK (0x7f << 8) +#define RT5668_ADC_L_VOL_SHIFT 8 +#define RT5668_ADC_R_MUTE_MASK (0x1 << 7) +#define RT5668_ADC_R_MUTE_SHIFT 7 +#define RT5668_ADC_R_VOL_MASK (0x7f) +#define RT5668_ADC_R_VOL_SHIFT 0 + +/* Stereo ADC Mixer Control (0x0026) */ +#define RT5668_M_STO1_ADC_L1 (0x1 << 15) +#define RT5668_M_STO1_ADC_L1_SHIFT 15 +#define RT5668_M_STO1_ADC_L2 (0x1 << 14) +#define RT5668_M_STO1_ADC_L2_SHIFT 14 +#define RT5668_STO1_ADC_L1_SRC (0x1 << 13) +#define RT5668_STO1_ADC_L1_SRC_SHIFT 13 +#define RT5668_STO1_ADC_L2_SRC (0x1 << 12) +#define RT5668_STO1_ADC_L2_SRC_SHIFT 12 +#define RT5668_STO1_ADC_L_SRC (0x3 << 10) +#define RT5668_STO1_ADC_L_SRC_SHIFT 10 +#define RT5668_M_STO1_ADC_R1 (0x1 << 7) +#define RT5668_M_STO1_ADC_R1_SHIFT 7 +#define RT5668_M_STO1_ADC_R2 (0x1 << 6) +#define RT5668_M_STO1_ADC_R2_SHIFT 6 +#define RT5668_STO1_ADC_R1_SRC (0x1 << 5) +#define RT5668_STO1_ADC_R1_SRC_SHIFT 5 +#define RT5668_STO1_ADC_R2_SRC (0x1 << 4) +#define RT5668_STO1_ADC_R2_SRC_SHIFT 4 +#define RT5668_STO1_ADC_R_SRC (0x3 << 2) +#define RT5668_STO1_ADC_R_SRC_SHIFT 2 + +/* ADC Mixer to DAC Mixer Control (0x0029) */ +#define RT5668_M_ADCMIX_L (0x1 << 15) +#define RT5668_M_ADCMIX_L_SHIFT 15 +#define RT5668_M_DAC1_L (0x1 << 14) +#define RT5668_M_DAC1_L_SHIFT 14 +#define RT5668_M_ADCMIX_R (0x1 << 7) +#define RT5668_M_ADCMIX_R_SHIFT 7 +#define RT5668_M_DAC1_R (0x1 << 6) +#define RT5668_M_DAC1_R_SHIFT 6 + +/* Stereo DAC Mixer Control (0x002a) */ +#define RT5668_M_DAC_L1_STO_L (0x1 << 15) +#define RT5668_M_DAC_L1_STO_L_SHIFT 15 +#define RT5668_M_DAC_R1_STO_L (0x1 << 13) +#define RT5668_M_DAC_R1_STO_L_SHIFT 13 +#define RT5668_M_DAC_L1_STO_R (0x1 << 7) +#define RT5668_M_DAC_L1_STO_R_SHIFT 7 +#define RT5668_M_DAC_R1_STO_R (0x1 << 5) +#define RT5668_M_DAC_R1_STO_R_SHIFT 5 + +/* Power Management for Digital 1 (0x0061) */ +#define RT5668_PWR_I2S1 (0x1 << 15) +#define RT5668_PWR_I2S1_SHIFT 15 +#define RT5668_PWR_DAC_L1 (0x1 << 11) +#define RT5668_PWR_DAC_L1_SHIFT 11 +#define RT5668_PWR_DAC_R1 (0x1 << 10) +#define RT5668_PWR_DAC_R1_SHIFT 10 +#define RT5668_PWR_LDO_DACREF_MASK (0x1 << 8) +#define RT5668_PWR_LDO_DACREF_SHIFT 8 +#define RT5668_PWR_LDO_DACREF_ON (0x1 << 8) +#define RT5668_PWR_LDO_DACREF_DOWN (0x0 << 8) +#define RT5668_PWR_LDO_SHIFT 8 +#define RT5668_PWR_ADC_L1 (0x1 << 4) +#define RT5668_PWR_ADC_L1_SHIFT 4 +#define RT5668_PWR_ADC_R1 (0x1 << 3) +#define RT5668_PWR_ADC_R1_SHIFT 3 + +/* Power Management for Digital 2 (0x0062) */ +#define RT5668_PWR_ADC_S1F (0x1 << 15) +#define RT5668_PWR_ADC_S1F_SHIFT 15 +#define RT5668_PWR_DAC_S1F (0x1 << 10) +#define RT5668_PWR_DAC_S1F_SHIFT 10 + +/* Power Management for Analog 1 (0x0063) */ +#define RT5668_PWR_VREF1 (0x1 << 15) +#define RT5668_PWR_VREF1_MASK (0x1 << 15) +#define RT5668_PWR_VREF1_SHIFT 15 +#define RT5668_PWR_FV1 (0x1 << 14) +#define RT5668_PWR_FV1_MASK (0x1 << 14) +#define RT5668_PWR_FV1_SHIFT 14 +#define RT5668_PWR_VREF2 (0x1 << 13) +#define RT5668_PWR_VREF2_MASK (0x1 << 13) +#define RT5668_PWR_VREF2_SHIFT 13 +#define RT5668_PWR_FV2 (0x1 << 12) +#define RT5668_PWR_FV2_MASK (0x1 << 12) +#define RT5668_PWR_FV2_SHIFT 12 +#define RT5668_PWR_MB (0x1 << 9) +#define RT5668_PWR_MB_MASK (0x1 << 9) +#define RT5668_PWR_MB_SHIFT 9 +#define RT5668_AMP_HP_MASK (0x3 << 2) +#define RT5668_AMP_HP_SHIFT 2 +#define RT5668_AMP_HP_1X (0x0 << 2) +#define RT5668_AMP_HP_3X (0x1 << 2) +#define RT5668_AMP_HP_5X (0x3 << 2) +#define RT5668_LDO1_DVO_MASK (0x3) +#define RT5668_LDO1_DVO_SHIFT 0 +#define RT5668_LDO1_DVO_0_9V (0x0) +#define RT5668_LDO1_DVO_1_0V (0x1) +#define RT5668_LDO1_DVO_1_2V (0x2) +#define RT5668_LDO1_DVO_1_4V (0x3) + +/* Power Management for Analog 2 (0x0064) */ +#define RT5668_PWR_BST1 (0x1 << 15) +#define RT5668_PWR_BST1_MASK (0x1 << 15) +#define RT5668_PWR_BST1_SHIFT 15 +#define RT5668_PWR_BST1_OFF (0x0 << 15) +#define RT5668_PWR_BST1_ON (0x1 << 15) +#define RT5668_PWR_BST2 (0x1 << 14) +#define RT5668_PWR_BST2_MASK (0x1 << 14) +#define RT5668_PWR_BST2_SHIFT 14 +#define RT5668_PWR_MB1 (0x1 << 11) +#define RT5668_PWR_MB1_SHIFT 11 +#define RT5668_PWR_MB2 (0x1 << 10) +#define RT5668_PWR_MB2_SHIFT 10 +#define RT5668_PWR_BST2_OP (0x1 << 6) +#define RT5668_PWR_BST2_OP_MASK (0x1 << 6) +#define RT5668_PWR_BST2_OP_SHIFT 6 +#define RT5668_PWR_JD1 (0x1 << 3) +#define RT5668_PWR_JD1_MASK (0x1 << 3) +#define RT5668_PWR_JD1_SHIFT 3 +#define RT5668_PWR_JD2 (0x1 << 2) +#define RT5668_PWR_JD2_MASK (0x1 << 2) +#define RT5668_PWR_JD2_SHIFT 2 +#define RT5668_PWR_RECMIX1 (0x1 << 1) +#define RT5668_PWR_RECMIX1_SHIFT 1 +#define RT5668_PWR_RECMIX2 (0x1) +#define RT5668_PWR_RECMIX2_SHIFT 0 + +/* Power Management for Analog 3 (0x0065) */ +#define RT5668_PWR_CBJ_MASK (0x1 << 9) +#define RT5668_PWR_CBJ_SHIFT 9 +#define RT5668_PWR_CBJ_OFF (0x0 << 9) +#define RT5668_PWR_CBJ_ON (0x1 << 9) +#define RT5668_PWR_PLL (0x1 << 6) +#define RT5668_PWR_PLL_SHIFT 6 +#define RT5668_PWR_LDO2 (0x1 << 2) +#define RT5668_PWR_LDO2_SHIFT 2 + +/* Power Management for Volume (0x0067) */ +#define RT5668_PWR_MIC_DET (0x1 << 5) +#define RT5668_PWR_MIC_DET_SHIFT 5 + +/* MCLK and System Clock Detection Control (0x006b) */ +#define RT5668_EN_ANA_CLK_DET_MASK (0x1 << 15) +#define RT5668_EN_ANA_CLK_DET_SHIFT 15 +#define RT5668_EN_ANA_CLK_DET_DIS (0x0 << 15) +#define RT5668_EN_ANA_CLK_DET_AUTO (0x1 << 15) +#define RT5668_PWR_CLK_DET_MASK (0x1) +#define RT5668_PWR_CLK_DET_SHIFT 0 +#define RT5668_PWR_CLK_DET_DIS (0x0) +#define RT5668_PWR_CLK_DET_EN (0x1) + +/* I2S1 Audio Serial Data Port Control (0x0070) */ +#define RT5668_I2S_MS_MASK (0x1 << 15) +#define RT5668_I2S_MS_SHIFT 15 +#define RT5668_I2S_MS_M (0x0 << 15) +#define RT5668_I2S_MS_S (0x1 << 15) +#define RT5668_I2S_BP_MASK (0x1 << 8) +#define RT5668_I2S_BP_SHIFT 8 +#define RT5668_I2S_BP_NOR (0x0 << 8) +#define RT5668_I2S_BP_INV (0x1 << 8) +#define RT5668_I2S_DL_MASK (0x3 << 4) +#define RT5668_I2S_DL_SHIFT 4 +#define RT5668_I2S_DL_16 (0x0 << 4) +#define RT5668_I2S_DL_20 (0x1 << 4) +#define RT5668_I2S_DL_24 (0x2 << 4) +#define RT5668_I2S_DL_8 (0x3 << 4) +#define RT5668_I2S_DF_MASK (0x7) +#define RT5668_I2S_DF_SHIFT 0 +#define RT5668_I2S_DF_I2S (0x0) +#define RT5668_I2S_DF_LEFT (0x1) +#define RT5668_I2S_DF_PCM_A (0x2) +#define RT5668_I2S_DF_PCM_B (0x3) +#define RT5668_I2S_DF_PCM_A_N (0x6) +#define RT5668_I2S_DF_PCM_B_N (0x7) + +/* ADC/DAC Clock Control 1 (0x0073) */ +#define RT5668_I2S_PD1_MASK (0x7 << 12) +#define RT5668_I2S_PD1_SHIFT 12 +#define RT5668_M_I2S_DIV_MASK (0x7 << 8) +#define RT5668_M_I2S_DIV_SHIFT 8 +#define RT5668_CLK_SRC_MASK (0x3 << 4) +#define RT5668_CLK_SRC_MCLK (0x0 << 4) +#define RT5668_CLK_SRC_PLL_OUT (0x1 << 4) +#define RT5668_CLK_SRC_DIV (0x2 << 4) +#define RT5668_CLK_SRC_RC (0x3 << 4) +#define RT5668_DAC_OSR_MASK (0x3 << 2) +#define RT5668_DAC_OSR_SHIFT 2 +#define RT5668_DAC_OSR_128 (0x0 << 2) +#define RT5668_DAC_OSR_64 (0x1 << 2) +#define RT5668_DAC_OSR_32 (0x2 << 2) +#define RT5668_ADC_OSR_MASK (0x3) +#define RT5668_ADC_OSR_SHIFT 0 +#define RT5668_ADC_OSR_128 (0x0) +#define RT5668_ADC_OSR_64 (0x1) +#define RT5668_ADC_OSR_32 (0x2) + +/* TDM1 control 1 (0x0078) */ +#define RT5668_TDM_MODE_MASK (0x1 << 15) +#define RT5668_TDM_MODE_SHIFT 15 +#define RT5668_TDM_MODE_I2S (0x0 << 15) +#define RT5668_TDM_MODE_TDM (0x1 << 15) +#define RT5668_TDM_IN_CH_MASK (0x3 << 10) +#define RT5668_TDM_IN_CH_SHIFT 10 +#define RT5668_TDM_IN_CH_2 (0x0 << 10) +#define RT5668_TDM_IN_CH_4 (0x1 << 10) +#define RT5668_TDM_IN_CH_6 (0x2 << 10) +#define RT5668_TDM_IN_CH_8 (0x3 << 10) +#define RT5668_TDM_OUT_CH_MASK (0x3 << 8) +#define RT5668_TDM_OUT_CH_SHIFT 8 +#define RT5668_TDM_OUT_CH_2 (0x0 << 8) +#define RT5668_TDM_OUT_CH_4 (0x1 << 8) +#define RT5668_TDM_OUT_CH_6 (0x2 << 8) +#define RT5668_TDM_OUT_CH_8 (0x3 << 8) +#define RT5668_TDM_IN_LEN_MASK (0x3 << 6) +#define RT5668_TDM_IN_LEN_SHIFT 6 +#define RT5668_TDM_IN_LEN_16 (0x0 << 6) +#define RT5668_TDM_IN_LEN_20 (0x1 << 6) +#define RT5668_TDM_IN_LEN_24 (0x2 << 6) +#define RT5668_TDM_IN_LEN_32 (0x3 << 6) +#define RT5668_TDM_OUT_LEN_MASK (0x3 << 4) +#define RT5668_TDM_OUT_LEN_SHIFT 4 +#define RT5668_TDM_OUT_LEN_16 (0x0 << 4) +#define RT5668_TDM_OUT_LEN_20 (0x1 << 4) +#define RT5668_TDM_OUT_LEN_24 (0x2 << 4) +#define RT5668_TDM_OUT_LEN_32 (0x3 << 4) + +/* Global Clock Control (0x0080) */ +#define RT5668_SCLK_SRC_MASK (0x3 << 14) +#define RT5668_SCLK_SRC_SHIFT 14 +#define RT5668_SCLK_SRC_MCLK (0x0 << 14) +#define RT5668_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5668_SCLK_SRC_RCCLK (0x2 << 14) +#define RT5668_PLL1_SRC_MASK (0x7 << 8) +#define RT5668_PLL1_SRC_SHIFT 8 +#define RT5668_PLL1_SRC_MCLK (0x0 << 8) +#define RT5668_PLL1_SRC_BCLK1 (0x1 << 8) +#define RT5668_PLL1_PD_MASK (0x1 << 4) +#define RT5668_PLL1_PD_SHIFT 4 + +#define RT5668_PLL_INP_MAX 40000000 +#define RT5668_PLL_INP_MIN 256000 +/* PLL M/N/K Code Control 1 (0x0081) */ +#define RT5668_PLL_N_MAX 0x001ff +#define RT5668_PLL_N_MASK (RT5668_PLL_N_MAX << 7) +#define RT5668_PLL_N_SHIFT 7 +#define RT5668_PLL_K_MAX 0x001f +#define RT5668_PLL_K_MASK (RT5668_PLL_K_MAX) +#define RT5668_PLL_K_SHIFT 0 + +/* PLL M/N/K Code Control 2 (0x0082) */ +#define RT5668_PLL_M_MAX 0x00f +#define RT5668_PLL_M_MASK (RT5668_PLL_M_MAX << 12) +#define RT5668_PLL_M_SHIFT 12 +#define RT5668_PLL_M_BP (0x1 << 11) +#define RT5668_PLL_M_BP_SHIFT 11 + +/* PLL tracking mode 1 (0x0083) */ +#define RT5668_I2S1_ASRC_MASK (0x1 << 13) +#define RT5668_I2S1_ASRC_SHIFT 13 +#define RT5668_DAC_STO1_ASRC_MASK (0x1 << 12) +#define RT5668_DAC_STO1_ASRC_SHIFT 12 +#define RT5668_ADC_STO1_ASRC_MASK (0x1 << 4) +#define RT5668_ADC_STO1_ASRC_SHIFT 4 + +/* PLL tracking mode 2 (0x0084)*/ +#define RT5668_DA_STO1_TRACK_MASK (0x7 << 12) +#define RT5668_DA_STO1_TRACK_SHIFT 12 +#define RT5668_DA_STO1_TRACK_SYSCLK (0x0 << 12) +#define RT5668_DA_STO1_TRACK_I2S1 (0x1 << 12) + +/* PLL tracking mode 3 (0x0085)*/ +#define RT5668_AD_STO1_TRACK_MASK (0x7 << 12) +#define RT5668_AD_STO1_TRACK_SHIFT 12 +#define RT5668_AD_STO1_TRACK_SYSCLK (0x0 << 12) +#define RT5668_AD_STO1_TRACK_I2S1 (0x1 << 12) + +/* HPOUT Charge pump control 1 (0x0091) */ +#define RT5668_OSW_HP_L_MASK (0x1 << 11) +#define RT5668_OSW_HP_L_SHIFT 11 +#define RT5668_OSW_HP_L_EN (0x1 << 11) +#define RT5668_OSW_HP_L_DIS (0x0 << 11) +#define RT5668_OSW_HP_R_MASK (0x1 << 10) +#define RT5668_OSW_HP_R_SHIFT 10 +#define RT5668_OSW_HP_R_EN (0x1 << 10) +#define RT5668_OSW_HP_R_DIS (0x0 << 10) +#define RT5668_SEL_PM_HP_MASK (0x3 << 8) +#define RT5668_SEL_PM_HP_SHIFT 8 +#define RT5668_SEL_PM_HP_0_6 (0x0 << 8) +#define RT5668_SEL_PM_HP_0_9 (0x1 << 8) +#define RT5668_SEL_PM_HP_1_8 (0x2 << 8) +#define RT5668_SEL_PM_HP_HIGH (0x3 << 8) +#define RT5668_OVCD_HP_MASK (0x1 << 2) +#define RT5668_OVCD_HP_SHIFT 2 +#define RT5668_OVCD_HP_EN (0x1 << 2) +#define RT5668_OVCD_HP_DIS (0x0 << 2) + +/* RC Clock Control (0x0094) */ +#define RT5668_DIG_25M_CLK_MASK (0x1 << 9) +#define RT5668_DIG_25M_CLK_SHIFT 9 +#define RT5668_DIG_25M_CLK_DIS (0x0 << 9) +#define RT5668_DIG_25M_CLK_EN (0x1 << 9) +#define RT5668_DIG_1M_CLK_MASK (0x1 << 8) +#define RT5668_DIG_1M_CLK_SHIFT 8 +#define RT5668_DIG_1M_CLK_DIS (0x0 << 8) +#define RT5668_DIG_1M_CLK_EN (0x1 << 8) + +/* Auto Turn On 1M RC CLK (0x009f) */ +#define RT5668_IRQ_POW_SAV_MASK (0x1 << 15) +#define RT5668_IRQ_POW_SAV_SHIFT 15 +#define RT5668_IRQ_POW_SAV_DIS (0x0 << 15) +#define RT5668_IRQ_POW_SAV_EN (0x1 << 15) +#define RT5668_IRQ_POW_SAV_JD1_MASK (0x1 << 14) +#define RT5668_IRQ_POW_SAV_JD1_SHIFT 14 +#define RT5668_IRQ_POW_SAV_JD1_DIS (0x0 << 14) +#define RT5668_IRQ_POW_SAV_JD1_EN (0x1 << 14) + +/* IRQ Control 1 (0x00b6) */ +#define RT5668_EN_CB_JD_MASK (0x1 << 3) +#define RT5668_EN_CB_JD_SHIFT 3 +#define RT5668_EN_CB_JD_EN (0x1 << 3) +#define RT5668_EN_CB_JD_DIS (0x0 << 3) + +/* IRQ Control 3 (0x00b8) */ +#define RT5668_EN_IRQ_INLINE_MASK (0x1 << 6) +#define RT5668_EN_IRQ_INLINE_SHIFT 6 +#define RT5668_EN_IRQ_INLINE_BYP (0x0 << 6) +#define RT5668_EN_IRQ_INLINE_NOR (0x1 << 6) + +/* GPIO Control 1 (0x00c0) */ +#define RT5668_GP1_PIN_MASK (0x1 << 15) +#define RT5668_GP1_PIN_SHIFT 15 +#define RT5668_GP1_PIN_GPIO1 (0x0 << 15) +#define RT5668_GP1_PIN_IRQ (0x1 << 15) + +/* GPIO Control 2 (0x00c1) */ +#define RT5668_GP4_PIN_CONF_MASK (0x1 << 5) +#define RT5668_GP4_PIN_CONF_SHIFT 5 +#define RT5668_GP4_PIN_CONF_INPUT (0x0 << 5) +#define RT5668_GP4_PIN_CONF_OUTPUT (0x1 << 5) + +/* GPIO Control 2 (0x00c2) */ +#define RT5668_GP8_PIN_CONF_MASK (0x1 << 13) +#define RT5668_GP8_PIN_CONF_SHIFT 13 +#define RT5668_GP8_PIN_CONF_INPUT (0x0 << 13) +#define RT5668_GP8_PIN_CONF_OUTPUT (0x1 << 13) + +/* 4 Buttons Inline Command Function 1 (0x00df) */ +#define RT5668_4BTN_CLK_DEB_MASK (0x3 << 2) +#define RT5668_4BTN_CLK_DEB_SHIFT 2 +#define RT5668_4BTN_CLK_DEB_8MS (0x0 << 2) +#define RT5668_4BTN_CLK_DEB_16MS (0x1 << 2) +#define RT5668_4BTN_CLK_DEB_32MS (0x2 << 2) +#define RT5668_4BTN_CLK_DEB_65MS (0x3 << 2) + +/* Inline Command Function 6 (0x00e0) */ +#define RT5668_EN_4BTN_INL_MASK (0x1 << 15) +#define RT5668_EN_4BTN_INL_SHIFT 15 +#define RT5668_EN_4BTN_INL_DIS (0x0 << 15) +#define RT5668_EN_4BTN_INL_EN (0x1 << 15) +#define RT5668_RESET_4BTN_INL_MASK (0x1 << 14) +#define RT5668_RESET_4BTN_INL_SHIFT 14 +#define RT5668_RESET_4BTN_INL_RESET (0x0 << 14) +#define RT5668_RESET_4BTN_INL_NOR (0x1 << 14) + +/* Digital Misc Control (0x00fa) */ +#define RT5668_DIG_GATE_CTRL_MASK 0x1 +#define RT5668_DIG_GATE_CTRL_SHIFT (0) +#define RT5668_DIG_GATE_CTRL_DIS 0x0 +#define RT5668_DIG_GATE_CTRL_EN 0x1 + +/* Chopper and Clock control for DAC L (0x013a)*/ +#define RT5668_CKXEN_DAC1_MASK (0x1 << 13) +#define RT5668_CKXEN_DAC1_SHIFT 13 +#define RT5668_CKGEN_DAC1_MASK (0x1 << 12) +#define RT5668_CKGEN_DAC1_SHIFT 12 + +/* Chopper and Clock control for ADC (0x013b)*/ +#define RT5668_CKXEN_ADCC_MASK (0x1 << 13) +#define RT5668_CKXEN_ADCC_SHIFT 13 +#define RT5668_CKGEN_ADCC_MASK (0x1 << 12) +#define RT5668_CKGEN_ADCC_SHIFT 12 + +/* HP Behavior Logic Control 2 (0x01db) */ +#define RT5668_HP_SIG_SRC1_MASK (0x3) +#define RT5668_HP_SIG_SRC1_SHIFT 0 +#define RT5668_HP_SIG_SRC1_HP_DC (0x0) +#define RT5668_HP_SIG_SRC1_HP_CALIB (0x1) +#define RT5668_HP_SIG_SRC1_REG (0x2) +#define RT5668_HP_SIG_SRC1_SILENCE (0x3) + +/* RT5663 specific register */ +#define RT5663_HP_OUT_EN 0x0002 +#define RT5663_HP_LCH_DRE 0x0005 +#define RT5663_HP_RCH_DRE 0x0006 +#define RT5663_CALIB_BST 0x000a +#define RT5663_RECMIX 0x0010 +#define RT5663_SIL_DET_CTL 0x0015 +#define RT5663_PWR_SAV_SILDET 0x0016 +#define RT5663_SIDETONE_CTL 0x0018 +#define RT5663_STO1_DAC_DIG_VOL 0x0019 +#define RT5663_STO1_ADC_DIG_VOL 0x001c +#define RT5663_STO1_BOOST 0x001f +#define RT5663_HP_IMP_GAIN_1 0x0022 +#define RT5663_HP_IMP_GAIN_2 0x0023 +#define RT5663_STO1_ADC_MIXER 0x0026 +#define RT5663_AD_DA_MIXER 0x0029 +#define RT5663_STO_DAC_MIXER 0x002a +#define RT5663_DIG_SIDE_MIXER 0x002c +#define RT5663_BYPASS_STO_DAC 0x002d +#define RT5663_CALIB_REC_MIX 0x0040 +#define RT5663_PWR_DIG_1 0x0061 +#define RT5663_PWR_DIG_2 0x0062 +#define RT5663_PWR_ANLG_1 0x0063 +#define RT5663_PWR_ANLG_2 0x0064 +#define RT5663_PWR_ANLG_3 0x0065 +#define RT5663_PWR_MIXER 0x0066 +#define RT5663_SIG_CLK_DET 0x006b +#define RT5663_PRE_DIV_GATING_1 0x006e +#define RT5663_PRE_DIV_GATING_2 0x006f +#define RT5663_I2S1_SDP 0x0070 +#define RT5663_ADDA_CLK_1 0x0073 +#define RT5663_ADDA_RST 0x0074 +#define RT5663_FRAC_DIV_1 0x0075 +#define RT5663_FRAC_DIV_2 0x0076 +#define RT5663_TDM_1 0x0077 +#define RT5663_TDM_2 0x0078 +#define RT5663_TDM_3 0x0079 +#define RT5663_TDM_4 0x007a +#define RT5663_TDM_5 0x007b +#define RT5663_GLB_CLK 0x0080 +#define RT5663_PLL_1 0x0081 +#define RT5663_PLL_2 0x0082 +#define RT5663_ASRC_1 0x0083 +#define RT5663_ASRC_2 0x0084 +#define RT5663_ASRC_4 0x0086 +#define RT5663_DUMMY_REG 0x0087 +#define RT5663_ASRC_8 0x008a +#define RT5663_ASRC_9 0x008b +#define RT5663_ASRC_11 0x008c +#define RT5663_DEPOP_1 0x008e +#define RT5663_DEPOP_2 0x008f +#define RT5663_DEPOP_3 0x0090 +#define RT5663_HP_CHARGE_PUMP_1 0x0091 +#define RT5663_HP_CHARGE_PUMP_2 0x0092 +#define RT5663_MICBIAS_1 0x0093 +#define RT5663_RC_CLK 0x0094 +#define RT5663_ASRC_11_2 0x0097 +#define RT5663_DUMMY_REG_2 0x0098 +#define RT5663_REC_PATH_GAIN 0x009a +#define RT5663_AUTO_1MRC_CLK 0x009f +#define RT5663_ADC_EQ_1 0x00ae +#define RT5663_ADC_EQ_2 0x00af +#define RT5663_IRQ_1 0x00b6 +#define RT5663_IRQ_2 0x00b7 +#define RT5663_IRQ_3 0x00b8 +#define RT5663_IRQ_4 0x00ba +#define RT5663_IRQ_5 0x00bb +#define RT5663_INT_ST_1 0x00be +#define RT5663_INT_ST_2 0x00bf +#define RT5663_GPIO_1 0x00c0 +#define RT5663_GPIO_2 0x00c1 +#define RT5663_GPIO_STA 0x00c5 +#define RT5663_SIN_GEN_1 0x00cb +#define RT5663_SIN_GEN_2 0x00cc +#define RT5663_SIN_GEN_3 0x00cd +#define RT5663_SOF_VOL_ZC1 0x00d9 +#define RT5663_IL_CMD_1 0x00db +#define RT5663_IL_CMD_2 0x00dc +#define RT5663_IL_CMD_3 0x00dd +#define RT5663_IL_CMD_4 0x00de +#define RT5663_IL_CMD_5 0x00df +#define RT5663_IL_CMD_6 0x00e0 +#define RT5663_IL_CMD_7 0x00e1 +#define RT5663_IL_CMD_8 0x00e2 +#define RT5663_IL_CMD_PWRSAV1 0x00e4 +#define RT5663_IL_CMD_PWRSAV2 0x00e5 +#define RT5663_EM_JACK_TYPE_1 0x00e6 +#define RT5663_EM_JACK_TYPE_2 0x00e7 +#define RT5663_EM_JACK_TYPE_3 0x00e8 +#define RT5663_EM_JACK_TYPE_4 0x00e9 +#define RT5663_EM_JACK_TYPE_5 0x00ea +#define RT5663_EM_JACK_TYPE_6 0x00eb +#define RT5663_STO1_HPF_ADJ1 0x00ec +#define RT5663_STO1_HPF_ADJ2 0x00ed +#define RT5663_FAST_OFF_MICBIAS 0x00f4 +#define RT5663_JD_CTRL1 0x00f6 +#define RT5663_JD_CTRL2 0x00f8 +#define RT5663_DIG_MISC 0x00fa +#define RT5663_DIG_VOL_ZCD 0x0100 +#define RT5663_ANA_BIAS_CUR_1 0x0108 +#define RT5663_ANA_BIAS_CUR_2 0x0109 +#define RT5663_ANA_BIAS_CUR_3 0x010a +#define RT5663_ANA_BIAS_CUR_4 0x010b +#define RT5663_ANA_BIAS_CUR_5 0x010c +#define RT5663_ANA_BIAS_CUR_6 0x010d +#define RT5663_BIAS_CUR_5 0x010e +#define RT5663_BIAS_CUR_6 0x010f +#define RT5663_BIAS_CUR_7 0x0110 +#define RT5663_BIAS_CUR_8 0x0111 +#define RT5663_DACREF_LDO 0x0112 +#define RT5663_DUMMY_REG_3 0x0113 +#define RT5663_BIAS_CUR_9 0x0114 +#define RT5663_DUMMY_REG_4 0x0116 +#define RT5663_VREFADJ_OP 0x0117 +#define RT5663_VREF_RECMIX 0x0118 +#define RT5663_CHARGE_PUMP_1 0x0125 +#define RT5663_CHARGE_PUMP_1_2 0x0126 +#define RT5663_CHARGE_PUMP_1_3 0x0127 +#define RT5663_CHARGE_PUMP_2 0x0128 +#define RT5663_DIG_IN_PIN1 0x0132 +#define RT5663_PAD_DRV_CTL 0x0137 +#define RT5663_PLL_INT_REG 0x0139 +#define RT5663_CHOP_DAC_L 0x013a +#define RT5663_CHOP_ADC 0x013b +#define RT5663_CALIB_ADC 0x013c +#define RT5663_CHOP_DAC_R 0x013d +#define RT5663_DUMMY_CTL_DACLR 0x013e +#define RT5663_DUMMY_REG_5 0x0140 +#define RT5663_SOFT_RAMP 0x0141 +#define RT5663_TEST_MODE_1 0x0144 +#define RT5663_TEST_MODE_2 0x0145 +#define RT5663_TEST_MODE_3 0x0146 +#define RT5663_STO_DRE_1 0x0160 +#define RT5663_STO_DRE_2 0x0161 +#define RT5663_STO_DRE_3 0x0162 +#define RT5663_STO_DRE_4 0x0163 +#define RT5663_STO_DRE_5 0x0164 +#define RT5663_STO_DRE_6 0x0165 +#define RT5663_STO_DRE_7 0x0166 +#define RT5663_STO_DRE_8 0x0167 +#define RT5663_STO_DRE_9 0x0168 +#define RT5663_STO_DRE_10 0x0169 +#define RT5663_MIC_DECRO_1 0x0180 +#define RT5663_MIC_DECRO_2 0x0181 +#define RT5663_MIC_DECRO_3 0x0182 +#define RT5663_MIC_DECRO_4 0x0183 +#define RT5663_MIC_DECRO_5 0x0184 +#define RT5663_MIC_DECRO_6 0x0185 +#define RT5663_HP_DECRO_1 0x01b0 +#define RT5663_HP_DECRO_2 0x01b1 +#define RT5663_HP_DECRO_3 0x01b2 +#define RT5663_HP_DECRO_4 0x01b3 +#define RT5663_HP_DECOUP 0x01b4 +#define RT5663_HP_IMP_SEN_MAP8 0x01b5 +#define RT5663_HP_IMP_SEN_MAP9 0x01b6 +#define RT5663_HP_IMP_SEN_MAP10 0x01b7 +#define RT5663_HP_IMP_SEN_MAP11 0x01b8 +#define RT5663_HP_IMP_SEN_1 0x01c0 +#define RT5663_HP_IMP_SEN_2 0x01c1 +#define RT5663_HP_IMP_SEN_3 0x01c2 +#define RT5663_HP_IMP_SEN_4 0x01c3 +#define RT5663_HP_IMP_SEN_5 0x01c4 +#define RT5663_HP_IMP_SEN_6 0x01c5 +#define RT5663_HP_IMP_SEN_7 0x01c6 +#define RT5663_HP_IMP_SEN_8 0x01c7 +#define RT5663_HP_IMP_SEN_9 0x01c8 +#define RT5663_HP_IMP_SEN_10 0x01c9 +#define RT5663_HP_IMP_SEN_11 0x01ca +#define RT5663_HP_IMP_SEN_12 0x01cb +#define RT5663_HP_IMP_SEN_13 0x01cc +#define RT5663_HP_IMP_SEN_14 0x01cd +#define RT5663_HP_IMP_SEN_15 0x01ce +#define RT5663_HP_IMP_SEN_16 0x01cf +#define RT5663_HP_IMP_SEN_17 0x01d0 +#define RT5663_HP_IMP_SEN_18 0x01d1 +#define RT5663_HP_IMP_SEN_19 0x01d2 +#define RT5663_HP_IMPSEN_DIG5 0x01d3 +#define RT5663_HP_IMPSEN_MAP1 0x01d4 +#define RT5663_HP_IMPSEN_MAP2 0x01d5 +#define RT5663_HP_IMPSEN_MAP3 0x01d6 +#define RT5663_HP_IMPSEN_MAP4 0x01d7 +#define RT5663_HP_IMPSEN_MAP5 0x01d8 +#define RT5663_HP_IMPSEN_MAP7 0x01d9 +#define RT5663_HP_LOGIC_1 0x01da +#define RT5663_HP_LOGIC_2 0x01db +#define RT5663_HP_CALIB_1 0x01dd +#define RT5663_HP_CALIB_1_1 0x01de +#define RT5663_HP_CALIB_2 0x01df +#define RT5663_HP_CALIB_3 0x01e0 +#define RT5663_HP_CALIB_4 0x01e1 +#define RT5663_HP_CALIB_5 0x01e2 +#define RT5663_HP_CALIB_5_1 0x01e3 +#define RT5663_HP_CALIB_6 0x01e4 +#define RT5663_HP_CALIB_7 0x01e5 +#define RT5663_HP_CALIB_9 0x01e6 +#define RT5663_HP_CALIB_10 0x01e7 +#define RT5663_HP_CALIB_11 0x01e8 +#define RT5663_HP_CALIB_ST1 0x01ea +#define RT5663_HP_CALIB_ST2 0x01eb +#define RT5663_HP_CALIB_ST3 0x01ec +#define RT5663_HP_CALIB_ST4 0x01ed +#define RT5663_HP_CALIB_ST5 0x01ee +#define RT5663_HP_CALIB_ST6 0x01ef +#define RT5663_HP_CALIB_ST7 0x01f0 +#define RT5663_HP_CALIB_ST8 0x01f1 +#define RT5663_HP_CALIB_ST9 0x01f2 +#define RT5663_HP_AMP_DET 0x0200 +#define RT5663_DUMMY_REG_6 0x0201 +#define RT5663_HP_BIAS 0x0202 +#define RT5663_CBJ_1 0x0250 +#define RT5663_CBJ_2 0x0251 +#define RT5663_CBJ_3 0x0252 +#define RT5663_DUMMY_1 0x02fa +#define RT5663_DUMMY_2 0x02fb +#define RT5663_DUMMY_3 0x02fc +#define RT5663_ANA_JD 0x0300 +#define RT5663_ADC_LCH_LPF1_A1 0x03d0 +#define RT5663_ADC_RCH_LPF1_A1 0x03d1 +#define RT5663_ADC_LCH_LPF1_H0 0x03d2 +#define RT5663_ADC_RCH_LPF1_H0 0x03d3 +#define RT5663_ADC_LCH_BPF1_A1 0x03d4 +#define RT5663_ADC_RCH_BPF1_A1 0x03d5 +#define RT5663_ADC_LCH_BPF1_A2 0x03d6 +#define RT5663_ADC_RCH_BPF1_A2 0x03d7 +#define RT5663_ADC_LCH_BPF1_H0 0x03d8 +#define RT5663_ADC_RCH_BPF1_H0 0x03d9 +#define RT5663_ADC_LCH_BPF2_A1 0x03da +#define RT5663_ADC_RCH_BPF2_A1 0x03db +#define RT5663_ADC_LCH_BPF2_A2 0x03dc +#define RT5663_ADC_RCH_BPF2_A2 0x03dd +#define RT5663_ADC_LCH_BPF2_H0 0x03de +#define RT5663_ADC_RCH_BPF2_H0 0x03df +#define RT5663_ADC_LCH_BPF3_A1 0x03e0 +#define RT5663_ADC_RCH_BPF3_A1 0x03e1 +#define RT5663_ADC_LCH_BPF3_A2 0x03e2 +#define RT5663_ADC_RCH_BPF3_A2 0x03e3 +#define RT5663_ADC_LCH_BPF3_H0 0x03e4 +#define RT5663_ADC_RCH_BPF3_H0 0x03e5 +#define RT5663_ADC_LCH_BPF4_A1 0x03e6 +#define RT5663_ADC_RCH_BPF4_A1 0x03e7 +#define RT5663_ADC_LCH_BPF4_A2 0x03e8 +#define RT5663_ADC_RCH_BPF4_A2 0x03e9 +#define RT5663_ADC_LCH_BPF4_H0 0x03ea +#define RT5663_ADC_RCH_BPF4_H0 0x03eb +#define RT5663_ADC_LCH_HPF1_A1 0x03ec +#define RT5663_ADC_RCH_HPF1_A1 0x03ed +#define RT5663_ADC_LCH_HPF1_H0 0x03ee +#define RT5663_ADC_RCH_HPF1_H0 0x03ef +#define RT5663_ADC_EQ_PRE_VOL_L 0x03f0 +#define RT5663_ADC_EQ_PRE_VOL_R 0x03f1 +#define RT5663_ADC_EQ_POST_VOL_L 0x03f2 +#define RT5663_ADC_EQ_POST_VOL_R 0x03f3 + +/* RT5663: RECMIX Control (0x0010) */ +#define RT5663_RECMIX1_BST1_MASK (0x1) +#define RT5663_RECMIX1_BST1_SHIFT 0 +#define RT5663_RECMIX1_BST1_ON (0x0) +#define RT5663_RECMIX1_BST1_OFF (0x1) + +/* RT5663: Bypass Stereo1 DAC Mixer Control (0x002d) */ +#define RT5663_DACL1_SRC_MASK (0x1 << 3) +#define RT5663_DACL1_SRC_SHIFT 3 +#define RT5663_DACR1_SRC_MASK (0x1 << 2) +#define RT5663_DACR1_SRC_SHIFT 2 + +/* RT5663: TDM control 2 (0x0078) */ +#define RT5663_DATA_SWAP_ADCDAT1_MASK (0x3 << 14) +#define RT5663_DATA_SWAP_ADCDAT1_SHIFT 14 +#define RT5663_DATA_SWAP_ADCDAT1_LR (0x0 << 14) +#define RT5663_DATA_SWAP_ADCDAT1_RL (0x1 << 14) +#define RT5663_DATA_SWAP_ADCDAT1_LL (0x2 << 14) +#define RT5663_DATA_SWAP_ADCDAT1_RR (0x3 << 14) + +/* RT5663: TDM control 5 (0x007b) */ +#define RT5663_TDM_LENGTN_MASK (0x3) +#define RT5663_TDM_LENGTN_SHIFT 0 +#define RT5663_TDM_LENGTN_16 (0x0) +#define RT5663_TDM_LENGTN_20 (0x1) +#define RT5663_TDM_LENGTN_24 (0x2) +#define RT5663_TDM_LENGTN_32 (0x3) + +/* RT5663: Global Clock Control (0x0080) */ +#define RT5663_SCLK_SRC_MASK (0x3 << 14) +#define RT5663_SCLK_SRC_SHIFT 14 +#define RT5663_SCLK_SRC_MCLK (0x0 << 14) +#define RT5663_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5663_SCLK_SRC_RCCLK (0x2 << 14) +#define RT5663_PLL1_SRC_MASK (0x7 << 11) +#define RT5663_PLL1_SRC_SHIFT 11 +#define RT5663_PLL1_SRC_MCLK (0x0 << 11) +#define RT5663_PLL1_SRC_BCLK1 (0x1 << 11) + +/* PLL tracking mode 1 (0x0083) */ +#define RT5663_I2S1_ASRC_MASK (0x1 << 11) +#define RT5663_I2S1_ASRC_SHIFT 11 +#define RT5663_DAC_STO1_ASRC_MASK (0x1 << 10) +#define RT5663_DAC_STO1_ASRC_SHIFT 10 +#define RT5663_ADC_STO1_ASRC_MASK (0x1 << 3) +#define RT5663_ADC_STO1_ASRC_SHIFT 3 + +/* PLL tracking mode 2 (0x0084)*/ +#define RT5663_DA_STO1_TRACK_MASK (0x7 << 12) +#define RT5663_DA_STO1_TRACK_SHIFT 12 +#define RT5663_DA_STO1_TRACK_SYSCLK (0x0 << 12) +#define RT5663_DA_STO1_TRACK_I2S1 (0x1 << 12) +#define RT5663_AD_STO1_TRACK_MASK (0x7) +#define RT5663_AD_STO1_TRACK_SHIFT 0 +#define RT5663_AD_STO1_TRACK_SYSCLK (0x0) +#define RT5663_AD_STO1_TRACK_I2S1 (0x1) + +/* RT5663: HPOUT Charge pump control 1 (0x0091) */ +#define RT5663_SI_HP_MASK (0x1 << 12) +#define RT5663_SI_HP_SHIFT 12 +#define RT5663_SI_HP_EN (0x1 << 12) +#define RT5663_SI_HP_DIS (0x0 << 12) + +/* RT5663: GPIO Control 2 (0x00b6) */ +#define RT5663_GP1_PIN_CONF_MASK (0x1 << 2) +#define RT5663_GP1_PIN_CONF_SHIFT 2 +#define RT5663_GP1_PIN_CONF_OUTPUT (0x1 << 2) +#define RT5663_GP1_PIN_CONF_INPUT (0x0 << 2) + +/* RT5663: GPIO Control 2 (0x00b7) */ +#define RT5663_EN_IRQ_INLINE_MASK (0x1 << 3) +#define RT5663_EN_IRQ_INLINE_SHIFT 3 +#define RT5663_EN_IRQ_INLINE_NOR (0x1 << 3) +#define RT5663_EN_IRQ_INLINE_BYP (0x0 << 3) + +/* RT5663: IRQ Control 1 (0x00c1) */ +#define RT5663_EN_IRQ_JD1_MASK (0x1 << 6) +#define RT5663_EN_IRQ_JD1_SHIFT 6 +#define RT5663_EN_IRQ_JD1_EN (0x1 << 6) +#define RT5663_EN_IRQ_JD1_DIS (0x0 << 6) + +/* RT5663: Inline Command Function 2 (0x00dc) */ +#define RT5663_PWR_MIC_DET_MASK (0x1) +#define RT5663_PWR_MIC_DET_SHIFT 0 +#define RT5663_PWR_MIC_DET_ON (0x1) +#define RT5663_PWR_MIC_DET_OFF (0x0) + +/* RT5663: Embeeded Jack and Type Detection Control 1 (0x00e6)*/ +#define RT5663_CBJ_DET_MASK (0x1 << 15) +#define RT5663_CBJ_DET_SHIFT 15 +#define RT5663_CBJ_DET_DIS (0x0 << 15) +#define RT5663_CBJ_DET_EN (0x1 << 15) +#define RT5663_EXT_JD_MASK (0x1 << 11) +#define RT5663_EXT_JD_SHIFT 11 +#define RT5663_EXT_JD_EN (0x1 << 11) +#define RT5663_EXT_JD_DIS (0x0 << 11) +#define RT5663_POL_EXT_JD_MASK (0x1 << 10) +#define RT5663_POL_EXT_JD_SHIFT 10 +#define RT5663_POL_EXT_JD_EN (0x1 << 10) +#define RT5663_POL_EXT_JD_DIS (0x0 << 10) + +/* RT5663: DACREF LDO Control (0x0112)*/ +#define RT5663_PWR_LDO_DACREFL_MASK (0x1 << 9) +#define RT5663_PWR_LDO_DACREFL_SHIFT 9 +#define RT5663_PWR_LDO_DACREFR_MASK (0x1 << 1) +#define RT5663_PWR_LDO_DACREFR_SHIFT 1 + +/* RT5663: Stereo Dynamic Range Enhancement Control 9 (0x0168, 0x0169)*/ +#define RT5663_DRE_GAIN_HP_MASK (0x1f) +#define RT5663_DRE_GAIN_HP_SHIFT 0 + +/* RT5663: Combo Jack Control (0x0250) */ +#define RT5663_INBUF_CBJ_BST1_MASK (0x1 << 11) +#define RT5663_INBUF_CBJ_BST1_SHIFT 11 +#define RT5663_INBUF_CBJ_BST1_ON (0x1 << 11) +#define RT5663_INBUF_CBJ_BST1_OFF (0x0 << 11) +#define RT5663_CBJ_SENSE_BST1_MASK (0x1 << 10) +#define RT5663_CBJ_SENSE_BST1_SHIFT 10 +#define RT5663_CBJ_SENSE_BST1_L (0x1 << 10) +#define RT5663_CBJ_SENSE_BST1_R (0x0 << 10) + +/* RT5663: Combo Jack Control (0x0251) */ +#define RT5663_GAIN_BST1_MASK (0xf) +#define RT5663_GAIN_BST1_SHIFT 0 + +/* RT5663: Dummy register 1 (0x02fa) */ +#define RT5663_EMB_CLK_MASK (0x1 << 9) +#define RT5663_EMB_CLK_SHIFT 9 +#define RT5663_EMB_CLK_EN (0x1 << 9) +#define RT5663_EMB_CLK_DIS (0x0 << 9) +#define RT5663_HPA_CPL_BIAS_MASK (0x7 << 6) +#define RT5663_HPA_CPL_BIAS_SHIFT 6 +#define RT5663_HPA_CPL_BIAS_0_5 (0x0 << 6) +#define RT5663_HPA_CPL_BIAS_1 (0x1 << 6) +#define RT5663_HPA_CPL_BIAS_2 (0x2 << 6) +#define RT5663_HPA_CPL_BIAS_3 (0x3 << 6) +#define RT5663_HPA_CPL_BIAS_4_1 (0x4 << 6) +#define RT5663_HPA_CPL_BIAS_4_2 (0x5 << 6) +#define RT5663_HPA_CPL_BIAS_6 (0x6 << 6) +#define RT5663_HPA_CPL_BIAS_8 (0x7 << 6) +#define RT5663_HPA_CPR_BIAS_MASK (0x7 << 3) +#define RT5663_HPA_CPR_BIAS_SHIFT 3 +#define RT5663_HPA_CPR_BIAS_0_5 (0x0 << 3) +#define RT5663_HPA_CPR_BIAS_1 (0x1 << 3) +#define RT5663_HPA_CPR_BIAS_2 (0x2 << 3) +#define RT5663_HPA_CPR_BIAS_3 (0x3 << 3) +#define RT5663_HPA_CPR_BIAS_4_1 (0x4 << 3) +#define RT5663_HPA_CPR_BIAS_4_2 (0x5 << 3) +#define RT5663_HPA_CPR_BIAS_6 (0x6 << 3) +#define RT5663_HPA_CPR_BIAS_8 (0x7 << 3) +#define RT5663_DUMMY_BIAS_MASK (0x7) +#define RT5663_DUMMY_BIAS_SHIFT 0 +#define RT5663_DUMMY_BIAS_0_5 (0x0) +#define RT5663_DUMMY_BIAS_1 (0x1) +#define RT5663_DUMMY_BIAS_2 (0x2) +#define RT5663_DUMMY_BIAS_3 (0x3) +#define RT5663_DUMMY_BIAS_4_1 (0x4) +#define RT5663_DUMMY_BIAS_4_2 (0x5) +#define RT5663_DUMMY_BIAS_6 (0x6) +#define RT5663_DUMMY_BIAS_8 (0x7) + + +/* System Clock Source */ +enum { + RT5663_SCLK_S_MCLK, + RT5663_SCLK_S_PLL1, + RT5663_SCLK_S_RCCLK, +}; + +/* PLL1 Source */ +enum { + RT5663_PLL1_S_MCLK, + RT5663_PLL1_S_BCLK1, +}; + +enum { + RT5663_AIF, + RT5663_AIFS, +}; + +/* asrc clock source */ +enum { + RT5663_CLK_SEL_SYS = 0x0, + RT5663_CLK_SEL_I2S1_ASRC = 0x1, +}; + +/* filter mask */ +enum { + RT5663_DA_STEREO_FILTER = 0x1, + RT5663_AD_STEREO_FILTER = 0x2, +}; + +int rt5663_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hs_jack); +int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); + +#endif /* __RT5663_H__ */ diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 8ef467f64f03..49caf1393aeb 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2777,12 +2777,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5670 = { .resume = rt5670_resume, .set_bias_level = rt5670_set_bias_level, .idle_bias_off = true, - .controls = rt5670_snd_controls, - .num_controls = ARRAY_SIZE(rt5670_snd_controls), - .dapm_widgets = rt5670_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rt5670_dapm_widgets), - .dapm_routes = rt5670_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rt5670_dapm_routes), + .component_driver = { + .controls = rt5670_snd_controls, + .num_controls = ARRAY_SIZE(rt5670_snd_controls), + .dapm_widgets = rt5670_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5670_dapm_widgets), + .dapm_routes = rt5670_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5670_dapm_routes), + }, }; static const struct regmap_config rt5670_regmap = { diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index da9483c1c6fb..abc802a5a479 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include <linux/acpi.h> #include <linux/fs.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -40,6 +41,15 @@ #define RT5677_PR_BASE (RT5677_PR_RANGE_BASE + (0 * RT5677_PR_SPACING)) +/* GPIO indexes defined by ACPI */ +enum { + RT5677_GPIO_PLUG_DET = 0, + RT5677_GPIO_MIC_PRESENT_L = 1, + RT5677_GPIO_HOTWORD_DET_L = 2, + RT5677_GPIO_DSP_INT = 3, + RT5677_GPIO_HP_AMP_SHDN_L = 4, +}; + static const struct regmap_range_cfg rt5677_ranges[] = { { .name = "PR", @@ -4657,7 +4667,7 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) return regmap_irq_get_virq(data, irq); } -static struct gpio_chip rt5677_template_chip = { +static const struct gpio_chip rt5677_template_chip = { .label = "rt5677", .owner = THIS_MODULE, .direction_output = rt5677_gpio_direction_out, @@ -4974,12 +4984,14 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5677 = { .resume = rt5677_resume, .set_bias_level = rt5677_set_bias_level, .idle_bias_off = true, - .controls = rt5677_snd_controls, - .num_controls = ARRAY_SIZE(rt5677_snd_controls), - .dapm_widgets = rt5677_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(rt5677_dapm_widgets), - .dapm_routes = rt5677_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes), + .component_driver = { + .controls = rt5677_snd_controls, + .num_controls = ARRAY_SIZE(rt5677_snd_controls), + .dapm_widgets = rt5677_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5677_dapm_widgets), + .dapm_routes = rt5677_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes), + }, }; static const struct regmap_config rt5677_regmap_physical = { @@ -5018,10 +5030,47 @@ static const struct regmap_config rt5677_regmap = { static const struct i2c_device_id rt5677_i2c_id[] = { { "rt5677", RT5677 }, { "rt5676", RT5676 }, + { "RT5677CE:00", RT5677 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); +static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false }; +static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false }; +static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false }; + +static const struct acpi_gpio_mapping bdw_rt5677_gpios[] = { + { "plug-det-gpios", &plug_det_gpio, 1 }, + { "mic-present-gpios", &mic_present_gpio, 1 }, + { "headphone-enable-gpios", &headphone_enable_gpio, 1 }, + { NULL }, +}; + +static void rt5677_read_acpi_properties(struct rt5677_priv *rt5677, + struct device *dev) +{ + int ret; + u32 val; + + ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), + bdw_rt5677_gpios); + if (ret) + dev_warn(dev, "Failed to add driver gpios\n"); + + if (!device_property_read_u32(dev, "DCLK", &val)) + rt5677->pdata.dmic2_clk_pin = val; + + rt5677->pdata.in1_diff = device_property_read_bool(dev, "IN1"); + rt5677->pdata.in2_diff = device_property_read_bool(dev, "IN2"); + rt5677->pdata.lout1_diff = device_property_read_bool(dev, "OUT1"); + rt5677->pdata.lout2_diff = device_property_read_bool(dev, "OUT2"); + rt5677->pdata.lout3_diff = device_property_read_bool(dev, "OUT3"); + + device_property_read_u32(dev, "JD1", &rt5677->pdata.jd1_gpio); + device_property_read_u32(dev, "JD2", &rt5677->pdata.jd2_gpio); + device_property_read_u32(dev, "JD3", &rt5677->pdata.jd3_gpio); +} + static void rt5677_read_device_properties(struct rt5677_priv *rt5677, struct device *dev) { @@ -5127,8 +5176,12 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, if (pdata) rt5677->pdata = *pdata; - else + else if (i2c->dev.of_node) rt5677_read_device_properties(rt5677, &i2c->dev); + else if (ACPI_HANDLE(&i2c->dev)) + rt5677_read_acpi_properties(rt5677, &i2c->dev); + else + return -EINVAL; /* pow-ldo2 and reset are optional. The codec pins may be statically * connected on the board without gpios. If the gpio device property diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 527b759c1562..1589325855bc 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -411,6 +411,8 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { 0, 8, 0x7f, 1, headphone_volume), + SOC_SINGLE("Headphone Playback Switch", SGTL5000_CHIP_ANA_CTRL, + 4, 1, 1), SOC_SINGLE("Headphone Playback ZC Switch", SGTL5000_CHIP_ANA_CTRL, 5, 1, 0), @@ -423,6 +425,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT, 0x1f, 1, lineout_volume), + SOC_SINGLE("Lineout Playback Switch", SGTL5000_CHIP_ANA_CTRL, 8, 1, 1), }; /* mute the codec used by alsa core */ @@ -1151,12 +1154,14 @@ static struct snd_soc_codec_driver sgtl5000_driver = { .remove = sgtl5000_remove, .set_bias_level = sgtl5000_set_bias_level, .suspend_bias_off = true, - .controls = sgtl5000_snd_controls, - .num_controls = ARRAY_SIZE(sgtl5000_snd_controls), - .dapm_widgets = sgtl5000_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(sgtl5000_dapm_widgets), - .dapm_routes = sgtl5000_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(sgtl5000_dapm_routes), + .component_driver = { + .controls = sgtl5000_snd_controls, + .num_controls = ARRAY_SIZE(sgtl5000_snd_controls), + .dapm_widgets = sgtl5000_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sgtl5000_dapm_widgets), + .dapm_routes = sgtl5000_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sgtl5000_dapm_routes), + }, }; static const struct regmap_config sgtl5000_regmap = { diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index a8402d0af0ea..5344f4aa8fde 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -238,10 +238,12 @@ static struct regmap *si476x_get_regmap(struct device *dev) static struct snd_soc_codec_driver soc_codec_dev_si476x = { .get_regmap = si476x_get_regmap, - .dapm_widgets = si476x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets), - .dapm_routes = si476x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(si476x_dapm_routes), + .component_driver = { + .dapm_widgets = si476x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets), + .dapm_routes = si476x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(si476x_dapm_routes), + }, }; static int si476x_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index 3a7de0159f24..eae54c37cff9 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -888,12 +888,14 @@ static struct snd_soc_codec_driver sn95031_codec = { .set_bias_level = sn95031_set_vaud_bias, .idle_bias_off = true, - .controls = sn95031_snd_controls, - .num_controls = ARRAY_SIZE(sn95031_snd_controls), - .dapm_widgets = sn95031_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(sn95031_dapm_widgets), - .dapm_routes = sn95031_audio_map, - .num_dapm_routes = ARRAY_SIZE(sn95031_audio_map), + .component_driver = { + .controls = sn95031_snd_controls, + .num_controls = ARRAY_SIZE(sn95031_snd_controls), + .dapm_widgets = sn95031_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sn95031_dapm_widgets), + .dapm_routes = sn95031_audio_map, + .num_dapm_routes = ARRAY_SIZE(sn95031_audio_map), + }, }; static int sn95031_device_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c index 3ec41ccbf4e2..234f87b54838 100644 --- a/sound/soc/codecs/spdif_receiver.c +++ b/sound/soc/codecs/spdif_receiver.c @@ -38,10 +38,12 @@ static const struct snd_soc_dapm_route dir_routes[] = { SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) static struct snd_soc_codec_driver soc_codec_spdif_dir = { - .dapm_widgets = dir_widgets, - .num_dapm_widgets = ARRAY_SIZE(dir_widgets), - .dapm_routes = dir_routes, - .num_dapm_routes = ARRAY_SIZE(dir_routes), + .component_driver = { + .dapm_widgets = dir_widgets, + .num_dapm_widgets = ARRAY_SIZE(dir_widgets), + .dapm_routes = dir_routes, + .num_dapm_routes = ARRAY_SIZE(dir_routes), + }, }; static struct snd_soc_dai_driver dir_stub_dai = { diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c index ef634a9ad673..ee367536a498 100644 --- a/sound/soc/codecs/spdif_transmitter.c +++ b/sound/soc/codecs/spdif_transmitter.c @@ -38,10 +38,12 @@ static const struct snd_soc_dapm_route dit_routes[] = { }; static struct snd_soc_codec_driver soc_codec_spdif_dit = { - .dapm_widgets = dit_widgets, - .num_dapm_widgets = ARRAY_SIZE(dit_widgets), - .dapm_routes = dit_routes, - .num_dapm_routes = ARRAY_SIZE(dit_routes), + .component_driver = { + .dapm_widgets = dit_widgets, + .num_dapm_widgets = ARRAY_SIZE(dit_widgets), + .dapm_routes = dit_routes, + .num_dapm_routes = ARRAY_SIZE(dit_routes), + }, }; static struct snd_soc_dai_driver dit_stub_dai = { diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index e2e0bfa7ec20..38a85f3adc80 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -715,12 +715,14 @@ static struct snd_soc_codec_driver ssm2518_codec_driver = { .set_sysclk = ssm2518_set_sysclk, .idle_bias_off = true, - .controls = ssm2518_snd_controls, - .num_controls = ARRAY_SIZE(ssm2518_snd_controls), - .dapm_widgets = ssm2518_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ssm2518_dapm_widgets), - .dapm_routes = ssm2518_routes, - .num_dapm_routes = ARRAY_SIZE(ssm2518_routes), + .component_driver = { + .controls = ssm2518_snd_controls, + .num_controls = ARRAY_SIZE(ssm2518_snd_controls), + .dapm_widgets = ssm2518_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ssm2518_dapm_widgets), + .dapm_routes = ssm2518_routes, + .num_dapm_routes = ARRAY_SIZE(ssm2518_routes), + }, }; static const struct regmap_config ssm2518_regmap_config = { diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 4452fea0b118..993bde29ca1b 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -597,12 +597,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { .set_bias_level = ssm2602_set_bias_level, .suspend_bias_off = true, - .controls = ssm260x_snd_controls, - .num_controls = ARRAY_SIZE(ssm260x_snd_controls), - .dapm_widgets = ssm260x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ssm260x_dapm_widgets), - .dapm_routes = ssm260x_routes, - .num_dapm_routes = ARRAY_SIZE(ssm260x_routes), + .component_driver = { + .controls = ssm260x_snd_controls, + .num_controls = ARRAY_SIZE(ssm260x_snd_controls), + .dapm_widgets = ssm260x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ssm260x_dapm_widgets), + .dapm_routes = ssm260x_routes, + .num_dapm_routes = ARRAY_SIZE(ssm260x_routes), + }, }; static bool ssm2602_register_volatile(struct device *dev, unsigned int reg) diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 080c78e88e10..2bb5a11c9ba1 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -421,12 +421,14 @@ static struct snd_soc_codec_driver ssm4567_codec_driver = { .set_bias_level = ssm4567_set_bias_level, .idle_bias_off = true, - .controls = ssm4567_snd_controls, - .num_controls = ARRAY_SIZE(ssm4567_snd_controls), - .dapm_widgets = ssm4567_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ssm4567_dapm_widgets), - .dapm_routes = ssm4567_routes, - .num_dapm_routes = ARRAY_SIZE(ssm4567_routes), + .component_driver = { + .controls = ssm4567_snd_controls, + .num_controls = ARRAY_SIZE(ssm4567_snd_controls), + .dapm_widgets = ssm4567_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ssm4567_dapm_widgets), + .dapm_routes = ssm4567_routes, + .num_dapm_routes = ARRAY_SIZE(ssm4567_routes), + }, }; static const struct regmap_config ssm4567_regmap_config = { diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index a9844b2ac829..0790ae8530d9 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -991,12 +991,14 @@ static const struct snd_soc_codec_driver sta32x_codec = { .remove = sta32x_remove, .set_bias_level = sta32x_set_bias_level, .suspend_bias_off = true, - .controls = sta32x_snd_controls, - .num_controls = ARRAY_SIZE(sta32x_snd_controls), - .dapm_widgets = sta32x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(sta32x_dapm_widgets), - .dapm_routes = sta32x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(sta32x_dapm_routes), + .component_driver = { + .controls = sta32x_snd_controls, + .num_controls = ARRAY_SIZE(sta32x_snd_controls), + .dapm_widgets = sta32x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sta32x_dapm_widgets), + .dapm_routes = sta32x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sta32x_dapm_routes), + }, }; static const struct regmap_config sta32x_regmap = { diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index 33a4612f0a07..9644c20f44e3 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -1057,12 +1057,14 @@ static const struct snd_soc_codec_driver sta350_codec = { .remove = sta350_remove, .set_bias_level = sta350_set_bias_level, .suspend_bias_off = true, - .controls = sta350_snd_controls, - .num_controls = ARRAY_SIZE(sta350_snd_controls), - .dapm_widgets = sta350_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(sta350_dapm_widgets), - .dapm_routes = sta350_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(sta350_dapm_routes), + .component_driver = { + .controls = sta350_snd_controls, + .num_controls = ARRAY_SIZE(sta350_snd_controls), + .dapm_widgets = sta350_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sta350_dapm_widgets), + .dapm_routes = sta350_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sta350_dapm_routes), + }, }; static const struct regmap_config sta350_regmap = { diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 2cdaca943a8c..d4b384e4b266 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -317,8 +317,10 @@ static const struct snd_soc_codec_driver sta529_codec_driver = { .set_bias_level = sta529_set_bias_level, .suspend_bias_off = true, - .controls = sta529_snd_controls, - .num_controls = ARRAY_SIZE(sta529_snd_controls), + .component_driver = { + .controls = sta529_snd_controls, + .num_controls = ARRAY_SIZE(sta529_snd_controls), + }, }; static const struct regmap_config sta529_regmap = { diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 0945c51df003..27f30d352867 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -85,10 +85,10 @@ static SOC_ENUM_SINGLE_DECL(stac9766_boost2_enum, static SOC_ENUM_SINGLE_DECL(stac9766_stereo_mic_enum, AC97_STAC_STEREO_MIC, 2, stac9766_stereo_mic); -static const DECLARE_TLV_DB_LINEAR(master_tlv, -4600, 0); -static const DECLARE_TLV_DB_LINEAR(record_tlv, 0, 2250); -static const DECLARE_TLV_DB_LINEAR(beep_tlv, -4500, 0); -static const DECLARE_TLV_DB_LINEAR(mix_tlv, -3450, 1200); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(master_tlv, -4650, 150, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(record_tlv, 0, 150, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(beep_tlv, -4500, 300, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(mix_tlv, -3450, 150, 0); static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = { SOC_DOUBLE_TLV("Speaker Volume", AC97_MASTER, 8, 0, 31, 1, master_tlv), @@ -320,8 +320,10 @@ static int stac9766_codec_remove(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_stac9766 = { - .controls = stac9766_snd_ac97_controls, - .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls), + .component_driver = { + .controls = stac9766_snd_ac97_controls, + .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls), + }, .write = stac9766_ac97_write, .read = stac9766_ac97_read, .set_bias_level = stac9766_set_bias_level, diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 160d61a66204..7b31ee9b82bc 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -591,11 +591,11 @@ static int sti_sas_driver_probe(struct platform_device *pdev) sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops; /* Set dapms*/ - sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets; - sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets; + sti_sas_driver.component_driver.dapm_widgets = drvdata->dev_data->dapm_widgets; + sti_sas_driver.component_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets; - sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes; - sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes; + sti_sas_driver.component_driver.dapm_routes = drvdata->dev_data->dapm_routes; + sti_sas_driver.component_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes; /* Store context */ dev_set_drvdata(&pdev->dev, drvdata); diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index cc1d3981fa4b..baf455e8c2f7 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -667,12 +667,14 @@ static struct snd_soc_codec_driver soc_codec_dev_tas2552 = { .resume = tas2552_resume, .ignore_pmdown_time = true, - .controls = tas2552_snd_controls, - .num_controls = ARRAY_SIZE(tas2552_snd_controls), - .dapm_widgets = tas2552_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tas2552_dapm_widgets), - .dapm_routes = tas2552_audio_map, - .num_dapm_routes = ARRAY_SIZE(tas2552_audio_map), + .component_driver = { + .controls = tas2552_snd_controls, + .num_controls = ARRAY_SIZE(tas2552_snd_controls), + .dapm_widgets = tas2552_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas2552_dapm_widgets), + .dapm_routes = tas2552_audio_map, + .num_dapm_routes = ARRAY_SIZE(tas2552_audio_map), + }, }; static const struct regmap_config tas2552_regmap_config = { diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index d49d25d51957..b7de857abb16 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -387,7 +387,7 @@ static int tas5086_hw_params(struct snd_pcm_substream *substream, val = index_in_array(tas5086_ratios, ARRAY_SIZE(tas5086_ratios), priv->mclk / priv->rate); if (val < 0) { - dev_err(codec->dev, "Inavlid MCLK / Fs ratio\n"); + dev_err(codec->dev, "Invalid MCLK / Fs ratio\n"); return -EINVAL; } @@ -890,12 +890,14 @@ static struct snd_soc_codec_driver soc_codec_dev_tas5086 = { .remove = tas5086_remove, .suspend = tas5086_soc_suspend, .resume = tas5086_soc_resume, - .controls = tas5086_controls, - .num_controls = ARRAY_SIZE(tas5086_controls), - .dapm_widgets = tas5086_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tas5086_dapm_widgets), - .dapm_routes = tas5086_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(tas5086_dapm_routes), + .component_driver = { + .controls = tas5086_controls, + .num_controls = ARRAY_SIZE(tas5086_controls), + .dapm_widgets = tas5086_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas5086_dapm_widgets), + .dapm_routes = tas5086_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(tas5086_dapm_routes), + }, }; static const struct i2c_device_id tas5086_i2c_id[] = { diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index d8baca3f8413..df5e5cb33baa 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c @@ -658,10 +658,12 @@ static const struct snd_soc_codec_driver tas571x_codec = { .set_bias_level = tas571x_set_bias_level, .idle_bias_off = true, - .dapm_widgets = tas571x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tas571x_dapm_widgets), - .dapm_routes = tas571x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(tas571x_dapm_routes), + .component_driver = { + .dapm_widgets = tas571x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas571x_dapm_widgets), + .dapm_routes = tas571x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(tas571x_dapm_routes), + }, }; static struct snd_soc_dai_driver tas571x_dai = { @@ -754,8 +756,8 @@ static int tas571x_i2c_probe(struct i2c_client *client, memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver)); - priv->codec_driver.controls = priv->chip->controls; - priv->codec_driver.num_controls = priv->chip->num_controls; + priv->codec_driver.component_driver.controls = priv->chip->controls; + priv->codec_driver.component_driver.num_controls = priv->chip->num_controls; if (priv->chip->vol_reg_size == 2) { /* diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index f54fb46b77c2..c65b917598d2 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -489,12 +489,14 @@ static struct snd_soc_codec_driver soc_codec_dev_tas5720 = { .suspend = tas5720_suspend, .resume = tas5720_resume, - .controls = tas5720_snd_controls, - .num_controls = ARRAY_SIZE(tas5720_snd_controls), - .dapm_widgets = tas5720_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets), - .dapm_routes = tas5720_audio_map, - .num_dapm_routes = ARRAY_SIZE(tas5720_audio_map), + .component_driver = { + .controls = tas5720_snd_controls, + .num_controls = ARRAY_SIZE(tas5720_snd_controls), + .dapm_widgets = tas5720_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets), + .dapm_routes = tas5720_audio_map, + .num_dapm_routes = ARRAY_SIZE(tas5720_audio_map), + }, }; /* PCM rates supported by the TAS5720 driver */ diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c index cb5310d89c0f..95e0a7abeb7a 100644 --- a/sound/soc/codecs/tfa9879.c +++ b/sound/soc/codecs/tfa9879.c @@ -231,13 +231,14 @@ static const struct snd_soc_dapm_route tfa9879_dapm_routes[] = { }; static const struct snd_soc_codec_driver tfa9879_codec = { - .controls = tfa9879_controls, - .num_controls = ARRAY_SIZE(tfa9879_controls), - - .dapm_widgets = tfa9879_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tfa9879_dapm_widgets), - .dapm_routes = tfa9879_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(tfa9879_dapm_routes), + .component_driver = { + .controls = tfa9879_controls, + .num_controls = ARRAY_SIZE(tfa9879_controls), + .dapm_widgets = tfa9879_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tfa9879_dapm_widgets), + .dapm_routes = tfa9879_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(tfa9879_dapm_routes), + }, }; static const struct regmap_config tfa9879_regmap = { diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index cd8c02b6e4de..410cae0f2060 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -583,12 +583,14 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { .set_bias_level = tlv320aic23_set_bias_level, .suspend_bias_off = true, - .controls = tlv320aic23_snd_controls, - .num_controls = ARRAY_SIZE(tlv320aic23_snd_controls), - .dapm_widgets = tlv320aic23_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets), - .dapm_routes = tlv320aic23_intercon, - .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon), + .component_driver = { + .controls = tlv320aic23_snd_controls, + .num_controls = ARRAY_SIZE(tlv320aic23_snd_controls), + .dapm_widgets = tlv320aic23_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets), + .dapm_routes = tlv320aic23_intercon, + .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon), + }, }; int tlv320aic23_probe(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 2c904d7150ad..14aa96d41719 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -321,12 +321,14 @@ static int aic26_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver aic26_soc_codec_dev = { .probe = aic26_probe, - .controls = aic26_snd_controls, - .num_controls = ARRAY_SIZE(aic26_snd_controls), - .dapm_widgets = tlv320aic26_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tlv320aic26_dapm_widgets), - .dapm_routes = tlv320aic26_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(tlv320aic26_dapm_routes), + .component_driver = { + .controls = aic26_snd_controls, + .num_controls = ARRAY_SIZE(aic26_snd_controls), + .dapm_widgets = tlv320aic26_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tlv320aic26_dapm_widgets), + .dapm_routes = tlv320aic26_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(tlv320aic26_dapm_routes), + }, }; static const struct regmap_config aic26_regmap = { diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 3c5e1df01c19..be1a64bfd320 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -273,10 +273,20 @@ static const DECLARE_TLV_DB_SCALE(sp_vol_tlv, -6350, 50, 0); /* * controls to be exported to the user space */ -static const struct snd_kcontrol_new aic31xx_snd_controls[] = { +static const struct snd_kcontrol_new common31xx_snd_controls[] = { SOC_DOUBLE_R_S_TLV("DAC Playback Volume", AIC31XX_LDACVOL, AIC31XX_RDACVOL, 0, -127, 48, 7, 0, dac_vol_tlv), + SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN, + AIC31XX_HPRGAIN, 2, 1, 0), + SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN, + AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv), + + SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL, + AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv), +}; + +static const struct snd_kcontrol_new aic31xx_snd_controls[] = { SOC_SINGLE_TLV("ADC Fine Capture Volume", AIC31XX_ADCFGA, 4, 4, 1, adc_fgain_tlv), @@ -286,14 +296,6 @@ static const struct snd_kcontrol_new aic31xx_snd_controls[] = { SOC_SINGLE_TLV("Mic PGA Capture Volume", AIC31XX_MICPGA, 0, 119, 0, mic_pga_tlv), - - SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN, - AIC31XX_HPRGAIN, 2, 1, 0), - SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN, - AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv), - - SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL, - AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv), }; static const struct snd_kcontrol_new aic311x_snd_controls[] = { @@ -397,17 +399,28 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w, return 0; } -static const struct snd_kcontrol_new left_output_switches[] = { +static const struct snd_kcontrol_new aic31xx_left_output_switches[] = { SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0), SOC_DAPM_SINGLE("From MIC1LP", AIC31XX_DACMIXERROUTE, 5, 1, 0), SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 4, 1, 0), }; -static const struct snd_kcontrol_new right_output_switches[] = { +static const struct snd_kcontrol_new aic31xx_right_output_switches[] = { SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0), SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 1, 1, 0), }; +static const struct snd_kcontrol_new dac31xx_left_output_switches[] = { + SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0), + SOC_DAPM_SINGLE("From AIN1", AIC31XX_DACMIXERROUTE, 5, 1, 0), + SOC_DAPM_SINGLE("From AIN2", AIC31XX_DACMIXERROUTE, 4, 1, 0), +}; + +static const struct snd_kcontrol_new dac31xx_right_output_switches[] = { + SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0), + SOC_DAPM_SINGLE("From AIN2", AIC31XX_DACMIXERROUTE, 1, 1, 0), +}; + static const struct snd_kcontrol_new p_term_mic1lp = SOC_DAPM_ENUM("MIC1LP P-Terminal", mic1lp_p_enum); @@ -457,7 +470,7 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, return 0; } -static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = { +static const struct snd_soc_dapm_widget common31xx_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_MUX("DAC Left Input", @@ -473,14 +486,7 @@ static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = { AIC31XX_DACSETUP, 6, 0, aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - /* Output Mixers */ - SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0, - left_output_switches, - ARRAY_SIZE(left_output_switches)), - SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0, - right_output_switches, - ARRAY_SIZE(right_output_switches)), - + /* HP */ SND_SOC_DAPM_SWITCH("HP Left", SND_SOC_NOPM, 0, 0, &aic31xx_dapm_hpl_switch), SND_SOC_DAPM_SWITCH("HP Right", SND_SOC_NOPM, 0, 0, @@ -494,10 +500,34 @@ static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = { NULL, 0, aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), - /* ADC */ - SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0, - aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_POST_PMD), + /* Mic Bias */ + SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, mic_bias_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + /* Outputs */ + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), +}; + +static const struct snd_soc_dapm_widget dac31xx_dapm_widgets[] = { + /* Inputs */ + SND_SOC_DAPM_INPUT("AIN1"), + SND_SOC_DAPM_INPUT("AIN2"), + + /* Output Mixers */ + SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0, + dac31xx_left_output_switches, + ARRAY_SIZE(dac31xx_left_output_switches)), + SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0, + dac31xx_right_output_switches, + ARRAY_SIZE(dac31xx_right_output_switches)), +}; + +static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = { + /* Inputs */ + SND_SOC_DAPM_INPUT("MIC1LP"), + SND_SOC_DAPM_INPUT("MIC1RP"), + SND_SOC_DAPM_INPUT("MIC1LM"), /* Input Selection to MIC_PGA */ SND_SOC_DAPM_MUX("MIC1LP P-Terminal", SND_SOC_NOPM, 0, 0, @@ -507,24 +537,25 @@ static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = { SND_SOC_DAPM_MUX("MIC1LM P-Terminal", SND_SOC_NOPM, 0, 0, &p_term_mic1lm), + /* ADC */ + SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0, + aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("MIC1LM M-Terminal", SND_SOC_NOPM, 0, 0, &m_term_mic1lm), + /* Enabling & Disabling MIC Gain Ctl */ SND_SOC_DAPM_PGA("MIC_GAIN_CTL", AIC31XX_MICPGA, 7, 1, NULL, 0), - /* Mic Bias */ - SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, mic_bias_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - - /* Outputs */ - SND_SOC_DAPM_OUTPUT("HPL"), - SND_SOC_DAPM_OUTPUT("HPR"), - - /* Inputs */ - SND_SOC_DAPM_INPUT("MIC1LP"), - SND_SOC_DAPM_INPUT("MIC1RP"), - SND_SOC_DAPM_INPUT("MIC1LM"), + /* Output Mixers */ + SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0, + aic31xx_left_output_switches, + ARRAY_SIZE(aic31xx_left_output_switches)), + SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0, + aic31xx_right_output_switches, + ARRAY_SIZE(aic31xx_right_output_switches)), }; static const struct snd_soc_dapm_widget aic311x_dapm_widgets[] = { @@ -554,7 +585,7 @@ static const struct snd_soc_dapm_widget aic310x_dapm_widgets[] = { }; static const struct snd_soc_dapm_route -aic31xx_audio_map[] = { +common31xx_audio_map[] = { /* DAC Input Routing */ {"DAC Left Input", "Left Data", "DAC IN"}, {"DAC Left Input", "Right Data", "DAC IN"}, @@ -565,6 +596,31 @@ aic31xx_audio_map[] = { {"DAC Left", NULL, "DAC Left Input"}, {"DAC Right", NULL, "DAC Right Input"}, + /* HPL path */ + {"HP Left", "Switch", "Output Left"}, + {"HPL Driver", NULL, "HP Left"}, + {"HPL", NULL, "HPL Driver"}, + + /* HPR path */ + {"HP Right", "Switch", "Output Right"}, + {"HPR Driver", NULL, "HP Right"}, + {"HPR", NULL, "HPR Driver"}, +}; + +static const struct snd_soc_dapm_route +dac31xx_audio_map[] = { + /* Left Output */ + {"Output Left", "From Left DAC", "DAC Left"}, + {"Output Left", "From AIN1", "AIN1"}, + {"Output Left", "From AIN2", "AIN2"}, + + /* Right Output */ + {"Output Right", "From Right DAC", "DAC Right"}, + {"Output Right", "From AIN2", "AIN2"}, +}; + +static const struct snd_soc_dapm_route +aic31xx_audio_map[] = { /* Mic input */ {"MIC1LP P-Terminal", "FFR 10 Ohm", "MIC1LP"}, {"MIC1LP P-Terminal", "FFR 20 Ohm", "MIC1LP"}, @@ -595,16 +651,6 @@ aic31xx_audio_map[] = { /* Right Output */ {"Output Right", "From Right DAC", "DAC Right"}, {"Output Right", "From MIC1RP", "MIC1RP"}, - - /* HPL path */ - {"HP Left", "Switch", "Output Left"}, - {"HPL Driver", NULL, "HP Left"}, - {"HPL", NULL, "HPL Driver"}, - - /* HPR path */ - {"HP Right", "Switch", "Output Right"}, - {"HPR Driver", NULL, "HP Right"}, - {"HPR", NULL, "HPR Driver"}, }; static const struct snd_soc_dapm_route @@ -633,6 +679,13 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec) int ret = 0; struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); + if (!(aic31xx->pdata.codec_type & DAC31XX_BIT)) + ret = snd_soc_add_codec_controls( + codec, aic31xx_snd_controls, + ARRAY_SIZE(aic31xx_snd_controls)); + if (ret) + return ret; + if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) ret = snd_soc_add_codec_controls( codec, aic311x_snd_controls, @@ -651,6 +704,30 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec) struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); int ret = 0; + if (aic31xx->pdata.codec_type & DAC31XX_BIT) { + ret = snd_soc_dapm_new_controls( + dapm, dac31xx_dapm_widgets, + ARRAY_SIZE(dac31xx_dapm_widgets)); + if (ret) + return ret; + + ret = snd_soc_dapm_add_routes(dapm, dac31xx_audio_map, + ARRAY_SIZE(dac31xx_audio_map)); + if (ret) + return ret; + } else { + ret = snd_soc_dapm_new_controls( + dapm, aic31xx_dapm_widgets, + ARRAY_SIZE(aic31xx_dapm_widgets)); + if (ret) + return ret; + + ret = snd_soc_dapm_add_routes(dapm, aic31xx_audio_map, + ARRAY_SIZE(aic31xx_audio_map)); + if (ret) + return ret; + } + if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) { ret = snd_soc_dapm_new_controls( dapm, aic311x_dapm_widgets, @@ -1114,12 +1191,14 @@ static struct snd_soc_codec_driver soc_codec_driver_aic31xx = { .set_bias_level = aic31xx_set_bias_level, .suspend_bias_off = true, - .controls = aic31xx_snd_controls, - .num_controls = ARRAY_SIZE(aic31xx_snd_controls), - .dapm_widgets = aic31xx_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(aic31xx_dapm_widgets), - .dapm_routes = aic31xx_audio_map, - .num_dapm_routes = ARRAY_SIZE(aic31xx_audio_map), + .component_driver = { + .controls = common31xx_snd_controls, + .num_controls = ARRAY_SIZE(common31xx_snd_controls), + .dapm_widgets = common31xx_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(common31xx_dapm_widgets), + .dapm_routes = common31xx_audio_map, + .num_dapm_routes = ARRAY_SIZE(common31xx_audio_map), + }, }; static const struct snd_soc_dai_ops aic31xx_dai_ops = { @@ -1129,19 +1208,34 @@ static const struct snd_soc_dai_ops aic31xx_dai_ops = { .digital_mute = aic31xx_dac_mute, }; +static struct snd_soc_dai_driver dac31xx_dai_driver[] = { + { + .name = "tlv32dac31xx-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = AIC31XX_RATES, + .formats = AIC31XX_FORMATS, + }, + .ops = &aic31xx_dai_ops, + .symmetric_rates = 1, + } +}; + static struct snd_soc_dai_driver aic31xx_dai_driver[] = { { .name = "tlv320aic31xx-hifi", .playback = { .stream_name = "Playback", - .channels_min = 1, + .channels_min = 2, .channels_max = 2, .rates = AIC31XX_RATES, .formats = AIC31XX_FORMATS, }, .capture = { .stream_name = "Capture", - .channels_min = 1, + .channels_min = 2, .channels_max = 2, .rates = AIC31XX_RATES, .formats = AIC31XX_FORMATS, @@ -1259,9 +1353,16 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, if (ret) return ret; - return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx, - aic31xx_dai_driver, - ARRAY_SIZE(aic31xx_dai_driver)); + if (aic31xx->pdata.codec_type & DAC31XX_BIT) + return snd_soc_register_codec(&i2c->dev, + &soc_codec_driver_aic31xx, + dac31xx_dai_driver, + ARRAY_SIZE(dac31xx_dai_driver)); + else + return snd_soc_register_codec(&i2c->dev, + &soc_codec_driver_aic31xx, + aic31xx_dai_driver, + ARRAY_SIZE(aic31xx_dai_driver)); } static int aic31xx_i2c_remove(struct i2c_client *i2c) @@ -1277,6 +1378,7 @@ static const struct i2c_device_id aic31xx_i2c_id[] = { { "tlv320aic3110", AIC3110 }, { "tlv320aic3120", AIC3120 }, { "tlv320aic3111", AIC3111 }, + { "tlv320dac3100", DAC3100 }, { } }; MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index ac9b146526eb..5acd5b69fb83 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -24,12 +24,14 @@ #define AIC31XX_STEREO_CLASS_D_BIT 0x1 #define AIC31XX_MINIDSP_BIT 0x2 +#define DAC31XX_BIT 0x4 enum aic31xx_type { AIC3100 = 0, AIC3110 = AIC31XX_STEREO_CLASS_D_BIT, AIC3120 = AIC31XX_MINIDSP_BIT, AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT), + DAC3100 = DAC31XX_BIT, }; struct aic31xx_pdata { diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 85d4978d0384..28fdfc5ec544 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -797,12 +797,14 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { .set_bias_level = aic32x4_set_bias_level, .suspend_bias_off = true, - .controls = aic32x4_snd_controls, - .num_controls = ARRAY_SIZE(aic32x4_snd_controls), - .dapm_widgets = aic32x4_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets), - .dapm_routes = aic32x4_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes), + .component_driver = { + .controls = aic32x4_snd_controls, + .num_controls = ARRAY_SIZE(aic32x4_snd_controls), + .dapm_widgets = aic32x4_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets), + .dapm_routes = aic32x4_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes), + }, }; static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index a564759845f9..5a8d96ec058c 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1670,12 +1670,14 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = { .idle_bias_off = true, .probe = aic3x_probe, .remove = aic3x_remove, - .controls = aic3x_snd_controls, - .num_controls = ARRAY_SIZE(aic3x_snd_controls), - .dapm_widgets = aic3x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets), - .dapm_routes = intercon, - .num_dapm_routes = ARRAY_SIZE(intercon), + .component_driver = { + .controls = aic3x_snd_controls, + .num_controls = ARRAY_SIZE(aic3x_snd_controls), + .dapm_widgets = aic3x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets), + .dapm_routes = intercon, + .num_dapm_routes = ARRAY_SIZE(intercon), + }, }; /* diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index f7a6ce7e5fb1..7bcf01efdf9a 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -90,7 +90,6 @@ static const char *dac33_supply_names[DAC33_NUM_SUPPLIES] = { struct tlv320dac33_priv { struct mutex mutex; - struct workqueue_struct *dac33_wq; struct work_struct work; struct snd_soc_codec *codec; struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES]; @@ -771,7 +770,7 @@ static irqreturn_t dac33_interrupt_handler(int irq, void *dev) /* Do not schedule the workqueue in Mode7 */ if (dac33->fifo_mode != DAC33_FIFO_MODE7) - queue_work(dac33->dac33_wq, &dac33->work); + schedule_work(&dac33->work); return IRQ_HANDLED; } @@ -1127,7 +1126,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (dac33->fifo_mode) { dac33->state = DAC33_PREFILL; - queue_work(dac33->dac33_wq, &dac33->work); + schedule_work(&dac33->work); } break; case SNDRV_PCM_TRIGGER_STOP: @@ -1135,7 +1134,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (dac33->fifo_mode) { dac33->state = DAC33_FLUSH; - queue_work(dac33->dac33_wq, &dac33->work); + schedule_work(&dac33->work); } break; default: @@ -1410,14 +1409,6 @@ static int dac33_soc_probe(struct snd_soc_codec *codec) dac33->irq = -1; } if (dac33->irq != -1) { - /* Setup work queue */ - dac33->dac33_wq = - create_singlethread_workqueue("tlv320dac33"); - if (dac33->dac33_wq == NULL) { - free_irq(dac33->irq, codec); - return -ENOMEM; - } - INIT_WORK(&dac33->work, dac33_work); } } @@ -1437,7 +1428,7 @@ static int dac33_soc_remove(struct snd_soc_codec *codec) if (dac33->irq >= 0) { free_irq(dac33->irq, dac33->codec); - destroy_workqueue(dac33->dac33_wq); + flush_work(&dac33->work); } return 0; } @@ -1453,12 +1444,14 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = { .probe = dac33_soc_probe, .remove = dac33_soc_remove, - .controls = dac33_snd_controls, - .num_controls = ARRAY_SIZE(dac33_snd_controls), - .dapm_widgets = dac33_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(dac33_dapm_widgets), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map), + .component_driver = { + .controls = dac33_snd_controls, + .num_controls = ARRAY_SIZE(dac33_snd_controls), + .dapm_widgets = dac33_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(dac33_dapm_widgets), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), + }, }; #define DAC33_RATES (SNDRV_PCM_RATE_44100 | \ diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index a5a4e9f75c57..a2104d68169d 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -2199,12 +2199,14 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = { .set_bias_level = twl4030_set_bias_level, .idle_bias_off = true, - .controls = twl4030_snd_controls, - .num_controls = ARRAY_SIZE(twl4030_snd_controls), - .dapm_widgets = twl4030_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(twl4030_dapm_widgets), - .dapm_routes = intercon, - .num_dapm_routes = ARRAY_SIZE(intercon), + .component_driver = { + .controls = twl4030_snd_controls, + .num_controls = ARRAY_SIZE(twl4030_snd_controls), + .dapm_widgets = twl4030_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(twl4030_dapm_widgets), + .dapm_routes = intercon, + .num_dapm_routes = ARRAY_SIZE(intercon), + }, }; static int twl4030_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 1f7081043566..748036e851ea 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -1156,12 +1156,14 @@ static struct snd_soc_codec_driver soc_codec_dev_twl6040 = { .suspend_bias_off = true, .ignore_pmdown_time = true, - .controls = twl6040_snd_controls, - .num_controls = ARRAY_SIZE(twl6040_snd_controls), - .dapm_widgets = twl6040_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets), - .dapm_routes = intercon, - .num_dapm_routes = ARRAY_SIZE(intercon), + .component_driver = { + .controls = twl6040_snd_controls, + .num_controls = ARRAY_SIZE(twl6040_snd_controls), + .dapm_widgets = twl6040_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets), + .dapm_routes = intercon, + .num_dapm_routes = ARRAY_SIZE(intercon), + }, }; static int twl6040_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index e4c694c758b8..5fdee874406d 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -523,10 +523,12 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = { .set_bias_level = uda134x_set_bias_level, .suspend_bias_off = true, - .dapm_widgets = uda134x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets), - .dapm_routes = uda134x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes), + .component_driver = { + .dapm_widgets = uda134x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets), + .dapm_routes = uda134x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes), + }, }; static const struct regmap_config uda134x_regmap_config = { @@ -544,6 +546,7 @@ static int uda134x_codec_probe(struct platform_device *pdev) { struct uda134x_platform_data *pd = pdev->dev.platform_data; struct uda134x_priv *uda134x; + int ret; if (!pd) { dev_err(&pdev->dev, "Missing L3 bitbang function\n"); @@ -557,6 +560,12 @@ static int uda134x_codec_probe(struct platform_device *pdev) uda134x->pd = pd; platform_set_drvdata(pdev, uda134x); + if (pd->l3.use_gpios) { + ret = l3_set_gpio_ops(&pdev->dev, &uda134x->pd->l3); + if (ret < 0) + return ret; + } + uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd, &uda134x_regmap_config); if (IS_ERR(uda134x->regmap)) diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 35f0469ebb16..533e3bb444e4 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -765,12 +765,14 @@ static struct snd_soc_codec_driver soc_codec_dev_uda1380 = { .reg_cache_default = uda1380_reg, .reg_cache_step = 1, - .controls = uda1380_snd_controls, - .num_controls = ARRAY_SIZE(uda1380_snd_controls), - .dapm_widgets = uda1380_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets), - .dapm_routes = uda1380_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes), + .component_driver = { + .controls = uda1380_snd_controls, + .num_controls = ARRAY_SIZE(uda1380_snd_controls), + .dapm_widgets = uda1380_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets), + .dapm_routes = uda1380_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes), + }, }; #if IS_ENABLED(CONFIG_I2C) diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index 1b79778098d2..fcffb6e707d9 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -484,12 +484,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wl1273 = { .probe = wl1273_probe, .remove = wl1273_remove, - .controls = wl1273_controls, - .num_controls = ARRAY_SIZE(wl1273_controls), - .dapm_widgets = wl1273_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets), - .dapm_routes = wl1273_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wl1273_dapm_routes), + .component_driver = { + .controls = wl1273_controls, + .num_controls = ARRAY_SIZE(wl1273_controls), + .dapm_widgets = wl1273_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets), + .dapm_routes = wl1273_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wl1273_dapm_routes), + }, }; static int wl1273_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index e3c34bdc2772..0eb5dcf4c29d 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -789,16 +789,18 @@ static int wm0010_set_sysclk(struct snd_soc_codec *codec, int source, static int wm0010_probe(struct snd_soc_codec *codec); -static struct snd_soc_codec_driver soc_codec_dev_wm0010 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm0010 = { .probe = wm0010_probe, .set_bias_level = wm0010_set_bias_level, .set_sysclk = wm0010_set_sysclk, .idle_bias_off = true, - .dapm_widgets = wm0010_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm0010_dapm_widgets), - .dapm_routes = wm0010_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm0010_dapm_routes), + .component_driver = { + .dapm_widgets = wm0010_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm0010_dapm_widgets), + .dapm_routes = wm0010_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm0010_dapm_routes), + }, }; #define WM0010_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c index ec45c5b220b1..cf5f0580df6a 100644 --- a/sound/soc/codecs/wm1250-ev1.c +++ b/sound/soc/codecs/wm1250-ev1.c @@ -141,12 +141,13 @@ static struct snd_soc_dai_driver wm1250_ev1_dai = { .ops = &wm1250_ev1_ops, }; -static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = { - .dapm_widgets = wm1250_ev1_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm1250_ev1_dapm_widgets), - .dapm_routes = wm1250_ev1_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm1250_ev1_dapm_routes), - +static const struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = { + .component_driver = { + .dapm_widgets = wm1250_ev1_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm1250_ev1_dapm_widgets), + .dapm_routes = wm1250_ev1_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm1250_ev1_dapm_routes), + }, .set_bias_level = wm1250_ev1_set_bias_level, .idle_bias_off = true, }; diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index a67ea10f41a1..23cde3a0dc11 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -581,7 +581,7 @@ static int wm2000_anc_transition(struct wm2000_priv *wm2000, if (anc_transitions[i].dest == ANC_OFF) clk_disable_unprepare(wm2000->mclk); - return ret; + return 0; } static int wm2000_anc_set_mode(struct wm2000_priv *wm2000) @@ -799,18 +799,20 @@ static int wm2000_remove(struct snd_soc_codec *codec) return wm2000_anc_transition(wm2000, ANC_OFF); } -static struct snd_soc_codec_driver soc_codec_dev_wm2000 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm2000 = { .probe = wm2000_probe, .remove = wm2000_remove, .suspend = wm2000_suspend, .resume = wm2000_resume, - .dapm_widgets = wm2000_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm2000_dapm_widgets), - .dapm_routes = wm2000_audio_map, - .num_dapm_routes = ARRAY_SIZE(wm2000_audio_map), - .controls = wm2000_controls, - .num_controls = ARRAY_SIZE(wm2000_controls), + .component_driver = { + .controls = wm2000_controls, + .num_controls = ARRAY_SIZE(wm2000_controls), + .dapm_widgets = wm2000_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm2000_dapm_widgets), + .dapm_routes = wm2000_audio_map, + .num_dapm_routes = ARRAY_SIZE(wm2000_audio_map), + }, }; static int wm2000_i2c_probe(struct i2c_client *i2c, diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index fd1439ecb50a..606bf88abfc4 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2103,7 +2103,7 @@ static struct snd_soc_dai_driver wm2200_dai = { .ops = &wm2200_dai_ops, }; -static struct snd_soc_codec_driver soc_codec_wm2200 = { +static const struct snd_soc_codec_driver soc_codec_wm2200 = { .probe = wm2200_probe, .idle_bias_off = true, @@ -2111,12 +2111,14 @@ static struct snd_soc_codec_driver soc_codec_wm2200 = { .set_sysclk = wm2200_set_sysclk, .set_pll = wm2200_set_fll, - .controls = wm2200_snd_controls, - .num_controls = ARRAY_SIZE(wm2200_snd_controls), - .dapm_widgets = wm2200_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm2200_dapm_widgets), - .dapm_routes = wm2200_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm2200_dapm_routes), + .component_driver = { + .controls = wm2200_snd_controls, + .num_controls = ARRAY_SIZE(wm2200_snd_controls), + .dapm_widgets = wm2200_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm2200_dapm_widgets), + .dapm_routes = wm2200_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm2200_dapm_routes), + }, }; static irqreturn_t wm2200_irq(int irq, void *data) diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 512a9d25fe6f..560575000cc5 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2285,7 +2285,7 @@ static int wm5100_gpio_direction_in(struct gpio_chip *chip, unsigned offset) (1 << WM5100_GP1_DIR_SHIFT)); } -static struct gpio_chip wm5100_template_chip = { +static const struct gpio_chip wm5100_template_chip = { .label = "wm5100", .owner = THIS_MODULE, .direction_output = wm5100_gpio_direction_out, @@ -2381,7 +2381,7 @@ static int wm5100_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm5100 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm5100 = { .probe = wm5100_probe, .remove = wm5100_remove, @@ -2390,12 +2390,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5100 = { .idle_bias_off = 1, .seq_notifier = wm5100_seq_notifier, - .controls = wm5100_snd_controls, - .num_controls = ARRAY_SIZE(wm5100_snd_controls), - .dapm_widgets = wm5100_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm5100_dapm_widgets), - .dapm_routes = wm5100_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm5100_dapm_routes), + .component_driver = { + .controls = wm5100_snd_controls, + .num_controls = ARRAY_SIZE(wm5100_snd_controls), + .dapm_widgets = wm5100_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm5100_dapm_widgets), + .dapm_routes = wm5100_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm5100_dapm_routes), + }, }; static const struct regmap_config wm5100_regmap = { diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 846deed6af41..93876c6d48ee 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1521,6 +1521,16 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { { "IN3L", NULL, "SYSCLK" }, { "IN3R", NULL, "SYSCLK" }, + { "ASRC1L", NULL, "SYSCLK" }, + { "ASRC1R", NULL, "SYSCLK" }, + { "ASRC2L", NULL, "SYSCLK" }, + { "ASRC2R", NULL, "SYSCLK" }, + + { "ASRC1L", NULL, "ASYNCCLK" }, + { "ASRC1R", NULL, "ASYNCCLK" }, + { "ASRC2L", NULL, "ASYNCCLK" }, + { "ASRC2R", NULL, "ASYNCCLK" }, + { "MICBIAS1", NULL, "MICVDD" }, { "MICBIAS2", NULL, "MICVDD" }, { "MICBIAS3", NULL, "MICVDD" }, @@ -1600,7 +1610,6 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { { "Slim3 Capture", NULL, "SYSCLK" }, { "Audio Trace DSP", NULL, "DSP1" }, - { "Audio Trace DSP", NULL, "SYSCLK" }, { "IN1L PGA", NULL, "IN1L" }, { "IN1R PGA", NULL, "IN1R" }, @@ -1990,7 +1999,7 @@ static struct regmap *wm5102_get_regmap(struct device *dev) return priv->core.arizona->regmap; } -static struct snd_soc_codec_driver soc_codec_dev_wm5102 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm5102 = { .probe = wm5102_codec_probe, .remove = wm5102_codec_remove, .get_regmap = wm5102_get_regmap, @@ -2000,12 +2009,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5102 = { .set_sysclk = arizona_set_sysclk, .set_pll = wm5102_set_fll, - .controls = wm5102_snd_controls, - .num_controls = ARRAY_SIZE(wm5102_snd_controls), - .dapm_widgets = wm5102_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm5102_dapm_widgets), - .dapm_routes = wm5102_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes), + .component_driver = { + .controls = wm5102_snd_controls, + .num_controls = ARRAY_SIZE(wm5102_snd_controls), + .dapm_widgets = wm5102_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm5102_dapm_widgets), + .dapm_routes = wm5102_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes), + }, }; static struct snd_compr_ops wm5102_compr_ops = { diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 156547026a40..06bae3b23fce 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -1745,6 +1745,16 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { { "IN4L", NULL, "SYSCLK" }, { "IN4R", NULL, "SYSCLK" }, + { "ASRC1L", NULL, "SYSCLK" }, + { "ASRC1R", NULL, "SYSCLK" }, + { "ASRC2L", NULL, "SYSCLK" }, + { "ASRC2R", NULL, "SYSCLK" }, + + { "ASRC1L", NULL, "ASYNCCLK" }, + { "ASRC1R", NULL, "ASYNCCLK" }, + { "ASRC2L", NULL, "ASYNCCLK" }, + { "ASRC2R", NULL, "ASYNCCLK" }, + { "MICBIAS1", NULL, "MICVDD" }, { "MICBIAS2", NULL, "MICVDD" }, { "MICBIAS3", NULL, "MICVDD" }, @@ -1832,10 +1842,8 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { { "Slim3 Capture", NULL, "SYSCLK" }, { "Voice Control DSP", NULL, "DSP3" }, - { "Voice Control DSP", NULL, "SYSCLK" }, { "Audio Trace DSP", NULL, "DSP1" }, - { "Audio Trace DSP", NULL, "SYSCLK" }, { "IN1L PGA", NULL, "IN1L" }, { "IN1R PGA", NULL, "IN1R" }, @@ -2347,7 +2355,7 @@ static struct regmap *wm5110_get_regmap(struct device *dev) return priv->core.arizona->regmap; } -static struct snd_soc_codec_driver soc_codec_dev_wm5110 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm5110 = { .probe = wm5110_codec_probe, .remove = wm5110_codec_remove, .get_regmap = wm5110_get_regmap, @@ -2357,12 +2365,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5110 = { .set_sysclk = arizona_set_sysclk, .set_pll = wm5110_set_fll, - .controls = wm5110_snd_controls, - .num_controls = ARRAY_SIZE(wm5110_snd_controls), - .dapm_widgets = wm5110_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm5110_dapm_widgets), - .dapm_routes = wm5110_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes), + .component_driver = { + .controls = wm5110_snd_controls, + .num_controls = ARRAY_SIZE(wm5110_snd_controls), + .dapm_widgets = wm5110_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm5110_dapm_widgets), + .dapm_routes = wm5110_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes), + }, }; static struct snd_compr_ops wm5110_compr_ops = { diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index ffbf3df8ae97..2efc5b41ad0f 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1587,19 +1587,21 @@ static struct regmap *wm8350_get_regmap(struct device *dev) return wm8350->regmap; } -static struct snd_soc_codec_driver soc_codec_dev_wm8350 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8350 = { .probe = wm8350_codec_probe, .remove = wm8350_codec_remove, .get_regmap = wm8350_get_regmap, .set_bias_level = wm8350_set_bias_level, .suspend_bias_off = true, - .controls = wm8350_snd_controls, - .num_controls = ARRAY_SIZE(wm8350_snd_controls), - .dapm_widgets = wm8350_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8350_dapm_widgets), - .dapm_routes = wm8350_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8350_dapm_routes), + .component_driver = { + .controls = wm8350_snd_controls, + .num_controls = ARRAY_SIZE(wm8350_snd_controls), + .dapm_widgets = wm8350_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8350_dapm_widgets), + .dapm_routes = wm8350_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8350_dapm_routes), + }, }; static int wm8350_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index b1d346aa4696..6c59fb933bd6 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1332,19 +1332,21 @@ static struct regmap *wm8400_get_regmap(struct device *dev) return wm8400->regmap; } -static struct snd_soc_codec_driver soc_codec_dev_wm8400 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8400 = { .probe = wm8400_codec_probe, .remove = wm8400_codec_remove, .get_regmap = wm8400_get_regmap, .set_bias_level = wm8400_set_bias_level, .suspend_bias_off = true, - .controls = wm8400_snd_controls, - .num_controls = ARRAY_SIZE(wm8400_snd_controls), - .dapm_widgets = wm8400_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8400_dapm_widgets), - .dapm_routes = wm8400_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8400_dapm_routes), + .component_driver = { + .controls = wm8400_snd_controls, + .num_controls = ARRAY_SIZE(wm8400_snd_controls), + .dapm_widgets = wm8400_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8400_dapm_widgets), + .dapm_routes = wm8400_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8400_dapm_routes), + }, }; static int wm8400_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 99e40e629cca..119ceac684ae 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -581,17 +581,19 @@ static int wm8510_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8510 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8510 = { .probe = wm8510_probe, .set_bias_level = wm8510_set_bias_level, .suspend_bias_off = true, - .controls = wm8510_snd_controls, - .num_controls = ARRAY_SIZE(wm8510_snd_controls), - .dapm_widgets = wm8510_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8510_dapm_widgets), - .dapm_routes = wm8510_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8510_dapm_routes), + .component_driver = { + .controls = wm8510_snd_controls, + .num_controls = ARRAY_SIZE(wm8510_snd_controls), + .dapm_widgets = wm8510_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8510_dapm_widgets), + .dapm_routes = wm8510_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8510_dapm_routes), + }, }; static const struct of_device_id wm8510_of_match[] = { diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index aa287a3965e7..deb2e075428e 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -413,17 +413,19 @@ static int wm8523_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8523 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8523 = { .probe = wm8523_probe, .set_bias_level = wm8523_set_bias_level, .suspend_bias_off = true, - .controls = wm8523_controls, - .num_controls = ARRAY_SIZE(wm8523_controls), - .dapm_widgets = wm8523_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8523_dapm_widgets), - .dapm_routes = wm8523_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8523_dapm_routes), + .component_driver = { + .controls = wm8523_controls, + .num_controls = ARRAY_SIZE(wm8523_controls), + .dapm_widgets = wm8523_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8523_dapm_widgets), + .dapm_routes = wm8523_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8523_dapm_routes), + }, }; static const struct of_device_id wm8523_of_match[] = { diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 66602bf02f6e..faa7287a5253 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -899,17 +899,19 @@ static int wm8580_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8580 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8580 = { .probe = wm8580_probe, .remove = wm8580_remove, .set_bias_level = wm8580_set_bias_level, - .controls = wm8580_snd_controls, - .num_controls = ARRAY_SIZE(wm8580_snd_controls), - .dapm_widgets = wm8580_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8580_dapm_widgets), - .dapm_routes = wm8580_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8580_dapm_routes), + .component_driver = { + .controls = wm8580_snd_controls, + .num_controls = ARRAY_SIZE(wm8580_snd_controls), + .dapm_widgets = wm8580_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8580_dapm_widgets), + .dapm_routes = wm8580_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8580_dapm_routes), + }, }; static const struct of_device_id wm8580_of_match[] = { diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index c759ec068e97..2b376c9c99af 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -367,17 +367,19 @@ static int wm8711_probe(struct snd_soc_codec *codec) } -static struct snd_soc_codec_driver soc_codec_dev_wm8711 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8711 = { .probe = wm8711_probe, .set_bias_level = wm8711_set_bias_level, .suspend_bias_off = true, - .controls = wm8711_snd_controls, - .num_controls = ARRAY_SIZE(wm8711_snd_controls), - .dapm_widgets = wm8711_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8711_dapm_widgets), - .dapm_routes = wm8711_intercon, - .num_dapm_routes = ARRAY_SIZE(wm8711_intercon), + .component_driver = { + .controls = wm8711_snd_controls, + .num_controls = ARRAY_SIZE(wm8711_snd_controls), + .dapm_widgets = wm8711_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8711_dapm_widgets), + .dapm_routes = wm8711_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8711_intercon), + }, }; static const struct of_device_id wm8711_of_match[] = { diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c index bb25a75f92a2..7fde077a014b 100644 --- a/sound/soc/codecs/wm8727.c +++ b/sound/soc/codecs/wm8727.c @@ -53,11 +53,13 @@ static struct snd_soc_dai_driver wm8727_dai = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_wm8727 = { - .dapm_widgets = wm8727_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8727_dapm_widgets), - .dapm_routes = wm8727_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8727_dapm_routes), +static const struct snd_soc_codec_driver soc_codec_dev_wm8727 = { + .component_driver = { + .dapm_widgets = wm8727_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8727_dapm_widgets), + .dapm_routes = wm8727_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8727_dapm_routes), + }, }; static int wm8727_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 1564e6926527..797cc6e7c70f 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -211,16 +211,18 @@ static struct snd_soc_dai_driver wm8728_dai = { .ops = &wm8728_dai_ops, }; -static struct snd_soc_codec_driver soc_codec_dev_wm8728 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8728 = { .set_bias_level = wm8728_set_bias_level, .suspend_bias_off = true, - .controls = wm8728_snd_controls, - .num_controls = ARRAY_SIZE(wm8728_snd_controls), - .dapm_widgets = wm8728_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8728_dapm_widgets), - .dapm_routes = wm8728_intercon, - .num_dapm_routes = ARRAY_SIZE(wm8728_intercon), + .component_driver = { + .controls = wm8728_snd_controls, + .num_controls = ARRAY_SIZE(wm8728_snd_controls), + .dapm_widgets = wm8728_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8728_dapm_widgets), + .dapm_routes = wm8728_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8728_intercon), + }, }; static const struct of_device_id wm8728_of_match[] = { diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index d18261a44256..4f9a1eb28120 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -628,16 +628,18 @@ err_regulator_enable: return ret; } -static struct snd_soc_codec_driver soc_codec_dev_wm8731 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8731 = { .set_bias_level = wm8731_set_bias_level, .suspend_bias_off = true, - .dapm_widgets = wm8731_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), - .dapm_routes = wm8731_intercon, - .num_dapm_routes = ARRAY_SIZE(wm8731_intercon), - .controls = wm8731_snd_controls, - .num_controls = ARRAY_SIZE(wm8731_snd_controls), + .component_driver = { + .controls = wm8731_snd_controls, + .num_controls = ARRAY_SIZE(wm8731_snd_controls), + .dapm_widgets = wm8731_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), + .dapm_routes = wm8731_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8731_intercon), + }, }; static const struct of_device_id wm8731_of_match[] = { diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index e7807601e675..f0cb1c4afe3c 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -573,17 +573,19 @@ err_get: return ret; } -static struct snd_soc_codec_driver soc_codec_dev_wm8737 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8737 = { .probe = wm8737_probe, .set_bias_level = wm8737_set_bias_level, .suspend_bias_off = true, - .controls = wm8737_snd_controls, - .num_controls = ARRAY_SIZE(wm8737_snd_controls), - .dapm_widgets = wm8737_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8737_dapm_widgets), - .dapm_routes = intercon, - .num_dapm_routes = ARRAY_SIZE(intercon), + .component_driver = { + .controls = wm8737_snd_controls, + .num_controls = ARRAY_SIZE(wm8737_snd_controls), + .dapm_widgets = wm8737_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8737_dapm_widgets), + .dapm_routes = intercon, + .num_dapm_routes = ARRAY_SIZE(intercon), + }, }; static const struct of_device_id wm8737_of_match[] = { diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 36ef91fe0511..565d477cd790 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -497,15 +497,17 @@ static int wm8741_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8741 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8741 = { .probe = wm8741_probe, .remove = wm8741_remove, .resume = wm8741_resume, - .dapm_widgets = wm8741_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8741_dapm_widgets), - .dapm_routes = wm8741_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8741_dapm_routes), + .component_driver = { + .dapm_widgets = wm8741_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8741_dapm_widgets), + .dapm_routes = wm8741_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8741_dapm_routes), + }, }; static const struct of_device_id wm8741_of_match[] = { diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index bd9dcd2161bc..0da2bbaf06d1 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -708,17 +708,19 @@ static int wm8750_probe(struct snd_soc_codec *codec) return ret; } -static struct snd_soc_codec_driver soc_codec_dev_wm8750 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8750 = { .probe = wm8750_probe, .set_bias_level = wm8750_set_bias_level, .suspend_bias_off = true, - .controls = wm8750_snd_controls, - .num_controls = ARRAY_SIZE(wm8750_snd_controls), - .dapm_widgets = wm8750_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets), - .dapm_routes = wm8750_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8750_dapm_routes), + .component_driver = { + .controls = wm8750_snd_controls, + .num_controls = ARRAY_SIZE(wm8750_snd_controls), + .dapm_widgets = wm8750_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets), + .dapm_routes = wm8750_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8750_dapm_routes), + }, }; static const struct of_device_id wm8750_of_match[] = { diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index cdcc91282e8a..9bdf5447f6f6 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1478,18 +1478,20 @@ static int wm8753_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8753 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8753 = { .probe = wm8753_probe, .resume = wm8753_resume, .set_bias_level = wm8753_set_bias_level, .suspend_bias_off = true, - .controls = wm8753_snd_controls, - .num_controls = ARRAY_SIZE(wm8753_snd_controls), - .dapm_widgets = wm8753_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8753_dapm_widgets), - .dapm_routes = wm8753_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8753_dapm_routes), + .component_driver = { + .controls = wm8753_snd_controls, + .num_controls = ARRAY_SIZE(wm8753_snd_controls), + .dapm_widgets = wm8753_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8753_dapm_widgets), + .dapm_routes = wm8753_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8753_dapm_routes), + }, }; static const struct of_device_id wm8753_of_match[] = { diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index df6178464b00..d6edcbbdec12 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -608,17 +608,19 @@ err_reg_enable: return ret; } -static struct snd_soc_codec_driver soc_codec_dev_wm8770 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8770 = { .probe = wm8770_probe, .set_bias_level = wm8770_set_bias_level, .idle_bias_off = true, - .controls = wm8770_snd_controls, - .num_controls = ARRAY_SIZE(wm8770_snd_controls), - .dapm_widgets = wm8770_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8770_dapm_widgets), - .dapm_routes = wm8770_intercon, - .num_dapm_routes = ARRAY_SIZE(wm8770_intercon), + .component_driver = { + .controls = wm8770_snd_controls, + .num_controls = ARRAY_SIZE(wm8770_snd_controls), + .dapm_widgets = wm8770_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8770_dapm_widgets), + .dapm_routes = wm8770_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8770_intercon), + }, }; static const struct of_device_id wm8770_of_match[] = { diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 5af44f9a8cf2..ae30480b3976 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -425,17 +425,19 @@ static int wm8776_probe(struct snd_soc_codec *codec) return ret; } -static struct snd_soc_codec_driver soc_codec_dev_wm8776 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8776 = { .probe = wm8776_probe, .set_bias_level = wm8776_set_bias_level, .suspend_bias_off = true, - .controls = wm8776_snd_controls, - .num_controls = ARRAY_SIZE(wm8776_snd_controls), - .dapm_widgets = wm8776_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8776_dapm_widgets), - .dapm_routes = routes, - .num_dapm_routes = ARRAY_SIZE(routes), + .component_driver = { + .controls = wm8776_snd_controls, + .num_controls = ARRAY_SIZE(wm8776_snd_controls), + .dapm_widgets = wm8776_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8776_dapm_widgets), + .dapm_routes = routes, + .num_dapm_routes = ARRAY_SIZE(routes), + }, }; static const struct of_device_id wm8776_of_match[] = { diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c index fb55fd845d27..bcda21018505 100644 --- a/sound/soc/codecs/wm8782.c +++ b/sound/soc/codecs/wm8782.c @@ -50,11 +50,13 @@ static struct snd_soc_dai_driver wm8782_dai = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_wm8782 = { - .dapm_widgets = wm8782_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8782_dapm_widgets), - .dapm_routes = wm8782_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8782_dapm_routes), +static const struct snd_soc_codec_driver soc_codec_dev_wm8782 = { + .component_driver = { + .dapm_widgets = wm8782_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8782_dapm_widgets), + .dapm_routes = wm8782_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8782_dapm_routes), + }, }; static int wm8782_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 8d914702cae4..af95d648265b 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -545,10 +545,12 @@ static struct snd_soc_dai_driver wm8804_dai = { static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = { .idle_bias_off = true, - .dapm_widgets = wm8804_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8804_dapm_widgets), - .dapm_routes = wm8804_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8804_dapm_routes), + .component_driver = { + .dapm_widgets = wm8804_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8804_dapm_widgets), + .dapm_routes = wm8804_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8804_dapm_routes), + }, }; const struct regmap_config wm8804_regmap_config = { diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 5d8dca88d612..c77b49a29311 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1208,18 +1208,20 @@ static int wm8900_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8900 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8900 = { .probe = wm8900_probe, .suspend = wm8900_suspend, .resume = wm8900_resume, .set_bias_level = wm8900_set_bias_level, - .controls = wm8900_snd_controls, - .num_controls = ARRAY_SIZE(wm8900_snd_controls), - .dapm_widgets = wm8900_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8900_dapm_widgets), - .dapm_routes = wm8900_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8900_dapm_routes), + .component_driver = { + .controls = wm8900_snd_controls, + .num_controls = ARRAY_SIZE(wm8900_snd_controls), + .dapm_widgets = wm8900_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8900_dapm_widgets), + .dapm_routes = wm8900_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8900_dapm_routes), + }, }; static const struct regmap_config wm8900_regmap = { diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index a26ca490cf31..6e887c2c42b1 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1830,7 +1830,7 @@ static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value) !!value << WM8903_GP1_LVL_SHIFT); } -static struct gpio_chip wm8903_template_chip = { +static const struct gpio_chip wm8903_template_chip = { .label = "wm8903", .owner = THIS_MODULE, .request = wm8903_gpio_request, @@ -1874,18 +1874,20 @@ static void wm8903_free_gpio(struct wm8903_priv *wm8903) } #endif -static struct snd_soc_codec_driver soc_codec_dev_wm8903 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8903 = { .resume = wm8903_resume, .set_bias_level = wm8903_set_bias_level, .seq_notifier = wm8903_seq_notifier, .suspend_bias_off = true, - .controls = wm8903_snd_controls, - .num_controls = ARRAY_SIZE(wm8903_snd_controls), - .dapm_widgets = wm8903_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8903_dapm_widgets), - .dapm_routes = wm8903_intercon, - .num_dapm_routes = ARRAY_SIZE(wm8903_intercon), + .component_driver = { + .controls = wm8903_snd_controls, + .num_controls = ARRAY_SIZE(wm8903_snd_controls), + .dapm_widgets = wm8903_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8903_dapm_widgets), + .dapm_routes = wm8903_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8903_intercon), + }, }; static const struct regmap_config wm8903_regmap = { diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index edd7a7709194..4fd350e8420d 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2086,7 +2086,7 @@ static int wm8904_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8904 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8904 = { .probe = wm8904_probe, .remove = wm8904_remove, .set_bias_level = wm8904_set_bias_level, diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 1c600819f768..b5935625feeb 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -723,17 +723,19 @@ static int wm8940_probe(struct snd_soc_codec *codec) return ret; } -static struct snd_soc_codec_driver soc_codec_dev_wm8940 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8940 = { .probe = wm8940_probe, .set_bias_level = wm8940_set_bias_level, .suspend_bias_off = true, - .controls = wm8940_snd_controls, - .num_controls = ARRAY_SIZE(wm8940_snd_controls), - .dapm_widgets = wm8940_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8940_dapm_widgets), - .dapm_routes = wm8940_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8940_dapm_routes), + .component_driver = { + .controls = wm8940_snd_controls, + .num_controls = ARRAY_SIZE(wm8940_snd_controls), + .dapm_widgets = wm8940_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8940_dapm_widgets), + .dapm_routes = wm8940_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8940_dapm_routes), + }, }; static const struct regmap_config wm8940_regmap = { diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 9db00d53abe7..1edc7b1df31d 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -940,17 +940,19 @@ err_enable: return ret; } -static struct snd_soc_codec_driver soc_codec_dev_wm8955 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8955 = { .probe = wm8955_probe, .set_bias_level = wm8955_set_bias_level, .suspend_bias_off = true, - .controls = wm8955_snd_controls, - .num_controls = ARRAY_SIZE(wm8955_snd_controls), - .dapm_widgets = wm8955_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8955_dapm_widgets), - .dapm_routes = wm8955_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8955_dapm_routes), + .component_driver = { + .controls = wm8955_snd_controls, + .num_controls = ARRAY_SIZE(wm8955_snd_controls), + .dapm_widgets = wm8955_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8955_dapm_widgets), + .dapm_routes = wm8955_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8955_dapm_routes), + }, }; static const struct regmap_config wm8955_regmap = { diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index d7f444f87460..3bf081a7e450 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -226,11 +226,10 @@ static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0); static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); static const DECLARE_TLV_DB_SCALE(lineinboost_tlv, -1500, 300, 1); -static const unsigned int micboost_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(micboost_tlv, 0, 1, TLV_DB_SCALE_ITEM(0, 1300, 0), 2, 3, TLV_DB_SCALE_ITEM(2000, 900, 0), -}; +); static const struct snd_kcontrol_new wm8960_snd_controls[] = { SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL, @@ -1264,7 +1263,7 @@ static int wm8960_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8960 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8960 = { .probe = wm8960_probe, .set_bias_level = wm8960_set_bias_level, .suspend_bias_off = true, diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index e30446a04740..e23ceac76015 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -882,18 +882,20 @@ static int wm8961_resume(struct snd_soc_codec *codec) #define wm8961_resume NULL #endif -static struct snd_soc_codec_driver soc_codec_dev_wm8961 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8961 = { .probe = wm8961_probe, .resume = wm8961_resume, .set_bias_level = wm8961_set_bias_level, .suspend_bias_off = true, - .controls = wm8961_snd_controls, - .num_controls = ARRAY_SIZE(wm8961_snd_controls), - .dapm_widgets = wm8961_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8961_dapm_widgets), - .dapm_routes = audio_paths, - .num_dapm_routes = ARRAY_SIZE(audio_paths), + .component_driver = { + .controls = wm8961_snd_controls, + .num_controls = ARRAY_SIZE(wm8961_snd_controls), + .dapm_widgets = wm8961_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8961_dapm_widgets), + .dapm_routes = audio_paths, + .num_dapm_routes = ARRAY_SIZE(audio_paths), + }, }; static const struct regmap_config wm8961_regmap = { diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index f3109da24769..fd2731d171dd 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3357,7 +3357,7 @@ static int wm8962_gpio_direction_out(struct gpio_chip *chip, return 0; } -static struct gpio_chip wm8962_template_chip = { +static const struct gpio_chip wm8962_template_chip = { .label = "wm8962", .owner = THIS_MODULE, .request = wm8962_gpio_request, @@ -3479,7 +3479,7 @@ static int wm8962_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8962 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8962 = { .probe = wm8962_probe, .remove = wm8962_remove, .set_bias_level = wm8962_set_bias_level, @@ -3713,7 +3713,7 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, ARRAY_SIZE(wm8962_dc_measure)); if (ret != 0) dev_err(&i2c->dev, - "Failed to configure for DC mesurement: %d\n", + "Failed to configure for DC measurement: %d\n", ret); } diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 2cdde32c43c6..887d31cf3945 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -649,17 +649,19 @@ static int wm8971_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8971 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8971 = { .probe = wm8971_probe, .set_bias_level = wm8971_set_bias_level, .suspend_bias_off = true, - .controls = wm8971_snd_controls, - .num_controls = ARRAY_SIZE(wm8971_snd_controls), - .dapm_widgets = wm8971_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8971_dapm_widgets), - .dapm_routes = wm8971_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8971_dapm_routes), + .component_driver = { + .controls = wm8971_snd_controls, + .num_controls = ARRAY_SIZE(wm8971_snd_controls), + .dapm_widgets = wm8971_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8971_dapm_widgets), + .dapm_routes = wm8971_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8971_dapm_routes), + }, }; static const struct regmap_config wm8971_regmap = { diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index dc8c3b1ebb6f..d414ddd6e197 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -676,17 +676,19 @@ static int wm8974_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8974 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8974 = { .probe = wm8974_probe, .set_bias_level = wm8974_set_bias_level, .suspend_bias_off = true, - .controls = wm8974_snd_controls, - .num_controls = ARRAY_SIZE(wm8974_snd_controls), - .dapm_widgets = wm8974_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8974_dapm_widgets), - .dapm_routes = wm8974_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8974_dapm_routes), + .component_driver = { + .controls = wm8974_snd_controls, + .num_controls = ARRAY_SIZE(wm8974_snd_controls), + .dapm_widgets = wm8974_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8974_dapm_widgets), + .dapm_routes = wm8974_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8974_dapm_routes), + }, }; static int wm8974_i2c_probe(struct i2c_client *i2c, diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index d36d6001fbb7..90b2d418ef60 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -993,18 +993,20 @@ static int wm8978_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8978 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8978 = { .probe = wm8978_probe, .suspend = wm8978_suspend, .resume = wm8978_resume, .set_bias_level = wm8978_set_bias_level, - .controls = wm8978_snd_controls, - .num_controls = ARRAY_SIZE(wm8978_snd_controls), - .dapm_widgets = wm8978_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8978_dapm_widgets), - .dapm_routes = wm8978_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8978_dapm_routes), + .component_driver = { + .controls = wm8978_snd_controls, + .num_controls = ARRAY_SIZE(wm8978_snd_controls), + .dapm_widgets = wm8978_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8978_dapm_widgets), + .dapm_routes = wm8978_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8978_dapm_routes), + }, }; static const struct regmap_config wm8978_regmap_config = { diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index 0c002a5712cb..bfdbe72ee687 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -976,16 +976,18 @@ static struct snd_soc_dai_driver wm8983_dai = { .symmetric_rates = 1 }; -static struct snd_soc_codec_driver soc_codec_dev_wm8983 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8983 = { .probe = wm8983_probe, .set_bias_level = wm8983_set_bias_level, .suspend_bias_off = true, - .controls = wm8983_snd_controls, - .num_controls = ARRAY_SIZE(wm8983_snd_controls), - .dapm_widgets = wm8983_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8983_dapm_widgets), - .dapm_routes = wm8983_audio_map, - .num_dapm_routes = ARRAY_SIZE(wm8983_audio_map), + .component_driver = { + .controls = wm8983_snd_controls, + .num_controls = ARRAY_SIZE(wm8983_snd_controls), + .dapm_widgets = wm8983_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8983_dapm_widgets), + .dapm_routes = wm8983_audio_map, + .num_dapm_routes = ARRAY_SIZE(wm8983_audio_map), + }, }; static const struct regmap_config wm8983_regmap = { diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 7347abff4b2c..05344f974ff3 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -1105,17 +1105,19 @@ static struct snd_soc_dai_driver wm8985_dai = { .symmetric_rates = 1 }; -static struct snd_soc_codec_driver soc_codec_dev_wm8985 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8985 = { .probe = wm8985_probe, .set_bias_level = wm8985_set_bias_level, .suspend_bias_off = true, - .controls = wm8985_common_snd_controls, - .num_controls = ARRAY_SIZE(wm8985_common_snd_controls), - .dapm_widgets = wm8985_common_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8985_common_dapm_widgets), - .dapm_routes = wm8985_common_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8985_common_dapm_routes), + .component_driver = { + .controls = wm8985_common_snd_controls, + .num_controls = ARRAY_SIZE(wm8985_common_snd_controls), + .dapm_widgets = wm8985_common_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8985_common_dapm_widgets), + .dapm_routes = wm8985_common_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8985_common_dapm_routes), + }, }; static const struct regmap_config wm8985_regmap = { diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 895721a256f0..b0d0219532f2 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -817,12 +817,14 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8988 = { .set_bias_level = wm8988_set_bias_level, .suspend_bias_off = true, - .controls = wm8988_snd_controls, - .num_controls = ARRAY_SIZE(wm8988_snd_controls), - .dapm_widgets = wm8988_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8988_dapm_widgets), - .dapm_routes = wm8988_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8988_dapm_routes), + .component_driver = { + .controls = wm8988_snd_controls, + .num_controls = ARRAY_SIZE(wm8988_snd_controls), + .dapm_widgets = wm8988_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8988_dapm_widgets), + .dapm_routes = wm8988_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8988_dapm_routes), + }, }; static const struct regmap_config wm8988_regmap = { diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 23ecd30d8bca..a8945001e696 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1294,17 +1294,19 @@ static int wm8990_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8990 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8990 = { .probe = wm8990_probe, .set_bias_level = wm8990_set_bias_level, .suspend_bias_off = true, - .controls = wm8990_snd_controls, - .num_controls = ARRAY_SIZE(wm8990_snd_controls), - .dapm_widgets = wm8990_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8990_dapm_widgets), - .dapm_routes = wm8990_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8990_dapm_routes), + .component_driver = { + .controls = wm8990_snd_controls, + .num_controls = ARRAY_SIZE(wm8990_snd_controls), + .dapm_widgets = wm8990_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8990_dapm_widgets), + .dapm_routes = wm8990_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8990_dapm_routes), + }, }; static const struct regmap_config wm8990_regmap = { diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index c9ee0ac6a654..802c0694e5c3 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -111,14 +111,24 @@ static bool wm8991_volatile(struct device *dev, unsigned int reg) } } -static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); -static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000); -static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, 0, -2100); -static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600); -static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0); -static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0); -static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763); -static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(in_pga_tlv, -1650, 150, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(out_mix_tlv, -2100, 300, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(out_pga_tlv, + 0x00, 0x2f, SNDRV_CTL_TLVD_DB_SCALE_ITEM(SNDRV_CTL_TLVD_DB_GAIN_MUTE, 0, 1), + 0x30, 0x7f, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-7300, 100, 0), +); +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(out_dac_tlv, + 0x00, 0xbf, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-71625, 375, 1), + 0xc0, 0xff, SNDRV_CTL_TLVD_DB_SCALE_ITEM(0, 0, 0), +); +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(in_adc_tlv, + 0x00, 0xef, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-71625, 375, 1), + 0xf0, 0xff, SNDRV_CTL_TLVD_DB_SCALE_ITEM(17625, 0, 0), +); +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(out_sidetone_tlv, + 0x00, 0x0c, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-3600, 300, 0), + 0x0d, 0x0f, SNDRV_CTL_TLVD_DB_SCALE_ITEM(0, 0, 0), +); static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -398,7 +408,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } /* INMIX dB values */ -static const DECLARE_TLV_DB_LINEAR(in_mix_tlv, -1200, 600); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(in_mix_tlv, -1200, 300, 1); /* Left In PGA Connections */ static const struct snd_kcontrol_new wm8991_dapm_lin12_pga_controls[] = { @@ -1232,16 +1242,18 @@ static struct snd_soc_dai_driver wm8991_dai = { .ops = &wm8991_ops }; -static struct snd_soc_codec_driver soc_codec_dev_wm8991 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8991 = { .set_bias_level = wm8991_set_bias_level, .suspend_bias_off = true, - .controls = wm8991_snd_controls, - .num_controls = ARRAY_SIZE(wm8991_snd_controls), - .dapm_widgets = wm8991_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8991_dapm_widgets), - .dapm_routes = wm8991_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8991_dapm_routes), + .component_driver = { + .controls = wm8991_snd_controls, + .num_controls = ARRAY_SIZE(wm8991_snd_controls), + .dapm_widgets = wm8991_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8991_dapm_widgets), + .dapm_routes = wm8991_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8991_dapm_routes), + }, }; static const struct regmap_config wm8991_regmap = { diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 8668c4c391b0..195f7bf6eb22 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1613,7 +1613,7 @@ static const struct regmap_config wm8993_regmap = { .num_reg_defaults = ARRAY_SIZE(wm8993_reg_defaults), }; -static struct snd_soc_codec_driver soc_codec_dev_wm8993 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8993 = { .probe = wm8993_probe, .suspend = wm8993_suspend, .resume = wm8993_resume, diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index a18aecb49935..3896523b71e9 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -4439,7 +4439,7 @@ static struct regmap *wm8994_get_regmap(struct device *dev) return control->regmap; } -static struct snd_soc_codec_driver soc_codec_dev_wm8994 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8994 = { .probe = wm8994_codec_probe, .remove = wm8994_codec_remove, .suspend = wm8994_codec_suspend, diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 24500bafb0a8..19b08a5cae62 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2192,12 +2192,14 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8995 = { .set_bias_level = wm8995_set_bias_level, .idle_bias_off = true, - .controls = wm8995_snd_controls, - .num_controls = ARRAY_SIZE(wm8995_snd_controls), - .dapm_widgets = wm8995_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8995_dapm_widgets), - .dapm_routes = wm8995_intercon, - .num_dapm_routes = ARRAY_SIZE(wm8995_intercon), + .component_driver = { + .controls = wm8995_snd_controls, + .num_controls = ARRAY_SIZE(wm8995_snd_controls), + .dapm_widgets = wm8995_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8995_dapm_widgets), + .dapm_routes = wm8995_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8995_intercon), + }, }; static const struct regmap_config wm8995_regmap = { diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index a73044251218..8affa4969120 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2184,7 +2184,7 @@ static int wm8996_gpio_direction_in(struct gpio_chip *chip, unsigned offset) (1 << WM8996_GP1_DIR_SHIFT)); } -static struct gpio_chip wm8996_template_chip = { +static const struct gpio_chip wm8996_template_chip = { .label = "wm8996", .owner = THIS_MODULE, .direction_output = wm8996_gpio_direction_out, @@ -2684,18 +2684,20 @@ static int wm8996_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8996 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8996 = { .probe = wm8996_probe, .remove = wm8996_remove, .set_bias_level = wm8996_set_bias_level, .idle_bias_off = true, .seq_notifier = wm8996_seq_notifier, - .controls = wm8996_snd_controls, - .num_controls = ARRAY_SIZE(wm8996_snd_controls), - .dapm_widgets = wm8996_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8996_dapm_widgets), - .dapm_routes = wm8996_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8996_dapm_routes), + .component_driver = { + .controls = wm8996_snd_controls, + .num_controls = ARRAY_SIZE(wm8996_snd_controls), + .dapm_widgets = wm8996_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8996_dapm_widgets), + .dapm_routes = wm8996_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8996_dapm_routes), + }, .set_pll = wm8996_set_fll, }; diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 6b0785b5a5c5..2f2821b3382f 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -1095,7 +1095,7 @@ static struct regmap *wm8997_get_regmap(struct device *dev) return priv->core.arizona->regmap; } -static struct snd_soc_codec_driver soc_codec_dev_wm8997 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8997 = { .probe = wm8997_codec_probe, .remove = wm8997_codec_remove, .get_regmap = wm8997_get_regmap, @@ -1105,12 +1105,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8997 = { .set_sysclk = arizona_set_sysclk, .set_pll = wm8997_set_fll, - .controls = wm8997_snd_controls, - .num_controls = ARRAY_SIZE(wm8997_snd_controls), - .dapm_widgets = wm8997_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8997_dapm_widgets), - .dapm_routes = wm8997_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8997_dapm_routes), + .component_driver = { + .controls = wm8997_snd_controls, + .num_controls = ARRAY_SIZE(wm8997_snd_controls), + .dapm_widgets = wm8997_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8997_dapm_widgets), + .dapm_routes = wm8997_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8997_dapm_routes), + }, }; static int wm8997_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 3a5c896a2d13..bcc2e1060a6c 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -966,6 +966,16 @@ static const struct snd_soc_dapm_route wm8998_dapm_routes[] = { { "IN2A", NULL, "SYSCLK" }, { "IN2B", NULL, "SYSCLK" }, + { "ASRC1L", NULL, "SYSCLK" }, + { "ASRC1R", NULL, "SYSCLK" }, + { "ASRC2L", NULL, "SYSCLK" }, + { "ASRC2R", NULL, "SYSCLK" }, + + { "ASRC1L", NULL, "ASYNCCLK" }, + { "ASRC1R", NULL, "ASYNCCLK" }, + { "ASRC2L", NULL, "ASYNCCLK" }, + { "ASRC2R", NULL, "ASYNCCLK" }, + { "SPD1", NULL, "SYSCLK" }, { "SPD1", NULL, "SPD1TX1" }, { "SPD1", NULL, "SPD1TX2" }, @@ -1351,7 +1361,7 @@ static struct regmap *wm8998_get_regmap(struct device *dev) return priv->core.arizona->regmap; } -static struct snd_soc_codec_driver soc_codec_dev_wm8998 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8998 = { .probe = wm8998_codec_probe, .remove = wm8998_codec_remove, .get_regmap = wm8998_get_regmap, @@ -1361,12 +1371,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8998 = { .set_sysclk = arizona_set_sysclk, .set_pll = wm8998_set_fll, - .controls = wm8998_snd_controls, - .num_controls = ARRAY_SIZE(wm8998_snd_controls), - .dapm_widgets = wm8998_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8998_dapm_widgets), - .dapm_routes = wm8998_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8998_dapm_routes), + .component_driver = { + .controls = wm8998_snd_controls, + .num_controls = ARRAY_SIZE(wm8998_snd_controls), + .dapm_widgets = wm8998_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8998_dapm_widgets), + .dapm_routes = wm8998_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8998_dapm_routes), + }, }; static int wm8998_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 363b3b667616..856867ec2813 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1274,7 +1274,7 @@ static int wm9081_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm9081 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm9081 = { .probe = wm9081_probe, .set_sysclk = wm9081_set_sysclk, @@ -1282,12 +1282,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9081 = { .idle_bias_off = true, - .controls = wm9081_snd_controls, - .num_controls = ARRAY_SIZE(wm9081_snd_controls), - .dapm_widgets = wm9081_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm9081_dapm_widgets), - .dapm_routes = wm9081_audio_paths, - .num_dapm_routes = ARRAY_SIZE(wm9081_audio_paths), + .component_driver = { + .controls = wm9081_snd_controls, + .num_controls = ARRAY_SIZE(wm9081_snd_controls), + .dapm_widgets = wm9081_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm9081_dapm_widgets), + .dapm_routes = wm9081_audio_paths, + .num_dapm_routes = ARRAY_SIZE(wm9081_audio_paths), + }, }; static const struct regmap_config wm9081_regmap = { diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 5d737290f547..5a131385cb2f 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -550,7 +550,7 @@ static int wm9090_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm9090 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm9090 = { .probe = wm9090_probe, .set_bias_level = wm9090_set_bias_level, .suspend_bias_off = true, diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 744842c76a60..dcdd055db57b 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -352,7 +352,7 @@ static int wm9705_soc_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm9705 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm9705 = { .probe = wm9705_soc_probe, .remove = wm9705_soc_remove, .suspend = wm9705_soc_suspend, @@ -364,12 +364,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9705 = { .reg_cache_step = 2, .reg_cache_default = wm9705_reg, - .controls = wm9705_snd_ac97_controls, - .num_controls = ARRAY_SIZE(wm9705_snd_ac97_controls), - .dapm_widgets = wm9705_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets), - .dapm_routes = wm9705_audio_map, - .num_dapm_routes = ARRAY_SIZE(wm9705_audio_map), + .component_driver = { + .controls = wm9705_snd_ac97_controls, + .num_controls = ARRAY_SIZE(wm9705_snd_ac97_controls), + .dapm_widgets = wm9705_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets), + .dapm_routes = wm9705_audio_map, + .num_dapm_routes = ARRAY_SIZE(wm9705_audio_map), + }, }; static int wm9705_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 488a92224249..557709eac698 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -669,7 +669,7 @@ static int wm9712_soc_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm9712 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm9712 = { .probe = wm9712_soc_probe, .remove = wm9712_soc_remove, .resume = wm9712_soc_resume, @@ -682,12 +682,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = { .reg_cache_step = 2, .reg_cache_default = wm9712_reg, - .controls = wm9712_snd_ac97_controls, - .num_controls = ARRAY_SIZE(wm9712_snd_ac97_controls), - .dapm_widgets = wm9712_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets), - .dapm_routes = wm9712_audio_map, - .num_dapm_routes = ARRAY_SIZE(wm9712_audio_map), + .component_driver = { + .controls = wm9712_snd_ac97_controls, + .num_controls = ARRAY_SIZE(wm9712_snd_ac97_controls), + .dapm_widgets = wm9712_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets), + .dapm_routes = wm9712_audio_map, + .num_dapm_routes = ARRAY_SIZE(wm9712_audio_map), + }, }; static int wm9712_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 9849643ef809..e4301ddb1b84 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1235,19 +1235,21 @@ static int wm9713_soc_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm9713 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm9713 = { .probe = wm9713_soc_probe, .remove = wm9713_soc_remove, .suspend = wm9713_soc_suspend, .resume = wm9713_soc_resume, .set_bias_level = wm9713_set_bias_level, - .controls = wm9713_snd_ac97_controls, - .num_controls = ARRAY_SIZE(wm9713_snd_ac97_controls), - .dapm_widgets = wm9713_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets), - .dapm_routes = wm9713_audio_map, - .num_dapm_routes = ARRAY_SIZE(wm9713_audio_map), + .component_driver = { + .controls = wm9713_snd_ac97_controls, + .num_controls = ARRAY_SIZE(wm9713_snd_ac97_controls), + .dapm_widgets = wm9713_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets), + .dapm_routes = wm9713_audio_map, + .num_dapm_routes = ARRAY_SIZE(wm9713_audio_map), + }, }; static int wm9713_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 21fbe7d07063..b943dde8dbe5 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -480,7 +480,7 @@ static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, mutex_lock(&dsp->pwr_lock); - if (!dsp->wmfw_file_name || !dsp->running) + if (!dsp->wmfw_file_name || !dsp->booted) ret = 0; else ret = simple_read_from_buffer(user_buf, count, ppos, @@ -500,7 +500,7 @@ static ssize_t wm_adsp_debugfs_bin_read(struct file *file, mutex_lock(&dsp->pwr_lock); - if (!dsp->bin_file_name || !dsp->running) + if (!dsp->bin_file_name || !dsp->booted) ret = 0; else ret = simple_read_from_buffer(user_buf, count, ppos, @@ -554,6 +554,9 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp, if (!root) goto err; + if (!debugfs_create_bool("booted", S_IRUGO, root, &dsp->booted)) + goto err; + if (!debugfs_create_bool("running", S_IRUGO, root, &dsp->running)) goto err; @@ -637,7 +640,7 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, mutex_lock(&dsp[e->shift_l].pwr_lock); - if (dsp[e->shift_l].running || dsp[e->shift_l].compr) + if (dsp[e->shift_l].booted || dsp[e->shift_l].compr) ret = -EBUSY; else dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0]; @@ -789,7 +792,7 @@ static int wm_coeff_put(struct snd_kcontrol *kctl, memcpy(ctl->cache, p, ctl->len); ctl->set = 1; - if (ctl->enabled) + if (ctl->enabled && ctl->dsp->running) ret = wm_coeff_write_control(ctl, p, ctl->len); mutex_unlock(&ctl->dsp->pwr_lock); @@ -811,7 +814,7 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, ret = -EFAULT; } else { ctl->set = 1; - if (ctl->enabled) + if (ctl->enabled && ctl->dsp->running) ret = wm_coeff_write_control(ctl, ctl->cache, size); } @@ -871,12 +874,12 @@ static int wm_coeff_get(struct snd_kcontrol *kctl, mutex_lock(&ctl->dsp->pwr_lock); if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { - if (ctl->enabled) + if (ctl->enabled && ctl->dsp->running) ret = wm_coeff_read_control(ctl, p, ctl->len); else ret = -EPERM; } else { - if (!ctl->flags && ctl->enabled) + if (!ctl->flags && ctl->enabled && ctl->dsp->running) ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len); memcpy(p, ctl->cache, ctl->len); @@ -898,12 +901,12 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, mutex_lock(&ctl->dsp->pwr_lock); if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { - if (ctl->enabled) + if (ctl->enabled && ctl->dsp->running) ret = wm_coeff_read_control(ctl, ctl->cache, size); else ret = -EPERM; } else { - if (!ctl->flags && ctl->enabled) + if (!ctl->flags && ctl->enabled && ctl->dsp->running) ret = wm_coeff_read_control(ctl, ctl->cache, size); } @@ -2166,13 +2169,20 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, if (ret != 0) goto err_ena; + dsp->booted = true; + /* Start the core running */ regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, ADSP1_CORE_ENA | ADSP1_START, ADSP1_CORE_ENA | ADSP1_START); + + dsp->running = true; break; case SND_SOC_DAPM_PRE_PMD: + dsp->running = false; + dsp->booted = false; + /* Halt the core */ regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, ADSP1_CORE_ENA | ADSP1_START, 0); @@ -2227,7 +2237,7 @@ static int wm_adsp2_ena(struct wm_adsp *dsp) if (val & ADSP2_RAM_RDY) break; - msleep(1); + usleep_range(250, 500); } if (!(val & ADSP2_RAM_RDY)) { @@ -2249,6 +2259,11 @@ static void wm_adsp2_boot_work(struct work_struct *work) mutex_lock(&dsp->pwr_lock); + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_MEM_ENA, ADSP2_MEM_ENA); + if (ret != 0) + goto err_mutex; + ret = wm_adsp2_ena(dsp); if (ret != 0) goto err_mutex; @@ -2270,13 +2285,14 @@ static void wm_adsp2_boot_work(struct work_struct *work) if (ret != 0) goto err_ena; - /* Sync set controls */ - ret = wm_coeff_sync_controls(dsp); + dsp->booted = true; + + /* Turn DSP back off until we are ready to run */ + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA, 0); if (ret != 0) goto err_ena; - dsp->running = true; - mutex_unlock(&dsp->pwr_lock); return; @@ -2307,6 +2323,7 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsp = &dsps[w->shift]; + struct wm_coeff_ctl *ctl; dsp->card = codec->component.card; @@ -2315,6 +2332,24 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, wm_adsp2_set_dspclk(dsp, freq); queue_work(system_unbound_wq, &dsp->boot_work); break; + case SND_SOC_DAPM_PRE_PMD: + wm_adsp_debugfs_clear(dsp); + + dsp->fw_id = 0; + dsp->fw_id_version = 0; + + dsp->booted = false; + + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_MEM_ENA, 0); + + list_for_each_entry(ctl, &dsp->ctl_list, list) + ctl->enabled = 0; + + wm_adsp_free_alg_regions(dsp); + + adsp_dbg(dsp, "Shutdown complete\n"); + break; default: break; } @@ -2329,16 +2364,24 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsp = &dsps[w->shift]; - struct wm_coeff_ctl *ctl; int ret; switch (event) { case SND_SOC_DAPM_POST_PMU: flush_work(&dsp->boot_work); - if (!dsp->running) + if (!dsp->booted) return -EIO; + ret = wm_adsp2_ena(dsp); + if (ret != 0) + goto err; + + /* Sync set controls */ + ret = wm_coeff_sync_controls(dsp); + if (ret != 0) + goto err; + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ADSP2_CORE_ENA | ADSP2_START, @@ -2346,6 +2389,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, if (ret != 0) goto err; + dsp->running = true; + mutex_lock(&dsp->pwr_lock); if (wm_adsp_fw[dsp->fw].num_caps != 0) @@ -2361,10 +2406,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, mutex_lock(&dsp->pwr_lock); - wm_adsp_debugfs_clear(dsp); - - dsp->fw_id = 0; - dsp->fw_id_version = 0; dsp->running = false; regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, @@ -2378,17 +2419,12 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ADSP2_SYS_ENA, 0); - list_for_each_entry(ctl, &dsp->ctl_list, list) - ctl->enabled = 0; - - wm_adsp_free_alg_regions(dsp); - if (wm_adsp_fw[dsp->fw].num_caps != 0) wm_adsp_buffer_free(dsp); mutex_unlock(&dsp->pwr_lock); - adsp_dbg(dsp, "Shutdown complete\n"); + adsp_dbg(dsp, "Execution stopped\n"); break; default: diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index be3b5bcb7f17..362dd7ce60d8 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -61,6 +61,8 @@ struct wm_adsp { int fw; int fw_ver; + + bool booted; bool running; struct list_head ctl_list; @@ -85,9 +87,10 @@ struct wm_adsp { wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) #define WM_ADSP2(wname, num, event_fn) \ -{ .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \ +{ .id = snd_soc_dapm_supply, .name = wname " Preloader", \ .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \ - .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }, \ + .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \ + .subseq = 100, /* Ensure we run after SYSCLK supply widget */ }, \ { .id = snd_soc_dapm_out_drv, .name = wname, \ .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 05c2d33aa74d..3c5a9804d3f5 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1218,7 +1218,7 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params, snd_mask_none(&nfmt); - for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { + for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { if (snd_mask_test(fmt, i)) { uint sbits = snd_pcm_format_width(i); int ppm; diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index dc97f4349e66..2998954a1c74 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -577,7 +577,6 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, dev->capability |= DWC_I2S_PLAY; dev->play_dma_data.dt.addr = res->start + I2S_TXDMA; dev->play_dma_data.dt.addr_width = bus_widths[idx]; - dev->play_dma_data.dt.chan_name = "TX"; dev->play_dma_data.dt.fifo_size = fifo_depth * (fifo_width[idx2]) >> 8; dev->play_dma_data.dt.maxburst = 16; @@ -588,7 +587,6 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, dev->capability |= DWC_I2S_RECORD; dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA; dev->capture_dma_data.dt.addr_width = bus_widths[idx]; - dev->capture_dma_data.dt.chan_name = "RX"; dev->capture_dma_data.dt.fifo_size = fifo_depth * (fifo_width[idx2] >> 8); dev->capture_dma_data.dt.maxburst = 16; diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index c1a0e01cb8e7..1d82f68305c3 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -726,7 +726,7 @@ static const struct regmap_config fsl_asrc_regmap_config = { .readable_reg = fsl_asrc_readable_reg, .volatile_reg = fsl_asrc_volatile_reg, .writeable_reg = fsl_asrc_writeable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_FLAT, }; /** @@ -879,7 +879,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) } } - if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx35-asrc")) { + if (of_device_is_compatible(np, "fsl,imx35-asrc")) { asrc_priv->channel_bits = 3; clk_map[IN] = input_clk_map_imx35; clk_map[OUT] = output_clk_map_imx35; @@ -892,7 +892,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) ret = fsl_asrc_init(asrc_priv); if (ret) { dev_err(&pdev->dev, "failed to init asrc %d\n", ret); - return -EINVAL; + return ret; } asrc_priv->channel_avail = 10; @@ -901,14 +901,14 @@ static int fsl_asrc_probe(struct platform_device *pdev) &asrc_priv->asrc_rate); if (ret) { dev_err(&pdev->dev, "failed to get output rate\n"); - return -EINVAL; + return ret; } ret = of_property_read_u32(np, "fsl,asrc-width", &asrc_priv->asrc_width); if (ret) { dev_err(&pdev->dev, "failed to get output width\n"); - return -EINVAL; + return ret; } if (asrc_priv->asrc_width != 16 && asrc_priv->asrc_width != 24) { @@ -933,8 +933,6 @@ static int fsl_asrc_probe(struct platform_device *pdev) return ret; } - dev_info(&pdev->dev, "driver registered\n"); - return 0; } diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index ffc000bc1f15..dc30d780f874 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -322,7 +322,7 @@ static snd_pcm_uframes_t fsl_asrc_dma_pcm_pointer(struct snd_pcm_substream *subs return bytes_to_frames(substream->runtime, pair->pos); } -static struct snd_pcm_ops fsl_asrc_dma_pcm_ops = { +static const struct snd_pcm_ops fsl_asrc_dma_pcm_ops = { .ioctl = snd_pcm_lib_ioctl, .hw_params = fsl_asrc_dma_hw_params, .hw_free = fsl_asrc_dma_hw_free, diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 26a90e12ede4..38bfd46f4ad8 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -77,19 +77,19 @@ static irqreturn_t esai_isr(int irq, void *devid) regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr); if (esr & ESAI_ESR_TINIT_MASK) - dev_dbg(&pdev->dev, "isr: Transmition Initialized\n"); + dev_dbg(&pdev->dev, "isr: Transmission Initialized\n"); if (esr & ESAI_ESR_RFF_MASK) dev_warn(&pdev->dev, "isr: Receiving overrun\n"); if (esr & ESAI_ESR_TFE_MASK) - dev_warn(&pdev->dev, "isr: Transmition underrun\n"); + dev_warn(&pdev->dev, "isr: Transmission underrun\n"); if (esr & ESAI_ESR_TLS_MASK) dev_dbg(&pdev->dev, "isr: Just transmitted the last slot\n"); if (esr & ESAI_ESR_TDE_MASK) - dev_dbg(&pdev->dev, "isr: Transmition data exception\n"); + dev_dbg(&pdev->dev, "isr: Transmission data exception\n"); if (esr & ESAI_ESR_TED_MASK) dev_dbg(&pdev->dev, "isr: Transmitting even slots\n"); @@ -781,7 +781,7 @@ static const struct regmap_config fsl_esai_regmap_config = { .readable_reg = fsl_esai_readable_reg, .volatile_reg = fsl_esai_volatile_reg, .writeable_reg = fsl_esai_writeable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_FLAT, }; static int fsl_esai_probe(struct platform_device *pdev) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 2147994ab46f..9fadf7e31c5f 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -801,8 +801,8 @@ static int fsl_sai_probe(struct platform_device *pdev) sai->pdev = pdev; - if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai") || - of_device_is_compatible(pdev->dev.of_node, "fsl,imx6ul-sai")) + if (of_device_is_compatible(np, "fsl,imx6sx-sai") || + of_device_is_compatible(np, "fsl,imx6ul-sai")) sai->sai_on_imx = true; sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); @@ -883,7 +883,7 @@ static int fsl_sai_probe(struct platform_device *pdev) } if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) && - of_device_is_compatible(pdev->dev.of_node, "fsl,imx6ul-sai")) { + of_device_is_compatible(np, "fsl,imx6ul-sai")) { gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr"); if (IS_ERR(gpr)) { dev_err(&pdev->dev, "cannot find iomuxc registers\n"); diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index beec7934a265..1ff467c9598a 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1103,7 +1103,7 @@ static const struct regmap_config fsl_spdif_regmap_config = { .readable_reg = fsl_spdif_readable_reg, .volatile_reg = fsl_spdif_volatile_reg, .writeable_reg = fsl_spdif_writeable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_FLAT, }; static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index bedec4a32581..50349437d961 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -182,7 +182,7 @@ static const struct regmap_config fsl_ssi_regconfig = { .volatile_reg = fsl_ssi_volatile_reg, .precious_reg = fsl_ssi_precious_reg, .writeable_reg = fsl_ssi_writeable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_FLAT, }; struct fsl_ssi_soc_data { diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index c01c5dd68601..d023959b8cd6 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -6,3 +6,11 @@ config SND_SIMPLE_CARD select SND_SIMPLE_CARD_UTILS help This option enables generic simple sound card support + +config SND_SIMPLE_SCU_CARD + tristate "ASoC Simple SCU sound card support" + depends on OF + select SND_SIMPLE_CARD_UTILS + help + This option enables generic simple SCU sound card support. + It supports DPCM of multi CPU single Codec system. diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index 45602ca8536e..ee750f3023ba 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile @@ -1,5 +1,7 @@ -obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) := simple-card-utils.o - +snd-soc-simple-card-utils-objs := simple-card-utils.o snd-soc-simple-card-objs := simple-card.o +snd-soc-simple-scu-card-objs := simple-scu-card.o -obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o +obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o +obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o +obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index d89a9a1b2471..1cb39309f5d5 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -7,6 +7,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include <linux/clk.h> +#include <linux/module.h> #include <linux/of.h> #include <sound/simple_card_utils.h> @@ -95,3 +97,148 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card, return 0; } EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); + +int asoc_simple_card_parse_clk(struct device_node *node, + struct device_node *dai_of_node, + struct asoc_simple_dai *simple_dai) +{ + struct clk *clk; + u32 val; + + /* + * Parse dai->sysclk come from "clocks = <&xxx>" + * (if system has common clock) + * or "system-clock-frequency = <xxx>" + * or device's module clock. + */ + clk = of_clk_get(node, 0); + if (!IS_ERR(clk)) { + simple_dai->sysclk = clk_get_rate(clk); + simple_dai->clk = clk; + } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) { + simple_dai->sysclk = val; + } else { + clk = of_clk_get(dai_of_node, 0); + if (!IS_ERR(clk)) + simple_dai->sysclk = clk_get_rate(clk); + } + + return 0; +} +EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk); + +int asoc_simple_card_parse_dai(struct device_node *node, + struct device_node **dai_of_node, + const char **dai_name, + const char *list_name, + const char *cells_name, + int *is_single_link) +{ + struct of_phandle_args args; + int ret; + + if (!node) + return 0; + + /* + * Get node via "sound-dai = <&phandle port>" + * it will be used as xxx_of_node on soc_bind_dai_link() + */ + ret = of_parse_phandle_with_args(node, list_name, cells_name, 0, &args); + if (ret) + return ret; + + /* Get dai->name */ + if (dai_name) { + ret = snd_soc_of_get_dai_name(node, dai_name); + if (ret < 0) + return ret; + } + + *dai_of_node = args.np; + + if (is_single_link) + *is_single_link = !args.args_count; + + return 0; +} +EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai); + +int asoc_simple_card_init_dai(struct snd_soc_dai *dai, + struct asoc_simple_dai *simple_dai) +{ + int ret; + + if (simple_dai->sysclk) { + ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk, 0); + if (ret && ret != -ENOTSUPP) { + dev_err(dai->dev, "simple-card: set_sysclk error\n"); + return ret; + } + } + + if (simple_dai->slots) { + ret = snd_soc_dai_set_tdm_slot(dai, + simple_dai->tx_slot_mask, + simple_dai->rx_slot_mask, + simple_dai->slots, + simple_dai->slot_width); + if (ret && ret != -ENOTSUPP) { + dev_err(dai->dev, "simple-card: set_tdm_slot error\n"); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); + +int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) +{ + if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) + return -EINVAL; + + /* Assumes platform == cpu */ + if (!dai_link->platform_of_node) + dai_link->platform_of_node = dai_link->cpu_of_node; + + return 0; +} +EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_dailink); + +void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link, + int is_single_links) +{ + /* + * In soc_bind_dai_link() will check cpu name after + * of_node matching if dai_link has cpu_dai_name. + * but, it will never match if name was created by + * fmt_single_name() remove cpu_dai_name if cpu_args + * was 0. See: + * fmt_single_name() + * fmt_multiple_name() + */ + if (is_single_links) + dai_link->cpu_dai_name = NULL; +} +EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_cpu); + +int asoc_simple_card_clean_reference(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *dai_link; + int num_links; + + for (num_links = 0, dai_link = card->dai_link; + num_links < card->num_links; + num_links++, dai_link++) { + of_node_put(dai_link->cpu_of_node); + of_node_put(dai_link->codec_of_node); + } + return 0; +} +EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference); + +/* Module information */ +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); +MODULE_DESCRIPTION("ALSA SoC Simple Card Utils"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 43295f024982..f608f8d23f3d 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -37,13 +37,15 @@ struct simple_card_data { unsigned int mclk_fs; struct asoc_simple_jack hp_jack; struct asoc_simple_jack mic_jack; - struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ + struct snd_soc_dai_link *dai_link; }; #define simple_priv_to_dev(priv) ((priv)->snd_card.dev) -#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i) -#define simple_priv_to_props(priv, i) ((priv)->dai_props + i) +#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i)) +#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) +#define DAI "sound-dai" +#define CELL "#sound-dai-cells" #define PREFIX "simple-audio-card," #define asoc_simple_card_init_hp(card, sjack, prefix)\ @@ -112,13 +114,13 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = - &priv->dai_props[rtd->num]; + simple_priv_to_props(priv, rtd->num); int ret; ret = clk_prepare_enable(dai_props->cpu_dai.clk); if (ret) return ret; - + ret = clk_prepare_enable(dai_props->codec_dai.clk); if (ret) clk_disable_unprepare(dai_props->cpu_dai.clk); @@ -131,7 +133,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = - &priv->dai_props[rtd->num]; + simple_priv_to_props(priv, rtd->num); clk_disable_unprepare(dai_props->cpu_dai.clk); @@ -145,7 +147,8 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = &priv->dai_props[rtd->num]; + struct simple_dai_props *dai_props = + simple_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; int ret = 0; @@ -177,51 +180,20 @@ static struct snd_soc_ops asoc_simple_card_ops = { .hw_params = asoc_simple_card_hw_params, }; -static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, - struct asoc_simple_dai *set) -{ - int ret; - - if (set->sysclk) { - ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0); - if (ret && ret != -ENOTSUPP) { - dev_err(dai->dev, "simple-card: set_sysclk error\n"); - goto err; - } - } - - if (set->slots) { - ret = snd_soc_dai_set_tdm_slot(dai, - set->tx_slot_mask, - set->rx_slot_mask, - set->slots, - set->slot_width); - if (ret && ret != -ENOTSUPP) { - dev_err(dai->dev, "simple-card: set_tdm_slot error\n"); - goto err; - } - } - - ret = 0; - -err: - return ret; -} - static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) { struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *codec = rtd->codec_dai; struct snd_soc_dai *cpu = rtd->cpu_dai; - struct simple_dai_props *dai_props; + struct simple_dai_props *dai_props = + simple_priv_to_props(priv, rtd->num); int ret; - dai_props = &priv->dai_props[rtd->num]; - ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai); + ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai); if (ret < 0) return ret; - ret = __asoc_simple_card_dai_init(cpu, &dai_props->cpu_dai); + ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai); if (ret < 0) return ret; @@ -236,78 +208,6 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static int -asoc_simple_card_sub_parse_of(struct device_node *np, - struct asoc_simple_dai *dai, - struct device_node **p_node, - const char **name, - int *args_count) -{ - struct of_phandle_args args; - struct clk *clk; - u32 val; - int ret; - - if (!np) - return 0; - - /* - * Get node via "sound-dai = <&phandle port>" - * it will be used as xxx_of_node on soc_bind_dai_link() - */ - ret = of_parse_phandle_with_args(np, "sound-dai", - "#sound-dai-cells", 0, &args); - if (ret) - return ret; - - *p_node = args.np; - - if (args_count) - *args_count = args.args_count; - - /* Get dai->name */ - if (name) { - ret = snd_soc_of_get_dai_name(np, name); - if (ret < 0) - return ret; - } - - if (!dai) - return 0; - - /* Parse TDM slot */ - ret = snd_soc_of_parse_tdm_slot(np, &dai->tx_slot_mask, - &dai->rx_slot_mask, - &dai->slots, &dai->slot_width); - if (ret) - return ret; - - /* - * Parse dai->sysclk come from "clocks = <&xxx>" - * (if system has common clock) - * or "system-clock-frequency = <xxx>" - * or device's module clock. - */ - if (of_property_read_bool(np, "clocks")) { - clk = of_clk_get(np, 0); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - return ret; - } - - dai->sysclk = clk_get_rate(clk); - dai->clk = clk; - } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { - dai->sysclk = val; - } else { - clk = of_clk_get(args.np, 0); - if (!IS_ERR(clk)) - dai->sysclk = clk_get_rate(clk); - } - - return 0; -} - static int asoc_simple_card_dai_link_of(struct device_node *node, struct simple_card_data *priv, int idx, @@ -316,13 +216,14 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); + struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai; + struct asoc_simple_dai *codec_dai = &dai_props->codec_dai; struct device_node *cpu = NULL; struct device_node *plat = NULL; struct device_node *codec = NULL; char prop[128]; char *prefix = ""; - int ret, cpu_args; - u32 val; + int ret, single_cpu; /* For single DAI link & old style of DT node */ if (is_top_level_node) @@ -348,36 +249,46 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, if (ret < 0) goto dai_link_of_err; - if (!of_property_read_u32(node, "mclk-fs", &val)) - dai_props->mclk_fs = val; + of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs); - ret = asoc_simple_card_sub_parse_of(cpu, &dai_props->cpu_dai, - &dai_link->cpu_of_node, - &dai_link->cpu_dai_name, - &cpu_args); + ret = asoc_simple_card_parse_cpu(cpu, dai_link, + DAI, CELL, &single_cpu); if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_card_sub_parse_of(codec, &dai_props->codec_dai, - &dai_link->codec_of_node, - &dai_link->codec_dai_name, NULL); + ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL); if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_card_sub_parse_of(plat, NULL, - &dai_link->platform_of_node, - NULL, NULL); + ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL); if (ret < 0) goto dai_link_of_err; - if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { - ret = -EINVAL; + ret = snd_soc_of_parse_tdm_slot(cpu, &cpu_dai->tx_slot_mask, + &cpu_dai->rx_slot_mask, + &cpu_dai->slots, + &cpu_dai->slot_width); + if (ret < 0) + goto dai_link_of_err; + + ret = snd_soc_of_parse_tdm_slot(codec, &codec_dai->tx_slot_mask, + &codec_dai->rx_slot_mask, + &codec_dai->slots, + &codec_dai->slot_width); + if (ret < 0) + goto dai_link_of_err; + + ret = asoc_simple_card_parse_clk_cpu(cpu, dai_link, cpu_dai); + if (ret < 0) goto dai_link_of_err; - } - /* Assumes platform == cpu */ - if (!dai_link->platform_of_node) - dai_link->platform_of_node = dai_link->cpu_of_node; + ret = asoc_simple_card_parse_clk_codec(codec, dai_link, codec_dai); + if (ret < 0) + goto dai_link_of_err; + + ret = asoc_simple_card_canonicalize_dailink(dai_link); + if (ret < 0) + goto dai_link_of_err; ret = asoc_simple_card_set_dailink_name(dev, dai_link, "%s-%s", @@ -398,17 +309,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, dai_link->codec_dai_name, dai_props->codec_dai.sysclk); - /* - * In soc_bind_dai_link() will check cpu name after - * of_node matching if dai_link has cpu_dai_name. - * but, it will never match if name was created by - * fmt_single_name() remove cpu_dai_name if cpu_args - * was 0. See: - * fmt_single_name() - * fmt_multiple_name() - */ - if (!cpu_args) - dai_link->cpu_dai_name = NULL; + asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); dai_link_of_err: of_node_put(cpu); @@ -417,22 +318,54 @@ dai_link_of_err: return ret; } +static int asoc_simple_card_parse_aux_devs(struct device_node *node, + struct simple_card_data *priv) +{ + struct device *dev = simple_priv_to_dev(priv); + struct device_node *aux_node; + int i, n, len; + + if (!of_find_property(node, PREFIX "aux-devs", &len)) + return 0; /* Ok to have no aux-devs */ + + n = len / sizeof(__be32); + if (n <= 0) + return -EINVAL; + + priv->snd_card.aux_dev = devm_kzalloc(dev, + n * sizeof(*priv->snd_card.aux_dev), GFP_KERNEL); + if (!priv->snd_card.aux_dev) + return -ENOMEM; + + for (i = 0; i < n; i++) { + aux_node = of_parse_phandle(node, PREFIX "aux-devs", i); + if (!aux_node) + return -EINVAL; + priv->snd_card.aux_dev[i].codec_of_node = aux_node; + } + + priv->snd_card.num_aux_devs = n; + return 0; +} + static int asoc_simple_card_parse_of(struct device_node *node, struct simple_card_data *priv) { struct device *dev = simple_priv_to_dev(priv); - u32 val; + struct device_node *dai_link; int ret; if (!node) return -EINVAL; + dai_link = of_get_child_by_name(node, PREFIX "dai-link"); + /* The off-codec widgets */ if (of_property_read_bool(node, PREFIX "widgets")) { ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, PREFIX "widgets"); if (ret) - return ret; + goto card_parse_end; } /* DAPM routes */ @@ -440,16 +373,14 @@ static int asoc_simple_card_parse_of(struct device_node *node, ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing"); if (ret) - return ret; + goto card_parse_end; } /* Factor to mclk, used in hw_params() */ - ret = of_property_read_u32(node, PREFIX "mclk-fs", &val); - if (ret == 0) - priv->mclk_fs = val; + of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs); /* Single/Muti DAI link(s) & New style of DT node */ - if (of_get_child_by_name(node, PREFIX "dai-link")) { + if (dai_link) { struct device_node *np = NULL; int i = 0; @@ -459,7 +390,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, i, false); if (ret < 0) { of_node_put(np); - return ret; + goto card_parse_end; } i++; } @@ -467,66 +398,55 @@ static int asoc_simple_card_parse_of(struct device_node *node, /* For single DAI link & old style of DT node */ ret = asoc_simple_card_dai_link_of(node, priv, 0, true); if (ret < 0) - return ret; + goto card_parse_end; } ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX); - if (ret) - return ret; + if (ret < 0) + goto card_parse_end; - return 0; -} + ret = asoc_simple_card_parse_aux_devs(node, priv); -/* Decrease the reference count of the device nodes */ -static int asoc_simple_card_unref(struct snd_soc_card *card) -{ - struct snd_soc_dai_link *dai_link; - int num_links; +card_parse_end: + of_node_put(dai_link); - for (num_links = 0, dai_link = card->dai_link; - num_links < card->num_links; - num_links++, dai_link++) { - of_node_put(dai_link->cpu_of_node); - of_node_put(dai_link->codec_of_node); - } - return 0; + return ret; } static int asoc_simple_card_probe(struct platform_device *pdev) { struct simple_card_data *priv; struct snd_soc_dai_link *dai_link; + struct simple_dai_props *dai_props; struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; - int num_links, ret; + int num, ret; /* Get the number of DAI links */ if (np && of_get_child_by_name(np, PREFIX "dai-link")) - num_links = of_get_child_count(np); + num = of_get_child_count(np); else - num_links = 1; + num = 1; /* Allocate the private data and the DAI link array */ - priv = devm_kzalloc(dev, - sizeof(*priv) + sizeof(*dai_link) * num_links, - GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - /* Init snd_soc_card */ - priv->snd_card.owner = THIS_MODULE; - priv->snd_card.dev = dev; - dai_link = priv->dai_link; - priv->snd_card.dai_link = dai_link; - priv->snd_card.num_links = num_links; - - /* Get room for the other properties */ - priv->dai_props = devm_kzalloc(dev, - sizeof(*priv->dai_props) * num_links, - GFP_KERNEL); - if (!priv->dai_props) + dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL); + dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL); + if (!dai_props || !dai_link) return -ENOMEM; + priv->dai_props = dai_props; + priv->dai_link = dai_link; + + /* Init snd_soc_card */ + priv->snd_card.owner = THIS_MODULE; + priv->snd_card.dev = dev; + priv->snd_card.dai_link = priv->dai_link; + priv->snd_card.num_links = num; + if (np && of_device_is_available(np)) { ret = asoc_simple_card_parse_of(np, priv); @@ -567,7 +487,6 @@ static int asoc_simple_card_probe(struct platform_device *pdev) sizeof(priv->dai_props->cpu_dai)); memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai, sizeof(priv->dai_props->codec_dai)); - } snd_soc_card_set_drvdata(&priv->snd_card, priv); @@ -575,9 +494,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); if (ret >= 0) return ret; - err: - asoc_simple_card_unref(&priv->snd_card); + asoc_simple_card_clean_reference(&priv->snd_card); + return ret; } @@ -589,7 +508,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev) asoc_simple_card_remove_jack(&priv->hp_jack); asoc_simple_card_remove_jack(&priv->mic_jack); - return asoc_simple_card_unref(card); + return asoc_simple_card_clean_reference(card); } static const struct of_device_id asoc_simple_of_match[] = { @@ -611,6 +530,6 @@ static struct platform_driver asoc_simple_card = { module_platform_driver(asoc_simple_card); MODULE_ALIAS("platform:asoc-simple-card"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("ASoC Simple Sound Card"); MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c new file mode 100644 index 000000000000..b9973a56bcb0 --- /dev/null +++ b/sound/soc/generic/simple-scu-card.c @@ -0,0 +1,345 @@ +/* + * ASoC simple SCU sound card support + * + * Copyright (C) 2015 Renesas Solutions Corp. + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * based on ${LINUX}/sound/soc/generic/simple-card.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <sound/jack.h> +#include <sound/soc.h> +#include <sound/soc-dai.h> +#include <sound/simple_card_utils.h> + +struct asoc_simple_card_priv { + struct snd_soc_card snd_card; + struct snd_soc_codec_conf codec_conf; + struct asoc_simple_dai *dai_props; + struct snd_soc_dai_link *dai_link; + u32 convert_rate; + u32 convert_channels; +}; + +#define simple_priv_to_dev(priv) ((priv)->snd_card.dev) +#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i)) +#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) + +#define DAI "sound-dai" +#define CELL "#sound-dai-cells" +#define PREFIX "simple-audio-card," + +static int asoc_simple_card_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct asoc_simple_dai *dai_props = + simple_priv_to_props(priv, rtd->num); + + return clk_prepare_enable(dai_props->clk); +} + +static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct asoc_simple_dai *dai_props = + simple_priv_to_props(priv, rtd->num); + + clk_disable_unprepare(dai_props->clk); +} + +static struct snd_soc_ops asoc_simple_card_ops = { + .startup = asoc_simple_card_startup, + .shutdown = asoc_simple_card_shutdown, +}; + +static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai; + struct snd_soc_dai_link *dai_link; + struct asoc_simple_dai *dai_props; + int num = rtd->num; + + dai_link = simple_priv_to_link(priv, num); + dai_props = simple_priv_to_props(priv, num); + dai = dai_link->dynamic ? + rtd->cpu_dai : + rtd->codec_dai; + + return asoc_simple_card_init_dai(dai, dai_props); +} + +static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + if (priv->convert_rate) + rate->min = + rate->max = priv->convert_rate; + + if (priv->convert_channels) + channels->min = + channels->max = priv->convert_channels; + + return 0; +} + +static int asoc_simple_card_parse_links(struct device_node *np, + struct asoc_simple_card_priv *priv, + unsigned int daifmt, + int idx, bool is_fe) +{ + struct device *dev = simple_priv_to_dev(priv); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); + struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, idx); + int ret; + + if (is_fe) { + int is_single_links = 0; + + /* BE is dummy */ + dai_link->codec_of_node = NULL; + dai_link->codec_dai_name = "snd-soc-dummy-dai"; + dai_link->codec_name = "snd-soc-dummy"; + + /* FE settings */ + dai_link->dynamic = 1; + dai_link->dpcm_merged_format = 1; + + ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, + &is_single_links); + if (ret) + return ret; + + ret = asoc_simple_card_parse_clk_cpu(np, dai_link, dai_props); + if (ret < 0) + return ret; + + ret = asoc_simple_card_set_dailink_name(dev, dai_link, + "fe.%s", + dai_link->cpu_dai_name); + if (ret < 0) + return ret; + + asoc_simple_card_canonicalize_cpu(dai_link, is_single_links); + } else { + /* FE is dummy */ + dai_link->cpu_of_node = NULL; + dai_link->cpu_dai_name = "snd-soc-dummy-dai"; + dai_link->cpu_name = "snd-soc-dummy"; + + /* BE settings */ + dai_link->no_pcm = 1; + dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; + + ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); + if (ret < 0) + return ret; + + ret = asoc_simple_card_parse_clk_codec(np, dai_link, dai_props); + if (ret < 0) + return ret; + + ret = asoc_simple_card_set_dailink_name(dev, dai_link, + "be.%s", + dai_link->codec_dai_name); + if (ret < 0) + return ret; + + snd_soc_of_parse_audio_prefix(&priv->snd_card, + &priv->codec_conf, + dai_link->codec_of_node, + PREFIX "prefix"); + } + + ret = snd_soc_of_parse_tdm_slot(np, + &dai_props->tx_slot_mask, + &dai_props->rx_slot_mask, + &dai_props->slots, + &dai_props->slot_width); + if (ret) + return ret; + + ret = asoc_simple_card_canonicalize_dailink(dai_link); + if (ret < 0) + return ret; + + dai_link->dai_fmt = daifmt; + dai_link->dpcm_playback = 1; + dai_link->dpcm_capture = 1; + dai_link->ops = &asoc_simple_card_ops; + dai_link->init = asoc_simple_card_dai_init; + + dev_dbg(dev, "\t%s / %04x / %d\n", + dai_link->name, + dai_link->dai_fmt, + dai_props->sysclk); + + return 0; +} + +static int asoc_simple_card_dai_link_of(struct device_node *node, + struct asoc_simple_card_priv *priv) +{ + struct device *dev = simple_priv_to_dev(priv); + struct device_node *np; + unsigned int daifmt = 0; + int ret, i; + bool is_fe; + + /* find 1st codec */ + np = of_get_child_by_name(node, PREFIX "codec"); + if (!np) + return -ENODEV; + + ret = asoc_simple_card_parse_daifmt(dev, node, np, + PREFIX, &daifmt); + if (ret < 0) + return ret; + + i = 0; + for_each_child_of_node(node, np) { + is_fe = false; + if (strcmp(np->name, PREFIX "cpu") == 0) + is_fe = true; + + ret = asoc_simple_card_parse_links(np, priv, daifmt, i, is_fe); + if (ret < 0) + return ret; + i++; + } + + return 0; +} + +static int asoc_simple_card_parse_of(struct device_node *node, + struct asoc_simple_card_priv *priv, + struct device *dev) +{ + struct asoc_simple_dai *props; + struct snd_soc_dai_link *links; + int ret; + int num; + + if (!node) + return -EINVAL; + + num = of_get_child_count(node); + props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL); + links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL); + if (!props || !links) + return -ENOMEM; + + priv->dai_props = props; + priv->dai_link = links; + + /* Init snd_soc_card */ + priv->snd_card.owner = THIS_MODULE; + priv->snd_card.dev = dev; + priv->snd_card.dai_link = priv->dai_link; + priv->snd_card.num_links = num; + priv->snd_card.codec_conf = &priv->codec_conf; + priv->snd_card.num_configs = 1; + + ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing"); + if (ret < 0) + return ret; + + /* sampling rate convert */ + of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate); + + /* channels transfer */ + of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels); + + ret = asoc_simple_card_dai_link_of(node, priv); + if (ret < 0) + return ret; + + ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX); + if (ret < 0) + return ret; + + dev_dbg(dev, "New card: %s\n", + priv->snd_card.name ? priv->snd_card.name : ""); + dev_dbg(dev, "convert_rate %d\n", priv->convert_rate); + dev_dbg(dev, "convert_channels %d\n", priv->convert_channels); + + return 0; +} + +static int asoc_simple_card_probe(struct platform_device *pdev) +{ + struct asoc_simple_card_priv *priv; + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + int ret; + + /* Allocate the private data */ + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + ret = asoc_simple_card_parse_of(np, priv, dev); + if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "parse error %d\n", ret); + goto err; + } + + snd_soc_card_set_drvdata(&priv->snd_card, priv); + + ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); + if (ret >= 0) + return ret; +err: + asoc_simple_card_clean_reference(&priv->snd_card); + + return ret; +} + +static int asoc_simple_card_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + return asoc_simple_card_clean_reference(card); +} + +static const struct of_device_id asoc_simple_of_match[] = { + { .compatible = "renesas,rsrc-card", }, + { .compatible = "simple-scu-audio-card", }, + {}, +}; +MODULE_DEVICE_TABLE(of, asoc_simple_of_match); + +static struct platform_driver asoc_simple_card = { + .driver = { + .name = "simple-scu-audio-card", + .of_match_table = asoc_simple_of_match, + }, + .probe = asoc_simple_card_probe, + .remove = asoc_simple_card_remove, +}; + +module_platform_driver(asoc_simple_card); + +MODULE_ALIAS("platform:asoc-simple-scu-card"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ASoC Simple SCU Sound Card"); +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c index 162a0fd68c7b..53e11c6d4e22 100644 --- a/sound/soc/img/pistachio-internal-dac.c +++ b/sound/soc/img/pistachio-internal-dac.c @@ -134,12 +134,14 @@ static int pistachio_internal_dac_codec_probe(struct snd_soc_codec *codec) static const struct snd_soc_codec_driver pistachio_internal_dac_driver = { .probe = pistachio_internal_dac_codec_probe, .idle_bias_off = true, - .controls = pistachio_internal_dac_snd_controls, - .num_controls = ARRAY_SIZE(pistachio_internal_dac_snd_controls), - .dapm_widgets = pistachio_internal_dac_widgets, - .num_dapm_widgets = ARRAY_SIZE(pistachio_internal_dac_widgets), - .dapm_routes = pistachio_internal_dac_routes, - .num_dapm_routes = ARRAY_SIZE(pistachio_internal_dac_routes), + .component_driver = { + .controls = pistachio_internal_dac_snd_controls, + .num_controls = ARRAY_SIZE(pistachio_internal_dac_snd_controls), + .dapm_widgets = pistachio_internal_dac_widgets, + .num_dapm_widgets = ARRAY_SIZE(pistachio_internal_dac_widgets), + .dapm_routes = pistachio_internal_dac_routes, + .num_dapm_routes = ARRAY_SIZE(pistachio_internal_dac_routes), + }, }; static int pistachio_internal_dac_probe(struct platform_device *pdev) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index a20c3dfbcb5d..26eb5a0a5575 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -25,6 +25,7 @@ config SND_SST_IPC_ACPI tristate select SND_SST_IPC select SND_SOC_INTEL_SST + select IOSF_MBI config SND_SOC_INTEL_SST tristate @@ -120,6 +121,17 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH This adds audio driver for Intel Baytrail platform based boards with the MAX98090 audio codec. +config SND_SOC_INTEL_BDW_RT5677_MACH + tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec" + depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC + depends on DW_DMAC_CORE=y + select SND_SOC_INTEL_SST + select SND_SOC_INTEL_HASWELL + select SND_SOC_RT5677 + help + This adds support for Intel Broadwell platform based boards with + the RT5677 audio codec. + config SND_SOC_INTEL_BROADWELL_MACH tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 98720a93de8a..0838478c4c3f 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -1,4 +1,4 @@ -/* + /* * sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld * * Copyright (C) 2013-14 Intel Corp @@ -534,6 +534,7 @@ static const DECLARE_TLV_DB_SCALE(sst_gain_tlv_common, SST_GAIN_MIN_VALUE * 10, /* Look up table to convert MIXER SW bit regs to SWM inputs */ static const uint swm_mixer_input_ids[SST_SWM_INPUT_COUNT] = { + [SST_IP_MODEM] = SST_SWM_IN_MODEM, [SST_IP_CODEC0] = SST_SWM_IN_CODEC0, [SST_IP_CODEC1] = SST_SWM_IN_CODEC1, [SST_IP_LOOP0] = SST_SWM_IN_SPROT_LOOP, @@ -674,6 +675,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w, /* SBA mixers - 16 inputs */ #define SST_SBA_DECLARE_MIX_CONTROLS(kctl_name) \ static const struct snd_kcontrol_new kctl_name[] = { \ + SOC_DAPM_SINGLE("modem_in Switch", SND_SOC_NOPM, SST_IP_MODEM, 1, 0), \ SOC_DAPM_SINGLE("codec_in0 Switch", SND_SOC_NOPM, SST_IP_CODEC0, 1, 0), \ SOC_DAPM_SINGLE("codec_in1 Switch", SND_SOC_NOPM, SST_IP_CODEC1, 1, 0), \ SOC_DAPM_SINGLE("sprot_loop_in Switch", SND_SOC_NOPM, SST_IP_LOOP0, 1, 0), \ @@ -684,6 +686,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w, } #define SST_SBA_MIXER_GRAPH_MAP(mix_name) \ + { mix_name, "modem_in Switch", "modem_in" }, \ { mix_name, "codec_in0 Switch", "codec_in0" }, \ { mix_name, "codec_in1 Switch", "codec_in1" }, \ { mix_name, "sprot_loop_in Switch", "sprot_loop_in" }, \ @@ -713,6 +716,7 @@ SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l2_controls); SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_voip_controls); SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec0_controls); SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec1_controls); +SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_modem_controls); /* * sst_handle_vb_timer - Start/Stop the DSP scheduler @@ -931,17 +935,26 @@ void sst_fill_ssp_defaults(struct snd_soc_dai *dai) int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) { struct sst_data *drv = snd_soc_dai_get_drvdata(dai); - const struct sst_ssp_config *config; + int ssp_id; dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); + if (strcmp(id, "ssp0-port") == 0) + ssp_id = SSP_MODEM; + else if (strcmp(id, "ssp2-port") == 0) + ssp_id = SSP_CODEC; + else { + dev_dbg(dai->dev, "port %s is not supported\n", id); + return -1; + } + SST_FILL_DEFAULT_DESTINATION(drv->ssp_cmd.header.dst); drv->ssp_cmd.header.command_id = SBA_HW_SET_SSP; drv->ssp_cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp) - sizeof(struct sst_dsp_header); - config = &sst_ssp_configs; - dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id); + drv->ssp_cmd.selection = ssp_id; + dev_dbg(dai->dev, "ssp_id: %u\n", ssp_id); if (enable) drv->ssp_cmd.switch_state = SST_SWITCH_ON; @@ -1047,8 +1060,10 @@ static int sst_set_media_loop(struct snd_soc_dapm_widget *w, } static const struct snd_soc_dapm_widget sst_dapm_widgets[] = { + SST_AIF_IN("modem_in", sst_set_be_modules), SST_AIF_IN("codec_in0", sst_set_be_modules), SST_AIF_IN("codec_in1", sst_set_be_modules), + SST_AIF_OUT("modem_out", sst_set_be_modules), SST_AIF_OUT("codec_out0", sst_set_be_modules), SST_AIF_OUT("codec_out1", sst_set_be_modules), @@ -1103,6 +1118,9 @@ static const struct snd_soc_dapm_widget sst_dapm_widgets[] = { sst_mix_codec0_controls, sst_swm_mixer_event), SST_SWM_MIXER("codec_out1 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC1, sst_mix_codec1_controls, sst_swm_mixer_event), + SST_SWM_MIXER("modem_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_MODEM, + sst_mix_modem_controls, sst_swm_mixer_event), + }; static const struct snd_soc_dapm_route intercon[] = { @@ -1148,6 +1166,9 @@ static const struct snd_soc_dapm_route intercon[] = { SST_SBA_MIXER_GRAPH_MAP("codec_out0 mix 0"), {"codec_out1", NULL, "codec_out1 mix 0"}, SST_SBA_MIXER_GRAPH_MAP("codec_out1 mix 0"), + {"modem_out", NULL, "modem_out mix 0"}, + SST_SBA_MIXER_GRAPH_MAP("modem_out mix 0"), + }; static const char * const slot_names[] = { @@ -1217,6 +1238,9 @@ static const struct snd_kcontrol_new sst_gain_controls[] = { SST_GAIN("media_loop2_out", SST_PATH_INDEX_MEDIA_LOOP2_OUT, SST_TASK_SBA, 0, &sst_gains[13]), SST_GAIN("sprot_loop_out", SST_PATH_INDEX_SPROT_LOOP_OUT, SST_TASK_SBA, 0, &sst_gains[14]), SST_VOLUME("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[15]), + SST_GAIN("modem_in", SST_PATH_INDEX_MODEM_IN, SST_TASK_SBA, 0, &sst_gains[16]), + SST_GAIN("modem_out", SST_PATH_INDEX_MODEM_OUT, SST_TASK_SBA, 0, &sst_gains[17]), + }; #define SST_GAIN_NUM_CONTROLS 3 diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h index e0113112f668..351d81469685 100644 --- a/sound/soc/intel/atom/sst-atom-controls.h +++ b/sound/soc/intel/atom/sst-atom-controls.h @@ -35,6 +35,8 @@ enum { /* define a bit for each mixer input */ #define SST_MIX_IP(x) (x) +#define SST_IP_MODEM SST_MIX_IP(0) +#define SST_IP_BT SST_MIX_IP(1) #define SST_IP_CODEC0 SST_MIX_IP(2) #define SST_IP_CODEC1 SST_MIX_IP(3) #define SST_IP_LOOP0 SST_MIX_IP(4) @@ -63,6 +65,7 @@ enum { * Audio DSP Path Ids. Specified by the audio DSP FW */ enum sst_path_index { + SST_PATH_INDEX_MODEM_OUT = (0x00 << SST_PATH_ID_SHIFT), SST_PATH_INDEX_CODEC_OUT0 = (0x02 << SST_PATH_ID_SHIFT), SST_PATH_INDEX_CODEC_OUT1 = (0x03 << SST_PATH_ID_SHIFT), @@ -80,6 +83,7 @@ enum sst_path_index { /* Start of input paths */ + SST_PATH_INDEX_MODEM_IN = (0x80 << SST_PATH_ID_SHIFT), SST_PATH_INDEX_CODEC_IN0 = (0x82 << SST_PATH_ID_SHIFT), SST_PATH_INDEX_CODEC_IN1 = (0x83 << SST_PATH_ID_SHIFT), @@ -105,6 +109,7 @@ enum sst_path_index { * path IDs */ enum sst_swm_inputs { + SST_SWM_IN_MODEM = (SST_PATH_INDEX_MODEM_IN | SST_DEFAULT_CELL_NBR), SST_SWM_IN_CODEC0 = (SST_PATH_INDEX_CODEC_IN0 | SST_DEFAULT_CELL_NBR), SST_SWM_IN_CODEC1 = (SST_PATH_INDEX_CODEC_IN1 | SST_DEFAULT_CELL_NBR), SST_SWM_IN_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_IN | SST_DEFAULT_CELL_NBR), @@ -124,6 +129,7 @@ enum sst_swm_inputs { * path IDs */ enum sst_swm_outputs { + SST_SWM_OUT_MODEM = (SST_PATH_INDEX_MODEM_OUT | SST_DEFAULT_CELL_NBR), SST_SWM_OUT_CODEC0 = (SST_PATH_INDEX_CODEC_OUT0 | SST_DEFAULT_CELL_NBR), SST_SWM_OUT_CODEC1 = (SST_PATH_INDEX_CODEC_OUT1 | SST_DEFAULT_CELL_NBR), SST_SWM_OUT_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_OUT | SST_DEFAULT_CELL_NBR), diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 52ed434cbca6..25c6d87c818e 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -670,7 +670,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer return str_info->buffer_ptr; } -static struct snd_pcm_ops sst_platform_ops = { +static const struct snd_pcm_ops sst_platform_ops = { .open = sst_platform_open, .ioctl = snd_pcm_lib_ioctl, .trigger = sst_platform_pcm_trigger, diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index a4b458e77089..9b6e27385dc9 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -190,7 +190,8 @@ int sst_driver_ops(struct intel_sst_drv *sst) default: dev_err(sst->dev, - "SST Driver capablities missing for dev_id: %x", sst->dev_id); + "SST Driver capabilities missing for dev_id: %x", + sst->dev_id); return -EINVAL; }; } @@ -441,7 +442,7 @@ static int intel_sst_suspend(struct device *dev) struct stream_info *stream = &ctx->streams[i]; if (stream->status == STREAM_RUNNING) { - dev_err(dev, "stream %d is running, cant susupend, abort\n", i); + dev_err(dev, "stream %d is running, can't suspend, abort\n", i); return -EBUSY; } } diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 4d3184971227..ba5c0d71720a 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -39,6 +39,8 @@ #include <acpi/platform/aclinux.h> #include <acpi/actypes.h> #include <acpi/acpi_bus.h> +#include <asm/cpu_device_id.h> +#include <asm/iosf_mbi.h> #include "../sst-mfld-platform.h" #include "../../common/sst-dsp.h" #include "../../common/sst-acpi.h" @@ -113,6 +115,28 @@ static const struct sst_res_info byt_rvp_res_info = { .acpi_ipc_irq_index = 5, }; +/* BYTCR has different BIOS from BYT */ +static const struct sst_res_info bytcr_res_info = { + .shim_offset = 0x140000, + .shim_size = 0x000100, + .shim_phy_addr = SST_BYT_SHIM_PHY_ADDR, + .ssp0_offset = 0xa0000, + .ssp0_size = 0x1000, + .dma0_offset = 0x98000, + .dma0_size = 0x4000, + .dma1_offset = 0x9c000, + .dma1_size = 0x4000, + .iram_offset = 0x0c0000, + .iram_size = 0x14000, + .dram_offset = 0x100000, + .dram_size = 0x28000, + .mbox_offset = 0x144000, + .mbox_size = 0x1000, + .acpi_lpe_res_index = 0, + .acpi_ddr_index = 2, + .acpi_ipc_irq_index = 0 +}; + static struct sst_platform_info byt_rvp_platform_data = { .probe_data = &byt_fwparse_info, .ipc_info = &byt_ipc_info, @@ -142,7 +166,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) rsrc = platform_get_resource(pdev, IORESOURCE_MEM, ctx->pdata->res_info->acpi_lpe_res_index); if (!rsrc) { - dev_err(ctx->dev, "Invalid SHIM base from IFWI"); + dev_err(ctx->dev, "Invalid SHIM base from IFWI\n"); return -EIO; } dev_info(ctx->dev, "LPE base: %#x size:%#x", (unsigned int) rsrc->start, @@ -154,7 +178,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) ctx->iram = devm_ioremap_nocache(ctx->dev, ctx->iram_base, ctx->pdata->res_info->iram_size); if (!ctx->iram) { - dev_err(ctx->dev, "unable to map IRAM"); + dev_err(ctx->dev, "unable to map IRAM\n"); return -EIO; } @@ -164,7 +188,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) ctx->dram = devm_ioremap_nocache(ctx->dev, ctx->dram_base, ctx->pdata->res_info->dram_size); if (!ctx->dram) { - dev_err(ctx->dev, "unable to map DRAM"); + dev_err(ctx->dev, "unable to map DRAM\n"); return -EIO; } @@ -173,7 +197,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) ctx->shim = devm_ioremap_nocache(ctx->dev, ctx->shim_phy_add, ctx->pdata->res_info->shim_size); if (!ctx->shim) { - dev_err(ctx->dev, "unable to map SHIM"); + dev_err(ctx->dev, "unable to map SHIM\n"); return -EIO; } @@ -186,7 +210,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) ctx->mailbox = devm_ioremap_nocache(ctx->dev, ctx->mailbox_add, ctx->pdata->res_info->mbox_size); if (!ctx->mailbox) { - dev_err(ctx->dev, "unable to map mailbox"); + dev_err(ctx->dev, "unable to map mailbox\n"); return -EIO; } @@ -196,7 +220,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) rsrc = platform_get_resource(pdev, IORESOURCE_MEM, ctx->pdata->res_info->acpi_ddr_index); if (!rsrc) { - dev_err(ctx->dev, "Invalid DDR base from IFWI"); + dev_err(ctx->dev, "Invalid DDR base from IFWI\n"); return -EIO; } ctx->ddr_base = rsrc->start; @@ -205,7 +229,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) ctx->ddr = devm_ioremap_nocache(ctx->dev, ctx->ddr_base, resource_size(rsrc)); if (!ctx->ddr) { - dev_err(ctx->dev, "unable to map DDR"); + dev_err(ctx->dev, "unable to map DDR\n"); return -EIO; } @@ -215,6 +239,46 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) return 0; } + +static int is_byt_cr(struct device *dev, bool *bytcr) +{ + int status = 0; + + if (IS_ENABLED(CONFIG_IOSF_MBI)) { + static const struct x86_cpu_id cpu_ids[] = { + { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ + {} + }; + u32 bios_status; + + if (!x86_match_cpu(cpu_ids) || !iosf_mbi_available()) { + /* bail silently */ + return status; + } + + status = iosf_mbi_read(BT_MBI_UNIT_PMC, /* 0x04 PUNIT */ + MBI_REG_READ, /* 0x10 */ + 0x006, /* BIOS_CONFIG */ + &bios_status); + + if (status) { + dev_err(dev, "could not read PUNIT BIOS_CONFIG\n"); + } else { + /* bits 26:27 mirror PMIC options */ + bios_status = (bios_status >> 26) & 3; + + if ((bios_status == 1) || (bios_status == 3)) + *bytcr = true; + else + dev_info(dev, "BYT-CR not detected\n"); + } + } else { + dev_info(dev, "IOSF_MBI not enabled, no BYT-CR detection\n"); + } + return status; +} + + static int sst_acpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -226,11 +290,12 @@ static int sst_acpi_probe(struct platform_device *pdev) struct platform_device *plat_dev; struct sst_platform_info *pdata; unsigned int dev_id; + bool bytcr = false; id = acpi_match_device(dev->driver->acpi_match_table, dev); if (!id) return -ENODEV; - dev_dbg(dev, "for %s", id->id); + dev_dbg(dev, "for %s\n", id->id); mach = (struct sst_acpi_mach *)id->driver_data; mach = sst_acpi_find_machine(mach); @@ -251,6 +316,18 @@ static int sst_acpi_probe(struct platform_device *pdev) dev_dbg(dev, "ACPI device id: %x\n", dev_id); + ret = sst_alloc_drv_context(&ctx, dev, dev_id); + if (ret < 0) + return ret; + + ret = is_byt_cr(dev, &bytcr); + if (!((ret < 0) || (bytcr == false))) { + dev_info(dev, "Detected Baytrail-CR platform\n"); + + /* override resource info */ + byt_rvp_platform_data.res_info = &bytcr_res_info; + } + plat_dev = platform_device_register_data(dev, pdata->platform, -1, NULL, 0); if (IS_ERR(plat_dev)) { @@ -271,10 +348,6 @@ static int sst_acpi_probe(struct platform_device *pdev) return PTR_ERR(mdev); } - ret = sst_alloc_drv_context(&ctx, dev, dev_id); - if (ret < 0) - return ret; - /* Fill sst platform data */ ctx->pdata = pdata; strcpy(ctx->firmware_name, mach->fw_filename); diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index 8afa6fe7b0b0..bfc889950bb2 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -267,6 +267,9 @@ static void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx, "Period elapsed rcvd for pipe id 0x%x\n", pipe_id); stream = &sst_drv_ctx->streams[str_id]; + /* If stream is dropped, skip processing this message*/ + if (stream->status == STREAM_INIT) + break; if (stream->period_elapsed) stream->period_elapsed(stream->pcm_substream); if (stream->compr_cb) diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index adb32fefd693..b1e6b8f34a6a 100644 --- a/sound/soc/intel/atom/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c @@ -279,17 +279,15 @@ int sst_prepare_and_post_msg(struct intel_sst_drv *sst, if (response) { ret = sst_wait_timeout(sst, block); - if (ret < 0) { + if (ret < 0) goto out; - } else if(block->data) { - if (!data) - goto out; - *data = kzalloc(block->size, GFP_KERNEL); - if (!(*data)) { + + if (data && block->data) { + *data = kmemdup(block->data, block->size, GFP_KERNEL); + if (!*data) { ret = -ENOMEM; goto out; - } else - memcpy(data, (void *) block->data, block->size); + } } } out: diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index dac03a06bfd8..5639f10774e6 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -1,6 +1,7 @@ snd-soc-sst-haswell-objs := haswell.o snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o +snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o snd-soc-sst-bxt-rt298-objs := bxt_rt298.o @@ -19,6 +20,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o +obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c new file mode 100644 index 000000000000..547e6705bf6d --- /dev/null +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -0,0 +1,347 @@ +/* + * ASoC machine driver for Intel Broadwell platforms with RT5677 codec + * + * Copyright (c) 2014, The Chromium OS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/gpio/consumer.h> +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/soc.h> +#include <sound/pcm_params.h> +#include <sound/jack.h> + +#include "../common/sst-dsp.h" +#include "../haswell/sst-haswell-ipc.h" + +#include "../../codecs/rt5677.h" + +struct bdw_rt5677_priv { + struct gpio_desc *gpio_hp_en; + struct snd_soc_codec *codec; +}; + +static int bdw_rt5677_event_hp(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card); + + if (SND_SOC_DAPM_EVENT_ON(event)) + msleep(70); + + gpiod_set_value_cansleep(bdw_rt5677->gpio_hp_en, + SND_SOC_DAPM_EVENT_ON(event)); + + return 0; +} + +static const struct snd_soc_dapm_widget bdw_rt5677_widgets[] = { + SND_SOC_DAPM_HP("Headphone", bdw_rt5677_event_hp), + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Local DMICs", NULL), + SND_SOC_DAPM_MIC("Remote DMICs", NULL), +}; + +static const struct snd_soc_dapm_route bdw_rt5677_map[] = { + /* Speakers */ + {"Speaker", NULL, "PDM1L"}, + {"Speaker", NULL, "PDM1R"}, + + /* Headset jack connectors */ + {"Headphone", NULL, "LOUT1"}, + {"Headphone", NULL, "LOUT2"}, + {"IN1P", NULL, "Headset Mic"}, + {"IN1N", NULL, "Headset Mic"}, + + /* Digital MICs + * Local DMICs: the two DMICs on the mainboard + * Remote DMICs: the two DMICs on the camera module + */ + {"DMIC L1", NULL, "Remote DMICs"}, + {"DMIC R1", NULL, "Remote DMICs"}, + {"DMIC L2", NULL, "Local DMICs"}, + {"DMIC R2", NULL, "Local DMICs"}, + + /* CODEC BE connections */ + {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, + {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, +}; + +static const struct snd_kcontrol_new bdw_rt5677_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Local DMICs"), + SOC_DAPM_PIN_SWITCH("Remote DMICs"), +}; + + +static struct snd_soc_jack headphone_jack; +static struct snd_soc_jack mic_jack; + +static struct snd_soc_jack_pin headphone_jack_pin = { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, +}; + +static struct snd_soc_jack_pin mic_jack_pin = { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, +}; + +static struct snd_soc_jack_gpio headphone_jack_gpio = { + .name = "plug-det", + .report = SND_JACK_HEADPHONE, + .debounce_time = 200, +}; + +static struct snd_soc_jack_gpio mic_jack_gpio = { + .name = "mic-present", + .report = SND_JACK_MICROPHONE, + .debounce_time = 200, + .invert = 1, +}; + +static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + /* The ADSP will covert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP0 to 16 bit */ + snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - + SNDRV_PCM_HW_PARAM_FIRST_MASK], + SNDRV_PCM_FORMAT_S16_LE); + return 0; +} + +static int bdw_rt5677_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_MCLK, 24576000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec sysclk configuration\n"); + return ret; + } + + return ret; +} + +static struct snd_soc_ops bdw_rt5677_ops = { + .hw_params = bdw_rt5677_hw_params, +}; + +static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd) +{ + struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev); + struct sst_hsw *broadwell = pdata->dsp; + int ret; + + /* Set ADSP SSP port settings */ + ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0, + SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, + SST_HSW_DEVICE_CLOCK_MASTER, 9); + if (ret < 0) { + dev_err(rtd->dev, "error: failed to set device config\n"); + return ret; + } + + return 0; +} + +static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) +{ + struct bdw_rt5677_priv *bdw_rt5677 = + snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + + /* Enable codec ASRC function for Stereo DAC/Stereo1 ADC/DMIC/I2S1. + * The ASRC clock source is clk_i2s1_asrc. + */ + rt5677_sel_asrc_clk_src(codec, RT5677_DA_STEREO_FILTER | + RT5677_AD_STEREO1_FILTER | RT5677_I2S1_SOURCE, + RT5677_CLK_SEL_I2S1_ASRC); + + /* Request rt5677 GPIO for headphone amp control */ + bdw_rt5677->gpio_hp_en = devm_gpiod_get_index(codec->dev, + "headphone-enable", 0, 0); + if (IS_ERR(bdw_rt5677->gpio_hp_en)) { + dev_err(codec->dev, "Can't find HP_AMP_SHDN_L gpio\n"); + return PTR_ERR(bdw_rt5677->gpio_hp_en); + } + gpiod_direction_output(bdw_rt5677->gpio_hp_en, 0); + + /* Create and initialize headphone jack */ + if (!snd_soc_card_jack_new(rtd->card, "Headphone Jack", + SND_JACK_HEADPHONE, &headphone_jack, + &headphone_jack_pin, 1)) { + headphone_jack_gpio.gpiod_dev = codec->dev; + if (snd_soc_jack_add_gpios(&headphone_jack, 1, + &headphone_jack_gpio)) + dev_err(codec->dev, "Can't add headphone jack gpio\n"); + } else { + dev_err(codec->dev, "Can't create headphone jack\n"); + } + + /* Create and initialize mic jack */ + if (!snd_soc_card_jack_new(rtd->card, "Mic Jack", + SND_JACK_MICROPHONE, &mic_jack, + &mic_jack_pin, 1)) { + mic_jack_gpio.gpiod_dev = codec->dev; + if (snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio)) + dev_err(codec->dev, "Can't add mic jack gpio\n"); + } else { + dev_err(codec->dev, "Can't create mic jack\n"); + } + bdw_rt5677->codec = codec; + + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); + return 0; +} + +/* broadwell digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link bdw_rt5677_dais[] = { + /* Front End DAI links */ + { + .name = "System PCM", + .stream_name = "System Playback/Capture", + .cpu_dai_name = "System Pin", + .platform_name = "haswell-pcm-audio", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .init = bdw_rt5677_rtd_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST + }, + .dpcm_capture = 1, + .dpcm_playback = 1, + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "Codec", + .id = 0, + .cpu_dai_name = "snd-soc-dummy-dai", + .platform_name = "snd-soc-dummy", + .no_pcm = 1, + .codec_name = "i2c-RT5677CE:00", + .codec_dai_name = "rt5677-aif1", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = broadwell_ssp0_fixup, + .ops = &bdw_rt5677_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = bdw_rt5677_init, + }, +}; + +static int bdw_rt5677_suspend_pre(struct snd_soc_card *card) +{ + struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card); + struct snd_soc_dapm_context *dapm; + + if (bdw_rt5677->codec) { + dapm = snd_soc_codec_get_dapm(bdw_rt5677->codec); + snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); + } + return 0; +} + +static int bdw_rt5677_resume_post(struct snd_soc_card *card) +{ + struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card); + struct snd_soc_dapm_context *dapm; + + if (bdw_rt5677->codec) { + dapm = snd_soc_codec_get_dapm(bdw_rt5677->codec); + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); + } + return 0; +} + +/* ASoC machine driver for Broadwell DSP + RT5677 */ +static struct snd_soc_card bdw_rt5677_card = { + .name = "bdw-rt5677", + .owner = THIS_MODULE, + .dai_link = bdw_rt5677_dais, + .num_links = ARRAY_SIZE(bdw_rt5677_dais), + .dapm_widgets = bdw_rt5677_widgets, + .num_dapm_widgets = ARRAY_SIZE(bdw_rt5677_widgets), + .dapm_routes = bdw_rt5677_map, + .num_dapm_routes = ARRAY_SIZE(bdw_rt5677_map), + .controls = bdw_rt5677_controls, + .num_controls = ARRAY_SIZE(bdw_rt5677_controls), + .fully_routed = true, + .suspend_pre = bdw_rt5677_suspend_pre, + .resume_post = bdw_rt5677_resume_post, +}; + +static int bdw_rt5677_probe(struct platform_device *pdev) +{ + struct bdw_rt5677_priv *bdw_rt5677; + + bdw_rt5677_card.dev = &pdev->dev; + + /* Allocate driver private struct */ + bdw_rt5677 = devm_kzalloc(&pdev->dev, sizeof(struct bdw_rt5677_priv), + GFP_KERNEL); + if (!bdw_rt5677) { + dev_err(&pdev->dev, "Can't allocate bdw_rt5677\n"); + return -ENOMEM; + } + + snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677); + + return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card); +} + +static struct platform_driver bdw_rt5677_audio = { + .probe = bdw_rt5677_probe, + .driver = { + .name = "bdw-rt5677", + }, +}; + +module_platform_driver(bdw_rt5677_audio) + +/* Module information */ +MODULE_AUTHOR("Ben Zhang"); +MODULE_DESCRIPTION("Intel Broadwell RT5677 machine driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bdw-rt5677"); diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 3774b117d365..6532b8f0ab2f 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -37,6 +37,7 @@ enum { BXT_DPCM_AUDIO_PB = 0, BXT_DPCM_AUDIO_CP, BXT_DPCM_AUDIO_REF_CP, + BXT_DPCM_AUDIO_DMIC_CP, BXT_DPCM_AUDIO_HDMI1_PB, BXT_DPCM_AUDIO_HDMI2_PB, BXT_DPCM_AUDIO_HDMI3_PB, @@ -252,10 +253,56 @@ static struct snd_soc_ops broxton_da7219_ops = { .hw_free = broxton_da7219_hw_free, }; +static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + channels->min = channels->max = DUAL_CHANNEL; + + return 0; +} + +static int broxton_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static const struct snd_soc_ops broxton_dmic_ops = { + .startup = broxton_dmic_startup, +}; + +static const unsigned int rates_16000[] = { + 16000, +}; + +static const struct snd_pcm_hw_constraint_list constraints_16000 = { + .count = ARRAY_SIZE(rates_16000), + .list = rates_16000, +}; + +static int broxton_refcap_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_16000); +}; + +static struct snd_soc_ops broxton_refcap_ops = { + .startup = broxton_refcap_startup, +}; + /* broxton digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link broxton_dais[] = { /* Front End DAI links */ - [BXT_DPCM_AUDIO_PB] + [BXT_DPCM_AUDIO_PB] = { .name = "Bxt Audio Port", .stream_name = "Audio", @@ -271,7 +318,7 @@ static struct snd_soc_dai_link broxton_dais[] = { .dpcm_playback = 1, .ops = &broxton_da7219_fe_ops, }, - [BXT_DPCM_AUDIO_CP] + [BXT_DPCM_AUDIO_CP] = { .name = "Bxt Audio Capture Port", .stream_name = "Audio Record", @@ -286,7 +333,7 @@ static struct snd_soc_dai_link broxton_dais[] = { .dpcm_capture = 1, .ops = &broxton_da7219_fe_ops, }, - [BXT_DPCM_AUDIO_REF_CP] + [BXT_DPCM_AUDIO_REF_CP] = { .name = "Bxt Audio Reference cap", .stream_name = "Refcap", @@ -299,8 +346,23 @@ static struct snd_soc_dai_link broxton_dais[] = { .ignore_suspend = 1, .nonatomic = 1, .dynamic = 1, + .ops = &broxton_refcap_ops, + }, + [BXT_DPCM_AUDIO_DMIC_CP] + { + .name = "Bxt Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:0e.0", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &broxton_dmic_ops, }, - [BXT_DPCM_AUDIO_HDMI1_PB] + [BXT_DPCM_AUDIO_HDMI1_PB] = { .name = "Bxt HDMI Port1", .stream_name = "Hdmi1", @@ -313,7 +375,7 @@ static struct snd_soc_dai_link broxton_dais[] = { .nonatomic = 1, .dynamic = 1, }, - [BXT_DPCM_AUDIO_HDMI2_PB] + [BXT_DPCM_AUDIO_HDMI2_PB] = { .name = "Bxt HDMI Port2", .stream_name = "Hdmi2", @@ -326,7 +388,7 @@ static struct snd_soc_dai_link broxton_dais[] = { .nonatomic = 1, .dynamic = 1, }, - [BXT_DPCM_AUDIO_HDMI3_PB] + [BXT_DPCM_AUDIO_HDMI3_PB] = { .name = "Bxt HDMI Port3", .stream_name = "Hdmi3", @@ -382,6 +444,7 @@ static struct snd_soc_dai_link broxton_dais[] = { .codec_dai_name = "dmic-hifi", .platform_name = "0000:00:0e.0", .ignore_suspend = 1, + .be_hw_params_fixup = broxton_dmic_fixup, .dpcm_capture = 1, .no_pcm = 1, }, diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 253d7bfbf511..d610bdca1608 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -271,7 +271,7 @@ static const struct snd_soc_ops broxton_rt286_fe_ops = { /* broxton digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link broxton_rt298_dais[] = { /* Front End DAI links */ - [BXT_DPCM_AUDIO_PB] + [BXT_DPCM_AUDIO_PB] = { .name = "Bxt Audio Port", .stream_name = "Audio", @@ -286,7 +286,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { .dpcm_playback = 1, .ops = &broxton_rt286_fe_ops, }, - [BXT_DPCM_AUDIO_CP] + [BXT_DPCM_AUDIO_CP] = { .name = "Bxt Audio Capture Port", .stream_name = "Audio Record", @@ -300,7 +300,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { .dpcm_capture = 1, .ops = &broxton_rt286_fe_ops, }, - [BXT_DPCM_AUDIO_REF_CP] + [BXT_DPCM_AUDIO_REF_CP] = { .name = "Bxt Audio Reference cap", .stream_name = "refcap", @@ -313,7 +313,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { .nonatomic = 1, .dynamic = 1, }, - [BXT_DPCM_AUDIO_DMIC_CP] + [BXT_DPCM_AUDIO_DMIC_CP] = { .name = "Bxt Audio DMIC cap", .stream_name = "dmiccap", @@ -327,7 +327,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { .dynamic = 1, .ops = &broxton_dmic_ops, }, - [BXT_DPCM_AUDIO_HDMI1_PB] + [BXT_DPCM_AUDIO_HDMI1_PB] = { .name = "Bxt HDMI Port1", .stream_name = "Hdmi1", @@ -340,7 +340,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { .nonatomic = 1, .dynamic = 1, }, - [BXT_DPCM_AUDIO_HDMI2_PB] + [BXT_DPCM_AUDIO_HDMI2_PB] = { .name = "Bxt HDMI Port2", .stream_name = "Hdmi2", @@ -353,7 +353,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { .nonatomic = 1, .dynamic = 1, }, - [BXT_DPCM_AUDIO_HDMI3_PB] + [BXT_DPCM_AUDIO_HDMI3_PB] = { .name = "Bxt HDMI Port3", .stream_name = "Hdmi3", diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 88efb62439ba..bff77a1f27fc 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -24,6 +24,9 @@ #include <linux/device.h> #include <linux/dmi.h> #include <linux/slab.h> +#include <asm/cpu_device_id.h> +#include <asm/platform_sst_audio.h> +#include <linux/clk.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -31,42 +34,153 @@ #include "../../codecs/rt5640.h" #include "../atom/sst-atom-controls.h" #include "../common/sst-acpi.h" +#include "../common/sst-dsp.h" enum { BYT_RT5640_DMIC1_MAP, BYT_RT5640_DMIC2_MAP, BYT_RT5640_IN1_MAP, + BYT_RT5640_IN3_MAP, }; #define BYT_RT5640_MAP(quirk) ((quirk) & 0xff) #define BYT_RT5640_DMIC_EN BIT(16) +#define BYT_RT5640_MONO_SPEAKER BIT(17) +#define BYT_RT5640_DIFF_MIC BIT(18) /* defaut is single-ended */ +#define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */ +#define BYT_RT5640_SSP0_AIF1 BIT(20) +#define BYT_RT5640_SSP0_AIF2 BIT(21) +#define BYT_RT5640_MCLK_EN BIT(22) +#define BYT_RT5640_MCLK_25MHZ BIT(23) + +struct byt_rt5640_private { + struct clk *mclk; +}; static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | - BYT_RT5640_DMIC_EN; + BYT_RT5640_DMIC_EN | + BYT_RT5640_MCLK_EN; + +static void log_quirks(struct device *dev) +{ + if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_DMIC1_MAP) + dev_info(dev, "quirk DMIC1_MAP enabled"); + if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_DMIC2_MAP) + dev_info(dev, "quirk DMIC2_MAP enabled"); + if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_IN1_MAP) + dev_info(dev, "quirk IN1_MAP enabled"); + if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_IN3_MAP) + dev_info(dev, "quirk IN3_MAP enabled"); + if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) + dev_info(dev, "quirk DMIC enabled"); + if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) + dev_info(dev, "quirk MONO_SPEAKER enabled"); + if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) + dev_info(dev, "quirk DIFF_MIC enabled"); + if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) + dev_info(dev, "quirk SSP2_AIF2 enabled"); + if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) + dev_info(dev, "quirk SSP0_AIF1 enabled"); + if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2) + dev_info(dev, "quirk SSP0_AIF2 enabled"); + if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) + dev_info(dev, "quirk MCLK_EN enabled"); + if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) + dev_info(dev, "quirk MCLK_25MHZ enabled"); +} + + +#define BYT_CODEC_DAI1 "rt5640-aif1" +#define BYT_CODEC_DAI2 "rt5640-aif2" + +static inline struct snd_soc_dai *byt_get_codec_dai(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI1, + strlen(BYT_CODEC_DAI1))) + return rtd->codec_dai; + if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI2, + strlen(BYT_CODEC_DAI2))) + return rtd->codec_dai; + + } + return NULL; +} + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); + int ret; + + codec_dai = byt_get_codec_dai(card); + if (!codec_dai) { + dev_err(card->dev, + "Codec dai not found; Unable to set platform clock\n"); + return -EIO; + } + + if (SND_SOC_DAPM_EVENT_ON(event)) { + if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) { + ret = clk_prepare_enable(priv->mclk); + if (ret < 0) { + dev_err(card->dev, + "could not configure MCLK state"); + return ret; + } + } + ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, + 48000 * 512, + SND_SOC_CLOCK_IN); + } else { + /* + * Set codec clock source to internal clock before + * turning off the platform clock. Codec needs clock + * for Jack detection and button press + */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_RCCLK, + 0, + SND_SOC_CLOCK_IN); + if (!ret) { + if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) + clk_disable_unprepare(priv->mclk); + } + } + + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); + return ret; + } + + return 0; +} static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Internal Mic", NULL), SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + }; static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { - {"AIF1 Playback", NULL, "ssp2 Tx"}, - {"ssp2 Tx", NULL, "codec_out0"}, - {"ssp2 Tx", NULL, "codec_out1"}, - {"codec_in0", NULL, "ssp2 Rx"}, - {"codec_in1", NULL, "ssp2 Rx"}, - {"ssp2 Rx", NULL, "AIF1 Capture"}, + {"Headphone", NULL, "Platform Clock"}, + {"Headset Mic", NULL, "Platform Clock"}, + {"Internal Mic", NULL, "Platform Clock"}, + {"Speaker", NULL, "Platform Clock"}, {"Headset Mic", NULL, "MICBIAS1"}, {"IN2P", NULL, "Headset Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, - {"Speaker", NULL, "SPOLP"}, - {"Speaker", NULL, "SPOLN"}, - {"Speaker", NULL, "SPORP"}, - {"Speaker", NULL, "SPORN"}, }; static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { @@ -82,6 +196,59 @@ static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { {"IN1P", NULL, "Internal Mic"}, }; +static const struct snd_soc_dapm_route byt_rt5640_intmic_in3_map[] = { + {"Internal Mic", NULL, "MICBIAS1"}, + {"IN3P", NULL, "Internal Mic"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_ssp2_aif1_map[] = { + {"ssp2 Tx", NULL, "codec_out0"}, + {"ssp2 Tx", NULL, "codec_out1"}, + {"codec_in0", NULL, "ssp2 Rx"}, + {"codec_in1", NULL, "ssp2 Rx"}, + + {"AIF1 Playback", NULL, "ssp2 Tx"}, + {"ssp2 Rx", NULL, "AIF1 Capture"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_ssp2_aif2_map[] = { + {"ssp2 Tx", NULL, "codec_out0"}, + {"ssp2 Tx", NULL, "codec_out1"}, + {"codec_in0", NULL, "ssp2 Rx"}, + {"codec_in1", NULL, "ssp2 Rx"}, + + {"AIF2 Playback", NULL, "ssp2 Tx"}, + {"ssp2 Rx", NULL, "AIF2 Capture"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_ssp0_aif1_map[] = { + {"ssp0 Tx", NULL, "modem_out"}, + {"modem_in", NULL, "ssp0 Rx"}, + + {"AIF1 Playback", NULL, "ssp0 Tx"}, + {"ssp0 Rx", NULL, "AIF1 Capture"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_ssp0_aif2_map[] = { + {"ssp0 Tx", NULL, "modem_out"}, + {"modem_in", NULL, "ssp0 Rx"}, + + {"AIF2 Playback", NULL, "ssp0 Tx"}, + {"ssp0 Rx", NULL, "AIF2 Capture"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_stereo_spk_map[] = { + {"Speaker", NULL, "SPOLP"}, + {"Speaker", NULL, "SPOLN"}, + {"Speaker", NULL, "SPORP"}, + {"Speaker", NULL, "SPORN"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_mono_spk_map[] = { + {"Speaker", NULL, "SPOLP"}, + {"Speaker", NULL, "SPOLN"}, +}; + static const struct snd_kcontrol_new byt_rt5640_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -96,19 +263,46 @@ static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; int ret; - snd_soc_dai_set_bclk_ratio(codec_dai, 50); - ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, params_rate(params) * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { dev_err(rtd->dev, "can't set codec clock %d\n", ret); return ret; } - ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1, - params_rate(params) * 50, - params_rate(params) * 512); + if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) { + /* use bitclock as PLL input */ + if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || + (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { + + /* 2x16 bit slots on SSP0 */ + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5640_PLL1_S_BCLK1, + params_rate(params) * 32, + params_rate(params) * 512); + } else { + /* 2x15 bit slots on SSP2 */ + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5640_PLL1_S_BCLK1, + params_rate(params) * 50, + params_rate(params) * 512); + } + } else { + if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) { + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5640_PLL1_S_MCLK, + 25000000, + params_rate(params) * 512); + } else { + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5640_PLL1_S_MCLK, + 19200000, + params_rate(params) * 512); + } + } + if (ret < 0) { dev_err(rtd->dev, "can't set codec pll: %d\n", ret); return ret; @@ -127,27 +321,73 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { { .callback = byt_rt5640_quirk_cb, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), + }, + .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_MCLK_EN), + }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"), }, - .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, + .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF2 | + BYT_RT5640_MCLK_EN + ), }, { .callback = byt_rt5640_quirk_cb, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "DellInc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "DellInc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), }, .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP | + BYT_RT5640_DMIC_EN | + BYT_RT5640_MCLK_EN), + }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"), + }, + .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_MCLK_EN), + }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), + DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), + }, + .driver_data = (unsigned long *)(BYT_RT5640_DMIC1_MAP | BYT_RT5640_DMIC_EN), }, { .callback = byt_rt5640_quirk_cb, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"), + DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"), + DMI_MATCH(DMI_BOARD_NAME, "tPAD"), }, - .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, + .driver_data = (unsigned long *)(BYT_RT5640_IN3_MAP | + BYT_RT5640_MCLK_EN | + BYT_RT5640_SSP0_AIF1), + }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), + }, + .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_MCLK_EN | + BYT_RT5640_SSP0_AIF1), + }, {} }; @@ -158,13 +398,18 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_codec *codec = runtime->codec; struct snd_soc_card *card = runtime->card; const struct snd_soc_dapm_route *custom_map; + struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); int num_routes; card->dapm.idle_bias_off = true; rt5640_sel_asrc_clk_src(codec, RT5640_DA_STEREO_FILTER | - RT5640_AD_STEREO_FILTER, + RT5640_DA_MONO_L_FILTER | + RT5640_DA_MONO_R_FILTER | + RT5640_AD_STEREO_FILTER | + RT5640_AD_MONO_L_FILTER | + RT5640_AD_MONO_R_FILTER, RT5640_CLK_SEL_ASRC); ret = snd_soc_add_card_controls(card, byt_rt5640_controls, @@ -179,6 +424,10 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) custom_map = byt_rt5640_intmic_in1_map; num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map); break; + case BYT_RT5640_IN3_MAP: + custom_map = byt_rt5640_intmic_in3_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_in3_map); + break; case BYT_RT5640_DMIC2_MAP: custom_map = byt_rt5640_intmic_dmic2_map; num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map); @@ -192,6 +441,43 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret; + if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) { + ret = snd_soc_dapm_add_routes(&card->dapm, + byt_rt5640_ssp2_aif2_map, + ARRAY_SIZE(byt_rt5640_ssp2_aif2_map)); + } else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) { + ret = snd_soc_dapm_add_routes(&card->dapm, + byt_rt5640_ssp0_aif1_map, + ARRAY_SIZE(byt_rt5640_ssp0_aif1_map)); + } else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2) { + ret = snd_soc_dapm_add_routes(&card->dapm, + byt_rt5640_ssp0_aif2_map, + ARRAY_SIZE(byt_rt5640_ssp0_aif2_map)); + } else { + ret = snd_soc_dapm_add_routes(&card->dapm, + byt_rt5640_ssp2_aif1_map, + ARRAY_SIZE(byt_rt5640_ssp2_aif1_map)); + } + if (ret) + return ret; + + if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) { + ret = snd_soc_dapm_add_routes(&card->dapm, + byt_rt5640_mono_spk_map, + ARRAY_SIZE(byt_rt5640_mono_spk_map)); + } else { + ret = snd_soc_dapm_add_routes(&card->dapm, + byt_rt5640_stereo_spk_map, + ARRAY_SIZE(byt_rt5640_stereo_spk_map)); + } + if (ret) + return ret; + + if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) { + snd_soc_update_bits(codec, RT5640_IN1_IN2, RT5640_IN_DF1, + RT5640_IN_DF1); + } + if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { ret = rt5640_dmic_enable(codec, 0, 0); if (ret) @@ -201,6 +487,30 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); + if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) { + /* + * The firmware might enable the clock at + * boot (this information may or may not + * be reflected in the enable clock register). + * To change the rate we must disable the clock + * first to cover these cases. Due to common + * clock framework restrictions that do not allow + * to disable a clock that has not been enabled, + * we need to enable the clock first. + */ + ret = clk_prepare_enable(priv->mclk); + if (!ret) + clk_disable_unprepare(priv->mclk); + + if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) + ret = clk_set_rate(priv->mclk, 25000000); + else + ret = clk_set_rate(priv->mclk, 19200000); + + if (ret) + dev_err(card->dev, "unable to set MCLK rate\n"); + } + return ret; } @@ -221,34 +531,63 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_CHANNELS); int ret; - /* The DSP will covert the FE rate to 48k, stereo, 24bits */ + /* The DSP will covert the FE rate to 48k, stereo */ rate->min = rate->max = 48000; channels->min = channels->max = 2; - /* set SSP2 to 24-bit */ - params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || + (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { + + /* set SSP0 to 16-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + + /* + * Default mode for SSP configuration is TDM 4 slot, override config + * with explicit setting to I2S 2ch 16-bit. The word length is set with + * dai_set_tdm_slot() since there is no other API exposed + */ + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_CBS_CFS + ); + if (ret < 0) { + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); + return ret; + } - /* - * Default mode for SSP configuration is TDM 4 slot, override config - * with explicit setting to I2S 2ch 24-bit. The word length is set with - * dai_set_tdm_slot() since there is no other API exposed - */ - ret = snd_soc_dai_set_fmt(rtd->cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_IF | - SND_SOC_DAIFMT_CBS_CFS - ); - if (ret < 0) { - dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); - return ret; - } + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } - ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); - if (ret < 0) { - dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); - return ret; - } + } else { + + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + + /* + * Default mode for SSP configuration is TDM 4 slot, override config + * with explicit setting to I2S 2ch 24-bit. The word length is set with + * dai_set_tdm_slot() since there is no other API exposed + */ + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_CBS_CFS + ); + if (ret < 0) { + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); + return ret; + } + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } + } return 0; } @@ -305,10 +644,10 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { { .name = "SSP2-Codec", .id = 1, - .cpu_dai_name = "ssp2-port", + .cpu_dai_name = "ssp2-port", /* overwritten for ssp0 routing */ .platform_name = "sst-mfld-platform", .no_pcm = 1, - .codec_dai_name = "rt5640-aif1", + .codec_dai_name = "rt5640-aif1", /* changed w/ quirk */ .codec_name = "i2c-10EC5640:00", /* overwritten with HID */ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, @@ -335,6 +674,21 @@ static struct snd_soc_card byt_rt5640_card = { }; static char byt_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */ +static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ +static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ + +static bool is_valleyview(void) +{ + static const struct x86_cpu_id cpu_ids[] = { + { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ + {} + }; + + if (!x86_match_cpu(cpu_ids)) + return false; + return true; +} + static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { @@ -343,10 +697,16 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) const char *i2c_name = NULL; int i; int dai_index; + struct byt_rt5640_private *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); + if (!priv) + return -ENOMEM; /* register the soc card */ byt_rt5640_card.dev = &pdev->dev; mach = byt_rt5640_card.dev->platform_data; + snd_soc_card_set_drvdata(&byt_rt5640_card, priv); /* fix index of codec dai */ dai_index = MERR_DPCM_COMPR + 1; @@ -366,8 +726,57 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) byt_rt5640_dais[dai_index].codec_name = byt_rt5640_codec_name; } + /* + * swap SSP0 if bytcr is detected + * (will be overridden if DMI quirk is detected) + */ + if (is_valleyview()) { + struct sst_platform_info *p_info = mach->pdata; + const struct sst_res_info *res_info = p_info->res_info; + + /* TODO: use CHAN package info from BIOS to detect AIF1/AIF2 */ + if (res_info->acpi_ipc_irq_index == 0) { + byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; + } + } + /* check quirks before creating card */ dmi_check_system(byt_rt5640_quirk_table); + log_quirks(&pdev->dev); + + if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) || + (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { + + /* fixup codec aif name */ + snprintf(byt_rt5640_codec_aif_name, + sizeof(byt_rt5640_codec_aif_name), + "%s", "rt5640-aif2"); + + byt_rt5640_dais[dai_index].codec_dai_name = + byt_rt5640_codec_aif_name; + } + + if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || + (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { + + /* fixup cpu dai name name */ + snprintf(byt_rt5640_cpu_dai_name, + sizeof(byt_rt5640_cpu_dai_name), + "%s", "ssp0-port"); + + byt_rt5640_dais[dai_index].cpu_dai_name = + byt_rt5640_cpu_dai_name; + } + + if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && (is_valleyview())) { + priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + if (IS_ERR(priv->mclk)) { + dev_err(&pdev->dev, + "Failed to get MCLK from pmc_plt_clk_3: %ld\n", + PTR_ERR(priv->mclk)); + return PTR_ERR(priv->mclk); + } + } ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c index 2c5eda14d510..1285cc597b6b 100644 --- a/sound/soc/intel/common/sst-acpi.c +++ b/sound/soc/intel/common/sst-acpi.c @@ -199,6 +199,7 @@ static struct sst_acpi_desc sst_acpi_haswell_desc = { static struct sst_acpi_mach broadwell_machines[] = { { "INT343A", "broadwell-audio", "intel/IntcSST2.bin", NULL, NULL, NULL }, + { "RT5677CE", "bdw-rt5677", "intel/IntcSST2.bin", NULL, NULL, NULL }, {} }; diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index 3154525c2b83..9e4094e2c6e3 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -871,7 +871,7 @@ out: return ret; } -static struct snd_pcm_ops hsw_pcm_ops = { +static const struct snd_pcm_ops hsw_pcm_ops = { .open = hsw_pcm_open, .close = hsw_pcm_close, .ioctl = snd_pcm_lib_ioctl, diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 2663781278aa..1d251d59bcb9 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -23,6 +23,7 @@ #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" #include "skl-sst-ipc.h" +#include "skl-tplg-interface.h" #define BXT_BASEFW_TIMEOUT 3000 #define BXT_INIT_TIMEOUT 500 @@ -40,11 +41,73 @@ #define BXT_INSTANCE_ID 0 #define BXT_BASE_FW_MODULE_ID 0 +#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000 + static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) { return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); } +static int +bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo) +{ + struct snd_dma_buffer dmab; + struct skl_sst *skl = ctx->thread_context; + const struct firmware *fw = NULL; + struct firmware stripped_fw; + int ret = 0, i, dma_id, stream_tag; + + /* library indices start from 1 to N. 0 represents base FW */ + for (i = 1; i < minfo->lib_count; i++) { + ret = request_firmware(&fw, minfo->lib[i].name, ctx->dev); + if (ret < 0) { + dev_err(ctx->dev, "Request lib %s failed:%d\n", + minfo->lib[i].name, ret); + return ret; + } + + if (skl->is_first_boot) { + ret = snd_skl_parse_uuids(ctx, fw, + BXT_ADSP_FW_BIN_HDR_OFFSET, i); + if (ret < 0) + goto load_library_failed; + } + + stripped_fw.data = fw->data; + stripped_fw.size = fw->size; + skl_dsp_strip_extended_manifest(&stripped_fw); + + stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, + stripped_fw.size, &dmab); + if (stream_tag <= 0) { + dev_err(ctx->dev, "Lib prepare DMA err: %x\n", + stream_tag); + ret = stream_tag; + goto load_library_failed; + } + + dma_id = stream_tag - 1; + memcpy(dmab.area, stripped_fw.data, stripped_fw.size); + + ctx->dsp_ops.trigger(ctx->dev, true, stream_tag); + ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i); + if (ret < 0) + dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n", + minfo->lib[i].name, ret); + + ctx->dsp_ops.trigger(ctx->dev, false, stream_tag); + ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag); + release_firmware(fw); + fw = NULL; + } + + return ret; + +load_library_failed: + release_firmware(fw); + return ret; +} + /* * First boot sequence has some extra steps. Core 0 waits for power * status on core 1, so power up core 1 also momentarily, keep it in @@ -157,8 +220,6 @@ static int sst_transfer_fw_host_dma(struct sst_dsp *ctx) return ret; } -#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000 - static int bxt_load_base_firmware(struct sst_dsp *ctx) { struct firmware stripped_fw; @@ -175,9 +236,12 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx) if (ctx->fw == NULL) goto sst_load_base_firmware_failed; - ret = snd_skl_parse_uuids(ctx, BXT_ADSP_FW_BIN_HDR_OFFSET); - if (ret < 0) - goto sst_load_base_firmware_failed; + /* prase uuids on first boot */ + if (skl->is_first_boot) { + ret = snd_skl_parse_uuids(ctx, ctx->fw, BXT_ADSP_FW_BIN_HDR_OFFSET, 0); + if (ret < 0) + goto sst_load_base_firmware_failed; + } stripped_fw.data = ctx->fw->data; stripped_fw.size = ctx->fw->size; @@ -230,12 +294,23 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) int ret; struct skl_ipc_dxstate_info dx; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); + struct skl_dfw_manifest *minfo = &skl->manifest; if (skl->fw_loaded == false) { skl->boot_complete = false; ret = bxt_load_base_firmware(ctx); - if (ret < 0) + if (ret < 0) { dev_err(ctx->dev, "reload fw failed: %d\n", ret); + return ret; + } + + if (minfo->lib_count > 1) { + ret = bxt_load_library(ctx, minfo); + if (ret < 0) { + dev_err(ctx->dev, "reload libs failed: %d\n", ret); + return ret; + } + } return ret; } @@ -329,7 +404,7 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) ret = skl_dsp_disable_core(ctx, core_mask); if (ret < 0) { - dev_err(ctx->dev, "Failed to disable core %d", ret); + dev_err(ctx->dev, "Failed to disable core %d\n", ret); return ret; } skl->cores.state[core_id] = SKL_DSP_RESET; @@ -341,6 +416,7 @@ static struct skl_dsp_fw_ops bxt_fw_ops = { .set_state_D3 = bxt_set_dsp_D3, .load_fw = bxt_load_base_firmware, .get_fw_errcode = bxt_get_errorcode, + .load_library = bxt_load_library, }; static struct sst_ops skl_ops = { @@ -397,22 +473,40 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, skl->cores.count = 2; skl->boot_complete = false; init_waitqueue_head(&skl->boot_wait); + skl->is_first_boot = true; + + if (dsp) + *dsp = skl; + + return 0; +} +EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); + +int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx) +{ + int ret; + struct sst_dsp *sst = ctx->dsp; ret = sst->fw_ops.load_fw(sst); if (ret < 0) { - dev_err(dev, "Load base fw failed: %x", ret); + dev_err(dev, "Load base fw failed: %x\n", ret); return ret; } skl_dsp_init_core_state(sst); - if (dsp) - *dsp = skl; + if (ctx->manifest.lib_count > 1) { + ret = sst->fw_ops.load_library(sst, &ctx->manifest); + if (ret < 0) { + dev_err(dev, "Load Library failed : %x\n", ret); + return ret; + } + } + ctx->is_first_boot = false; return 0; } -EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); - +EXPORT_SYMBOL_GPL(bxt_sst_init_fw); void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) { diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 44ab595ce21a..805b7f2173f3 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -203,32 +203,35 @@ static const struct skl_dsp_ops dsp_ops[] = { .id = 0x9d70, .loader_ops = skl_get_loader_ops, .init = skl_sst_dsp_init, + .init_fw = skl_sst_init_fw, .cleanup = skl_sst_dsp_cleanup }, { .id = 0x9d71, .loader_ops = skl_get_loader_ops, .init = skl_sst_dsp_init, + .init_fw = skl_sst_init_fw, .cleanup = skl_sst_dsp_cleanup }, { .id = 0x5a98, .loader_ops = bxt_get_loader_ops, .init = bxt_sst_dsp_init, + .init_fw = bxt_sst_init_fw, .cleanup = bxt_sst_dsp_cleanup }, }; -static int skl_get_dsp_ops(int pci_id) +const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) { int i; for (i = 0; i < ARRAY_SIZE(dsp_ops); i++) { if (dsp_ops[i].id == pci_id) - return i; + return &dsp_ops[i]; } - return -EINVAL; + return NULL; } int skl_init_dsp(struct skl *skl) @@ -238,7 +241,8 @@ int skl_init_dsp(struct skl *skl) struct hdac_bus *bus = ebus_to_hbus(ebus); struct skl_dsp_loader_ops loader_ops; int irq = bus->irq; - int ret, index; + const struct skl_dsp_ops *ops; + int ret; /* enable ppcap interrupt */ snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true); @@ -251,18 +255,18 @@ int skl_init_dsp(struct skl *skl) return -ENXIO; } - index = skl_get_dsp_ops(skl->pci->device); - if (index < 0) - return -EINVAL; + ops = skl_get_dsp_ops(skl->pci->device); + if (!ops) + return -EIO; - loader_ops = dsp_ops[index].loader_ops(); - ret = dsp_ops[index].init(bus->dev, mmio_base, irq, - skl->fw_name, loader_ops, &skl->skl_sst); + loader_ops = ops->loader_ops(); + ret = ops->init(bus->dev, mmio_base, irq, + skl->fw_name, loader_ops, + &skl->skl_sst); if (ret < 0) return ret; - skl_dsp_enable_notification(skl->skl_sst, false); dev_dbg(bus->dev, "dsp registration status=%d\n", ret); return ret; @@ -273,16 +277,16 @@ int skl_free_dsp(struct skl *skl) struct hdac_ext_bus *ebus = &skl->ebus; struct hdac_bus *bus = ebus_to_hbus(ebus); struct skl_sst *ctx = skl->skl_sst; - int index; + const struct skl_dsp_ops *ops; /* disable ppcap interrupt */ snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false); - index = skl_get_dsp_ops(skl->pci->device); - if (index < 0) + ops = skl_get_dsp_ops(skl->pci->device); + if (!ops) return -EIO; - dsp_ops[index].cleanup(bus->dev, ctx); + ops->cleanup(bus->dev, ctx); if (ctx->dsp->addr.lpe) iounmap(ctx->dsp->addr.lpe); @@ -296,7 +300,7 @@ int skl_suspend_dsp(struct skl *skl) int ret; /* if ppcap is not supported return 0 */ - if (!skl->ebus.ppcap) + if (!skl->ebus.bus.ppcap) return 0; ret = skl_dsp_sleep(ctx->dsp); @@ -316,13 +320,17 @@ int skl_resume_dsp(struct skl *skl) int ret; /* if ppcap is not supported return 0 */ - if (!skl->ebus.ppcap) + if (!skl->ebus.bus.ppcap) return 0; /* enable ppcap interrupt */ snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true); snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true); + /* check if DSP 1st boot is done */ + if (skl->skl_sst->is_first_boot == true) + return 0; + ret = skl_dsp_wake(ctx->dsp); if (ret < 0) return ret; @@ -672,6 +680,7 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx, return param_size; case SKL_MODULE_TYPE_BASE_OUTFMT: + case SKL_MODULE_TYPE_KPB: return sizeof(struct skl_base_outfmt_cfg); default: @@ -725,6 +734,7 @@ static int skl_set_module_format(struct skl_sst *ctx, break; case SKL_MODULE_TYPE_BASE_OUTFMT: + case SKL_MODULE_TYPE_KPB: skl_set_base_outfmt_format(ctx, module_config, *param_data); break; @@ -779,6 +789,7 @@ static int skl_alloc_queue(struct skl_module_pin *mpin, mpin[i].in_use = true; mpin[i].id.module_id = id.module_id; mpin[i].id.instance_id = id.instance_id; + mpin[i].id.pvt_id = id.pvt_id; mpin[i].tgt_mcfg = tgt_cfg; return i; } @@ -802,6 +813,7 @@ static void skl_free_queue(struct skl_module_pin *mpin, int q_index) mpin[q_index].in_use = false; mpin[q_index].id.module_id = 0; mpin[q_index].id.instance_id = 0; + mpin[q_index].id.pvt_id = 0; } mpin[q_index].pin_state = SKL_PIN_UNBIND; mpin[q_index].tgt_mcfg = NULL; @@ -842,7 +854,7 @@ int skl_init_module(struct skl_sst *ctx, struct skl_ipc_init_instance_msg msg; dev_dbg(ctx->dev, "%s: module_id = %d instance=%d\n", __func__, - mconfig->id.module_id, mconfig->id.instance_id); + mconfig->id.module_id, mconfig->id.pvt_id); if (mconfig->pipe->state != SKL_PIPE_CREATED) { dev_err(ctx->dev, "Pipe not created state= %d pipe_id= %d\n", @@ -858,10 +870,11 @@ int skl_init_module(struct skl_sst *ctx, } msg.module_id = mconfig->id.module_id; - msg.instance_id = mconfig->id.instance_id; + msg.instance_id = mconfig->id.pvt_id; msg.ppl_instance_id = mconfig->pipe->ppl_id; msg.param_data_size = module_config_size; msg.core_id = mconfig->core_id; + msg.domain = mconfig->domain; ret = skl_ipc_init_instance(&ctx->ipc, &msg, param_data); if (ret < 0) { @@ -878,9 +891,9 @@ static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg *src_module, struct skl_module_cfg *dst_module) { dev_dbg(ctx->dev, "%s: src module_id = %d src_instance=%d\n", - __func__, src_module->id.module_id, src_module->id.instance_id); + __func__, src_module->id.module_id, src_module->id.pvt_id); dev_dbg(ctx->dev, "%s: dst_module=%d dst_instacne=%d\n", __func__, - dst_module->id.module_id, dst_module->id.instance_id); + dst_module->id.module_id, dst_module->id.pvt_id); dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n", src_module->m_state, dst_module->m_state); @@ -927,9 +940,9 @@ int skl_unbind_modules(struct skl_sst *ctx, return 0; msg.module_id = src_mcfg->id.module_id; - msg.instance_id = src_mcfg->id.instance_id; + msg.instance_id = src_mcfg->id.pvt_id; msg.dst_module_id = dst_mcfg->id.module_id; - msg.dst_instance_id = dst_mcfg->id.instance_id; + msg.dst_instance_id = dst_mcfg->id.pvt_id; msg.bind = false; ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); @@ -988,9 +1001,9 @@ int skl_bind_modules(struct skl_sst *ctx, msg.src_queue, msg.dst_queue); msg.module_id = src_mcfg->id.module_id; - msg.instance_id = src_mcfg->id.instance_id; + msg.instance_id = src_mcfg->id.pvt_id; msg.dst_module_id = dst_mcfg->id.module_id; - msg.dst_instance_id = dst_mcfg->id.instance_id; + msg.dst_instance_id = dst_mcfg->id.pvt_id; msg.bind = true; ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); @@ -1168,7 +1181,7 @@ int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, struct skl_ipc_large_config_msg msg; msg.module_id = mcfg->id.module_id; - msg.instance_id = mcfg->id.instance_id; + msg.instance_id = mcfg->id.pvt_id; msg.param_data_size = size; msg.large_param_id = param_id; @@ -1181,7 +1194,7 @@ int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, struct skl_ipc_large_config_msg msg; msg.module_id = mcfg->id.module_id; - msg.instance_id = mcfg->id.instance_id; + msg.instance_id = mcfg->id.pvt_id; msg.param_data_size = size; msg.large_param_id = param_id; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 6e05bf8622f7..58c728662600 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -106,7 +106,7 @@ static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus, static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *ebus) { - if (ebus->ppcap) + if ((ebus_to_hbus(ebus))->ppcap) return HDAC_EXT_STREAM_TYPE_HOST; else return HDAC_EXT_STREAM_TYPE_COUPLED; @@ -188,7 +188,7 @@ static int skl_get_format(struct snd_pcm_substream *substream, struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); int format_val = 0; - if (ebus->ppcap) { + if ((ebus_to_hbus(ebus))->ppcap) { struct snd_pcm_runtime *runtime = substream->runtime; format_val = snd_hdac_calc_stream_format(runtime->rate, @@ -648,7 +648,8 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .channels_min = HDA_MONO, .channels_max = HDA_STEREO, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { .stream_name = "System Capture", @@ -1020,7 +1021,7 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, { struct hdac_ext_bus *ebus = get_bus_ctx(substream); - if (!ebus->ppcap) + if (!(ebus_to_hbus(ebus))->ppcap) return skl_coupled_trigger(substream, cmd); return 0; @@ -1093,7 +1094,7 @@ static int skl_get_time_info(struct snd_pcm_substream *substream, return 0; } -static struct snd_pcm_ops skl_platform_ops = { +static const struct snd_pcm_ops skl_platform_ops = { .open = skl_platform_open, .ioctl = snd_pcm_lib_ioctl, .trigger = skl_platform_pcm_trigger, @@ -1138,20 +1139,67 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) return retval; } +static int skl_populate_modules(struct skl *skl) +{ + struct skl_pipeline *p; + struct skl_pipe_module *m; + struct snd_soc_dapm_widget *w; + struct skl_module_cfg *mconfig; + int ret; + + list_for_each_entry(p, &skl->ppl_list, node) { + list_for_each_entry(m, &p->pipe->w_list, node) { + + w = m->w; + mconfig = w->priv; + + ret = snd_skl_get_module_info(skl->skl_sst, mconfig); + if (ret < 0) { + dev_err(skl->skl_sst->dev, + "query module info failed:%d\n", ret); + goto err; + } + } + } +err: + return ret; +} + static int skl_platform_soc_probe(struct snd_soc_platform *platform) { struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev); struct skl *skl = ebus_to_skl(ebus); + const struct skl_dsp_ops *ops; int ret; - if (ebus->ppcap) { + pm_runtime_get_sync(platform->dev); + if ((ebus_to_hbus(ebus))->ppcap) { ret = skl_tplg_init(platform, ebus); if (ret < 0) { dev_err(platform->dev, "Failed to init topology!\n"); return ret; } skl->platform = platform; + + /* load the firmwares, since all is set */ + ops = skl_get_dsp_ops(skl->pci->device); + if (!ops) + return -EIO; + + if (skl->skl_sst->is_first_boot == false) { + dev_err(platform->dev, "DSP reports first boot done!!!\n"); + return -EIO; + } + + ret = ops->init_fw(platform->dev, skl->skl_sst); + if (ret < 0) { + dev_err(platform->dev, "Failed to boot first fw: %d\n", ret); + return ret; + } + skl_populate_modules(skl); } + pm_runtime_mark_last_busy(platform->dev); + pm_runtime_put_autosuspend(platform->dev); return 0; } diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index da2329d17f4d..efa2532114ba 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -341,14 +341,14 @@ int skl_cldma_prepare(struct sst_dsp *ctx) ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize); if (ret < 0) { - dev_err(ctx->dev, "Alloc buffer for base fw failed: %x", ret); + dev_err(ctx->dev, "Alloc buffer for base fw failed: %x\n", ret); return ret; } /* Setup Code loader BDL */ ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl, PAGE_SIZE); if (ret < 0) { - dev_err(ctx->dev, "Alloc buffer for blde failed: %x", ret); + dev_err(ctx->dev, "Alloc buffer for blde failed: %x\n", ret); ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); return ret; } diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index 0f8629ef79ac..b9e71d051fb1 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -20,6 +20,7 @@ #include <sound/memalloc.h> #include "skl-sst-cldma.h" #include "skl-tplg-interface.h" +#include "skl-topology.h" struct sst_dsp; struct skl_sst; @@ -133,6 +134,8 @@ enum skl_dsp_states { struct skl_dsp_fw_ops { int (*load_fw)(struct sst_dsp *ctx); /* FW module parser/loader */ + int (*load_library)(struct sst_dsp *ctx, + struct skl_dfw_manifest *minfo); int (*parse_fw)(struct sst_dsp *ctx); int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id); @@ -203,12 +206,21 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp); +int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx); +int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx); void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); -int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid, - struct skl_dfw_module *dfw_config); -int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset); +int snd_skl_get_module_info(struct skl_sst *ctx, + struct skl_module_cfg *mconfig); +int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, + unsigned int offset, int index); +int skl_get_pvt_id(struct skl_sst *ctx, + struct skl_module_cfg *mconfig); +int skl_put_pvt_id(struct skl_sst *ctx, + struct skl_module_cfg *mconfig); +int skl_get_pvt_instance_id_map(struct skl_sst *ctx, + int module_id, int instance_id); void skl_freeup_uuid_list(struct skl_sst *ctx); int skl_dsp_strip_extended_manifest(struct firmware *fw); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 96f2f6889b18..0bd01e62622c 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -114,6 +114,11 @@ #define IPC_CORE_ID(x) (((x) & IPC_CORE_ID_MASK) \ << IPC_CORE_ID_SHIFT) +#define IPC_DOMAIN_SHIFT 28 +#define IPC_DOMAIN_MASK 0x1 +#define IPC_DOMAIN(x) (((x) & IPC_DOMAIN_MASK) \ + << IPC_DOMAIN_SHIFT) + /* Bind/Unbind message extension register */ #define IPC_DST_MOD_ID_SHIFT 0 #define IPC_DST_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ @@ -190,6 +195,7 @@ enum skl_ipc_glb_type { IPC_GLB_GET_PPL_CONTEXT_SIZE = 21, IPC_GLB_SAVE_PPL = 22, IPC_GLB_RESTORE_PPL = 23, + IPC_GLB_LOAD_LIBRARY = 24, IPC_GLB_NOTIFY = 26, IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */ }; @@ -338,7 +344,7 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc, break; default: - dev_err(ipc->dev, "ipc: Unhandled error msg=%x", + dev_err(ipc->dev, "ipc: Unhandled error msg=%x\n", header.primary); break; } @@ -379,13 +385,13 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, break; default: - dev_err(ipc->dev, "Unknown ipc reply: 0x%x", reply); + dev_err(ipc->dev, "Unknown ipc reply: 0x%x\n", reply); msg->errno = -EINVAL; break; } if (reply != IPC_GLB_REPLY_SUCCESS) { - dev_err(ipc->dev, "ipc FW reply: reply=%d", reply); + dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply); dev_err(ipc->dev, "FW Error Code: %u\n", ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); } @@ -434,9 +440,9 @@ irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE); header.primary = hipct; header.extension = hipcte; - dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x", + dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x\n", header.primary); - dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x", + dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x\n", header.extension); if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { @@ -704,6 +710,7 @@ int skl_ipc_init_instance(struct sst_generic_ipc *ipc, header.extension = IPC_CORE_ID(msg->core_id); header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id); header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size); + header.extension |= IPC_DOMAIN(msg->domain); dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, header.primary, header.extension); @@ -742,7 +749,7 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, header.extension); ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); if (ret < 0) { - dev_err(ipc->dev, "ipc: bind/unbind faileden"); + dev_err(ipc->dev, "ipc: bind/unbind failed\n"); return ret; } @@ -902,3 +909,25 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, return ret; } EXPORT_SYMBOL_GPL(skl_ipc_get_large_config); + +int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, + u8 dma_id, u8 table_id) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret = 0; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_LIBRARY); + header.primary |= IPC_MOD_INSTANCE_ID(table_id); + header.primary |= IPC_MOD_ID(dma_id); + + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + + if (ret < 0) + dev_err(ipc->dev, "ipc: load lib failed\n"); + + return ret; +} +EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 2e3d4e80ef97..0334ed4af031 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -66,7 +66,7 @@ struct skl_sst { /* callback for miscbdge */ void (*enable_miscbdcge)(struct device *dev, bool enable); - /*Is CGCTL.MISCBDCGE disabled*/ + /* Is CGCTL.MISCBDCGE disabled */ bool miscbdcg_disabled; /* Populate module information */ @@ -75,8 +75,14 @@ struct skl_sst { /* Is firmware loaded */ bool fw_loaded; + /* first boot ? */ + bool is_first_boot; + /* multi-core */ struct skl_dsp_cores cores; + + /* tplg manifest */ + struct skl_dfw_manifest manifest; }; struct skl_ipc_init_instance_msg { @@ -85,6 +91,7 @@ struct skl_ipc_init_instance_msg { u16 param_data_size; u8 ppl_instance_id; u8 core_id; + u8 domain; }; struct skl_ipc_bind_unbind_msg { @@ -145,6 +152,9 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, struct skl_ipc_large_config_msg *msg, u32 *param); +int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, + u8 dma_id, u8 table_id); + void skl_ipc_int_enable(struct sst_dsp *dsp); void skl_ipc_op_int_enable(struct sst_dsp *ctx); void skl_ipc_op_int_disable(struct sst_dsp *ctx); diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c index 25fcb796bd86..8dc03039b311 100644 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ b/sound/soc/intel/skylake/skl-sst-utils.c @@ -28,11 +28,6 @@ /* FW Extended Manifest Header id = $AE1 */ #define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124 -struct skl_dfw_module_mod { - char name[100]; - struct skl_dfw_module skl_dfw_mod; -}; - struct UUID { u8 id[16]; }; @@ -99,10 +94,15 @@ struct adsp_fw_hdr { u32 load_offset; } __packed; +#define MAX_INSTANCE_BUFF 2 + struct uuid_module { uuid_le uuid; int id; int is_loadable; + int max_instance; + u64 pvt_id[MAX_INSTANCE_BUFF]; + int *instance_id; struct list_head list; }; @@ -115,18 +115,23 @@ struct skl_ext_manifest_hdr { u32 entries; }; -int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid, - struct skl_dfw_module *dfw_config) +int snd_skl_get_module_info(struct skl_sst *ctx, + struct skl_module_cfg *mconfig) { struct uuid_module *module; uuid_le *uuid_mod; - uuid_mod = (uuid_le *)uuid; + uuid_mod = (uuid_le *)mconfig->guid; + + if (list_empty(&ctx->uuid_list)) { + dev_err(ctx->dev, "Module list is empty\n"); + return -EINVAL; + } list_for_each_entry(module, &ctx->uuid_list, list) { if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { - dfw_config->module_id = module->id; - dfw_config->is_loadable = module->is_loadable; + mconfig->id.module_id = module->id; + mconfig->is_loadable = module->is_loadable; return 0; } @@ -136,15 +141,154 @@ int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid, } EXPORT_SYMBOL_GPL(snd_skl_get_module_info); +static int skl_get_pvtid_map(struct uuid_module *module, int instance_id) +{ + int pvt_id; + + for (pvt_id = 0; pvt_id < module->max_instance; pvt_id++) { + if (module->instance_id[pvt_id] == instance_id) + return pvt_id; + } + return -EINVAL; +} + +int skl_get_pvt_instance_id_map(struct skl_sst *ctx, + int module_id, int instance_id) +{ + struct uuid_module *module; + + list_for_each_entry(module, &ctx->uuid_list, list) { + if (module->id == module_id) + return skl_get_pvtid_map(module, instance_id); + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(skl_get_pvt_instance_id_map); + +static inline int skl_getid_32(struct uuid_module *module, u64 *val, + int word1_mask, int word2_mask) +{ + int index, max_inst, pvt_id; + u32 mask_val; + + max_inst = module->max_instance; + mask_val = (u32)(*val >> word1_mask); + + if (mask_val != 0xffffffff) { + index = ffz(mask_val); + pvt_id = index + word1_mask + word2_mask; + if (pvt_id <= (max_inst - 1)) { + *val |= 1 << (index + word1_mask); + return pvt_id; + } + } + + return -EINVAL; +} + +static inline int skl_pvtid_128(struct uuid_module *module) +{ + int j, i, word1_mask, word2_mask = 0, pvt_id; + + for (j = 0; j < MAX_INSTANCE_BUFF; j++) { + word1_mask = 0; + + for (i = 0; i < 2; i++) { + pvt_id = skl_getid_32(module, &module->pvt_id[j], + word1_mask, word2_mask); + if (pvt_id >= 0) + return pvt_id; + + word1_mask += 32; + if ((word1_mask + word2_mask) >= module->max_instance) + return -EINVAL; + } + + word2_mask += 64; + if (word2_mask >= module->max_instance) + return -EINVAL; + } + + return -EINVAL; +} + +/** + * skl_get_pvt_id: generate a private id for use as module id + * + * @ctx: driver context + * @mconfig: module configuration data + * + * This generates a 128 bit private unique id for a module TYPE so that + * module instance is unique + */ +int skl_get_pvt_id(struct skl_sst *ctx, struct skl_module_cfg *mconfig) +{ + struct uuid_module *module; + uuid_le *uuid_mod; + int pvt_id; + + uuid_mod = (uuid_le *)mconfig->guid; + + list_for_each_entry(module, &ctx->uuid_list, list) { + if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { + + pvt_id = skl_pvtid_128(module); + if (pvt_id >= 0) { + module->instance_id[pvt_id] = + mconfig->id.instance_id; + return pvt_id; + } + } + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(skl_get_pvt_id); + +/** + * skl_put_pvt_id: free up the private id allocated + * + * @ctx: driver context + * @mconfig: module configuration data + * + * This frees a 128 bit private unique id previously generated + */ +int skl_put_pvt_id(struct skl_sst *ctx, struct skl_module_cfg *mconfig) +{ + int i; + uuid_le *uuid_mod; + struct uuid_module *module; + + uuid_mod = (uuid_le *)mconfig->guid; + list_for_each_entry(module, &ctx->uuid_list, list) { + if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { + + if (mconfig->id.pvt_id != 0) + i = (mconfig->id.pvt_id) / 64; + else + i = 0; + + module->pvt_id[i] &= ~(1 << (mconfig->id.pvt_id)); + mconfig->id.pvt_id = -1; + return 0; + } + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(skl_put_pvt_id); + /* * Parse the firmware binary to get the UUID, module id * and loadable flags */ -int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset) +int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, + unsigned int offset, int index) { struct adsp_fw_hdr *adsp_hdr; struct adsp_module_entry *mod_entry; - int i, num_entry; + int i, num_entry, size; uuid_le *uuid_bin; const char *buf; struct skl_sst *skl = ctx->thread_context; @@ -153,8 +297,8 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset) unsigned int safe_file; /* Get the FW pointer to derive ADSP header */ - stripped_fw.data = ctx->fw->data; - stripped_fw.size = ctx->fw->size; + stripped_fw.data = fw->data; + stripped_fw.size = fw->size; skl_dsp_strip_extended_manifest(&stripped_fw); @@ -205,8 +349,15 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset) uuid_bin = (uuid_le *)mod_entry->uuid.id; memcpy(&module->uuid, uuid_bin, sizeof(module->uuid)); - module->id = i; + module->id = (i | (index << 12)); module->is_loadable = mod_entry->type.load_type; + module->max_instance = mod_entry->instance_max_count; + size = sizeof(int) * mod_entry->instance_max_count; + module->instance_id = devm_kzalloc(ctx->dev, size, GFP_KERNEL); + if (!module->instance_id) { + kfree(module); + return -ENOMEM; + } list_add_tail(&module->list, &skl->uuid_list); diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 588f899ceb65..8fc3178bc79c 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -88,13 +88,15 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) } } - ret = snd_skl_parse_uuids(ctx, SKL_ADSP_FW_BIN_HDR_OFFSET); - if (ret < 0) { - dev_err(ctx->dev, - "UUID parsing err: %d\n", ret); - release_firmware(ctx->fw); - skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - return ret; + /* prase uuids on first boot */ + if (skl->is_first_boot) { + ret = snd_skl_parse_uuids(ctx, ctx->fw, SKL_ADSP_FW_BIN_HDR_OFFSET, 0); + if (ret < 0) { + dev_err(ctx->dev, "UUID parsing err: %d\n", ret); + release_firmware(ctx->fw); + skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); + return ret; + } } /* check for extended manifest */ @@ -105,13 +107,13 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) ret = skl_dsp_boot(ctx); if (ret < 0) { - dev_err(ctx->dev, "Boot dsp core failed ret: %d", ret); + dev_err(ctx->dev, "Boot dsp core failed ret: %d\n", ret); goto skl_load_base_firmware_failed; } ret = skl_cldma_prepare(ctx); if (ret < 0) { - dev_err(ctx->dev, "CL dma prepare failed : %d", ret); + dev_err(ctx->dev, "CL dma prepare failed : %d\n", ret); goto skl_load_base_firmware_failed; } @@ -484,25 +486,32 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, return ret; skl->cores.count = 2; + skl->is_first_boot = true; + + if (dsp) + *dsp = skl; + + return ret; +} +EXPORT_SYMBOL_GPL(skl_sst_dsp_init); + +int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx) +{ + int ret; + struct sst_dsp *sst = ctx->dsp; ret = sst->fw_ops.load_fw(sst); if (ret < 0) { - dev_err(dev, "Load base fw failed : %d", ret); - goto cleanup; + dev_err(dev, "Load base fw failed : %d\n", ret); + return ret; } skl_dsp_init_core_state(sst); + ctx->is_first_boot = false; - if (dsp) - *dsp = skl; - - return ret; - -cleanup: - skl_sst_dsp_cleanup(dev, skl); - return ret; + return 0; } -EXPORT_SYMBOL_GPL(skl_sst_dsp_init); +EXPORT_SYMBOL_GPL(skl_sst_init_fw); void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) { diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index cc0150fc2601..b5b1934d8550 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -21,6 +21,7 @@ #include <linux/firmware.h> #include <sound/soc.h> #include <sound/soc-topology.h> +#include <uapi/sound/snd_sst_tokens.h> #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" #include "skl-topology.h" @@ -32,6 +33,8 @@ #define SKL_CH_FIXUP_MASK (1 << 0) #define SKL_RATE_FIXUP_MASK (1 << 1) #define SKL_FMT_FIXUP_MASK (1 << 2) +#define SKL_IN_DIR_BIT_MASK BIT(0) +#define SKL_PIN_COUNT_MASK GENMASK(7, 4) /* * SKL DSP driver modelling uses only few DAPM widgets so for rest we will @@ -473,6 +476,14 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) w = w_module->w; mconfig = w->priv; + /* check if module ids are populated */ + if (mconfig->id.module_id < 0) { + dev_err(skl->skl_sst->dev, + "module %pUL id not populated\n", + (uuid_le *)mconfig->guid); + return -EIO; + } + /* check resource available */ if (!skl_is_pipe_mcps_avail(skl, mconfig)) return -ENOMEM; @@ -494,12 +505,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) * FE/BE params */ skl_tplg_update_module_params(w, ctx); - + mconfig->id.pvt_id = skl_get_pvt_id(ctx, mconfig); + if (mconfig->id.pvt_id < 0) + return ret; skl_tplg_set_module_init_data(w); ret = skl_init_module(ctx, mconfig); - if (ret < 0) + if (ret < 0) { + skl_put_pvt_id(ctx, mconfig); return ret; - + } skl_tplg_alloc_pipe_mcps(skl, mconfig); ret = skl_tplg_set_module_params(w, ctx); if (ret < 0) @@ -512,6 +526,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, struct skl_pipe *pipe) { + int ret; struct skl_pipe_module *w_module = NULL; struct skl_module_cfg *mconfig = NULL; @@ -519,9 +534,13 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, mconfig = w_module->w->priv; if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod && - mconfig->m_state > SKL_MODULE_UNINIT) - return ctx->dsp->fw_ops.unload_mod(ctx->dsp, + mconfig->m_state > SKL_MODULE_UNINIT) { + ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp, mconfig->id.module_id); + if (ret < 0) + return -EIO; + } + skl_put_pvt_id(ctx, mconfig); } /* no modules to unload in this path, so return */ @@ -588,6 +607,26 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, return 0; } +static int skl_fill_sink_instance_id(struct skl_sst *ctx, + struct skl_algo_data *alg_data) +{ + struct skl_kpb_params *params = (struct skl_kpb_params *)alg_data->params; + struct skl_mod_inst_map *inst; + int i, pvt_id; + + inst = params->map; + + for (i = 0; i < params->num_modules; i++) { + pvt_id = skl_get_pvt_instance_id_map(ctx, + inst->mod_id, inst->inst_id); + if (pvt_id < 0) + return -EINVAL; + inst->inst_id = pvt_id; + inst++; + } + return 0; +} + /* * Some modules require params to be set after the module is bound to * all pins connected. @@ -636,6 +675,8 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, bc = (struct skl_algo_data *)sb->dobj.private; if (bc->set_params == SKL_PARAM_BIND) { + if (mconfig->m_type == SKL_MODULE_TYPE_KPB) + skl_fill_sink_instance_id(ctx, bc); ret = skl_set_module_params(ctx, (u32 *)bc->params, bc->max, bc->param_id, mconfig); @@ -1460,85 +1501,570 @@ static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { skl_tplg_tlv_control_set}, }; -/* - * The topology binary passes the pin info for a module so initialize the pin - * info passed into module instance - */ -static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin, - struct skl_module_pin *m_pin, - bool is_dynamic, int max_pin) +static int skl_tplg_fill_pipe_tkn(struct device *dev, + struct skl_pipe *pipe, u32 tkn, + u32 tkn_val) { - int i; - for (i = 0; i < max_pin; i++) { - m_pin[i].id.module_id = dfw_pin[i].module_id; - m_pin[i].id.instance_id = dfw_pin[i].instance_id; - m_pin[i].in_use = false; - m_pin[i].is_dynamic = is_dynamic; - m_pin[i].pin_state = SKL_PIN_UNBIND; + switch (tkn) { + case SKL_TKN_U32_PIPE_CONN_TYPE: + pipe->conn_type = tkn_val; + break; + + case SKL_TKN_U32_PIPE_PRIORITY: + pipe->pipe_priority = tkn_val; + break; + + case SKL_TKN_U32_PIPE_MEM_PGS: + pipe->memory_pages = tkn_val; + break; + + default: + dev_err(dev, "Token not handled %d\n", tkn); + return -EINVAL; } + + return 0; } /* - * Add pipeline from topology binary into driver pipeline list - * - * If already added we return that instance - * Otherwise we create a new instance and add into driver list + * Add pipeline by parsing the relevant tokens + * Return an existing pipe if the pipe already exists. */ -static struct skl_pipe *skl_tplg_add_pipe(struct device *dev, - struct skl *skl, struct skl_dfw_pipe *dfw_pipe) +static int skl_tplg_add_pipe(struct device *dev, + struct skl_module_cfg *mconfig, struct skl *skl, + struct snd_soc_tplg_vendor_value_elem *tkn_elem) { struct skl_pipeline *ppl; struct skl_pipe *pipe; struct skl_pipe_params *params; list_for_each_entry(ppl, &skl->ppl_list, node) { - if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) - return ppl->pipe; + if (ppl->pipe->ppl_id == tkn_elem->value) { + mconfig->pipe = ppl->pipe; + return EEXIST; + } } ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); if (!ppl) - return NULL; + return -ENOMEM; pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); if (!pipe) - return NULL; + return -ENOMEM; params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); if (!params) - return NULL; + return -ENOMEM; - pipe->ppl_id = dfw_pipe->pipe_id; - pipe->memory_pages = dfw_pipe->memory_pages; - pipe->pipe_priority = dfw_pipe->pipe_priority; - pipe->conn_type = dfw_pipe->conn_type; - pipe->state = SKL_PIPE_INVALID; pipe->p_params = params; + pipe->ppl_id = tkn_elem->value; INIT_LIST_HEAD(&pipe->w_list); ppl->pipe = pipe; list_add(&ppl->node, &skl->ppl_list); - return ppl->pipe; + mconfig->pipe = pipe; + mconfig->pipe->state = SKL_PIPE_INVALID; + + return 0; +} + +static int skl_tplg_fill_pin(struct device *dev, u32 tkn, + struct skl_module_pin *m_pin, + int pin_index, u32 value) +{ + switch (tkn) { + case SKL_TKN_U32_PIN_MOD_ID: + m_pin[pin_index].id.module_id = value; + break; + + case SKL_TKN_U32_PIN_INST_ID: + m_pin[pin_index].id.instance_id = value; + break; + + default: + dev_err(dev, "%d Not a pin token\n", value); + return -EINVAL; + } + + return 0; +} + +/* + * Parse for pin config specific tokens to fill up the + * module private data + */ +static int skl_tplg_fill_pins_info(struct device *dev, + struct skl_module_cfg *mconfig, + struct snd_soc_tplg_vendor_value_elem *tkn_elem, + int dir, int pin_count) +{ + int ret; + struct skl_module_pin *m_pin; + + switch (dir) { + case SKL_DIR_IN: + m_pin = mconfig->m_in_pin; + break; + + case SKL_DIR_OUT: + m_pin = mconfig->m_out_pin; + break; + + default: + dev_err(dev, "Invalid direction value\n"); + return -EINVAL; + } + + ret = skl_tplg_fill_pin(dev, tkn_elem->token, + m_pin, pin_count, tkn_elem->value); + + if (ret < 0) + return ret; + + m_pin[pin_count].in_use = false; + m_pin[pin_count].pin_state = SKL_PIN_UNBIND; + + return 0; +} + +/* + * Fill up input/output module config format based + * on the direction + */ +static int skl_tplg_fill_fmt(struct device *dev, + struct skl_module_cfg *mconfig, u32 tkn, + u32 value, u32 dir, u32 pin_count) +{ + struct skl_module_fmt *dst_fmt; + + switch (dir) { + case SKL_DIR_IN: + dst_fmt = mconfig->in_fmt; + dst_fmt += pin_count; + break; + + case SKL_DIR_OUT: + dst_fmt = mconfig->out_fmt; + dst_fmt += pin_count; + break; + + default: + dev_err(dev, "Invalid direction value\n"); + return -EINVAL; + } + + switch (tkn) { + case SKL_TKN_U32_FMT_CH: + dst_fmt->channels = value; + break; + + case SKL_TKN_U32_FMT_FREQ: + dst_fmt->s_freq = value; + break; + + case SKL_TKN_U32_FMT_BIT_DEPTH: + dst_fmt->bit_depth = value; + break; + + case SKL_TKN_U32_FMT_SAMPLE_SIZE: + dst_fmt->valid_bit_depth = value; + break; + + case SKL_TKN_U32_FMT_CH_CONFIG: + dst_fmt->ch_cfg = value; + break; + + case SKL_TKN_U32_FMT_INTERLEAVE: + dst_fmt->interleaving_style = value; + break; + + case SKL_TKN_U32_FMT_SAMPLE_TYPE: + dst_fmt->sample_type = value; + break; + + case SKL_TKN_U32_FMT_CH_MAP: + dst_fmt->ch_map = value; + break; + + default: + dev_err(dev, "Invalid token %d\n", tkn); + return -EINVAL; + } + + return 0; } -static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt, - struct skl_dfw_module_fmt *src_fmt, - int pins) +static int skl_tplg_get_uuid(struct device *dev, struct skl_module_cfg *mconfig, + struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) +{ + if (uuid_tkn->token == SKL_TKN_UUID) + memcpy(&mconfig->guid, &uuid_tkn->uuid, 16); + else { + dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token); + return -EINVAL; + } + + return 0; +} + +static void skl_tplg_fill_pin_dynamic_val( + struct skl_module_pin *mpin, u32 pin_count, u32 value) { int i; - for (i = 0; i < pins; i++) { - dst_fmt[i].channels = src_fmt[i].channels; - dst_fmt[i].s_freq = src_fmt[i].freq; - dst_fmt[i].bit_depth = src_fmt[i].bit_depth; - dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth; - dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg; - dst_fmt[i].ch_map = src_fmt[i].ch_map; - dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style; - dst_fmt[i].sample_type = src_fmt[i].sample_type; + for (i = 0; i < pin_count; i++) + mpin[i].is_dynamic = value; +} + +/* + * Parse tokens to fill up the module private data + */ +static int skl_tplg_get_token(struct device *dev, + struct snd_soc_tplg_vendor_value_elem *tkn_elem, + struct skl *skl, struct skl_module_cfg *mconfig) +{ + int tkn_count = 0; + int ret; + static int is_pipe_exists; + static int pin_index, dir; + + if (tkn_elem->token > SKL_TKN_MAX) + return -EINVAL; + + switch (tkn_elem->token) { + case SKL_TKN_U8_IN_QUEUE_COUNT: + mconfig->max_in_queue = tkn_elem->value; + mconfig->m_in_pin = devm_kzalloc(dev, mconfig->max_in_queue * + sizeof(*mconfig->m_in_pin), + GFP_KERNEL); + if (!mconfig->m_in_pin) + return -ENOMEM; + + break; + + case SKL_TKN_U8_OUT_QUEUE_COUNT: + mconfig->max_out_queue = tkn_elem->value; + mconfig->m_out_pin = devm_kzalloc(dev, mconfig->max_out_queue * + sizeof(*mconfig->m_out_pin), + GFP_KERNEL); + + if (!mconfig->m_out_pin) + return -ENOMEM; + + break; + + case SKL_TKN_U8_DYN_IN_PIN: + if (!mconfig->m_in_pin) + return -ENOMEM; + + skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, + mconfig->max_in_queue, tkn_elem->value); + + break; + + case SKL_TKN_U8_DYN_OUT_PIN: + if (!mconfig->m_out_pin) + return -ENOMEM; + + skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, + mconfig->max_out_queue, tkn_elem->value); + + break; + + case SKL_TKN_U8_TIME_SLOT: + mconfig->time_slot = tkn_elem->value; + break; + + case SKL_TKN_U8_CORE_ID: + mconfig->core_id = tkn_elem->value; + + case SKL_TKN_U8_MOD_TYPE: + mconfig->m_type = tkn_elem->value; + break; + + case SKL_TKN_U8_DEV_TYPE: + mconfig->dev_type = tkn_elem->value; + break; + + case SKL_TKN_U8_HW_CONN_TYPE: + mconfig->hw_conn_type = tkn_elem->value; + break; + + case SKL_TKN_U16_MOD_INST_ID: + mconfig->id.instance_id = + tkn_elem->value; + break; + + case SKL_TKN_U32_MEM_PAGES: + mconfig->mem_pages = tkn_elem->value; + break; + + case SKL_TKN_U32_MAX_MCPS: + mconfig->mcps = tkn_elem->value; + break; + + case SKL_TKN_U32_OBS: + mconfig->obs = tkn_elem->value; + break; + + case SKL_TKN_U32_IBS: + mconfig->ibs = tkn_elem->value; + break; + + case SKL_TKN_U32_VBUS_ID: + mconfig->vbus_id = tkn_elem->value; + break; + + case SKL_TKN_U32_PARAMS_FIXUP: + mconfig->params_fixup = tkn_elem->value; + break; + + case SKL_TKN_U32_CONVERTER: + mconfig->converter = tkn_elem->value; + break; + + case SKL_TKN_U32_PIPE_ID: + ret = skl_tplg_add_pipe(dev, + mconfig, skl, tkn_elem); + + if (ret < 0) + return is_pipe_exists; + + if (ret == EEXIST) + is_pipe_exists = 1; + + break; + + case SKL_TKN_U32_PIPE_CONN_TYPE: + case SKL_TKN_U32_PIPE_PRIORITY: + case SKL_TKN_U32_PIPE_MEM_PGS: + if (is_pipe_exists) { + ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe, + tkn_elem->token, tkn_elem->value); + if (ret < 0) + return ret; + } + + break; + + /* + * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both + * direction and the pin count. The first four bits represent + * direction and next four the pin count. + */ + case SKL_TKN_U32_DIR_PIN_COUNT: + dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK; + pin_index = (tkn_elem->value & + SKL_PIN_COUNT_MASK) >> 4; + + break; + + case SKL_TKN_U32_FMT_CH: + case SKL_TKN_U32_FMT_FREQ: + case SKL_TKN_U32_FMT_BIT_DEPTH: + case SKL_TKN_U32_FMT_SAMPLE_SIZE: + case SKL_TKN_U32_FMT_CH_CONFIG: + case SKL_TKN_U32_FMT_INTERLEAVE: + case SKL_TKN_U32_FMT_SAMPLE_TYPE: + case SKL_TKN_U32_FMT_CH_MAP: + ret = skl_tplg_fill_fmt(dev, mconfig, tkn_elem->token, + tkn_elem->value, dir, pin_index); + + if (ret < 0) + return ret; + + break; + + case SKL_TKN_U32_PIN_MOD_ID: + case SKL_TKN_U32_PIN_INST_ID: + ret = skl_tplg_fill_pins_info(dev, + mconfig, tkn_elem, dir, + pin_index); + if (ret < 0) + return ret; + + break; + + case SKL_TKN_U32_CAPS_SIZE: + mconfig->formats_config.caps_size = + tkn_elem->value; + + break; + + case SKL_TKN_U32_PROC_DOMAIN: + mconfig->domain = + tkn_elem->value; + + break; + + case SKL_TKN_U8_IN_PIN_TYPE: + case SKL_TKN_U8_OUT_PIN_TYPE: + case SKL_TKN_U8_CONN_TYPE: + break; + + default: + dev_err(dev, "Token %d not handled\n", + tkn_elem->token); + return -EINVAL; + } + + tkn_count++; + + return tkn_count; +} + +/* + * Parse the vendor array for specific tokens to construct + * module private data + */ +static int skl_tplg_get_tokens(struct device *dev, + char *pvt_data, struct skl *skl, + struct skl_module_cfg *mconfig, int block_size) +{ + struct snd_soc_tplg_vendor_array *array; + struct snd_soc_tplg_vendor_value_elem *tkn_elem; + int tkn_count = 0, ret; + int off = 0, tuple_size = 0; + + if (block_size <= 0) + return -EINVAL; + + while (tuple_size < block_size) { + array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); + + off += array->size; + + switch (array->type) { + case SND_SOC_TPLG_TUPLE_TYPE_STRING: + dev_warn(dev, "no string tokens expected for skl tplg\n"); + continue; + + case SND_SOC_TPLG_TUPLE_TYPE_UUID: + ret = skl_tplg_get_uuid(dev, mconfig, array->uuid); + if (ret < 0) + return ret; + + tuple_size += sizeof(*array->uuid); + + continue; + + default: + tkn_elem = array->value; + tkn_count = 0; + break; + } + + while (tkn_count <= (array->num_elems - 1)) { + ret = skl_tplg_get_token(dev, tkn_elem, + skl, mconfig); + + if (ret < 0) + return ret; + + tkn_count = tkn_count + ret; + tkn_elem++; + } + + tuple_size += tkn_count * sizeof(*tkn_elem); + } + + return 0; +} + +/* + * Every data block is preceded by a descriptor to read the number + * of data blocks, they type of the block and it's size + */ +static int skl_tplg_get_desc_blocks(struct device *dev, + struct snd_soc_tplg_vendor_array *array) +{ + struct snd_soc_tplg_vendor_value_elem *tkn_elem; + + tkn_elem = array->value; + + switch (tkn_elem->token) { + case SKL_TKN_U8_NUM_BLOCKS: + case SKL_TKN_U8_BLOCK_TYPE: + case SKL_TKN_U16_BLOCK_SIZE: + return tkn_elem->value; + + default: + dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token); + break; + } + + return -EINVAL; +} + +/* + * Parse the private data for the token and corresponding value. + * The private data can have multiple data blocks. So, a data block + * is preceded by a descriptor for number of blocks and a descriptor + * for the type and size of the suceeding data block. + */ +static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, + struct skl *skl, struct device *dev, + struct skl_module_cfg *mconfig) +{ + struct snd_soc_tplg_vendor_array *array; + int num_blocks, block_size = 0, block_type, off = 0; + char *data; + int ret; + + /* Read the NUM_DATA_BLOCKS descriptor */ + array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data; + ret = skl_tplg_get_desc_blocks(dev, array); + if (ret < 0) + return ret; + num_blocks = ret; + + off += array->size; + array = (struct snd_soc_tplg_vendor_array *)(tplg_w->priv.data + off); + + /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ + while (num_blocks > 0) { + ret = skl_tplg_get_desc_blocks(dev, array); + + if (ret < 0) + return ret; + block_type = ret; + off += array->size; + + array = (struct snd_soc_tplg_vendor_array *) + (tplg_w->priv.data + off); + + ret = skl_tplg_get_desc_blocks(dev, array); + + if (ret < 0) + return ret; + block_size = ret; + off += array->size; + + array = (struct snd_soc_tplg_vendor_array *) + (tplg_w->priv.data + off); + + data = (tplg_w->priv.data + off); + + if (block_type == SKL_TYPE_TUPLE) { + ret = skl_tplg_get_tokens(dev, data, + skl, mconfig, block_size); + + if (ret < 0) + return ret; + + --num_blocks; + } else { + if (mconfig->formats_config.caps_size > 0) + memcpy(mconfig->formats_config.caps, data, + mconfig->formats_config.caps_size); + --num_blocks; + } } + + return 0; } static void skl_clear_pin_config(struct snd_soc_platform *platform, @@ -1606,9 +2132,6 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, struct skl *skl = ebus_to_skl(ebus); struct hdac_bus *bus = ebus_to_hbus(ebus); struct skl_module_cfg *mconfig; - struct skl_pipe *pipe; - struct skl_dfw_module *dfw_config = - (struct skl_dfw_module *)tplg_w->priv.data; if (!tplg_w->priv.size) goto bind_event; @@ -1619,76 +2142,17 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, return -ENOMEM; w->priv = mconfig; - memcpy(&mconfig->guid, &dfw_config->uuid, 16); - ret = snd_skl_get_module_info(skl->skl_sst, mconfig->guid, dfw_config); + /* + * module binary can be loaded later, so set it to query when + * module is load for a use case + */ + mconfig->id.module_id = -1; + + /* Parse private data for tuples */ + ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig); if (ret < 0) return ret; - - mconfig->id.module_id = dfw_config->module_id; - mconfig->id.instance_id = dfw_config->instance_id; - mconfig->mcps = dfw_config->max_mcps; - mconfig->ibs = dfw_config->ibs; - mconfig->obs = dfw_config->obs; - mconfig->core_id = dfw_config->core_id; - mconfig->max_in_queue = dfw_config->max_in_queue; - mconfig->max_out_queue = dfw_config->max_out_queue; - mconfig->is_loadable = dfw_config->is_loadable; - skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt, - MODULE_MAX_IN_PINS); - skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt, - MODULE_MAX_OUT_PINS); - - mconfig->params_fixup = dfw_config->params_fixup; - mconfig->converter = dfw_config->converter; - mconfig->m_type = dfw_config->module_type; - mconfig->vbus_id = dfw_config->vbus_id; - mconfig->mem_pages = dfw_config->mem_pages; - - pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe); - if (pipe) - mconfig->pipe = pipe; - - mconfig->dev_type = dfw_config->dev_type; - mconfig->hw_conn_type = dfw_config->hw_conn_type; - mconfig->time_slot = dfw_config->time_slot; - mconfig->formats_config.caps_size = dfw_config->caps.caps_size; - - mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) * - sizeof(*mconfig->m_in_pin), - GFP_KERNEL); - if (!mconfig->m_in_pin) - return -ENOMEM; - - mconfig->m_out_pin = devm_kzalloc(bus->dev, (mconfig->max_out_queue) * - sizeof(*mconfig->m_out_pin), - GFP_KERNEL); - if (!mconfig->m_out_pin) - return -ENOMEM; - - skl_fill_module_pin_info(dfw_config->in_pin, mconfig->m_in_pin, - dfw_config->is_dynamic_in_pin, - mconfig->max_in_queue); - - skl_fill_module_pin_info(dfw_config->out_pin, mconfig->m_out_pin, - dfw_config->is_dynamic_out_pin, - mconfig->max_out_queue); - - - if (mconfig->formats_config.caps_size == 0) - goto bind_event; - - mconfig->formats_config.caps = (u32 *)devm_kzalloc(bus->dev, - mconfig->formats_config.caps_size, GFP_KERNEL); - - if (mconfig->formats_config.caps == NULL) - return -ENOMEM; - - memcpy(mconfig->formats_config.caps, dfw_config->caps.caps, - dfw_config->caps.caps_size); - mconfig->formats_config.param_id = dfw_config->caps.param_id; - mconfig->formats_config.set_params = dfw_config->caps.set_params; - bind_event: if (tplg_w->event_type == 0) { dev_dbg(bus->dev, "ASoC: No event handler required\n"); @@ -1767,11 +2231,229 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt, return 0; } +static int skl_tplg_fill_str_mfest_tkn(struct device *dev, + struct snd_soc_tplg_vendor_string_elem *str_elem, + struct skl_dfw_manifest *minfo) +{ + int tkn_count = 0; + static int ref_count; + + switch (str_elem->token) { + case SKL_TKN_STR_LIB_NAME: + if (ref_count > minfo->lib_count - 1) { + ref_count = 0; + return -EINVAL; + } + + strncpy(minfo->lib[ref_count].name, str_elem->string, + ARRAY_SIZE(minfo->lib[ref_count].name)); + ref_count++; + tkn_count++; + break; + + default: + dev_err(dev, "Not a string token %d\n", str_elem->token); + break; + } + + return tkn_count; +} + +static int skl_tplg_get_str_tkn(struct device *dev, + struct snd_soc_tplg_vendor_array *array, + struct skl_dfw_manifest *minfo) +{ + int tkn_count = 0, ret; + struct snd_soc_tplg_vendor_string_elem *str_elem; + + str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value; + while (tkn_count < array->num_elems) { + ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, minfo); + str_elem++; + + if (ret < 0) + return ret; + + tkn_count = tkn_count + ret; + } + + return tkn_count; +} + +static int skl_tplg_get_int_tkn(struct device *dev, + struct snd_soc_tplg_vendor_value_elem *tkn_elem, + struct skl_dfw_manifest *minfo) +{ + int tkn_count = 0; + + switch (tkn_elem->token) { + case SKL_TKN_U32_LIB_COUNT: + minfo->lib_count = tkn_elem->value; + tkn_count++; + break; + + default: + dev_err(dev, "Not a manifest token %d\n", tkn_elem->token); + return -EINVAL; + } + + return tkn_count; +} + +/* + * Fill the manifest structure by parsing the tokens based on the + * type. + */ +static int skl_tplg_get_manifest_tkn(struct device *dev, + char *pvt_data, struct skl_dfw_manifest *minfo, + int block_size) +{ + int tkn_count = 0, ret; + int off = 0, tuple_size = 0; + struct snd_soc_tplg_vendor_array *array; + struct snd_soc_tplg_vendor_value_elem *tkn_elem; + + if (block_size <= 0) + return -EINVAL; + + while (tuple_size < block_size) { + array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); + off += array->size; + switch (array->type) { + case SND_SOC_TPLG_TUPLE_TYPE_STRING: + ret = skl_tplg_get_str_tkn(dev, array, minfo); + + if (ret < 0) + return ret; + tkn_count += ret; + + tuple_size += tkn_count * + sizeof(struct snd_soc_tplg_vendor_string_elem); + continue; + + case SND_SOC_TPLG_TUPLE_TYPE_UUID: + dev_warn(dev, "no uuid tokens for skl tplf manifest\n"); + continue; + + default: + tkn_elem = array->value; + tkn_count = 0; + break; + } + + while (tkn_count <= array->num_elems - 1) { + ret = skl_tplg_get_int_tkn(dev, + tkn_elem, minfo); + if (ret < 0) + return ret; + + tkn_count = tkn_count + ret; + tkn_elem++; + tuple_size += tkn_count * + sizeof(struct snd_soc_tplg_vendor_value_elem); + break; + } + tkn_count = 0; + } + + return 0; +} + +/* + * Parse manifest private data for tokens. The private data block is + * preceded by descriptors for type and size of data block. + */ +static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, + struct device *dev, struct skl_dfw_manifest *minfo) +{ + struct snd_soc_tplg_vendor_array *array; + int num_blocks, block_size = 0, block_type, off = 0; + char *data; + int ret; + + /* Read the NUM_DATA_BLOCKS descriptor */ + array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data; + ret = skl_tplg_get_desc_blocks(dev, array); + if (ret < 0) + return ret; + num_blocks = ret; + + off += array->size; + array = (struct snd_soc_tplg_vendor_array *) + (manifest->priv.data + off); + + /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ + while (num_blocks > 0) { + ret = skl_tplg_get_desc_blocks(dev, array); + + if (ret < 0) + return ret; + block_type = ret; + off += array->size; + + array = (struct snd_soc_tplg_vendor_array *) + (manifest->priv.data + off); + + ret = skl_tplg_get_desc_blocks(dev, array); + + if (ret < 0) + return ret; + block_size = ret; + off += array->size; + + array = (struct snd_soc_tplg_vendor_array *) + (manifest->priv.data + off); + + data = (manifest->priv.data + off); + + if (block_type == SKL_TYPE_TUPLE) { + ret = skl_tplg_get_manifest_tkn(dev, data, minfo, + block_size); + + if (ret < 0) + return ret; + + --num_blocks; + } else { + return -EINVAL; + } + } + + return 0; +} + +static int skl_manifest_load(struct snd_soc_component *cmpnt, + struct snd_soc_tplg_manifest *manifest) +{ + struct skl_dfw_manifest *minfo; + struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct skl *skl = ebus_to_skl(ebus); + int ret = 0; + + /* proceed only if we have private data defined */ + if (manifest->priv.size == 0) + return 0; + + minfo = &skl->skl_sst->manifest; + + skl_tplg_get_manifest_data(manifest, bus->dev, minfo); + + if (minfo->lib_count > HDA_MAX_LIB) { + dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", + minfo->lib_count); + ret = -EINVAL; + } + + return ret; +} + static struct snd_soc_tplg_ops skl_tplg_ops = { .widget_load = skl_tplg_widget_load, .control_load = skl_tplg_control_load, .bytes_ext_ops = skl_tlv_ops, .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), + .manifest = skl_manifest_load, }; /* diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 22d3ef83817d..a519360f42a6 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -133,7 +133,7 @@ struct skl_i2s_config_blob { struct skl_dma_control { u32 node_id; u32 config_length; - u32 config_data[1]; + u32 config_data[0]; } __packed; struct skl_cpr_cfg { @@ -215,9 +215,20 @@ struct skl_module_fmt { struct skl_module_cfg; +struct skl_mod_inst_map { + u16 mod_id; + u16 inst_id; +}; + +struct skl_kpb_params { + u32 num_modules; + struct skl_mod_inst_map map[0]; +}; + struct skl_module_inst_id { - u32 module_id; + int module_id; u32 instance_id; + int pvt_id; }; enum skl_module_pin_state { diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index a32e5e9cc530..2f6281e056d6 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -80,7 +80,8 @@ enum skl_module_type { SKL_MODULE_TYPE_UPDWMIX, SKL_MODULE_TYPE_SRCINT, SKL_MODULE_TYPE_ALGO, - SKL_MODULE_TYPE_BASE_OUTFMT + SKL_MODULE_TYPE_BASE_OUTFMT, + SKL_MODULE_TYPE_KPB, }; enum skl_core_affinity { @@ -148,84 +149,34 @@ enum skl_module_param_type { SKL_PARAM_BIND }; -struct skl_dfw_module_pin { - u16 module_id; - u16 instance_id; -} __packed; - -struct skl_dfw_module_fmt { - u32 channels; - u32 freq; - u32 bit_depth; - u32 valid_bit_depth; - u32 ch_cfg; - u32 interleaving_style; - u32 sample_type; - u32 ch_map; -} __packed; - -struct skl_dfw_module_caps { +struct skl_dfw_algo_data { u32 set_params:2; u32 rsvd:30; u32 param_id; - u32 caps_size; - u32 caps[HDA_SST_CFG_MAX]; -}; - -struct skl_dfw_pipe { - u8 pipe_id; - u8 pipe_priority; - u16 conn_type:4; - u16 rsvd:4; - u16 memory_pages:8; + u32 max; + char params[0]; } __packed; -struct skl_dfw_module { - u8 uuid[16]; - - u16 module_id; - u16 instance_id; - u32 max_mcps; - u32 mem_pages; - u32 obs; - u32 ibs; - u32 vbus_id; - - u32 max_in_queue:8; - u32 max_out_queue:8; - u32 time_slot:8; - u32 core_id:4; - u32 rsvd1:4; - - u32 module_type:8; - u32 conn_type:4; - u32 dev_type:4; - u32 hw_conn_type:4; - u32 rsvd2:12; - - u32 params_fixup:8; - u32 converter:8; - u32 input_pin_type:1; - u32 output_pin_type:1; - u32 is_dynamic_in_pin:1; - u32 is_dynamic_out_pin:1; - u32 is_loadable:1; - u32 rsvd3:11; - - struct skl_dfw_pipe pipe; - struct skl_dfw_module_fmt in_fmt[MAX_IN_QUEUE]; - struct skl_dfw_module_fmt out_fmt[MAX_OUT_QUEUE]; - struct skl_dfw_module_pin in_pin[MAX_IN_QUEUE]; - struct skl_dfw_module_pin out_pin[MAX_OUT_QUEUE]; - struct skl_dfw_module_caps caps; +#define LIB_NAME_LENGTH 128 +#define HDA_MAX_LIB 16 + +struct lib_info { + char name[LIB_NAME_LENGTH]; } __packed; -struct skl_dfw_algo_data { - u32 set_params:2; - u32 rsvd:30; - u32 param_id; - u32 max; - char params[0]; +struct skl_dfw_manifest { + u32 lib_count; + struct lib_info lib[HDA_MAX_LIB]; } __packed; +enum skl_tkn_dir { + SKL_DIR_IN, + SKL_DIR_OUT +}; + +enum skl_tuple_type { + SKL_TYPE_TUPLE, + SKL_TYPE_DATA +}; + #endif diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index cd59536a761d..2989c164dafe 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -587,7 +587,7 @@ static int skl_first_init(struct hdac_ext_bus *ebus) return -ENXIO; } - snd_hdac_ext_bus_parse_capabilities(ebus); + snd_hdac_bus_parse_capabilities(bus); if (skl_acquire_irq(ebus, 0) < 0) return -EBUSY; @@ -672,8 +672,10 @@ static int skl_probe(struct pci_dev *pci, skl->nhlt = skl_nhlt_init(bus->dev); - if (skl->nhlt == NULL) + if (skl->nhlt == NULL) { + err = -ENODEV; goto out_free; + } skl_nhlt_update_topology_bin(skl); @@ -682,7 +684,7 @@ static int skl_probe(struct pci_dev *pci, skl_dmic_data.dmic_num = skl_get_dmic_geo(skl); /* check if dsp is there */ - if (ebus->ppcap) { + if (bus->ppcap) { err = skl_machine_device_register(skl, (void *)pci_id->driver_data); if (err < 0) @@ -696,7 +698,7 @@ static int skl_probe(struct pci_dev *pci, skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; } - if (ebus->mlcap) + if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(ebus); /* create device for soc dmic */ diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 9064e5b0d676..5d4fbb094c48 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -105,6 +105,7 @@ struct skl_dsp_ops { int irq, const char *fw_name, struct skl_dsp_loader_ops loader_ops, struct skl_sst **skl_sst); + int (*init_fw)(struct device *dev, struct skl_sst *ctx); void (*cleanup)(struct device *dev, struct skl_sst *ctx); }; @@ -123,4 +124,5 @@ int skl_free_dsp(struct skl *skl); int skl_suspend_dsp(struct skl *skl); int skl_resume_dsp(struct skl *skl); void skl_cleanup_resources(struct skl *skl); +const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); #endif /* __SOUND_SOC_SKL_H */ diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index dbfdfe99c69d..dafd22e874e9 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -242,7 +242,7 @@ static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream return count; } -static struct snd_pcm_ops kirkwood_dma_ops = { +static const struct snd_pcm_ops kirkwood_dma_ops = { .open = kirkwood_dma_open, .close = kirkwood_dma_close, .ioctl = snd_pcm_lib_ioctl, diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c index b788791b0a35..ac231d33d8fe 100644 --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c @@ -23,7 +23,8 @@ #define AFE_BASE_END_OFFSET 8 -int mtk_regmap_update_bits(struct regmap *map, int reg, unsigned int mask, +static int mtk_regmap_update_bits(struct regmap *map, int reg, + unsigned int mask, unsigned int val) { if (reg < 0) @@ -31,7 +32,7 @@ int mtk_regmap_update_bits(struct regmap *map, int reg, unsigned int mask, return regmap_update_bits(map, reg, mask, val); } -int mtk_regmap_write(struct regmap *map, int reg, unsigned int val) +static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val) { if (reg < 0) return 0; diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index 76ce33199bf9..06fec5699cc8 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c @@ -221,7 +221,8 @@ void omap_mcbsp_config(struct omap_mcbsp *mcbsp, /* Enable TX/RX sync error interrupts by default */ if (mcbsp->irq) - MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN); + MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN | + RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN); } /** diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index 0843a68f277c..89fe95e877db 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -38,10 +38,10 @@ struct abe_twl6040 { int jack_detection; /* board can detect jack events */ int mclk_freq; /* MCLK frequency speed for twl6040 */ - - struct platform_device *dmic_codec_dev; }; +struct platform_device *dmic_codec_dev; + static int omap_abe_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -258,8 +258,6 @@ static int omap_abe_probe(struct platform_device *pdev) if (priv == NULL) return -ENOMEM; - priv->dmic_codec_dev = ERR_PTR(-EINVAL); - if (snd_soc_of_parse_card_name(card, "ti,model")) { dev_err(&pdev->dev, "Card name is not provided\n"); return -ENODEV; @@ -284,13 +282,6 @@ static int omap_abe_probe(struct platform_device *pdev) num_links = 2; abe_twl6040_dai_links[1].cpu_of_node = dai_node; abe_twl6040_dai_links[1].platform_of_node = dai_node; - - priv->dmic_codec_dev = platform_device_register_simple( - "dmic-codec", -1, NULL, 0); - if (IS_ERR(priv->dmic_codec_dev)) { - dev_err(&pdev->dev, "Can't instantiate dmic-codec\n"); - return PTR_ERR(priv->dmic_codec_dev); - } } else { num_links = 1; } @@ -299,16 +290,14 @@ static int omap_abe_probe(struct platform_device *pdev) of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq); if (!priv->mclk_freq) { dev_err(&pdev->dev, "MCLK frequency not provided\n"); - ret = -EINVAL; - goto err_unregister; + return -EINVAL; } card->fully_routed = 1; if (!priv->mclk_freq) { dev_err(&pdev->dev, "MCLK frequency missing\n"); - ret = -ENODEV; - goto err_unregister; + return -ENODEV; } card->dai_link = abe_twl6040_dai_links; @@ -316,35 +305,14 @@ static int omap_abe_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, priv); - ret = snd_soc_register_card(card); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) + dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", ret); - goto err_unregister; - } - - return 0; - -err_unregister: - if (!IS_ERR(priv->dmic_codec_dev)) - platform_device_unregister(priv->dmic_codec_dev); return ret; } -static int omap_abe_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); - - snd_soc_unregister_card(card); - - if (!IS_ERR(priv->dmic_codec_dev)) - platform_device_unregister(priv->dmic_codec_dev); - - return 0; -} - static const struct of_device_id omap_abe_of_match[] = { {.compatible = "ti,abe-twl6040", }, { }, @@ -358,10 +326,35 @@ static struct platform_driver omap_abe_driver = { .of_match_table = omap_abe_of_match, }, .probe = omap_abe_probe, - .remove = omap_abe_remove, }; -module_platform_driver(omap_abe_driver); +static int __init omap_abe_init(void) +{ + int ret; + + dmic_codec_dev = platform_device_register_simple("dmic-codec", -1, NULL, + 0); + if (IS_ERR(dmic_codec_dev)) { + pr_err("%s: dmic-codec device registration failed\n", __func__); + return PTR_ERR(dmic_codec_dev); + } + + ret = platform_driver_register(&omap_abe_driver); + if (ret) { + pr_err("%s: platform driver registration failed\n", __func__); + platform_device_unregister(dmic_codec_dev); + } + + return ret; +} +module_init(omap_abe_init); + +static void __exit omap_abe_exit(void) +{ + platform_driver_unregister(&omap_abe_driver); + platform_device_unregister(dmic_codec_dev); +} +module_exit(omap_abe_exit); MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); MODULE_DESCRIPTION("ALSA SoC for OMAP boards with ABE and twl6040 codec"); diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index e7cdc51fd806..64609c77a79d 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -31,7 +31,6 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/irq.h> -#include <linux/clk.h> #include <linux/slab.h> #include <linux/pm_runtime.h> #include <linux/of_device.h> @@ -55,7 +54,6 @@ struct omap_mcpdm { unsigned long phys_base; void __iomem *io_base; int irq; - struct clk *pdmclk; struct mutex mutex; @@ -390,15 +388,14 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai) struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); int ret; - clk_prepare_enable(mcpdm->pdmclk); pm_runtime_enable(mcpdm->dev); /* Disable lines while request is ongoing */ pm_runtime_get_sync(mcpdm->dev); omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00); - ret = devm_request_irq(mcpdm->dev, mcpdm->irq, omap_mcpdm_irq_handler, - 0, "McPDM", (void *)mcpdm); + ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, 0, "McPDM", + (void *)mcpdm); pm_runtime_put_sync(mcpdm->dev); @@ -423,9 +420,9 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai) { struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); + free_irq(mcpdm->irq, (void *)mcpdm); pm_runtime_disable(mcpdm->dev); - clk_disable_unprepare(mcpdm->pdmclk); return 0; } @@ -445,8 +442,6 @@ static int omap_mcpdm_suspend(struct snd_soc_dai *dai) mcpdm->pm_active_count++; } - clk_disable_unprepare(mcpdm->pdmclk); - return 0; } @@ -454,8 +449,6 @@ static int omap_mcpdm_resume(struct snd_soc_dai *dai) { struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); - clk_prepare_enable(mcpdm->pdmclk); - if (mcpdm->pm_active_count) { while (mcpdm->pm_active_count--) pm_runtime_get_sync(mcpdm->dev); @@ -549,15 +542,6 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) mcpdm->dev = &pdev->dev; - mcpdm->pdmclk = devm_clk_get(&pdev->dev, "pdmclk"); - if (IS_ERR(mcpdm->pdmclk)) { - if (PTR_ERR(mcpdm->pdmclk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - dev_warn(&pdev->dev, "Error getting pdmclk (%ld)!\n", - PTR_ERR(mcpdm->pdmclk)); - mcpdm->pdmclk = NULL; - } - ret = devm_snd_soc_register_component(&pdev->dev, &omap_mcpdm_component, &omap_mcpdm_dai, 1); diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index a84f677234f0..94e9ff791f3a 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -58,7 +58,7 @@ static void omap_pcm_limit_supported_formats(void) { int i; - for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { + for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { switch (snd_pcm_format_physical_width(i)) { case 8: case 16: diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index 1289543c8fb2..07f91e918b23 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -85,6 +85,15 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) return ERR_PTR(ret); } + /* DAPM routes */ + if (of_property_read_bool(node, "qcom,audio-routing")) { + ret = snd_soc_of_parse_audio_routing(card, + "qcom,audio-routing"); + if (ret) + return ERR_PTR(ret); + } + + /* Populate links */ num_links = of_get_child_count(node); @@ -147,6 +156,15 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) return data; } +static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { + + SND_SOC_DAPM_MIC("Handset Mic", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Secondary Mic", NULL), + SND_SOC_DAPM_MIC("Digital Mic1", NULL), + SND_SOC_DAPM_MIC("Digital Mic2", NULL), +}; + static int apq8016_sbc_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -159,6 +177,8 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev) return -ENOMEM; card->dev = dev; + card->dapm_widgets = apq8016_sbc_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(apq8016_sbc_dapm_widgets); data = apq8016_sbc_parse_of(card); if (IS_ERR(data)) { dev_err(&pdev->dev, "Error resolving dai links: %ld\n", diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index db000c6987a1..e2ff538a8aa5 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -84,9 +84,9 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime); struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); + struct lpass_pcm_data *pcm_data = drvdata->private_data; struct lpass_variant *v = drvdata->variant; snd_pcm_format_t format = params_format(params); unsigned int channels = params_channels(params); @@ -177,9 +177,9 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime); struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); + struct lpass_pcm_data *pcm_data = drvdata->private_data; struct lpass_variant *v = drvdata->variant; unsigned int reg; int ret; @@ -201,9 +201,9 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime); struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); + struct lpass_pcm_data *pcm_data = drvdata->private_data; struct lpass_variant *v = drvdata->variant; int ret, ch, dir = substream->stream; @@ -255,9 +255,9 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime); struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); + struct lpass_pcm_data *pcm_data = drvdata->private_data; struct lpass_variant *v = drvdata->variant; int ret, ch, dir = substream->stream; @@ -331,9 +331,9 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime); struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); + struct lpass_pcm_data *pcm_data = drvdata->private_data; struct lpass_variant *v = drvdata->variant; unsigned int base_addr, curr_addr; int ret, ch, dir = substream->stream; @@ -372,7 +372,7 @@ static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream, runtime->dma_bytes); } -static struct snd_pcm_ops lpass_platform_pcm_ops = { +static const struct snd_pcm_ops lpass_platform_pcm_ops = { .open = lpass_platform_pcmops_open, .ioctl = snd_pcm_lib_ioctl, .hw_params = lpass_platform_pcmops_hw_params, @@ -483,7 +483,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) return -ENOMEM; data->i2s_port = cpu_dai->driver->id; - snd_soc_pcm_set_drvdata(soc_runtime, data); + drvdata->private_data = data; psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; if (psubstream) { @@ -570,8 +570,8 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm) substream = pcm->streams[i].substream; if (substream) { rt = substream->private_data; - data = snd_soc_pcm_get_drvdata(rt); drvdata = snd_soc_platform_get_drvdata(rt->platform); + data = drvdata->private_data; ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? data->rdma_ch diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 30714ad1e138..35b3cea8207d 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -58,6 +58,8 @@ struct lpass_data { /* 8016 specific */ struct clk *pcnoc_mport_clk; struct clk *pcnoc_sway_clk; + + void *private_data; }; /* Vairant data per each SOC */ diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index f1e0c703e0d2..c783f9a22595 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig @@ -41,3 +41,15 @@ config SND_SOC_ROCKCHIP_RT5645 help Say Y or M here if you want to add support for SoC audio on Rockchip boards using the RT5645/RT5650 codec, such as Veyron. + +config SND_SOC_RK3399_GRU_SOUND + tristate "ASoC support multiple codecs for Rockchip RK3399 GRU boards" + depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && CLKDEV_LOOKUP && SPI + select SND_SOC_ROCKCHIP_I2S + select SND_SOC_MAX98357A + select SND_SOC_RT5514 + select SND_SOC_DA7219 + select SND_SOC_RT5514_SPI + help + Say Y or M here if you want to add support multiple codecs for SoC + audio on Rockchip RK3399 GRU boards. diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile index c0bf560125f3..84e5c7c700e7 100644 --- a/sound/soc/rockchip/Makefile +++ b/sound/soc/rockchip/Makefile @@ -7,6 +7,8 @@ obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o snd-soc-rockchip-max98090-objs := rockchip_max98090.o snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o +snd-soc-rk3399-gru-sound-objs := rk3399_gru_sound.o obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o +obj-$(CONFIG_SND_SOC_RK3399_GRU_SOUND) += snd-soc-rk3399-gru-sound.o diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c new file mode 100644 index 000000000000..9ed735a6cf49 --- /dev/null +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -0,0 +1,397 @@ +/* + * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219 + * + * Copyright (c) 2016, ROCKCHIP CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/delay.h> +#include <linux/spi/spi.h> +#include <linux/input.h> +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "rockchip_i2s.h" +#include "../codecs/da7219.h" +#include "../codecs/da7219-aad.h" +#include "../codecs/rt5514.h" + +#define DRV_NAME "rk3399-gru-sound" + +#define SOUND_FS 256 + +unsigned int rt5514_dmic_delay; + +static struct snd_soc_jack rockchip_sound_jack; + +static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphones", NULL), + SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), +}; + +static const struct snd_soc_dapm_route rockchip_dapm_routes[] = { + /* Input Lines */ + {"MIC", NULL, "Headset Mic"}, + {"DMIC1L", NULL, "Int Mic"}, + {"DMIC1R", NULL, "Int Mic"}, + + /* Output Lines */ + {"Headphones", NULL, "HPL"}, + {"Headphones", NULL, "HPR"}, + {"Speakers", NULL, "Speaker"}, +}; + +static const struct snd_kcontrol_new rockchip_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphones"), + SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Int Mic"), +}; + +static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + unsigned int mclk; + int ret; + + /* max98357a supports these sample rates */ + switch (params_rate(params)) { + case 8000: + case 16000: + case 48000: + case 96000: + mclk = params_rate(params) * SOUND_FS; + break; + default: + dev_err(rtd->card->dev, "%s() doesn't support this sample rate: %d\n", + __func__, params_rate(params)); + return -EINVAL; + } + + ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0); + if (ret) { + dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n", + __func__, mclk, ret); + return ret; + } + + return 0; +} + +static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + unsigned int mclk; + int ret; + + mclk = params_rate(params) * SOUND_FS; + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, + SND_SOC_CLOCK_OUT); + if (ret < 0) { + dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK, + mclk, SND_SOC_CLOCK_IN); + if (ret) { + dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n", + __func__, params_rate(params) * 512, ret); + return ret; + } + + /* Wait for DMIC stable */ + msleep(rt5514_dmic_delay); + + return 0; +} + +static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int mclk, ret; + + /* in bypass mode, the mclk has to be one of the frequencies below */ + switch (params_rate(params)) { + case 8000: + case 16000: + case 24000: + case 32000: + case 48000: + case 64000: + case 96000: + mclk = 12288000; + break; + case 11025: + case 22050: + case 44100: + case 88200: + mclk = 11289600; + break; + default: + return -EINVAL; + } + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, + SND_SOC_CLOCK_OUT); + if (ret < 0) { + dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0); + if (ret < 0) { + dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret); + return ret; + } + + return 0; +} + +static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec_dais[0]->codec; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + /* We need default MCLK and PLL settings for the accessory detection */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 12288000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "Init can't set codec clock in %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0); + if (ret < 0) { + dev_err(codec_dai->dev, "Init can't set pll sysclk mclk %d\n", ret); + return ret; + } + + /* Enable Headset and 4 Buttons Jack detection */ + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &rockchip_sound_jack, NULL, 0); + + if (ret) { + dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret); + return ret; + } + + snd_jack_set_key(rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_MEDIA); + snd_jack_set_key( + rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key( + rockchip_sound_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key( + rockchip_sound_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + da7219_aad_jack_det(codec, &rockchip_sound_jack); + + return 0; +} + +static struct snd_soc_ops rockchip_sound_max98357a_ops = { + .hw_params = rockchip_sound_max98357a_hw_params, +}; + +static struct snd_soc_ops rockchip_sound_rt5514_ops = { + .hw_params = rockchip_sound_rt5514_hw_params, +}; + +static struct snd_soc_ops rockchip_sound_da7219_ops = { + .hw_params = rockchip_sound_da7219_hw_params, +}; + +enum { + DAILINK_MAX98357A, + DAILINK_RT5514, + DAILINK_DA7219, + DAILINK_RT5514_DSP, +}; + +#define DAILINK_ENTITIES (DAILINK_DA7219 + 1) + +static struct snd_soc_dai_link rockchip_dailinks[] = { + [DAILINK_MAX98357A] = { + .name = "MAX98357A", + .stream_name = "MAX98357A PCM", + .codec_dai_name = "HiFi", + .ops = &rockchip_sound_max98357a_ops, + /* set max98357a as slave */ + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + }, + [DAILINK_RT5514] = { + .name = "RT5514", + .stream_name = "RT5514 PCM", + .codec_dai_name = "rt5514-aif1", + .ops = &rockchip_sound_rt5514_ops, + /* set rt5514 as slave */ + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + }, + [DAILINK_DA7219] = { + .name = "DA7219", + .stream_name = "DA7219 PCM", + .codec_dai_name = "da7219-hifi", + .init = rockchip_sound_da7219_init, + .ops = &rockchip_sound_da7219_ops, + /* set da7219 as slave */ + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + }, + /* RT5514 DSP for voice wakeup via spi bus */ + [DAILINK_RT5514_DSP] = { + .name = "RT5514 DSP", + .stream_name = "Wake on Voice", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + }, +}; + +static struct snd_soc_card rockchip_sound_card = { + .name = "rk3399-gru-sound", + .owner = THIS_MODULE, + .dai_link = rockchip_dailinks, + .num_links = ARRAY_SIZE(rockchip_dailinks), + .dapm_widgets = rockchip_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets), + .dapm_routes = rockchip_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes), + .controls = rockchip_controls, + .num_controls = ARRAY_SIZE(rockchip_controls), +}; + +static int rockchip_sound_match_stub(struct device *dev, void *data) +{ + return 1; +} + +static int rockchip_sound_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &rockchip_sound_card; + struct device_node *cpu_node; + struct device *dev; + struct device_driver *drv; + int i, ret; + + cpu_node = of_parse_phandle(pdev->dev.of_node, "rockchip,cpu", 0); + if (!cpu_node) { + dev_err(&pdev->dev, "Property 'rockchip,cpu' missing or invalid\n"); + return -EINVAL; + } + + for (i = 0; i < DAILINK_ENTITIES; i++) { + rockchip_dailinks[i].platform_of_node = cpu_node; + rockchip_dailinks[i].cpu_of_node = cpu_node; + + rockchip_dailinks[i].codec_of_node = + of_parse_phandle(pdev->dev.of_node, "rockchip,codec", i); + if (!rockchip_dailinks[i].codec_of_node) { + dev_err(&pdev->dev, + "Property[%d] 'rockchip,codec' missing or invalid\n", i); + return -EINVAL; + } + } + + /** + * To acquire the spi driver of the rt5514 and set the dai-links names + * for soc_bind_dai_link + */ + drv = driver_find("rt5514", &spi_bus_type); + if (!drv) { + dev_err(&pdev->dev, "Can not find the rt5514 driver at the spi bus\n"); + return -EINVAL; + } + + dev = driver_find_device(drv, NULL, NULL, rockchip_sound_match_stub); + if (!dev) { + dev_err(&pdev->dev, "Can not find the rt5514 device\n"); + return -ENODEV; + } + + /* Set DMIC delay */ + ret = device_property_read_u32(&pdev->dev, "dmic-delay", + &rt5514_dmic_delay); + if (ret) { + rt5514_dmic_delay = 0; + dev_dbg(&pdev->dev, + "no optional property 'dmic-delay' found, default: no delay\n"); + } + + rockchip_dailinks[DAILINK_RT5514_DSP].cpu_name = kstrdup_const(dev_name(dev), GFP_KERNEL); + rockchip_dailinks[DAILINK_RT5514_DSP].cpu_dai_name = kstrdup_const(dev_name(dev), GFP_KERNEL); + rockchip_dailinks[DAILINK_RT5514_DSP].platform_name = kstrdup_const(dev_name(dev), GFP_KERNEL); + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) + dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", + __func__, ret); + + return ret; +} + +static const struct of_device_id rockchip_sound_of_match[] = { + { .compatible = "rockchip,rk3399-gru-sound", }, + {}, +}; + +static struct platform_driver rockchip_sound_driver = { + .probe = rockchip_sound_probe, + .driver = { + .name = DRV_NAME, + .of_match_table = rockchip_sound_of_match, +#ifdef CONFIG_PM + .pm = &snd_soc_pm_ops, +#endif + }, +}; + +module_platform_driver(rockchip_sound_driver); + +MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>"); +MODULE_DESCRIPTION("Rockchip ASoC Machine Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, rockchip_sound_of_match); diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 652e8c5ea166..974915cb4c4f 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -57,6 +57,7 @@ static int i2s_runtime_suspend(struct device *dev) { struct rk_i2s_dev *i2s = dev_get_drvdata(dev); + regcache_cache_only(i2s->regmap, true); clk_disable_unprepare(i2s->mclk); return 0; @@ -73,7 +74,14 @@ static int i2s_runtime_resume(struct device *dev) return ret; } - return 0; + regcache_cache_only(i2s->regmap, false); + regcache_mark_dirty(i2s->regmap); + + ret = regcache_sync(i2s->regmap); + if (ret) + clk_disable_unprepare(i2s->mclk); + + return ret; } static inline struct rk_i2s_dev *to_info(struct snd_soc_dai *dai) diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index 4ca265737eda..fa8101d1e16f 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -65,6 +65,7 @@ static int __maybe_unused rk_spdif_runtime_suspend(struct device *dev) { struct rk_spdif_dev *spdif = dev_get_drvdata(dev); + regcache_cache_only(spdif->regmap, true); clk_disable_unprepare(spdif->mclk); clk_disable_unprepare(spdif->hclk); @@ -88,7 +89,16 @@ static int __maybe_unused rk_spdif_runtime_resume(struct device *dev) return ret; } - return 0; + regcache_cache_only(spdif->regmap, false); + regcache_mark_dirty(spdif->regmap); + + ret = regcache_sync(spdif->regmap); + if (ret) { + clk_disable_unprepare(spdif->mclk); + clk_disable_unprepare(spdif->hclk); + } + + return ret; } static int rk_spdif_hw_params(struct snd_pcm_substream *substream, diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 7b722b0094d9..f6023b46c107 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -1,12 +1,14 @@ -config SND_SOC_SAMSUNG +menuconfig SND_SOC_SAMSUNG tristate "ASoC support for Samsung" depends on (PLAT_SAMSUNG || ARCH_EXYNOS) select SND_SOC_GENERIC_DMAENGINE_PCM - help + ---help--- Say Y or M if you want to add support for codecs attached to the Samsung SoCs' Audio interfaces. You will also need to select the audio interfaces to support below. +if SND_SOC_SAMSUNG + config SND_S3C24XX_I2S tristate @@ -18,22 +20,22 @@ config SND_S3C2412_SOC_I2S select SND_S3C_I2SV2_SOC config SND_SAMSUNG_PCM - tristate + tristate "Samsung PCM interface support" config SND_SAMSUNG_AC97 tristate select SND_SOC_AC97_BUS config SND_SAMSUNG_SPDIF - tristate + tristate "Samsung SPDIF transmitter support" select SND_SOC_SPDIF config SND_SAMSUNG_I2S - tristate + tristate "Samsung I2S interface support" config SND_SOC_SAMSUNG_NEO1973_WM8753 tristate "Audio support for Openmoko Neo1973 Smartphones (GTA02)" - depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02 + depends on MACH_NEO1973_GTA02 select SND_S3C24XX_I2S select SND_SOC_WM8753 select SND_SOC_BT_SCO @@ -43,7 +45,7 @@ config SND_SOC_SAMSUNG_NEO1973_WM8753 config SND_SOC_SAMSUNG_JIVE_WM8750 tristate "SoC I2S Audio support for Jive" - depends on SND_SOC_SAMSUNG && MACH_JIVE && I2C + depends on MACH_JIVE && I2C select SND_SOC_WM8750 select SND_S3C2412_SOC_I2S help @@ -51,7 +53,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 config SND_SOC_SAMSUNG_SMDK_WM8580 tristate "SoC I2S Audio support for WM8580 on SMDK" - depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110) + depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 depends on I2C select SND_SOC_WM8580 select SND_SAMSUNG_I2S @@ -60,7 +62,6 @@ config SND_SOC_SAMSUNG_SMDK_WM8580 config SND_SOC_SAMSUNG_SMDK_WM8994 tristate "SoC I2S Audio support for WM8994 on SMDK" - depends on SND_SOC_SAMSUNG depends on I2C=y select MFD_WM8994 select SND_SOC_WM8994 @@ -70,7 +71,7 @@ config SND_SOC_SAMSUNG_SMDK_WM8994 config SND_SOC_SAMSUNG_SMDK2443_WM9710 tristate "SoC AC97 Audio support for SMDK2443 - WM9710" - depends on SND_SOC_SAMSUNG && MACH_SMDK2443 + depends on MACH_SMDK2443 select AC97_BUS select SND_SOC_AC97_CODEC select SND_SAMSUNG_AC97 @@ -80,7 +81,7 @@ config SND_SOC_SAMSUNG_SMDK2443_WM9710 config SND_SOC_SAMSUNG_LN2440SBC_ALC650 tristate "SoC AC97 Audio support for LN2440SBC - ALC650" - depends on SND_SOC_SAMSUNG && ARCH_S3C24XX + depends on ARCH_S3C24XX select AC97_BUS select SND_SOC_AC97_CODEC select SND_SAMSUNG_AC97 @@ -90,7 +91,7 @@ config SND_SOC_SAMSUNG_LN2440SBC_ALC650 config SND_SOC_SAMSUNG_S3C24XX_UDA134X tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" - depends on SND_SOC_SAMSUNG && ARCH_S3C24XX + depends on ARCH_S3C24XX select SND_S3C24XX_I2S select SND_SOC_L3 select SND_SOC_UDA134X @@ -102,21 +103,21 @@ config SND_SOC_SAMSUNG_SIMTEC config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23 tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards" - depends on SND_SOC_SAMSUNG && ARCH_S3C24XX && I2C + depends on ARCH_S3C24XX && I2C select SND_S3C24XX_I2S select SND_SOC_TLV320AIC23_I2C select SND_SOC_SAMSUNG_SIMTEC config SND_SOC_SAMSUNG_SIMTEC_HERMES tristate "SoC I2S Audio support for Simtec Hermes board" - depends on SND_SOC_SAMSUNG && ARCH_S3C24XX && I2C + depends on ARCH_S3C24XX && I2C select SND_S3C24XX_I2S select SND_SOC_TLV320AIC3X select SND_SOC_SAMSUNG_SIMTEC config SND_SOC_SAMSUNG_H1940_UDA1380 tristate "Audio support for the HP iPAQ H1940" - depends on SND_SOC_SAMSUNG && ARCH_H1940 && I2C + depends on ARCH_H1940 && I2C select SND_S3C24XX_I2S select SND_SOC_UDA1380 help @@ -124,7 +125,7 @@ config SND_SOC_SAMSUNG_H1940_UDA1380 config SND_SOC_SAMSUNG_RX1950_UDA1380 tristate "Audio support for the HP iPAQ RX1950" - depends on SND_SOC_SAMSUNG && MACH_RX1950 && I2C + depends on MACH_RX1950 && I2C select SND_S3C24XX_I2S select SND_SOC_UDA1380 help @@ -132,7 +133,7 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380 config SND_SOC_SAMSUNG_SMDK_WM9713 tristate "SoC AC97 Audio support for SMDK with WM9713" - depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110) + depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 select SND_SOC_WM9713 select SND_SAMSUNG_AC97 help @@ -140,20 +141,19 @@ config SND_SOC_SAMSUNG_SMDK_WM9713 config SND_SOC_SMARTQ tristate "SoC I2S Audio support for SmartQ board" - depends on SND_SOC_SAMSUNG && MACH_SMARTQ && I2C + depends on MACH_SMARTQ && I2C select SND_SAMSUNG_I2S select SND_SOC_WM8750 config SND_SOC_SAMSUNG_SMDK_SPDIF tristate "SoC S/PDIF Audio support for SMDK" - depends on SND_SOC_SAMSUNG select SND_SAMSUNG_SPDIF help Say Y if you want to add support for SoC S/PDIF audio on the SMDK. config SND_SOC_SMDK_WM8580_PCM tristate "SoC PCM Audio support for WM8580 on SMDK" - depends on SND_SOC_SAMSUNG && (MACH_SMDKV210 || MACH_SMDKC110) + depends on MACH_SMDKV210 || MACH_SMDKC110 depends on I2C select SND_SOC_WM8580 select SND_SAMSUNG_PCM @@ -162,7 +162,6 @@ config SND_SOC_SMDK_WM8580_PCM config SND_SOC_SMDK_WM8994_PCM tristate "SoC PCM Audio support for WM8994 on SMDK" - depends on SND_SOC_SAMSUNG depends on I2C=y select MFD_WM8994 select SND_SOC_WM8994 @@ -172,7 +171,7 @@ config SND_SOC_SMDK_WM8994_PCM config SND_SOC_SPEYSIDE tristate "Audio support for Wolfson Speyside" - depends on SND_SOC_SAMSUNG && I2C && SPI_MASTER + depends on I2C && SPI_MASTER depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST select SND_SAMSUNG_I2S select SND_SOC_WM8996 @@ -182,14 +181,14 @@ config SND_SOC_SPEYSIDE config SND_SOC_TOBERMORY tristate "Audio support for Wolfson Tobermory" - depends on SND_SOC_SAMSUNG && INPUT && I2C + depends on INPUT && I2C depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST select SND_SAMSUNG_I2S select SND_SOC_WM8962 config SND_SOC_BELLS tristate "Audio support for Wolfson Bells" - depends on SND_SOC_SAMSUNG && MFD_ARIZONA && I2C && SPI_MASTER + depends on MFD_ARIZONA && I2C && SPI_MASTER depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST select SND_SAMSUNG_I2S select SND_SOC_WM5102 @@ -200,7 +199,7 @@ config SND_SOC_BELLS config SND_SOC_LOWLAND tristate "Audio support for Wolfson Lowland" - depends on SND_SOC_SAMSUNG && I2C + depends on I2C depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST select SND_SAMSUNG_I2S select SND_SOC_WM5100 @@ -208,7 +207,7 @@ config SND_SOC_LOWLAND config SND_SOC_LITTLEMILL tristate "Audio support for Wolfson Littlemill" - depends on SND_SOC_SAMSUNG && I2C + depends on I2C depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST select SND_SAMSUNG_I2S select MFD_WM8994 @@ -216,7 +215,7 @@ config SND_SOC_LITTLEMILL config SND_SOC_SNOW tristate "Audio support for Google Snow boards" - depends on SND_SOC_SAMSUNG && I2C + depends on I2C select SND_SOC_MAX98090 select SND_SOC_MAX98095 select SND_SAMSUNG_I2S @@ -226,6 +225,8 @@ config SND_SOC_SNOW config SND_SOC_ARNDALE_RT5631_ALC5631 tristate "Audio support for RT5631(ALC5631) on Arndale Board" - depends on SND_SOC_SAMSUNG && I2C + depends on I2C select SND_SAMSUNG_I2S select SND_SOC_RT5631 + +endif #SND_SOC_SAMSUNG diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index 547d31032088..97d6700b1009 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -38,16 +38,16 @@ struct s3c_ac97_info { }; static struct s3c_ac97_info s3c_ac97; -static struct s3c_dma_params s3c_ac97_pcm_out = { - .dma_size = 4, +static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_out = { + .addr_width = 4, }; -static struct s3c_dma_params s3c_ac97_pcm_in = { - .dma_size = 4, +static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_in = { + .addr_width = 4, }; -static struct s3c_dma_params s3c_ac97_mic_in = { - .dma_size = 4, +static struct snd_dmaengine_dai_dma_data s3c_ac97_mic_in = { + .addr_width = 4, }; static void s3c_ac97_activate(struct snd_ac97 *ac97) @@ -74,7 +74,7 @@ static void s3c_ac97_activate(struct snd_ac97 *ac97) writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) - pr_err("AC97: Unable to activate!"); + pr_err("AC97: Unable to activate!\n"); } static unsigned short s3c_ac97_read(struct snd_ac97 *ac97, @@ -100,7 +100,7 @@ static unsigned short s3c_ac97_read(struct snd_ac97 *ac97, writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) - pr_err("AC97: Unable to read!"); + pr_err("AC97: Unable to read!\n"); stat = readl(s3c_ac97.regs + S3C_AC97_STAT); addr = (stat >> 16) & 0x7f; @@ -137,7 +137,7 @@ static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg, writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) - pr_err("AC97: Unable to write!"); + pr_err("AC97: Unable to write!\n"); ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ; @@ -273,14 +273,14 @@ static const struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = { static int s3c_ac97_dai_probe(struct snd_soc_dai *dai) { - samsung_asoc_init_dma_data(dai, &s3c_ac97_pcm_out, &s3c_ac97_pcm_in); + snd_soc_dai_init_dma_data(dai, &s3c_ac97_pcm_out, &s3c_ac97_pcm_in); return 0; } static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai) { - samsung_asoc_init_dma_data(dai, NULL, &s3c_ac97_mic_in); + snd_soc_dai_init_dma_data(dai, NULL, &s3c_ac97_mic_in); return 0; } @@ -346,12 +346,12 @@ static int s3c_ac97_probe(struct platform_device *pdev) if (IS_ERR(s3c_ac97.regs)) return PTR_ERR(s3c_ac97.regs); - s3c_ac97_pcm_out.slave = ac97_pdata->dma_playback; - s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; - s3c_ac97_pcm_in.slave = ac97_pdata->dma_capture; - s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; - s3c_ac97_mic_in.slave = ac97_pdata->dma_capture_mic; - s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA; + s3c_ac97_pcm_out.filter_data = ac97_pdata->dma_playback; + s3c_ac97_pcm_out.addr = mem_res->start + S3C_AC97_PCM_DATA; + s3c_ac97_pcm_in.filter_data = ac97_pdata->dma_capture; + s3c_ac97_pcm_in.addr = mem_res->start + S3C_AC97_PCM_DATA; + s3c_ac97_mic_in.filter_data = ac97_pdata->dma_capture_mic; + s3c_ac97_mic_in.addr = mem_res->start + S3C_AC97_MIC_DATA; init_completion(&s3c_ac97.done); mutex_init(&s3c_ac97.lock); diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index 3830f297e0b6..7ae580d677c8 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -1,6 +1,4 @@ /* - * dma.h -- - * * 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 @@ -9,27 +7,15 @@ * ALSA PCM interface for the Samsung SoC */ -#ifndef _S3C_AUDIO_H -#define _S3C_AUDIO_H +#ifndef _SAMSUNG_DMA_H +#define _SAMSUNG_DMA_H #include <sound/dmaengine_pcm.h> -#include <linux/dmaengine.h> - -struct s3c_dma_params { - void *slave; /* Channel ID */ - dma_addr_t dma_addr; - int dma_size; /* Size of the DMA transfer */ - char *ch_name; - struct snd_dmaengine_dai_dma_data dma_data; -}; -void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, - struct s3c_dma_params *playback, - struct s3c_dma_params *capture); /* * @tx, @rx arguments can be NULL if the DMA channel names are "tx", "rx", * otherwise actual DMA channel names must be passed to this function. */ int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, const char *tx, const char *rx); -#endif +#endif /* _SAMSUNG_DMA_H */ diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c index 2c87f380bfc4..9104c98deeb7 100644 --- a/sound/soc/samsung/dmaengine.c +++ b/sound/soc/samsung/dmaengine.c @@ -16,49 +16,18 @@ */ #include <linux/module.h> -#include <linux/amba/pl08x.h> -#include <linux/platform_data/dma-s3c24xx.h> - #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/dmaengine_pcm.h> #include <sound/soc.h> -#include <sound/soc-dai.h> #include "dma.h" -void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, - struct s3c_dma_params *playback, - struct s3c_dma_params *capture) -{ - struct snd_dmaengine_dai_dma_data *playback_data = NULL; - struct snd_dmaengine_dai_dma_data *capture_data = NULL; - - if (playback) { - playback_data = &playback->dma_data; - playback_data->filter_data = playback->slave; - playback_data->chan_name = playback->ch_name; - playback_data->addr = playback->dma_addr; - playback_data->addr_width = playback->dma_size; - } - if (capture) { - capture_data = &capture->dma_data; - capture_data->filter_data = capture->slave; - capture_data->chan_name = capture->ch_name; - capture_data->addr = capture->dma_addr; - capture_data->addr_width = capture->dma_size; - } - - snd_soc_dai_init_dma_data(dai, playback_data, capture_data); -} -EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data); - int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, const char *tx, const char *rx) { unsigned int flags = SND_DMAENGINE_PCM_FLAG_COMPAT; - struct snd_dmaengine_pcm_config *pcm_conf; pcm_conf = devm_kzalloc(dev, sizeof(*pcm_conf), GFP_KERNEL); diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 50635ee8ff20..7e32cf4581f8 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -87,9 +87,9 @@ struct i2s_dai { /* Driver for this DAI */ struct snd_soc_dai_driver i2s_dai_drv; /* DMA parameters */ - struct s3c_dma_params dma_playback; - struct s3c_dma_params dma_capture; - struct s3c_dma_params idma_playback; + struct snd_dmaengine_dai_dma_data dma_playback; + struct snd_dmaengine_dai_dma_data dma_capture; + struct snd_dmaengine_dai_dma_data idma_playback; dma_filter_fn filter; u32 quirks; u32 suspend_i2smod; @@ -692,15 +692,15 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, break; case 2: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - i2s->dma_playback.dma_size = 4; + i2s->dma_playback.addr_width = 4; else - i2s->dma_capture.dma_size = 4; + i2s->dma_capture.addr_width = 4; break; case 1: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - i2s->dma_playback.dma_size = 2; + i2s->dma_playback.addr_width = 2; else - i2s->dma_capture.dma_size = 2; + i2s->dma_capture.addr_width = 2; break; default: @@ -754,7 +754,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, writel(mod, i2s->addr + I2SMOD); spin_unlock_irqrestore(i2s->lock, flags); - samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); + snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); i2s->frmclk = params_rate(params); @@ -991,10 +991,10 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) unsigned long flags; if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */ - samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback, + snd_soc_dai_init_dma_data(dai, &other->sec_dai->dma_playback, NULL); } else { - samsung_asoc_init_dma_data(dai, &i2s->dma_playback, + snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); if (i2s->quirks & QUIRK_NEED_RSTCLR) @@ -1002,7 +1002,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) if (i2s->quirks & QUIRK_SUPPORTS_IDMA) idma_reg_addr_init(i2s->addr, - i2s->sec_dai->idma_playback.dma_addr); + i2s->sec_dai->idma_playback.addr); } /* Reset any constraint on RFS and BFS */ @@ -1262,8 +1262,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) return -EINVAL; } - pri_dai->dma_playback.slave = i2s_pdata->dma_playback; - pri_dai->dma_capture.slave = i2s_pdata->dma_capture; + pri_dai->dma_playback.filter_data = i2s_pdata->dma_playback; + pri_dai->dma_capture.filter_data = i2s_pdata->dma_capture; pri_dai->filter = i2s_pdata->dma_filter; if (&i2s_pdata->type) @@ -1302,12 +1302,12 @@ static int samsung_i2s_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); return ret; } - pri_dai->dma_playback.dma_addr = regs_base + I2STXD; - pri_dai->dma_capture.dma_addr = regs_base + I2SRXD; - pri_dai->dma_playback.ch_name = "tx"; - pri_dai->dma_capture.ch_name = "rx"; - pri_dai->dma_playback.dma_size = 4; - pri_dai->dma_capture.dma_size = 4; + pri_dai->dma_playback.addr = regs_base + I2STXD; + pri_dai->dma_capture.addr = regs_base + I2SRXD; + pri_dai->dma_playback.chan_name = "tx"; + pri_dai->dma_capture.chan_name = "rx"; + pri_dai->dma_playback.addr_width = 4; + pri_dai->dma_capture.addr_width = 4; pri_dai->quirks = quirks; pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs; @@ -1318,31 +1318,33 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai = i2s_alloc_dai(pdev, true); if (!sec_dai) { dev_err(&pdev->dev, "Unable to alloc I2S_sec\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err_disable_clk; } sec_dai->lock = &pri_dai->spinlock; sec_dai->variant_regs = pri_dai->variant_regs; - sec_dai->dma_playback.dma_addr = regs_base + I2STXDS; - sec_dai->dma_playback.ch_name = "tx-sec"; + sec_dai->dma_playback.addr = regs_base + I2STXDS; + sec_dai->dma_playback.chan_name = "tx-sec"; if (!np) { - sec_dai->dma_playback.slave = i2s_pdata->dma_play_sec; + sec_dai->dma_playback.filter_data = i2s_pdata->dma_play_sec; sec_dai->filter = i2s_pdata->dma_filter; } - sec_dai->dma_playback.dma_size = 4; + sec_dai->dma_playback.addr_width = 4; sec_dai->addr = pri_dai->addr; sec_dai->clk = pri_dai->clk; sec_dai->quirks = quirks; - sec_dai->idma_playback.dma_addr = idma_addr; + sec_dai->idma_playback.addr = idma_addr; sec_dai->pri_dai = pri_dai; pri_dai->sec_dai = sec_dai; } if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { dev_err(&pdev->dev, "Unable to configure gpio\n"); - return -EINVAL; + ret = -EINVAL; + goto err_disable_clk; } ret = devm_snd_soc_register_component(&pri_dai->pdev->dev, @@ -1366,6 +1368,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) err_free_dai: if (sec_dai) i2s_free_sec_dai(sec_dai); +err_disable_clk: + clk_disable_unprepare(pri_dai->clk); return ret; } diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c index 4ed29ffc1c54..3e408158625d 100644 --- a/sound/soc/samsung/idma.c +++ b/sound/soc/samsung/idma.c @@ -22,7 +22,6 @@ #include "i2s.h" #include "idma.h" -#include "dma.h" #include "i2s-regs.h" #define ST_RUNNING (1<<0) diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 490c1a87fd66..43e367a9acc3 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -127,25 +127,25 @@ struct s3c_pcm_info { struct clk *pclk; struct clk *cclk; - struct s3c_dma_params *dma_playback; - struct s3c_dma_params *dma_capture; + struct snd_dmaengine_dai_dma_data *dma_playback; + struct snd_dmaengine_dai_dma_data *dma_capture; }; -static struct s3c_dma_params s3c_pcm_stereo_out[] = { +static struct snd_dmaengine_dai_dma_data s3c_pcm_stereo_out[] = { [0] = { - .dma_size = 4, + .addr_width = 4, }, [1] = { - .dma_size = 4, + .addr_width = 4, }, }; -static struct s3c_dma_params s3c_pcm_stereo_in[] = { +static struct snd_dmaengine_dai_dma_data s3c_pcm_stereo_in[] = { [0] = { - .dma_size = 4, + .addr_width = 4, }, [1] = { - .dma_size = 4, + .addr_width = 4, }, }; @@ -552,15 +552,13 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) } clk_prepare_enable(pcm->pclk); - s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start - + S3C_PCM_RXFIFO; - s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start - + S3C_PCM_TXFIFO; + s3c_pcm_stereo_in[pdev->id].addr = mem_res->start + S3C_PCM_RXFIFO; + s3c_pcm_stereo_out[pdev->id].addr = mem_res->start + S3C_PCM_TXFIFO; filter = NULL; if (pcm_pdata) { - s3c_pcm_stereo_in[pdev->id].slave = pcm_pdata->dma_capture; - s3c_pcm_stereo_out[pdev->id].slave = pcm_pdata->dma_playback; + s3c_pcm_stereo_in[pdev->id].filter_data = pcm_pdata->dma_capture; + s3c_pcm_stereo_out[pdev->id].filter_data = pcm_pdata->dma_playback; filter = pcm_pdata->dma_filter; } diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index bf8ae79b0fd2..644f186fd35c 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c @@ -24,7 +24,6 @@ #include "regs-i2s-v2.h" #include "s3c-i2s-v2.h" -#include "dma.h" #undef S3C_IIS_V2_SUPPORTED @@ -302,7 +301,7 @@ static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct s3c_i2sv2_info *i2s = to_info(dai); - struct s3c_dma_params *dma_data; + struct snd_dmaengine_dai_dma_data *dma_data; u32 iismod; pr_debug("Entered %s\n", __func__); diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h index d0684145ed1f..182d80564e37 100644 --- a/sound/soc/samsung/s3c-i2s-v2.h +++ b/sound/soc/samsung/s3c-i2s-v2.h @@ -60,8 +60,8 @@ struct s3c_i2sv2_info { unsigned char master; - struct s3c_dma_params *dma_playback; - struct s3c_dma_params *dma_capture; + struct snd_dmaengine_dai_dma_data *dma_playback; + struct snd_dmaengine_dai_dma_data *dma_capture; u32 suspend_iismod; u32 suspend_iiscon; diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index d45dffb297d8..3e89fbc0c51d 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -34,14 +34,14 @@ #include <linux/platform_data/asoc-s3c.h> -static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = { - .ch_name = "tx", - .dma_size = 4, +static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_out = { + .chan_name = "tx", + .addr_width = 4, }; -static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = { - .ch_name = "rx", - .dma_size = 4, +static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_in = { + .chan_name = "rx", + .addr_width = 4, }; static struct s3c_i2sv2_info s3c2412_i2s; @@ -52,8 +52,8 @@ static int s3c2412_i2s_probe(struct snd_soc_dai *dai) pr_debug("Entered %s\n", __func__); - samsung_asoc_init_dma_data(dai, &s3c2412_i2s_pcm_stereo_out, - &s3c2412_i2s_pcm_stereo_in); + snd_soc_dai_init_dma_data(dai, &s3c2412_i2s_pcm_stereo_out, + &s3c2412_i2s_pcm_stereo_in); ret = s3c_i2sv2_probe(dai, &s3c2412_i2s, S3C2410_PA_IIS); if (ret) @@ -163,10 +163,10 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) if (IS_ERR(s3c2412_i2s.regs)) return PTR_ERR(s3c2412_i2s.regs); - s3c2412_i2s_pcm_stereo_out.dma_addr = res->start + S3C2412_IISTXD; - s3c2412_i2s_pcm_stereo_out.slave = pdata->dma_playback; - s3c2412_i2s_pcm_stereo_in.dma_addr = res->start + S3C2412_IISRXD; - s3c2412_i2s_pcm_stereo_in.slave = pdata->dma_capture; + s3c2412_i2s_pcm_stereo_out.addr = res->start + S3C2412_IISTXD; + s3c2412_i2s_pcm_stereo_out.filter_data = pdata->dma_playback; + s3c2412_i2s_pcm_stereo_in.addr = res->start + S3C2412_IISRXD; + s3c2412_i2s_pcm_stereo_in.filter_data = pdata->dma_capture; ret = s3c_i2sv2_register_component(&pdev->dev, -1, &s3c2412_i2s_component, diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 3e76f2a75a24..c78a936a3099 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -32,14 +32,14 @@ #include <linux/platform_data/asoc-s3c.h> -static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = { - .ch_name = "tx", - .dma_size = 2, +static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_out = { + .chan_name = "tx", + .addr_width = 2, }; -static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = { - .ch_name = "rx", - .dma_size = 2, +static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_in = { + .chan_name = "rx", + .addr_width = 2, }; struct s3c24xx_i2s_info { @@ -360,8 +360,8 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai) { pr_debug("Entered %s\n", __func__); - samsung_asoc_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out, - &s3c24xx_i2s_pcm_stereo_in); + snd_soc_dai_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out, + &s3c24xx_i2s_pcm_stereo_in); s3c24xx_i2s.iis_clk = devm_clk_get(dai->dev, "iis"); if (IS_ERR(s3c24xx_i2s.iis_clk)) { @@ -469,10 +469,10 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) if (IS_ERR(s3c24xx_i2s.regs)) return PTR_ERR(s3c24xx_i2s.regs); - s3c24xx_i2s_pcm_stereo_out.dma_addr = res->start + S3C2410_IISFIFO; - s3c24xx_i2s_pcm_stereo_out.slave = pdata->dma_playback; - s3c24xx_i2s_pcm_stereo_in.dma_addr = res->start + S3C2410_IISFIFO; - s3c24xx_i2s_pcm_stereo_in.slave = pdata->dma_capture; + s3c24xx_i2s_pcm_stereo_out.addr = res->start + S3C2410_IISFIFO; + s3c24xx_i2s_pcm_stereo_out.filter_data = pdata->dma_playback; + s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO; + s3c24xx_i2s_pcm_stereo_in.filter_data = pdata->dma_capture; ret = devm_snd_soc_register_component(&pdev->dev, &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1); diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c index 50849e137fc0..7853fbe6ccc9 100644 --- a/sound/soc/samsung/s3c24xx_uda134x.c +++ b/sound/soc/samsung/s3c24xx_uda134x.c @@ -54,28 +54,27 @@ static struct snd_pcm_hw_constraint_list hw_constraints_rates = { }; #endif -static struct platform_device *s3c24xx_uda134x_snd_device; - static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) { - int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; #ifdef ENFORCE_RATES struct snd_pcm_runtime *runtime = substream->runtime; #endif + int ret = 0; mutex_lock(&clk_lock); - pr_debug("%s %d\n", __func__, clk_users); + if (clk_users == 0) { - xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal"); + xtal = clk_get(rtd->dev, "xtal"); if (IS_ERR(xtal)) { - printk(KERN_ERR "%s cannot get xtal\n", __func__); + dev_err(rtd->dev, "%s cannot get xtal\n", __func__); ret = PTR_ERR(xtal); } else { - pclk = clk_get(&s3c24xx_uda134x_snd_device->dev, - "pclk"); + pclk = clk_get(cpu_dai->dev, "iis"); if (IS_ERR(pclk)) { - printk(KERN_ERR "%s cannot get pclk\n", - __func__); + dev_err(rtd->dev, "%s cannot get pclk\n", + __func__); clk_put(xtal); ret = PTR_ERR(pclk); } @@ -101,8 +100,8 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); if (ret < 0) - printk(KERN_ERR "%s cannot set constraints\n", - __func__); + dev_err(rtd->dev, "%s cannot set constraints\n", + __func__); #endif } return ret; @@ -111,7 +110,6 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream) { mutex_lock(&clk_lock); - pr_debug("%s %d\n", __func__, clk_users); clk_users -= 1; if (clk_users == 0) { clk_put(xtal); @@ -158,18 +156,19 @@ static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream, clk_source = S3C24XX_CLKSRC_PCLK; div = bi % 33; } - pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi); + + dev_dbg(rtd->dev, "%s desired rate %lu, %d\n", __func__, rate, bi); clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate; - pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__, - fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS", - clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK", - div, clk, err); + + dev_dbg(rtd->dev, "%s will use: %s %s %d sysclk %d err %ld\n", __func__, + fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS", + clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK", + div, clk, err); if ((err * 100 / rate) > 5) { - printk(KERN_ERR "S3C24XX_UDA134X: effective frequency " - "too different from desired (%ld%%)\n", - err * 100 / rate); + dev_err(rtd->dev, "effective frequency too different " + "from desired (%ld%%)\n", err * 100 / rate); return -EINVAL; } @@ -226,115 +225,27 @@ static struct snd_soc_card snd_soc_s3c24xx_uda134x = { .num_links = 1, }; -static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins; - -static void setdat(int v) -{ - gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0); -} - -static void setclk(int v) -{ - gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0); -} - -static void setmode(int v) -{ - gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0); -} - -/* FIXME - This must be codec platform data but in which board file ?? */ -static struct uda134x_platform_data s3c24xx_uda134x = { - .l3 = { - .setdat = setdat, - .setclk = setclk, - .setmode = setmode, - .data_hold = 1, - .data_setup = 1, - .clock_high = 1, - .mode_hold = 1, - .mode = 1, - .mode_setup = 1, - }, -}; - -static int s3c24xx_uda134x_setup_pin(int pin, char *fun) -{ - if (gpio_request(pin, "s3c24xx_uda134x") < 0) { - printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " - "l3 %s pin already in use", fun); - return -EBUSY; - } - gpio_direction_output(pin, 0); - return 0; -} - static int s3c24xx_uda134x_probe(struct platform_device *pdev) { + struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x; int ret; - printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n"); + platform_set_drvdata(pdev, card); + card->dev = &pdev->dev; - s3c24xx_uda134x_l3_pins = pdev->dev.platform_data; - if (s3c24xx_uda134x_l3_pins == NULL) { - printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " - "unable to find platform data\n"); - return -ENODEV; - } - s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power; - s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model; - - if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data, - "data") < 0) - return -EBUSY; - if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk, - "clk") < 0) { - gpio_free(s3c24xx_uda134x_l3_pins->l3_data); - return -EBUSY; - } - if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode, - "mode") < 0) { - gpio_free(s3c24xx_uda134x_l3_pins->l3_data); - gpio_free(s3c24xx_uda134x_l3_pins->l3_clk); - return -EBUSY; - } - - s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1); - if (!s3c24xx_uda134x_snd_device) { - printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " - "Unable to register\n"); - return -ENOMEM; - } - - platform_set_drvdata(s3c24xx_uda134x_snd_device, - &snd_soc_s3c24xx_uda134x); - platform_device_add_data(s3c24xx_uda134x_snd_device, &s3c24xx_uda134x, sizeof(s3c24xx_uda134x)); - ret = platform_device_add(s3c24xx_uda134x_snd_device); - if (ret) { - printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n"); - platform_device_put(s3c24xx_uda134x_snd_device); - } + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) + dev_err(&pdev->dev, "failed to register card: %d\n", ret); return ret; } -static int s3c24xx_uda134x_remove(struct platform_device *pdev) -{ - platform_device_unregister(s3c24xx_uda134x_snd_device); - gpio_free(s3c24xx_uda134x_l3_pins->l3_data); - gpio_free(s3c24xx_uda134x_l3_pins->l3_clk); - gpio_free(s3c24xx_uda134x_l3_pins->l3_mode); - return 0; -} - static struct platform_driver s3c24xx_uda134x_driver = { .probe = s3c24xx_uda134x_probe, - .remove = s3c24xx_uda134x_remove, .driver = { .name = "s3c24xx_uda134x", }, }; - module_platform_driver(s3c24xx_uda134x_driver); MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>"); diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c index 6deec5234c92..a6d223310c67 100644 --- a/sound/soc/samsung/smdk_wm8580pcm.c +++ b/sound/soc/samsung/smdk_wm8580pcm.c @@ -16,7 +16,6 @@ #include <asm/mach-types.h> #include "../codecs/wm8580.h" -#include "dma.h" #include "pcm.h" /* diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c index b1c89ec2d999..2e621496be8b 100644 --- a/sound/soc/samsung/smdk_wm8994pcm.c +++ b/sound/soc/samsung/smdk_wm8994pcm.c @@ -15,7 +15,6 @@ #include <sound/pcm_params.h> #include "../codecs/wm8994.h" -#include "dma.h" #include "pcm.h" /* diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index 0cb9c8567546..26c1fbed4d35 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -90,10 +90,10 @@ struct samsung_spdif_info { u32 saved_clkcon; u32 saved_con; u32 saved_cstas; - struct s3c_dma_params *dma_playback; + struct snd_dmaengine_dai_dma_data *dma_playback; }; -static struct s3c_dma_params spdif_stereo_out; +static struct snd_dmaengine_dai_dma_data spdif_stereo_out; static struct samsung_spdif_info spdif_info; static inline struct samsung_spdif_info *to_info(struct snd_soc_dai *cpu_dai) @@ -179,7 +179,7 @@ static int spdif_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai); void __iomem *regs = spdif->regs; - struct s3c_dma_params *dma_data; + struct snd_dmaengine_dai_dma_data *dma_data; u32 con, clkcon, cstas; unsigned long flags; int i, ratio; @@ -425,11 +425,11 @@ static int spdif_probe(struct platform_device *pdev) goto err4; } - spdif_stereo_out.dma_size = 2; - spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF; + spdif_stereo_out.addr_width = 2; + spdif_stereo_out.addr = mem_res->start + DATA_OUTBUF; filter = NULL; if (spdif_pdata) { - spdif_stereo_out.slave = spdif_pdata->dma_playback; + spdif_stereo_out.filter_data = spdif_pdata->dma_playback; filter = spdif_pdata->dma_filter; } diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 9311f119feb5..6db6405d952f 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -42,12 +42,6 @@ config SND_SOC_RCAR help This option enables R-Car SRU/SCU/SSIU/SSI sound support -config SND_SOC_RSRC_CARD - tristate "Renesas Sampling Rate Convert Sound Card" - select SND_SIMPLE_CARD_UTILS - help - This option enables simple sound if you need sampling rate convert - ## ## Boards ## diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index a89ddf758695..9c3d5aed99d1 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,5 +1,2 @@ snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o - -snd-soc-rsrc-card-objs := rsrc-card.o -obj-$(CONFIG_SND_SOC_RSRC_CARD) += snd-soc-rsrc-card.o diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 3351a701c60e..f18141098b50 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -110,6 +110,7 @@ MODULE_DEVICE_TABLE(of, rsnd_of_match); /* * rsnd_mod functions */ +#ifdef DEBUG void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) { if (mod->type != type) { @@ -120,6 +121,7 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) rsnd_mod_name(mod), rsnd_mod_id(mod)); } } +#endif char *rsnd_mod_name(struct rsnd_mod *mod) { @@ -574,6 +576,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: rsnd_dai_stream_init(io, substream); ret = rsnd_dai_call(init, io, priv); @@ -590,6 +593,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, break; case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: ret = rsnd_dai_call(irq, io, priv, 0); ret |= rsnd_dai_call(stop, io, priv); diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c deleted file mode 100644 index fa37f842b62f..000000000000 --- a/sound/soc/sh/rcar/rsrc-card.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Renesas Sampling Rate Convert Sound Card for DPCM - * - * Copyright (C) 2015 Renesas Solutions Corp. - * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - * - * based on ${LINUX}/sound/soc/generic/simple-card.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/clk.h> -#include <linux/device.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/platform_device.h> -#include <linux/string.h> -#include <sound/jack.h> -#include <sound/soc.h> -#include <sound/soc-dai.h> -#include <sound/simple_card_utils.h> - -struct rsrc_card_of_data { - const char *prefix; - const struct snd_soc_dapm_route *routes; - int num_routes; -}; - -static const struct snd_soc_dapm_route routes_ssi0_ak4642[] = { - {"ak4642 Playback", NULL, "DAI0 Playback"}, - {"DAI0 Capture", NULL, "ak4642 Capture"}, -}; - -static const struct rsrc_card_of_data routes_of_ssi0_ak4642 = { - .prefix = "ak4642", - .routes = routes_ssi0_ak4642, - .num_routes = ARRAY_SIZE(routes_ssi0_ak4642), -}; - -static const struct of_device_id rsrc_card_of_match[] = { - { .compatible = "renesas,rsrc-card,lager", .data = &routes_of_ssi0_ak4642 }, - { .compatible = "renesas,rsrc-card,koelsch", .data = &routes_of_ssi0_ak4642 }, - { .compatible = "renesas,rsrc-card", }, - {}, -}; -MODULE_DEVICE_TABLE(of, rsrc_card_of_match); - -#define IDX_CPU 0 -#define IDX_CODEC 1 -struct rsrc_card_priv { - struct snd_soc_card snd_card; - struct snd_soc_codec_conf codec_conf; - struct asoc_simple_dai *dai_props; - struct snd_soc_dai_link *dai_link; - u32 convert_rate; - u32 convert_channels; -}; - -#define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev) -#define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i)) -#define rsrc_priv_to_props(priv, i) ((priv)->dai_props + (i)) - -static int rsrc_card_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct asoc_simple_dai *dai_props = - rsrc_priv_to_props(priv, rtd->num); - - return clk_prepare_enable(dai_props->clk); -} - -static void rsrc_card_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct asoc_simple_dai *dai_props = - rsrc_priv_to_props(priv, rtd->num); - - clk_disable_unprepare(dai_props->clk); -} - -static struct snd_soc_ops rsrc_card_ops = { - .startup = rsrc_card_startup, - .shutdown = rsrc_card_shutdown, -}; - -static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) -{ - struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai; - struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dai_props; - int num = rtd->num; - int ret; - - dai_link = rsrc_priv_to_link(priv, num); - dai_props = rsrc_priv_to_props(priv, num); - dai = dai_link->dynamic ? - rtd->cpu_dai : - rtd->codec_dai; - - if (dai_props->sysclk) { - ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0); - if (ret && ret != -ENOTSUPP) { - dev_err(dai->dev, "set_sysclk error\n"); - goto err; - } - } - - if (dai_props->slots) { - ret = snd_soc_dai_set_tdm_slot(dai, - dai_props->tx_slot_mask, - dai_props->rx_slot_mask, - dai_props->slots, - dai_props->slot_width); - if (ret && ret != -ENOTSUPP) { - dev_err(dai->dev, "set_tdm_slot error\n"); - goto err; - } - } - - ret = 0; - -err: - return ret; -} - -static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *channels = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - if (priv->convert_rate) - rate->min = - rate->max = priv->convert_rate; - - if (priv->convert_channels) - channels->min = - channels->max = priv->convert_channels; - - return 0; -} - -static int rsrc_card_parse_links(struct device_node *np, - struct rsrc_card_priv *priv, - int idx, bool is_fe) -{ - struct device *dev = rsrc_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); - struct asoc_simple_dai *dai_props = rsrc_priv_to_props(priv, idx); - struct of_phandle_args args; - int ret; - - /* - * Get node via "sound-dai = <&phandle port>" - * it will be used as xxx_of_node on soc_bind_dai_link() - */ - ret = of_parse_phandle_with_args(np, "sound-dai", - "#sound-dai-cells", 0, &args); - if (ret) - return ret; - - /* Parse TDM slot */ - ret = snd_soc_of_parse_tdm_slot(np, - &dai_props->tx_slot_mask, - &dai_props->rx_slot_mask, - &dai_props->slots, - &dai_props->slot_width); - if (ret) - return ret; - - if (is_fe) { - /* BE is dummy */ - dai_link->codec_of_node = NULL; - dai_link->codec_dai_name = "snd-soc-dummy-dai"; - dai_link->codec_name = "snd-soc-dummy"; - - /* FE settings */ - dai_link->dynamic = 1; - dai_link->dpcm_merged_format = 1; - dai_link->cpu_of_node = args.np; - ret = snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "fe.%s", - dai_link->cpu_dai_name); - if (ret < 0) - return ret; - - /* - * In soc_bind_dai_link() will check cpu name after - * of_node matching if dai_link has cpu_dai_name. - * but, it will never match if name was created by - * fmt_single_name() remove cpu_dai_name if cpu_args - * was 0. See: - * fmt_single_name() - * fmt_multiple_name() - */ - if (!args.args_count) - dai_link->cpu_dai_name = NULL; - } else { - const struct rsrc_card_of_data *of_data; - - of_data = of_device_get_match_data(dev); - - /* FE is dummy */ - dai_link->cpu_of_node = NULL; - dai_link->cpu_dai_name = "snd-soc-dummy-dai"; - dai_link->cpu_name = "snd-soc-dummy"; - - /* BE settings */ - dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup; - dai_link->codec_of_node = args.np; - ret = snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "be.%s", - dai_link->codec_dai_name); - if (ret < 0) - return ret; - - /* additional name prefix */ - if (of_data) { - priv->codec_conf.of_node = dai_link->codec_of_node; - priv->codec_conf.name_prefix = of_data->prefix; - } else { - snd_soc_of_parse_audio_prefix(&priv->snd_card, - &priv->codec_conf, - dai_link->codec_of_node, - "audio-prefix"); - } - } - - /* Simple Card assumes platform == cpu */ - dai_link->platform_of_node = dai_link->cpu_of_node; - dai_link->dpcm_playback = 1; - dai_link->dpcm_capture = 1; - dai_link->ops = &rsrc_card_ops; - dai_link->init = rsrc_card_dai_init; - - return 0; -} - -static int rsrc_card_parse_clk(struct device_node *np, - struct rsrc_card_priv *priv, - int idx, bool is_fe) -{ - struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); - struct asoc_simple_dai *dai_props = rsrc_priv_to_props(priv, idx); - struct clk *clk; - struct device_node *of_np = is_fe ? dai_link->cpu_of_node : - dai_link->codec_of_node; - u32 val; - - /* - * Parse dai->sysclk come from "clocks = <&xxx>" - * (if system has common clock) - * or "system-clock-frequency = <xxx>" - * or device's module clock. - */ - if (of_property_read_bool(np, "clocks")) { - clk = of_clk_get(np, 0); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - dai_props->sysclk = clk_get_rate(clk); - dai_props->clk = clk; - } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { - dai_props->sysclk = val; - } else { - clk = of_clk_get(of_np, 0); - if (!IS_ERR(clk)) - dai_props->sysclk = clk_get_rate(clk); - } - - return 0; -} - -static int rsrc_card_dai_sub_link_of(struct device_node *node, - struct device_node *np, - struct rsrc_card_priv *priv, - int idx, bool is_fe) -{ - struct device *dev = rsrc_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); - struct asoc_simple_dai *dai_props = rsrc_priv_to_props(priv, idx); - int ret; - - ret = rsrc_card_parse_links(np, priv, idx, is_fe); - if (ret < 0) - return ret; - - ret = rsrc_card_parse_clk(np, priv, idx, is_fe); - if (ret < 0) - return ret; - - dev_dbg(dev, "\t%s / %04x / %d\n", - dai_link->name, - dai_link->dai_fmt, - dai_props->sysclk); - - return ret; -} - -static int rsrc_card_dai_link_of(struct device_node *node, - struct rsrc_card_priv *priv) -{ - struct device *dev = rsrc_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link; - struct device_node *np; - unsigned int daifmt = 0; - int ret, i; - bool is_fe; - - /* find 1st codec */ - i = 0; - for_each_child_of_node(node, np) { - dai_link = rsrc_priv_to_link(priv, i); - - if (strcmp(np->name, "codec") == 0) { - ret = asoc_simple_card_parse_daifmt(dev, node, np, - NULL, &daifmt); - if (ret < 0) - return ret; - break; - } - i++; - } - - i = 0; - for_each_child_of_node(node, np) { - dai_link = rsrc_priv_to_link(priv, i); - dai_link->dai_fmt = daifmt; - - is_fe = false; - if (strcmp(np->name, "cpu") == 0) - is_fe = true; - - ret = rsrc_card_dai_sub_link_of(node, np, priv, i, is_fe); - if (ret < 0) - return ret; - i++; - } - - return 0; -} - -static int rsrc_card_parse_of(struct device_node *node, - struct rsrc_card_priv *priv, - struct device *dev) -{ - const struct rsrc_card_of_data *of_data = of_device_get_match_data(dev); - struct asoc_simple_dai *props; - struct snd_soc_dai_link *links; - int ret; - int num; - - if (!node) - return -EINVAL; - - num = of_get_child_count(node); - props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL); - links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL); - if (!props || !links) - return -ENOMEM; - - priv->dai_props = props; - priv->dai_link = links; - - /* Init snd_soc_card */ - priv->snd_card.owner = THIS_MODULE; - priv->snd_card.dev = dev; - priv->snd_card.dai_link = priv->dai_link; - priv->snd_card.num_links = num; - priv->snd_card.codec_conf = &priv->codec_conf; - priv->snd_card.num_configs = 1; - - if (of_data) { - priv->snd_card.of_dapm_routes = of_data->routes; - priv->snd_card.num_of_dapm_routes = of_data->num_routes; - } else { - snd_soc_of_parse_audio_routing(&priv->snd_card, - "audio-routing"); - } - - /* sampling rate convert */ - of_property_read_u32(node, "convert-rate", &priv->convert_rate); - - /* channels transfer */ - of_property_read_u32(node, "convert-channels", &priv->convert_channels); - - dev_dbg(dev, "New rsrc-audio-card: %s\n", - priv->snd_card.name ? priv->snd_card.name : ""); - dev_dbg(dev, "SRC : convert_rate %d\n", priv->convert_rate); - dev_dbg(dev, "CTU : convert_channels %d\n", priv->convert_channels); - - ret = rsrc_card_dai_link_of(node, priv); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_card_name(&priv->snd_card, "card-"); - if (ret < 0) - return ret; - - return 0; -} - -/* Decrease the reference count of the device nodes */ -static int rsrc_card_unref(struct snd_soc_card *card) -{ - struct snd_soc_dai_link *dai_link; - int num_links; - - for (num_links = 0, dai_link = card->dai_link; - num_links < card->num_links; - num_links++, dai_link++) { - of_node_put(dai_link->cpu_of_node); - of_node_put(dai_link->codec_of_node); - } - return 0; -} - -static int rsrc_card_probe(struct platform_device *pdev) -{ - struct rsrc_card_priv *priv; - struct device_node *np = pdev->dev.of_node; - struct device *dev = &pdev->dev; - int ret; - - /* Allocate the private data */ - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - ret = rsrc_card_parse_of(np, priv, dev); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "parse error %d\n", ret); - goto err; - } - - snd_soc_card_set_drvdata(&priv->snd_card, priv); - - ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); - if (ret >= 0) - return ret; -err: - rsrc_card_unref(&priv->snd_card); - - return ret; -} - -static int rsrc_card_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - return rsrc_card_unref(card); -} - -static struct platform_driver rsrc_card = { - .driver = { - .name = "renesas-src-audio-card", - .of_match_table = rsrc_card_of_match, - }, - .probe = rsrc_card_probe, - .remove = rsrc_card_remove, -}; - -module_platform_driver(rsrc_card); - -MODULE_ALIAS("platform:renesas-src-audio-card"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Renesas Sampling Rate Convert Sound Card"); -MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index e39f916d0f2f..969a5169de25 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -226,8 +226,12 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, ifscr = 0; fsrate = 0; if (fin != fout) { + u64 n; + ifscr = 1; - fsrate = 0x0400000 / fout * fin; + n = (u64)0x0400000 * fin; + do_div(n, fout); + fsrate = n; } /* diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 5f848f054745..6cb6db005fc4 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -928,7 +928,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) } ops = &rsnd_ssi_non_ops; - if (of_get_property(np, "pio-transfer", NULL)) + if (of_property_read_bool(np, "pio-transfer")) ops = &rsnd_ssi_pio_ops; else ops = &rsnd_ssi_dma_ops; diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c index bc4a55bb3fd9..6c8b0b0c56ec 100644 --- a/sound/soc/soc-ac97.c +++ b/sound/soc/soc-ac97.c @@ -116,7 +116,7 @@ static int snd_soc_ac97_gpio_direction_out(struct gpio_chip *chip, return snd_soc_update_bits(codec, AC97_GPIO_CFG, 1 << offset, 0); } -static struct gpio_chip snd_soc_ac97_gpio_chip = { +static const struct gpio_chip snd_soc_ac97_gpio_chip = { .label = "snd_soc_ac97", .owner = THIS_MODULE, .request = snd_soc_ac97_gpio_request, diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index d2df46c14c68..bf7b52fce597 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -121,7 +121,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) dpcm_be_disconnect(fe, stream); fe->dpcm[stream].runtime = NULL; - goto fe_err; + goto path_err; } dpcm_clear_pending_state(fe, stream); @@ -136,6 +136,8 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) return 0; +path_err: + dpcm_path_put(&list); fe_err: if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown) fe->dai_link->compr_ops->shutdown(cstream); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 16369cad4803..c0bbcd903261 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1056,7 +1056,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, if (!rtd->platform) { dev_err(card->dev, "ASoC: platform %s not registered\n", dai_link->platform_name); - return -EPROBE_DEFER; + goto _err_defer; } soc_add_pcm_runtime(card, rtd); @@ -2083,14 +2083,13 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) /* remove auxiliary devices */ soc_remove_aux_devices(card); + snd_soc_dapm_free(&card->dapm); soc_cleanup_card_debugfs(card); /* remove the card */ if (card->remove) card->remove(card); - snd_soc_dapm_free(&card->dapm); - snd_card_free(card->snd_card); return 0; @@ -3333,19 +3332,6 @@ int snd_soc_register_codec(struct device *dev, if (ret) goto err_free; - if (codec_drv->controls) { - codec->component.controls = codec_drv->controls; - codec->component.num_controls = codec_drv->num_controls; - } - if (codec_drv->dapm_widgets) { - codec->component.dapm_widgets = codec_drv->dapm_widgets; - codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets; - } - if (codec_drv->dapm_routes) { - codec->component.dapm_routes = codec_drv->dapm_routes; - codec->component.num_dapm_routes = codec_drv->num_dapm_routes; - } - if (codec_drv->probe) codec->component.probe = snd_soc_codec_drv_probe; if (codec_drv->remove) @@ -3733,7 +3719,7 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, * SND_SOC_DAIFMT_CLOCK_MASK area */ snprintf(prop, sizeof(prop), "%scontinuous-clock", prefix); - if (of_get_property(np, prop, NULL)) + if (of_property_read_bool(np, prop)) format |= SND_SOC_DAIFMT_CONT; else format |= SND_SOC_DAIFMT_GATED; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8698c26773b3..3bbe32ee4630 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -823,6 +823,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w, case snd_soc_dapm_switch: case snd_soc_dapm_mixer: case snd_soc_dapm_pga: + case snd_soc_dapm_out_drv: wname_in_long_name = true; kcname_in_long_name = true; break; @@ -1169,7 +1170,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, * @custom_stop_condition: (optional) a function meant to stop the widget graph * walk based on custom logic. * - * Queries DAPM graph as to whether an valid audio stream path exists for + * Queries DAPM graph as to whether a valid audio stream path exists for * the initial stream specified by name. This takes into account * current mixer and mux kcontrol settings. Creates list of valid widgets. * @@ -1294,8 +1295,7 @@ static int dapm_widget_power_check(struct snd_soc_dapm_widget *w) return w->new_power; } -/* Generic check to see if a widget should be powered. - */ +/* Generic check to see if a widget should be powered. */ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) { int in, out; @@ -1646,7 +1646,7 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie) struct snd_soc_dapm_context *d = data; int ret; - /* If we're off and we're not supposed to be go into STANDBY */ + /* If we're off and we're not supposed to go into STANDBY */ if (d->bias_level == SND_SOC_BIAS_OFF && d->target_bias_level != SND_SOC_BIAS_OFF) { if (d->dev) @@ -1798,7 +1798,7 @@ static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm) * A complete path is a route that has valid endpoints i.e.:- * * o DAC to output pin. - * o Input Pin to ADC. + * o Input pin to ADC. * o Input pin to Output pin (bypass, sidetone) * o DAC to ADC (loopback). */ @@ -2114,7 +2114,7 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) * soc_dapm_connect_path() - Connects or disconnects a path * @path: The path to update * @connect: The new connect state of the path. True if the path is connected, - * false if it is disconneted. + * false if it is disconnected. * @reason: The reason why the path changed (for debugging only) */ static void soc_dapm_connect_path(struct snd_soc_dapm_path *path, @@ -2233,7 +2233,7 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt, if (w->dapm != dapm) continue; - /* only display widgets that burnm power */ + /* only display widgets that burn power */ switch (w->id) { case snd_soc_dapm_hp: case snd_soc_dapm_mic: @@ -2461,7 +2461,7 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) switch (w->id) { case snd_soc_dapm_input: - /* On a fully routed card a input is never a source */ + /* On a fully routed card an input is never a source */ if (w->dapm->card->fully_routed) return; ep = SND_SOC_DAPM_EP_SOURCE; @@ -3049,6 +3049,9 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, } mutex_unlock(&card->dapm_mutex); + if (ret) + return ret; + if (invert) ucontrol->value.integer.value[0] = max - val; else @@ -3200,7 +3203,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, if (e->shift_l != e->shift_r) { if (item[1] > e->items) return -EINVAL; - val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l; + val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r; mask |= e->mask << e->shift_r; } @@ -3445,7 +3448,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->endpoints[dir] = -1; } - /* machine layer set ups unconnected pins and insertions */ + /* machine layer sets up unconnected pins and insertions */ w->connected = 1; return w; } @@ -3493,6 +3496,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, const struct snd_soc_pcm_stream *config = w->params + w->params_select; struct snd_pcm_substream substream; struct snd_pcm_hw_params *params = NULL; + struct snd_pcm_runtime *runtime = NULL; u64 fmt; int ret; @@ -3541,6 +3545,14 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, memset(&substream, 0, sizeof(substream)); + /* Allocate a dummy snd_pcm_runtime for startup() and other ops() */ + runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); + if (!runtime) { + ret = -ENOMEM; + goto out; + } + substream.runtime = runtime; + switch (event) { case SND_SOC_DAPM_PRE_PMU: substream.stream = SNDRV_PCM_STREAM_CAPTURE; @@ -3606,6 +3618,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, } out: + kfree(runtime); kfree(params); return ret; } diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index a513a34a51d2..9fc1a7bb8b95 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -77,7 +77,7 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, item = snd_soc_enum_val_to_item(e, val); ucontrol->value.enumerated.item[0] = item; if (e->shift_l != e->shift_r) { - val = (reg_val >> e->shift_l) & e->mask; + val = (reg_val >> e->shift_r) & e->mask; item = snd_soc_enum_val_to_item(e, val); ucontrol->value.enumerated.item[1] = item; } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 60d702f8b9f0..d56a16a0f6fa 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1694,6 +1694,9 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, struct snd_soc_pcm_runtime *rtd = be_substream->private_data; int i; + if (rtd->dai_link->be_hw_params_fixup) + continue; + if (soc_pcm_has_symmetry(be_substream)) be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; @@ -1790,7 +1793,7 @@ int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) continue; dev_dbg(be->dev, "ASoC: close BE %s\n", - dpcm->fe->dai_link->name); + be->dai_link->name); soc_pcm_close(be_substream); be_substream->runtime = NULL; @@ -1856,7 +1859,7 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) continue; dev_dbg(be->dev, "ASoC: hw_free BE %s\n", - dpcm->fe->dai_link->name); + be->dai_link->name); soc_pcm_hw_free(be_substream); @@ -1934,7 +1937,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) continue; dev_dbg(be->dev, "ASoC: hw_params BE %s\n", - dpcm->fe->dai_link->name); + be->dai_link->name); ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params); if (ret < 0) { @@ -2014,7 +2017,7 @@ static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm, int ret; dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n", - dpcm->fe->dai_link->name, cmd); + dpcm->be->dai_link->name, cmd); ret = soc_pcm_trigger(substream, cmd); if (ret < 0) @@ -2229,7 +2232,7 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) continue; dev_dbg(be->dev, "ASoC: prepare BE %s\n", - dpcm->fe->dai_link->name); + be->dai_link->name); ret = soc_pcm_prepare(be_substream); if (ret < 0) { diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index ee7f15aa46fc..6b05047a4134 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -48,9 +48,10 @@ #define SOC_TPLG_PASS_PCM_DAI 4 #define SOC_TPLG_PASS_GRAPH 5 #define SOC_TPLG_PASS_PINS 6 +#define SOC_TPLG_PASS_BE_DAI 7 #define SOC_TPLG_PASS_START SOC_TPLG_PASS_MANIFEST -#define SOC_TPLG_PASS_END SOC_TPLG_PASS_PINS +#define SOC_TPLG_PASS_END SOC_TPLG_PASS_BE_DAI struct soc_tplg { const struct firmware *fw; @@ -1475,6 +1476,7 @@ widget: if (widget == NULL) { dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n", w->name); + ret = -ENOMEM; goto hdr_err; } @@ -1554,6 +1556,25 @@ static void set_stream_info(struct snd_soc_pcm_stream *stream, stream->rate_min = caps->rate_min; stream->rate_max = caps->rate_max; stream->formats = caps->formats; + stream->sig_bits = caps->sig_bits; +} + +static void set_dai_flags(struct snd_soc_dai_driver *dai_drv, + unsigned int flag_mask, unsigned int flags) +{ + if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES) + dai_drv->symmetric_rates = + flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES ? 1 : 0; + + if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS) + dai_drv->symmetric_channels = + flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS ? + 1 : 0; + + if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS) + dai_drv->symmetric_samplebits = + flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS ? + 1 : 0; } static int soc_tplg_dai_create(struct soc_tplg *tplg, @@ -1690,8 +1711,96 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, return 0; } +/* * + * soc_tplg_be_dai_config - Find and configure an existing BE DAI. + * @tplg: topology context + * @be: topology BE DAI configs. + * + * The BE dai should already be registered by the platform driver. The + * platform driver should specify the BE DAI name and ID for matching. + */ +static int soc_tplg_be_dai_config(struct soc_tplg *tplg, + struct snd_soc_tplg_be_dai *be) +{ + struct snd_soc_dai_link_component dai_component = {0}; + struct snd_soc_dai *dai; + struct snd_soc_dai_driver *dai_drv; + struct snd_soc_pcm_stream *stream; + struct snd_soc_tplg_stream_caps *caps; + int ret; + + dai_component.dai_name = be->dai_name; + dai = snd_soc_find_dai(&dai_component); + if (!dai) { + dev_err(tplg->dev, "ASoC: BE DAI %s not registered\n", + be->dai_name); + return -EINVAL; + } + + if (be->dai_id != dai->id) { + dev_err(tplg->dev, "ASoC: BE DAI %s id mismatch\n", + be->dai_name); + return -EINVAL; + } + + dai_drv = dai->driver; + if (!dai_drv) + return -EINVAL; + + if (be->playback) { + stream = &dai_drv->playback; + caps = &be->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; + set_stream_info(stream, caps); + } + + if (be->capture) { + stream = &dai_drv->capture; + caps = &be->caps[SND_SOC_TPLG_STREAM_CAPTURE]; + set_stream_info(stream, caps); + } + + if (be->flag_mask) + set_dai_flags(dai_drv, be->flag_mask, be->flags); + + /* pass control to component driver for optional further init */ + ret = soc_tplg_dai_load(tplg, dai_drv); + if (ret < 0) { + dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n"); + return ret; + } + + return 0; +} + +static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg, + struct snd_soc_tplg_hdr *hdr) +{ + struct snd_soc_tplg_be_dai *be; + int count = hdr->count; + int i; + + if (tplg->pass != SOC_TPLG_PASS_BE_DAI) + return 0; + + /* config the existing BE DAIs */ + for (i = 0; i < count; i++) { + be = (struct snd_soc_tplg_be_dai *)tplg->pos; + if (be->size != sizeof(*be)) { + dev_err(tplg->dev, "ASoC: invalid BE DAI size\n"); + return -EINVAL; + } + + soc_tplg_be_dai_config(tplg, be); + tplg->pos += (sizeof(*be) + be->priv.size); + } + + dev_dbg(tplg->dev, "ASoC: Configure %d BE DAIs\n", count); + return 0; +} + + static int soc_tplg_manifest_load(struct soc_tplg *tplg, - struct snd_soc_tplg_hdr *hdr) + struct snd_soc_tplg_hdr *hdr) { struct snd_soc_tplg_manifest *manifest; @@ -1793,6 +1902,8 @@ static int soc_tplg_load_header(struct soc_tplg *tplg, return soc_tplg_dapm_widget_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_PCM: return soc_tplg_pcm_elems_load(tplg, hdr); + case SND_SOC_TPLG_TYPE_BE_DAI: + return soc_tplg_be_dai_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_MANIFEST: return soc_tplg_manifest_load(tplg, hdr); default: diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 53dd085d3ee2..393e8f0fe2cc 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -80,7 +80,7 @@ static int dummy_dma_open(struct snd_pcm_substream *substream) return 0; } -static struct snd_pcm_ops dummy_dma_ops = { +static const struct snd_pcm_ops dummy_dma_ops = { .open = dummy_dma_open, .ioctl = snd_pcm_lib_ioctl, }; diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 488ef4ed8fba..549fac349fa0 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -19,6 +19,84 @@ #define UNIPERIF_MAX_FRAME_SZ 0x20 #define UNIPERIF_ALLOWED_FRAME_SZ (0x08 | 0x10 | 0x18 | UNIPERIF_MAX_FRAME_SZ) +struct sti_uniperiph_dev_data { + unsigned int id; /* Nb available player instances */ + unsigned int version; /* player IP version */ + unsigned int stream; + const char *dai_names; + enum uniperif_type type; +}; + +static const struct sti_uniperiph_dev_data sti_uniplayer_hdmi = { + .id = 0, + .version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0, + .stream = SNDRV_PCM_STREAM_PLAYBACK, + .dai_names = "Uni Player #0 (HDMI)", + .type = SND_ST_UNIPERIF_TYPE_HDMI +}; + +static const struct sti_uniperiph_dev_data sti_uniplayer_pcm_out = { + .id = 1, + .version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0, + .stream = SNDRV_PCM_STREAM_PLAYBACK, + .dai_names = "Uni Player #1 (PCM OUT)", + .type = SND_ST_UNIPERIF_TYPE_PCM | SND_ST_UNIPERIF_TYPE_TDM, +}; + +static const struct sti_uniperiph_dev_data sti_uniplayer_dac = { + .id = 2, + .version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0, + .stream = SNDRV_PCM_STREAM_PLAYBACK, + .dai_names = "Uni Player #2 (DAC)", + .type = SND_ST_UNIPERIF_TYPE_PCM, +}; + +static const struct sti_uniperiph_dev_data sti_uniplayer_spdif = { + .id = 3, + .version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0, + .stream = SNDRV_PCM_STREAM_PLAYBACK, + .dai_names = "Uni Player #3 (SPDIF)", + .type = SND_ST_UNIPERIF_TYPE_SPDIF +}; + +static const struct sti_uniperiph_dev_data sti_unireader_pcm_in = { + .id = 0, + .version = SND_ST_UNIPERIF_VERSION_UNI_RDR_1_0, + .stream = SNDRV_PCM_STREAM_CAPTURE, + .dai_names = "Uni Reader #0 (PCM IN)", + .type = SND_ST_UNIPERIF_TYPE_PCM | SND_ST_UNIPERIF_TYPE_TDM, +}; + +static const struct sti_uniperiph_dev_data sti_unireader_hdmi_in = { + .id = 1, + .version = SND_ST_UNIPERIF_VERSION_UNI_RDR_1_0, + .stream = SNDRV_PCM_STREAM_CAPTURE, + .dai_names = "Uni Reader #1 (HDMI IN)", + .type = SND_ST_UNIPERIF_TYPE_PCM, +}; + +static const struct of_device_id snd_soc_sti_match[] = { + { .compatible = "st,stih407-uni-player-hdmi", + .data = &sti_uniplayer_hdmi + }, + { .compatible = "st,stih407-uni-player-pcm-out", + .data = &sti_uniplayer_pcm_out + }, + { .compatible = "st,stih407-uni-player-dac", + .data = &sti_uniplayer_dac + }, + { .compatible = "st,stih407-uni-player-spdif", + .data = &sti_uniplayer_spdif + }, + { .compatible = "st,stih407-uni-reader-pcm_in", + .data = &sti_unireader_pcm_in + }, + { .compatible = "st,stih407-uni-reader-hdmi", + .data = &sti_unireader_hdmi_in + }, + {}, +}; + int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) @@ -167,8 +245,8 @@ static int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai) * Uniperipheral instance ID */ ctrl = &uni->snd_ctrls[i]; - ctrl->index = uni->info->id; - ctrl->device = uni->info->id; + ctrl->index = uni->id; + ctrl->device = uni->id; } return snd_soc_add_dai_controls(dai, uni->snd_ctrls, uni->num_ctrls); @@ -186,7 +264,7 @@ int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, struct snd_dmaengine_dai_dma_data *dma_data; int transfer_size; - if (uni->info->type == SND_ST_UNIPERIF_TYPE_TDM) + if (uni->type == SND_ST_UNIPERIF_TYPE_TDM) /* transfer size = user frame size (in 32-bits FIFO cell) */ transfer_size = snd_soc_params_to_frame_size(params) / 32; else @@ -235,7 +313,7 @@ static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai) struct uniperif *uni = priv->dai_data.uni; int ret; - if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) { + if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) { ret = uni_player_resume(uni); if (ret) return ret; @@ -256,7 +334,7 @@ static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai) struct sti_uniperiph_dai *dai_data = &priv->dai_data; /* DMA settings*/ - if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) + if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) snd_soc_dai_init_dma_data(dai, &dai_data->dma_data, NULL); else snd_soc_dai_init_dma_data(dai, NULL, &dai_data->dma_data); @@ -280,25 +358,32 @@ static const struct snd_soc_component_driver sti_uniperiph_dai_component = { static int sti_uniperiph_cpu_dai_of(struct device_node *node, struct sti_uniperiph_data *priv) { - const char *str; - int ret; struct device *dev = &priv->pdev->dev; struct sti_uniperiph_dai *dai_data = &priv->dai_data; struct snd_soc_dai_driver *dai = priv->dai; struct snd_soc_pcm_stream *stream; struct uniperif *uni; + const struct of_device_id *of_id; + const struct sti_uniperiph_dev_data *dev_data; + const char *mode; + + /* Populate data structure depending on compatibility */ + of_id = of_match_node(snd_soc_sti_match, node); + if (!of_id->data) { + dev_err(dev, "data associated to device is missing"); + return -EINVAL; + } + dev_data = (struct sti_uniperiph_dev_data *)of_id->data; uni = devm_kzalloc(dev, sizeof(*uni), GFP_KERNEL); if (!uni) return -ENOMEM; + uni->id = dev_data->id; + uni->ver = dev_data->version; + *dai = sti_uniperiph_dai_template; - ret = of_property_read_string(node, "dai-name", &str); - if (ret < 0) { - dev_err(dev, "%s: dai name missing.\n", __func__); - return -EINVAL; - } - dai->name = str; + dai->name = dev_data->dai_names; /* Get resources */ uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0); @@ -322,9 +407,20 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, return -ENXIO; } + uni->type = dev_data->type; + + /* check if player should be configured for tdm */ + if (dev_data->type & SND_ST_UNIPERIF_TYPE_TDM) { + if (!of_property_read_string(node, "st,tdm-mode", &mode)) + uni->type = SND_ST_UNIPERIF_TYPE_TDM; + else + uni->type = SND_ST_UNIPERIF_TYPE_PCM; + } + dai_data->uni = uni; + dai_data->stream = dev_data->stream; - if (of_device_is_compatible(node, "st,sti-uni-player")) { + if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) { uni_player_init(priv->pdev, uni); stream = &dai->playback; } else { @@ -376,12 +472,6 @@ static int sti_uniperiph_probe(struct platform_device *pdev) &dmaengine_pcm_config, 0); } -static const struct of_device_id snd_soc_sti_match[] = { - { .compatible = "st,sti-uni-player", }, - { .compatible = "st,sti-uni-reader", }, - {}, -}; - static struct platform_driver sti_uniperiph_driver = { .driver = { .name = "sti-uniperiph-dai", diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index eb9933c62ad6..1993c655fb79 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1220,16 +1220,16 @@ #define UNIPERIF_FIFO_FRAMES 4 /* FDMA trigger limit in frames */ #define UNIPERIF_TYPE_IS_HDMI(p) \ - ((p)->info->type == SND_ST_UNIPERIF_TYPE_HDMI) + ((p)->type == SND_ST_UNIPERIF_TYPE_HDMI) #define UNIPERIF_TYPE_IS_PCM(p) \ - ((p)->info->type == SND_ST_UNIPERIF_TYPE_PCM) + ((p)->type == SND_ST_UNIPERIF_TYPE_PCM) #define UNIPERIF_TYPE_IS_SPDIF(p) \ - ((p)->info->type == SND_ST_UNIPERIF_TYPE_SPDIF) + ((p)->type == SND_ST_UNIPERIF_TYPE_SPDIF) #define UNIPERIF_TYPE_IS_IEC958(p) \ (UNIPERIF_TYPE_IS_HDMI(p) || \ UNIPERIF_TYPE_IS_SPDIF(p)) #define UNIPERIF_TYPE_IS_TDM(p) \ - ((p)->info->type == SND_ST_UNIPERIF_TYPE_TDM) + ((p)->type == SND_ST_UNIPERIF_TYPE_TDM) /* * Uniperipheral IP revisions @@ -1249,11 +1249,11 @@ enum uniperif_version { }; enum uniperif_type { - SND_ST_UNIPERIF_TYPE_NONE, - SND_ST_UNIPERIF_TYPE_HDMI, - SND_ST_UNIPERIF_TYPE_PCM, - SND_ST_UNIPERIF_TYPE_SPDIF, - SND_ST_UNIPERIF_TYPE_TDM + SND_ST_UNIPERIF_TYPE_NONE = 0x00, + SND_ST_UNIPERIF_TYPE_HDMI = 0x01, + SND_ST_UNIPERIF_TYPE_PCM = 0x02, + SND_ST_UNIPERIF_TYPE_SPDIF = 0x04, + SND_ST_UNIPERIF_TYPE_TDM = 0x08 }; enum uniperif_state { @@ -1278,12 +1278,6 @@ enum uniperif_word_pos { WORD_MAX }; -struct uniperif_info { - int id; /* instance value of the uniperipheral IP */ - enum uniperif_type type; - int underflow_enabled; /* Underflow recovery mode */ -}; - struct uniperif_iec958_settings { enum uniperif_iec958_encoding_mode encoding_mode; struct snd_aes_iec958 iec958; @@ -1298,8 +1292,10 @@ struct dai_tdm_slot { struct uniperif { /* System information */ - struct uniperif_info *info; + enum uniperif_type type; + int underflow_enabled; /* Underflow recovery mode */ struct device *dev; + int id; /* instance value of the uniperipheral IP */ int ver; /* IP version, used by register access macros */ struct regmap_field *clk_sel; struct regmap_field *valid_sel; diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index 1ac2db205a0d..1bc8ebc2528e 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -100,7 +100,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) dev_err(player->dev, "FIFO underflow error detected"); /* Interrupt is just for information when underflow recovery */ - if (player->info->underflow_enabled) { + if (player->underflow_enabled) { /* Update state to underflow */ player->state = UNIPERIF_STATE_UNDERFLOW; @@ -134,7 +134,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) /* Check for underflow recovery done */ if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) { - if (!player->info->underflow_enabled) { + if (!player->underflow_enabled) { dev_err(player->dev, "unexpected Underflow recovering"); return -EPERM; } @@ -764,7 +764,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, } /* Calculate transfer size (in fifo cells and bytes) for frame count */ - if (player->info->type == SND_ST_UNIPERIF_TYPE_TDM) { + if (player->type == SND_ST_UNIPERIF_TYPE_TDM) { /* transfer size = user frame size (in 32 bits FIFO cell) */ transfer_size = sti_uniperiph_get_user_frame_size(runtime) / 4; @@ -794,7 +794,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit); /* Uniperipheral setup depends on player type */ - switch (player->info->type) { + switch (player->type) { case SND_ST_UNIPERIF_TYPE_HDMI: ret = uni_player_prepare_iec958(player, runtime); break; @@ -884,7 +884,7 @@ static int uni_player_start(struct uniperif *player) SET_UNIPERIF_ITM_BSET_FIFO_ERROR(player); /* Enable underflow recovery interrupts */ - if (player->info->underflow_enabled) { + if (player->underflow_enabled) { SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(player); SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player); } @@ -893,8 +893,10 @@ static int uni_player_start(struct uniperif *player) SET_UNIPERIF_SOFT_RST_SOFT_RST(player); ret = reset_player(player); - if (ret < 0) + if (ret < 0) { + clk_disable_unprepare(player->clk); return ret; + } /* * Does not use IEC61937 features of the uniperipheral hardware. @@ -1021,8 +1023,8 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, struct reg_field regfield[2] = { /* PCM_CLK_SEL */ REG_FIELD(SYS_CFG_AUDIO_GLUE, - 8 + player->info->id, - 8 + player->info->id), + 8 + player->id, + 8 + player->id), /* PCMP_VALID_SEL */ REG_FIELD(SYS_CFG_AUDIO_GLUE, 0, 1) }; @@ -1040,60 +1042,6 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, return 0; } -static int uni_player_parse_dt(struct platform_device *pdev, - struct uniperif *player) -{ - struct uniperif_info *info; - struct device *dev = &pdev->dev; - struct device_node *pnode = pdev->dev.of_node; - const char *mode; - - /* Allocate memory for the info structure */ - info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - if (of_property_read_u32(pnode, "st,version", &player->ver) || - player->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) { - dev_err(dev, "Unknown uniperipheral version "); - return -EINVAL; - } - /* Underflow recovery is only supported on later ip revisions */ - if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) - info->underflow_enabled = 1; - - if (of_property_read_u32(pnode, "st,uniperiph-id", &info->id)) { - dev_err(dev, "uniperipheral id not defined"); - return -EINVAL; - } - - /* Read the device mode property */ - if (of_property_read_string(pnode, "st,mode", &mode)) { - dev_err(dev, "uniperipheral mode not defined"); - return -EINVAL; - } - - if (strcasecmp(mode, "hdmi") == 0) - info->type = SND_ST_UNIPERIF_TYPE_HDMI; - else if (strcasecmp(mode, "pcm") == 0) - info->type = SND_ST_UNIPERIF_TYPE_PCM; - else if (strcasecmp(mode, "spdif") == 0) - info->type = SND_ST_UNIPERIF_TYPE_SPDIF; - else if (strcasecmp(mode, "tdm") == 0) - info->type = SND_ST_UNIPERIF_TYPE_TDM; - else - info->type = SND_ST_UNIPERIF_TYPE_NONE; - - /* Save the info structure */ - player->info = info; - - /* Get PCM_CLK_SEL & PCMP_VALID_SEL from audio-glue-ctrl SoC reg */ - if (uni_player_parse_dt_audio_glue(pdev, player)) - return -EINVAL; - - return 0; -} - static const struct snd_soc_dai_ops uni_player_dai_ops = { .startup = uni_player_startup, .shutdown = uni_player_shutdown, @@ -1114,13 +1062,18 @@ int uni_player_init(struct platform_device *pdev, player->state = UNIPERIF_STATE_STOPPED; player->dai_ops = &uni_player_dai_ops; - ret = uni_player_parse_dt(pdev, player); + /* Get PCM_CLK_SEL & PCMP_VALID_SEL from audio-glue-ctrl SoC reg */ + ret = uni_player_parse_dt_audio_glue(pdev, player); if (ret < 0) { dev_err(player->dev, "Failed to parse DeviceTree"); return ret; } + /* Underflow recovery is only supported on later ip revisions */ + if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + player->underflow_enabled = 1; + if (UNIPERIF_TYPE_IS_TDM(player)) player->hw = &uni_tdm_hw; else @@ -1144,8 +1097,8 @@ int uni_player_init(struct platform_device *pdev, /* connect to I2S/TDM TX bus */ if (player->valid_sel && - (player->info->id == UNIPERIF_PLAYER_I2S_OUT)) { - ret = regmap_field_write(player->valid_sel, player->info->id); + (player->id == UNIPERIF_PLAYER_I2S_OUT)) { + ret = regmap_field_write(player->valid_sel, player->id); if (ret) { dev_err(player->dev, "%s: unable to connect to tdm bus", __func__); diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index eb74a328c928..0e1c3ee56675 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -13,6 +13,7 @@ #include "uniperif.h" +#define UNIPERIF_READER_I2S_IN 0 /* reader id connected to I2S/TDM TX bus */ /* * Note: snd_pcm_hardware is linked to DMA controller but is declared here to * integrate unireader capability in term of rate and supported channels @@ -195,7 +196,7 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, } /* Calculate transfer size (in fifo cells and bytes) for frame count */ - if (reader->info->type == SND_ST_UNIPERIF_TYPE_TDM) { + if (reader->type == SND_ST_UNIPERIF_TYPE_TDM) { /* transfer size = unip frame size (in 32 bits FIFO cell) */ transfer_size = sti_uniperiph_get_user_frame_size(runtime) / 4; @@ -280,7 +281,7 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, SET_UNIPERIF_ITM_BSET_MEM_BLK_READ(reader); /* Enable underflow recovery interrupts */ - if (reader->info->underflow_enabled) { + if (reader->underflow_enabled) { SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(reader); SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(reader); } @@ -394,41 +395,6 @@ static void uni_reader_shutdown(struct snd_pcm_substream *substream, } } -static int uni_reader_parse_dt(struct platform_device *pdev, - struct uniperif *reader) -{ - struct uniperif_info *info; - struct device_node *node = pdev->dev.of_node; - const char *mode; - - /* Allocate memory for the info structure */ - info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - if (of_property_read_u32(node, "st,version", &reader->ver) || - reader->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) { - dev_err(&pdev->dev, "Unknown uniperipheral version "); - return -EINVAL; - } - - /* Read the device mode property */ - if (of_property_read_string(node, "st,mode", &mode)) { - dev_err(&pdev->dev, "uniperipheral mode not defined"); - return -EINVAL; - } - - if (strcasecmp(mode, "tdm") == 0) - info->type = SND_ST_UNIPERIF_TYPE_TDM; - else - info->type = SND_ST_UNIPERIF_TYPE_PCM; - - /* Save the info structure */ - reader->info = info; - - return 0; -} - static const struct snd_soc_dai_ops uni_reader_dai_ops = { .startup = uni_reader_startup, .shutdown = uni_reader_shutdown, @@ -448,12 +414,6 @@ int uni_reader_init(struct platform_device *pdev, reader->state = UNIPERIF_STATE_STOPPED; reader->dai_ops = &uni_reader_dai_ops; - ret = uni_reader_parse_dt(pdev, reader); - if (ret < 0) { - dev_err(reader->dev, "Failed to parse DeviceTree"); - return ret; - } - if (UNIPERIF_TYPE_IS_TDM(reader)) reader->hw = &uni_tdm_hw; else diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 2a954bd01fd8..dd2368297fd3 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -1,4 +1,5 @@ menu "Allwinner SoC Audio support" + depends on ARCH_SUNXI || COMPILE_TEST config SND_SUN4I_CODEC tristate "Allwinner A10 Codec Support" diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 44f170c73b06..e047ec06d538 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -96,8 +96,8 @@ /* Other various ADC registers */ #define SUN4I_CODEC_DAC_TXCNT (0x30) #define SUN4I_CODEC_ADC_RXCNT (0x34) -#define SUN4I_CODEC_AC_SYS_VERI (0x38) -#define SUN4I_CODEC_AC_MIC_PHONE_CAL (0x3c) +#define SUN7I_CODEC_AC_DAC_CAL (0x38) +#define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c) struct sun4i_codec { struct device *dev; @@ -509,7 +509,7 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute = static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1); -static const struct snd_kcontrol_new sun4i_codec_widgets[] = { +static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, sun4i_codec_pa_volume_scale), @@ -628,12 +628,14 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { }; static struct snd_soc_codec_driver sun4i_codec_codec = { - .controls = sun4i_codec_widgets, - .num_controls = ARRAY_SIZE(sun4i_codec_widgets), - .dapm_widgets = sun4i_codec_codec_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets), - .dapm_routes = sun4i_codec_codec_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes), + .component_driver = { + .controls = sun4i_codec_controls, + .num_controls = ARRAY_SIZE(sun4i_codec_controls), + .dapm_widgets = sun4i_codec_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets), + .dapm_routes = sun4i_codec_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes), + }, }; static const struct snd_soc_component_driver sun4i_codec_component = { @@ -680,12 +682,37 @@ static const struct regmap_config sun4i_codec_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = SUN4I_CODEC_AC_MIC_PHONE_CAL, + .max_register = SUN4I_CODEC_ADC_RXCNT, +}; + +static const struct regmap_config sun7i_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL, +}; + +struct sun4i_codec_quirks { + const struct regmap_config *regmap_config; +}; + +static const struct sun4i_codec_quirks sun4i_codec_quirks = { + .regmap_config = &sun4i_codec_regmap_config, +}; + +static const struct sun4i_codec_quirks sun7i_codec_quirks = { + .regmap_config = &sun7i_codec_regmap_config, }; static const struct of_device_id sun4i_codec_of_match[] = { - { .compatible = "allwinner,sun4i-a10-codec" }, - { .compatible = "allwinner,sun7i-a20-codec" }, + { + .compatible = "allwinner,sun4i-a10-codec", + .data = &sun4i_codec_quirks, + }, + { + .compatible = "allwinner,sun7i-a20-codec", + .data = &sun7i_codec_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); @@ -758,6 +785,7 @@ static int sun4i_codec_probe(struct platform_device *pdev) { struct snd_soc_card *card; struct sun4i_codec *scodec; + const struct sun4i_codec_quirks *quirks; struct resource *res; void __iomem *base; int ret; @@ -775,8 +803,14 @@ static int sun4i_codec_probe(struct platform_device *pdev) return PTR_ERR(base); } + quirks = of_device_get_match_data(&pdev->dev); + if (quirks == NULL) { + dev_err(&pdev->dev, "Failed to determine the quirks to use\n"); + return -ENODEV; + } + scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base, - &sun4i_codec_regmap_config); + quirks->regmap_config); if (IS_ERR(scodec->regmap)) { dev_err(&pdev->dev, "Failed to create our regmap\n"); return PTR_ERR(scodec->regmap); diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c index 0b04fb02125c..88fbb3a1e660 100644 --- a/sound/soc/sunxi/sun4i-spdif.c +++ b/sound/soc/sunxi/sun4i-spdif.c @@ -29,6 +29,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include <sound/dmaengine_pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -162,6 +163,7 @@ struct sun4i_spdif_dev { struct platform_device *pdev; struct clk *spdif_clk; struct clk *apb_clk; + struct reset_control *rst; struct snd_soc_dai_driver cpu_dai_drv; struct regmap *regmap; struct snd_dmaengine_dai_dma_data dma_params_tx; @@ -411,6 +413,7 @@ static const struct snd_soc_dapm_route dit_routes[] = { static const struct of_device_id sun4i_spdif_of_match[] = { { .compatible = "allwinner,sun4i-a10-spdif", }, + { .compatible = "allwinner,sun6i-a31-spdif", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match); @@ -482,11 +485,23 @@ static int sun4i_spdif_probe(struct platform_device *pdev) } host->dma_params_tx.addr = res->start + SUN4I_SPDIF_TXFIFO; - host->dma_params_tx.maxburst = 4; + host->dma_params_tx.maxburst = 8; host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; platform_set_drvdata(pdev, host); + if (of_device_is_compatible(pdev->dev.of_node, + "allwinner,sun6i-a31-spdif")) { + host->rst = devm_reset_control_get_optional(&pdev->dev, NULL); + if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + dev_err(&pdev->dev, "Failed to get reset: %d\n", ret); + goto err_disable_apb_clk; + } + if (!IS_ERR(host->rst)) + reset_control_deassert(host->rst); + } + ret = devm_snd_soc_register_component(&pdev->dev, &sun4i_spdif_component, &sun4i_spdif_dai, 1); if (ret) diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index a6768f832c6f..efbe8d4c019e 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -138,3 +138,14 @@ config SND_SOC_TEGRA_RT5677 help Say Y or M here if you want to add support for SoC audio on Tegra boards using the RT5677 codec, such as Ryu. + +config SND_SOC_TEGRA_SGTL5000 + tristate "SoC Audio support for Tegra boards using a SGTL5000 codec" + depends on SND_SOC_TEGRA && I2C && GPIOLIB + select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC + select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC + select SND_SOC_SGTL5000 + help + Say Y or M here if you want to add support for SoC audio on Tegra + boards using the SGTL5000 codec, such as Apalis T30, Apalis TK1 or + Colibri T30. diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 9171655ad843..f214a3fd0024 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -26,6 +26,7 @@ snd-soc-tegra-wm9712-objs := tegra_wm9712.o snd-soc-tegra-trimslice-objs := trimslice.o snd-soc-tegra-alc5632-objs := tegra_alc5632.o snd-soc-tegra-max98090-objs := tegra_max98090.o +snd-soc-tegra-sgtl5000-objs := tegra_sgtl5000.o obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o obj-$(CONFIG_SND_SOC_TEGRA_RT5677) += snd-soc-tegra-rt5677.o @@ -35,3 +36,4 @@ obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o +obj-$(CONFIG_SND_SOC_TEGRA_SGTL5000) += snd-soc-tegra-sgtl5000.o
\ No newline at end of file diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index 773daecaa5e8..e5ef4e9c4ac5 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -1,5 +1,5 @@ /* -* tegra_rt5640.c - Tegra machine ASoC driver for boards using WM8903 codec. +* tegra_rt5640.c - Tegra machine ASoC driver for boards using RT5640 codec. * * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. * diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c new file mode 100644 index 000000000000..1e76869dd488 --- /dev/null +++ b/sound/soc/tegra/tegra_sgtl5000.c @@ -0,0 +1,212 @@ +/* + * tegra_sgtl5000.c - Tegra machine ASoC driver for boards using SGTL5000 codec + * + * Author: Marcel Ziswiler <marcel@ziswiler.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>. + * + * Based on code copyright/by: + * + * Copyright (C) 2010-2012 - NVIDIA, Inc. + * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. + * Copyright 2007 Wolfson Microelectronics PLC. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "../codecs/sgtl5000.h" + +#include "tegra_asoc_utils.h" + +#define DRV_NAME "tegra-snd-sgtl5000" + +struct tegra_sgtl5000 { + struct tegra_asoc_utils_data util_data; +}; + +static int tegra_sgtl5000_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_card *card = rtd->card; + struct tegra_sgtl5000 *machine = snd_soc_card_get_drvdata(card); + int srate, mclk; + int err; + + srate = params_rate(params); + switch (srate) { + case 11025: + case 22050: + case 44100: + case 88200: + mclk = 11289600; + break; + default: + mclk = 12288000; + break; + } + + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); + if (err < 0) { + dev_err(card->dev, "Can't configure clocks\n"); + return err; + } + + err = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, + SND_SOC_CLOCK_IN); + if (err < 0) { + dev_err(card->dev, "codec_dai clock not set\n"); + return err; + } + + return 0; +} + +static struct snd_soc_ops tegra_sgtl5000_ops = { + .hw_params = tegra_sgtl5000_hw_params, +}; + +static const struct snd_soc_dapm_widget tegra_sgtl5000_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_LINE("Line In Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), +}; + +static struct snd_soc_dai_link tegra_sgtl5000_dai = { + .name = "sgtl5000", + .stream_name = "HiFi", + .codec_dai_name = "sgtl5000", + .ops = &tegra_sgtl5000_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, +}; + +static struct snd_soc_card snd_soc_tegra_sgtl5000 = { + .name = "tegra-sgtl5000", + .owner = THIS_MODULE, + .dai_link = &tegra_sgtl5000_dai, + .num_links = 1, + .dapm_widgets = tegra_sgtl5000_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra_sgtl5000_dapm_widgets), + .fully_routed = true, +}; + +static int tegra_sgtl5000_driver_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct snd_soc_card *card = &snd_soc_tegra_sgtl5000; + struct tegra_sgtl5000 *machine; + int ret; + + machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_sgtl5000), + GFP_KERNEL); + if (!machine) { + dev_err(&pdev->dev, "Can't allocate tegra_sgtl5000 struct\n"); + return -ENOMEM; + } + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, machine); + + ret = snd_soc_of_parse_card_name(card, "nvidia,model"); + if (ret) + goto err; + + ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); + if (ret) + goto err; + + tegra_sgtl5000_dai.codec_of_node = of_parse_phandle(np, + "nvidia,audio-codec", 0); + if (!tegra_sgtl5000_dai.codec_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,audio-codec' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + + tegra_sgtl5000_dai.cpu_of_node = of_parse_phandle(np, + "nvidia,i2s-controller", 0); + if (!tegra_sgtl5000_dai.cpu_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,i2s-controller' missing/invalid\n"); + ret = -EINVAL; + goto err; + } + + tegra_sgtl5000_dai.platform_of_node = tegra_sgtl5000_dai.cpu_of_node; + + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + if (ret) + goto err; + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err_fini_utils; + } + + return 0; + +err_fini_utils: + tegra_asoc_utils_fini(&machine->util_data); +err: + return ret; +} + +static int tegra_sgtl5000_driver_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct tegra_sgtl5000 *machine = snd_soc_card_get_drvdata(card); + int ret; + + ret = snd_soc_unregister_card(card); + + tegra_asoc_utils_fini(&machine->util_data); + + return ret; +} + +static const struct of_device_id tegra_sgtl5000_of_match[] = { + { .compatible = "nvidia,tegra-audio-sgtl5000", }, + { /* sentinel */ }, +}; + +static struct platform_driver tegra_sgtl5000_driver = { + .driver = { + .name = DRV_NAME, + .pm = &snd_soc_pm_ops, + .of_match_table = tegra_sgtl5000_of_match, + }, + .probe = tegra_sgtl5000_driver_probe, + .remove = tegra_sgtl5000_driver_remove, +}; +module_platform_driver(tegra_sgtl5000_driver); + +MODULE_AUTHOR("Marcel Ziswiler <marcel@ziswiler.com>"); +MODULE_DESCRIPTION("Tegra SGTL5000 machine ASoC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_sgtl5000_of_match); diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 6d5698b25bd4..b343efd9be5b 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -187,7 +187,7 @@ static int setup_clocking(struct snd_soc_dai *dai, default: dev_err(dai->dev, - "%s: Error: Unsopported inversion (fmt = 0x%x)!\n", + "%s: Error: Unsupported inversion (fmt = 0x%x)!\n", __func__, fmt); return -EINVAL; @@ -218,7 +218,7 @@ static int setup_clocking(struct snd_soc_dai *dai, break; default: - dev_err(dai->dev, "%s: Error: Unsopported master (fmt = 0x%x)!\n", + dev_err(dai->dev, "%s: Error: Unsupported master (fmt = 0x%x)!\n", __func__, fmt); return -EINVAL; @@ -374,7 +374,7 @@ static int setup_msp_config(struct snd_pcm_substream *substream, break; default: - dev_err(dai->dev, "%s: Error: Unsopported format (%d)!\n", + dev_err(dai->dev, "%s: Error: Unsupported format (%d)!\n", __func__, fmt); return -EINVAL; } diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index 204cc074adb9..41aa3355e920 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -55,7 +55,6 @@ static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol, err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE); if (err < 0) { line6pcm->impulse_volume = 0; - line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE); return err; } } else { @@ -211,7 +210,9 @@ static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction, spin_lock_irqsave(&pstr->lock, flags); clear_bit(type, &pstr->running); if (!pstr->running) { + spin_unlock_irqrestore(&pstr->lock, flags); line6_unlink_audio_urbs(line6pcm, pstr); + spin_lock_irqsave(&pstr->lock, flags); if (direction == SNDRV_PCM_STREAM_CAPTURE) { line6pcm->prev_fbuf = NULL; line6pcm->prev_fsize = 0; diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c index daf81d169a42..45dd34874f43 100644 --- a/sound/usb/line6/pod.c +++ b/sound/usb/line6/pod.c @@ -244,8 +244,8 @@ static int pod_set_system_param_int(struct usb_line6_pod *pod, int value, static ssize_t serial_number_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct usb_interface *interface = to_usb_interface(dev); - struct usb_line6_pod *pod = usb_get_intfdata(interface); + struct snd_card *card = dev_to_snd_card(dev); + struct usb_line6_pod *pod = card->private_data; return sprintf(buf, "%u\n", pod->serial_number); } @@ -256,8 +256,8 @@ static ssize_t serial_number_show(struct device *dev, static ssize_t firmware_version_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct usb_interface *interface = to_usb_interface(dev); - struct usb_line6_pod *pod = usb_get_intfdata(interface); + struct snd_card *card = dev_to_snd_card(dev); + struct usb_line6_pod *pod = card->private_data; return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100, pod->firmware_version % 100); @@ -269,8 +269,8 @@ static ssize_t firmware_version_show(struct device *dev, static ssize_t device_id_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct usb_interface *interface = to_usb_interface(dev); - struct usb_line6_pod *pod = usb_get_intfdata(interface); + struct snd_card *card = dev_to_snd_card(dev); + struct usb_line6_pod *pod = card->private_data; return sprintf(buf, "%d\n", pod->device_id); } diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 6adde457b602..152292e5ee2b 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1128,6 +1128,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) { /* devices which do not support reading the sample rate. */ switch (chip->usb_id) { + case USB_ID(0x041E, 0x4080): /* Creative Live Cam VF0610 */ case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema */ case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */ case USB_ID(0x045E, 0x076E): /* MS Lifecam HD-5001 */ @@ -1138,7 +1139,9 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */ case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */ + case USB_ID(0x05A3, 0x9420): /* ELP HD USB Camera */ case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */ + case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */ case USB_ID(0x1de7, 0x0013): /* Phoenix Audio MT202exe */ case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */ case USB_ID(0x1de7, 0x0114): /* Phoenix Audio MT202pcs */ |