diff options
Diffstat (limited to 'sound')
141 files changed, 1854 insertions, 2144 deletions
diff --git a/sound/core/control.c b/sound/core/control.c index 35324a8e83c8..eeb691d1911f 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1170,6 +1170,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, if (info->count < 1) return -EINVAL; + if (!*info->id.name) + return -EINVAL; + if (strnlen(info->id.name, sizeof(info->id.name)) >= sizeof(info->id.name)) + return -EINVAL; access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| SNDRV_CTL_ELEM_ACCESS_INACTIVE| diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index b03a638b420c..279e24f61305 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1552,6 +1552,8 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state) if (! snd_pcm_playback_empty(substream)) { snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING); snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING); + } else { + runtime->status->state = SNDRV_PCM_STATE_SETUP; } break; case SNDRV_PCM_STATE_RUNNING: diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c index f62780ed64ad..7821b07415a7 100644 --- a/sound/drivers/opl3/opl3_midi.c +++ b/sound/drivers/opl3/opl3_midi.c @@ -105,6 +105,8 @@ static void snd_opl3_calc_pitch(unsigned char *fnum, unsigned char *blocknum, int pitchbend = chan->midi_pitchbend; int segment; + if (pitchbend < -0x2000) + pitchbend = -0x2000; if (pitchbend > 0x1FFF) pitchbend = 0x1FFF; diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 0d580186ef1a..5cc356db5351 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -33,7 +33,7 @@ */ #define MAX_MIDI_RX_BLOCKS 8 -#define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 µs */ +#define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 microseconds */ /* isochronous header parameters */ #define ISO_DATA_LENGTH_SHIFT 16 @@ -78,7 +78,7 @@ static void pcm_period_tasklet(unsigned long data); int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, enum cip_flags flags) { - s->unit = fw_unit_get(unit); + s->unit = unit; s->direction = dir; s->flags = flags; s->context = ERR_PTR(-1); @@ -102,7 +102,6 @@ void amdtp_stream_destroy(struct amdtp_stream *s) { WARN_ON(amdtp_stream_running(s)); mutex_destroy(&s->mutex); - fw_unit_put(s->unit); } EXPORT_SYMBOL(amdtp_stream_destroy); diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index fc19c99654aa..611b7dae7ee5 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -116,11 +116,22 @@ end: return err; } +/* + * This module releases the FireWire unit data after all ALSA character devices + * are released by applications. This is for releasing stream data or finishing + * transactions safely. Thus at returning from .remove(), this module still keep + * references for the unit. + */ static void bebob_card_free(struct snd_card *card) { struct snd_bebob *bebob = card->private_data; + snd_bebob_stream_destroy_duplex(bebob); + fw_unit_put(bebob->unit); + + kfree(bebob->maudio_special_quirk); + if (bebob->card_index >= 0) { mutex_lock(&devices_mutex); clear_bit(bebob->card_index, devices_used); @@ -205,7 +216,7 @@ bebob_probe(struct fw_unit *unit, card->private_free = bebob_card_free; bebob->card = card; - bebob->unit = unit; + bebob->unit = fw_unit_get(unit); bebob->spec = spec; mutex_init(&bebob->mutex); spin_lock_init(&bebob->lock); @@ -306,10 +317,11 @@ static void bebob_remove(struct fw_unit *unit) if (bebob == NULL) return; - kfree(bebob->maudio_special_quirk); + /* Awake bus-reset waiters. */ + if (!completion_done(&bebob->bus_reset)) + complete_all(&bebob->bus_reset); - snd_bebob_stream_destroy_duplex(bebob); - snd_card_disconnect(bebob->card); + /* No need to wait for releasing card object in this context. */ snd_card_free_when_closed(bebob->card); } diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 0ebcabfdc7ce..98e4fc8121a1 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -410,8 +410,6 @@ break_both_connections(struct snd_bebob *bebob) static void destroy_both_connections(struct snd_bebob *bebob) { - break_both_connections(bebob); - cmp_connection_destroy(&bebob->in_conn); cmp_connection_destroy(&bebob->out_conn); } @@ -712,22 +710,16 @@ void snd_bebob_stream_update_duplex(struct snd_bebob *bebob) mutex_unlock(&bebob->mutex); } +/* + * This function should be called before starting streams or after stopping + * streams. + */ void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob) { - mutex_lock(&bebob->mutex); - - amdtp_stream_pcm_abort(&bebob->rx_stream); - amdtp_stream_pcm_abort(&bebob->tx_stream); - - amdtp_stream_stop(&bebob->rx_stream); - amdtp_stream_stop(&bebob->tx_stream); - amdtp_stream_destroy(&bebob->rx_stream); amdtp_stream_destroy(&bebob->tx_stream); destroy_both_connections(bebob); - - mutex_unlock(&bebob->mutex); } /* diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index fa9cf761b610..07dbd01d7a6b 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -311,14 +311,21 @@ end: return err; } +/* + * This function should be called before starting streams or after stopping + * streams. + */ static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream) { - amdtp_stream_destroy(stream); + struct fw_iso_resources *resources; if (stream == &dice->tx_stream) - fw_iso_resources_destroy(&dice->tx_resources); + resources = &dice->tx_resources; else - fw_iso_resources_destroy(&dice->rx_resources); + resources = &dice->rx_resources; + + amdtp_stream_destroy(stream); + fw_iso_resources_destroy(resources); } int snd_dice_stream_init_duplex(struct snd_dice *dice) @@ -332,6 +339,8 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice) goto end; err = init_stream(dice, &dice->rx_stream); + if (err < 0) + destroy_stream(dice, &dice->tx_stream); end: return err; } @@ -340,10 +349,7 @@ void snd_dice_stream_destroy_duplex(struct snd_dice *dice) { snd_dice_transaction_clear_enable(dice); - stop_stream(dice, &dice->tx_stream); destroy_stream(dice, &dice->tx_stream); - - stop_stream(dice, &dice->rx_stream); destroy_stream(dice, &dice->rx_stream); dice->substreams_counter = 0; diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 90d8f40ff727..70a111d7f428 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -226,11 +226,20 @@ static void dice_card_strings(struct snd_dice *dice) strcpy(card->mixername, "DICE"); } +/* + * This module releases the FireWire unit data after all ALSA character devices + * are released by applications. This is for releasing stream data or finishing + * transactions safely. Thus at returning from .remove(), this module still keep + * references for the unit. + */ static void dice_card_free(struct snd_card *card) { struct snd_dice *dice = card->private_data; + snd_dice_stream_destroy_duplex(dice); snd_dice_transaction_destroy(dice); + fw_unit_put(dice->unit); + mutex_destroy(&dice->mutex); } @@ -251,7 +260,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) dice = card->private_data; dice->card = card; - dice->unit = unit; + dice->unit = fw_unit_get(unit); card->private_free = dice_card_free; spin_lock_init(&dice->lock); @@ -305,10 +314,7 @@ static void dice_remove(struct fw_unit *unit) { struct snd_dice *dice = dev_get_drvdata(&unit->device); - snd_card_disconnect(dice->card); - - snd_dice_stream_destroy_duplex(dice); - + /* No need to wait for releasing card object in this context. */ snd_card_free_when_closed(dice->card); } diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 3e2ed8e82cbc..2682e7e3e5c9 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -173,11 +173,23 @@ end: return err; } +/* + * This module releases the FireWire unit data after all ALSA character devices + * are released by applications. This is for releasing stream data or finishing + * transactions safely. Thus at returning from .remove(), this module still keep + * references for the unit. + */ static void efw_card_free(struct snd_card *card) { struct snd_efw *efw = card->private_data; + snd_efw_stream_destroy_duplex(efw); + snd_efw_transaction_remove_instance(efw); + fw_unit_put(efw->unit); + + kfree(efw->resp_buf); + if (efw->card_index >= 0) { mutex_lock(&devices_mutex); clear_bit(efw->card_index, devices_used); @@ -185,7 +197,6 @@ efw_card_free(struct snd_card *card) } mutex_destroy(&efw->mutex); - kfree(efw->resp_buf); } static int @@ -218,7 +229,7 @@ efw_probe(struct fw_unit *unit, card->private_free = efw_card_free; efw->card = card; - efw->unit = unit; + efw->unit = fw_unit_get(unit); mutex_init(&efw->mutex); spin_lock_init(&efw->lock); init_waitqueue_head(&efw->hwdep_wait); @@ -289,10 +300,7 @@ static void efw_remove(struct fw_unit *unit) { struct snd_efw *efw = dev_get_drvdata(&unit->device); - snd_efw_stream_destroy_duplex(efw); - snd_efw_transaction_remove_instance(efw); - - snd_card_disconnect(efw->card); + /* No need to wait for releasing card object in this context. */ snd_card_free_when_closed(efw->card); } diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 4f440e163667..c55db1bddc80 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -100,17 +100,22 @@ end: return err; } +/* + * This function should be called before starting the stream or after stopping + * the streams. + */ static void destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream) { - stop_stream(efw, stream); - - amdtp_stream_destroy(stream); + struct cmp_connection *conn; if (stream == &efw->tx_stream) - cmp_connection_destroy(&efw->out_conn); + conn = &efw->out_conn; else - cmp_connection_destroy(&efw->in_conn); + conn = &efw->in_conn; + + amdtp_stream_destroy(stream); + cmp_connection_destroy(&efw->out_conn); } static int @@ -319,12 +324,8 @@ void snd_efw_stream_update_duplex(struct snd_efw *efw) void snd_efw_stream_destroy_duplex(struct snd_efw *efw) { - mutex_lock(&efw->mutex); - destroy_stream(efw, &efw->rx_stream); destroy_stream(efw, &efw->tx_stream); - - mutex_unlock(&efw->mutex); } void snd_efw_stream_lock_changed(struct snd_efw *efw) diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c index 5f17b77ee152..f0e4d502d604 100644 --- a/sound/firewire/iso-resources.c +++ b/sound/firewire/iso-resources.c @@ -26,7 +26,7 @@ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) { r->channels_mask = ~0uLL; - r->unit = fw_unit_get(unit); + r->unit = unit; mutex_init(&r->mutex); r->allocated = false; @@ -42,7 +42,6 @@ void fw_iso_resources_destroy(struct fw_iso_resources *r) { WARN_ON(r->allocated); mutex_destroy(&r->mutex); - fw_unit_put(r->unit); } EXPORT_SYMBOL(fw_iso_resources_destroy); diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index bda845afb470..e6757cd85724 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -171,9 +171,10 @@ static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream, } /* Wait first packet */ - err = amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT); - if (err < 0) + if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) { stop_stream(oxfw, stream); + err = -ETIMEDOUT; + } end: return err; } @@ -337,6 +338,10 @@ void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw, stop_stream(oxfw, stream); } +/* + * This function should be called before starting the stream or after stopping + * the streams. + */ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream) { @@ -347,8 +352,6 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, else conn = &oxfw->in_conn; - stop_stream(oxfw, stream); - amdtp_stream_destroy(stream); cmp_connection_destroy(conn); } diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 60e5cad0531a..8c6ce019f437 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -104,11 +104,23 @@ end: return err; } +/* + * This module releases the FireWire unit data after all ALSA character devices + * are released by applications. This is for releasing stream data or finishing + * transactions safely. Thus at returning from .remove(), this module still keep + * references for the unit. + */ static void oxfw_card_free(struct snd_card *card) { struct snd_oxfw *oxfw = card->private_data; unsigned int i; + snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); + if (oxfw->has_output) + snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); + + fw_unit_put(oxfw->unit); + for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { kfree(oxfw->tx_stream_formats[i]); kfree(oxfw->rx_stream_formats[i]); @@ -136,7 +148,7 @@ static int oxfw_probe(struct fw_unit *unit, oxfw = card->private_data; oxfw->card = card; mutex_init(&oxfw->mutex); - oxfw->unit = unit; + oxfw->unit = fw_unit_get(unit); oxfw->device_info = (const struct device_info *)id->driver_data; spin_lock_init(&oxfw->lock); init_waitqueue_head(&oxfw->hwdep_wait); @@ -212,12 +224,7 @@ static void oxfw_remove(struct fw_unit *unit) { struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); - snd_card_disconnect(oxfw->card); - - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); - if (oxfw->has_output) - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); - + /* No need to wait for releasing card object in this context. */ snd_card_free_when_closed(oxfw->card); } diff --git a/sound/isa/msnd/msnd_pinnacle_mixer.c b/sound/isa/msnd/msnd_pinnacle_mixer.c index 17e49a071af4..b408540798c1 100644 --- a/sound/isa/msnd/msnd_pinnacle_mixer.c +++ b/sound/isa/msnd/msnd_pinnacle_mixer.c @@ -306,11 +306,12 @@ int snd_msndmix_new(struct snd_card *card) spin_lock_init(&chip->mixer_lock); strcpy(card->mixername, "MSND Pinnacle Mixer"); - for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++) + for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++) { err = snd_ctl_add(card, snd_ctl_new1(snd_msnd_controls + idx, chip)); if (err < 0) return err; + } return 0; } diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index dfcb5e929f9f..17c2637d842c 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -961,7 +961,6 @@ static int azx_alloc_cmd_io(struct azx *chip) dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n"); return err; } -EXPORT_SYMBOL_GPL(azx_alloc_cmd_io); static void azx_init_cmd_io(struct azx *chip) { @@ -1026,7 +1025,6 @@ static void azx_init_cmd_io(struct azx *chip) azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN); spin_unlock_irq(&chip->reg_lock); } -EXPORT_SYMBOL_GPL(azx_init_cmd_io); static void azx_free_cmd_io(struct azx *chip) { @@ -1036,7 +1034,6 @@ static void azx_free_cmd_io(struct azx *chip) azx_writeb(chip, CORBCTL, 0); spin_unlock_irq(&chip->reg_lock); } -EXPORT_SYMBOL_GPL(azx_free_cmd_io); static unsigned int azx_command_addr(u32 cmd) { @@ -1167,7 +1164,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, } } - if (!bus->no_response_fallback) + if (bus->no_response_fallback) return -1; if (!chip->polling_mode && chip->poll_count < 2) { @@ -1316,7 +1313,6 @@ static int azx_send_cmd(struct hda_bus *bus, unsigned int val) else return azx_corb_send_cmd(bus, val); } -EXPORT_SYMBOL_GPL(azx_send_cmd); /* get a response */ static unsigned int azx_get_response(struct hda_bus *bus, @@ -1330,7 +1326,6 @@ static unsigned int azx_get_response(struct hda_bus *bus, else return azx_rirb_get_response(bus, addr); } -EXPORT_SYMBOL_GPL(azx_get_response); #ifdef CONFIG_SND_HDA_DSP_LOADER /* diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index b680b4ec6331..8ec5289f8e05 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -687,12 +687,45 @@ static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, return val; } +/* is this a stereo widget or a stereo-to-mono mix? */ +static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir) +{ + unsigned int wcaps = get_wcaps(codec, nid); + hda_nid_t conn; + + if (wcaps & AC_WCAP_STEREO) + return true; + if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX) + return false; + if (snd_hda_get_num_conns(codec, nid) != 1) + return false; + if (snd_hda_get_connections(codec, nid, &conn, 1) < 0) + return false; + return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO); +} + /* initialize the amp value (only at the first time) */ static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) { unsigned int caps = query_amp_caps(codec, nid, dir); int val = get_amp_val_to_activate(codec, nid, dir, caps, false); - snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); + + if (is_stereo_amps(codec, nid, dir)) + snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); + else + snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val); +} + +/* update the amp, doing in stereo or mono depending on NID */ +static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx, + unsigned int mask, unsigned int val) +{ + if (is_stereo_amps(codec, nid, dir)) + return snd_hda_codec_amp_stereo(codec, nid, dir, idx, + mask, val); + else + return snd_hda_codec_amp_update(codec, nid, 0, dir, idx, + mask, val); } /* calculate amp value mask we can modify; @@ -732,7 +765,7 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, return; val &= mask; - snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val); + update_amp(codec, nid, dir, idx, mask, val); } static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, @@ -4424,13 +4457,11 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix) has_amp = nid_has_mute(codec, mix, HDA_INPUT); for (i = 0; i < nums; i++) { if (has_amp) - snd_hda_codec_amp_stereo(codec, mix, - HDA_INPUT, i, - 0xff, HDA_AMP_MUTE); + update_amp(codec, mix, HDA_INPUT, i, + 0xff, HDA_AMP_MUTE); else if (nid_has_volume(codec, conn[i], HDA_OUTPUT)) - snd_hda_codec_amp_stereo(codec, conn[i], - HDA_OUTPUT, 0, - 0xff, HDA_AMP_MUTE); + update_amp(codec, conn[i], HDA_OUTPUT, 0, + 0xff, HDA_AMP_MUTE); } } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 36d2f20db7a4..a8a1e14272a1 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1966,7 +1966,7 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* Panther Point */ { PCI_DEVICE(0x8086, 0x1e20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* Lynx Point */ { PCI_DEVICE(0x8086, 0x8c20), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, @@ -1989,7 +1989,7 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Sunrise Point */ { PCI_DEVICE(0x8086, 0xa170), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, /* Sunrise Point-LP */ { PCI_DEVICE(0x8086, 0x9d70), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index ce5a6da83419..05e19f78b4cb 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -134,13 +134,38 @@ static void print_amp_caps(struct snd_info_buffer *buffer, (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT); } +/* is this a stereo widget or a stereo-to-mono mix? */ +static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, + int dir, unsigned int wcaps, int indices) +{ + hda_nid_t conn; + + if (wcaps & AC_WCAP_STEREO) + return true; + /* check for a stereo-to-mono mix; it must be: + * only a single connection, only for input, and only a mixer widget + */ + if (indices != 1 || dir != HDA_INPUT || + get_wcaps_type(wcaps) != AC_WID_AUD_MIX) + return false; + + if (snd_hda_get_raw_connections(codec, nid, &conn, 1) < 0) + return false; + /* the connection source is a stereo? */ + wcaps = snd_hda_param_read(codec, conn, AC_PAR_AUDIO_WIDGET_CAP); + return !!(wcaps & AC_WCAP_STEREO); +} + static void print_amp_vals(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid, - int dir, int stereo, int indices) + int dir, unsigned int wcaps, int indices) { unsigned int val; + bool stereo; int i; + stereo = is_stereo_amps(codec, nid, dir, wcaps, indices); + dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; for (i = 0; i < indices; i++) { snd_iprintf(buffer, " ["); @@ -757,12 +782,10 @@ static void print_codec_info(struct snd_info_entry *entry, (codec->single_adc_amp && wid_type == AC_WID_AUD_IN)) print_amp_vals(buffer, codec, nid, HDA_INPUT, - wid_caps & AC_WCAP_STEREO, - 1); + wid_caps, 1); else print_amp_vals(buffer, codec, nid, HDA_INPUT, - wid_caps & AC_WCAP_STEREO, - conn_len); + wid_caps, conn_len); } if (wid_caps & AC_WCAP_OUT_AMP) { snd_iprintf(buffer, " Amp-Out caps: "); @@ -771,11 +794,10 @@ static void print_codec_info(struct snd_info_entry *entry, if (wid_type == AC_WID_PIN && codec->pin_amp_workaround) print_amp_vals(buffer, codec, nid, HDA_OUTPUT, - wid_caps & AC_WCAP_STEREO, - conn_len); + wid_caps, conn_len); else print_amp_vals(buffer, codec, nid, HDA_OUTPUT, - wid_caps & AC_WCAP_STEREO, 1); + wid_caps, 1); } switch (wid_type) { diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 1589c9bcce3e..dd2b3d92071f 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -393,6 +393,7 @@ static const struct snd_pci_quirk cs420x_fixup_tbl[] = { SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81), SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122), SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101), + SND_PCI_QUIRK(0x106b, 0x5600, "MacBookAir 5,2", CS420X_MBP81), SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42), SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE), {} /* terminator */ @@ -584,6 +585,7 @@ static int patch_cs420x(struct hda_codec *codec) return -ENOMEM; spec->gen.automute_hook = cs_automute; + codec->single_adc_amp = 1; snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl, cs420x_fixups); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index fd3ed18670e9..da67ea8645a6 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -223,6 +223,7 @@ enum { CXT_PINCFG_LENOVO_TP410, CXT_PINCFG_LEMOTE_A1004, CXT_PINCFG_LEMOTE_A1205, + CXT_PINCFG_COMPAQ_CQ60, CXT_FIXUP_STEREO_DMIC, CXT_FIXUP_INC_MIC_BOOST, CXT_FIXUP_HEADPHONE_MIC_PIN, @@ -660,6 +661,15 @@ static const struct hda_fixup cxt_fixups[] = { .type = HDA_FIXUP_PINS, .v.pins = cxt_pincfg_lemote, }, + [CXT_PINCFG_COMPAQ_CQ60] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* 0x17 was falsely set up as a mic, it should 0x1d */ + { 0x17, 0x400001f0 }, + { 0x1d, 0x97a70120 }, + { } + } + }, [CXT_FIXUP_STEREO_DMIC] = { .type = HDA_FIXUP_FUNC, .v.func = cxt_fixup_stereo_dmic, @@ -769,6 +779,7 @@ static const struct hda_model_fixup cxt5047_fixup_models[] = { }; static const struct snd_pci_quirk cxt5051_fixups[] = { + SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200), {} }; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b2b24a8b3dac..74382137b9f5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -396,7 +396,7 @@ static void alc_auto_setup_eapd(struct hda_codec *codec, bool on) { /* We currently only handle front, HP */ static hda_nid_t pins[] = { - 0x0f, 0x10, 0x14, 0x15, 0 + 0x0f, 0x10, 0x14, 0x15, 0x17, 0 }; hda_nid_t *p; for (p = pins; *p; p++) @@ -5036,6 +5036,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), @@ -5209,6 +5210,13 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x17, 0x40000000}, {0x1d, 0x40700001}, {0x21, 0x02211040}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC255_STANDARD_PINS, + {0x12, 0x90a60170}, + {0x14, 0x90170140}, + {0x17, 0x40000000}, + {0x1d, 0x40700001}, + {0x21, 0x02211050}), SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4, {0x12, 0x90a60130}, {0x13, 0x40000000}, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6d36c5b78805..87eff3173ce9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -79,6 +79,7 @@ enum { STAC_ALIENWARE_M17X, STAC_92HD89XX_HP_FRONT_JACK, STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK, + STAC_92HD73XX_ASUS_MOBO, STAC_92HD73XX_MODELS }; @@ -1911,7 +1912,18 @@ static const struct hda_fixup stac92hd73xx_fixups[] = { [STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK] = { .type = HDA_FIXUP_PINS, .v.pins = stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs, - } + }, + [STAC_92HD73XX_ASUS_MOBO] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* enable 5.1 and SPDIF out */ + { 0x0c, 0x01014411 }, + { 0x0d, 0x01014410 }, + { 0x0e, 0x01014412 }, + { 0x22, 0x014b1180 }, + { } + } + }, }; static const struct hda_model_fixup stac92hd73xx_models[] = { @@ -1923,6 +1935,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = { { .id = STAC_DELL_M6_BOTH, .name = "dell-m6" }, { .id = STAC_DELL_EQ, .name = "dell-eq" }, { .id = STAC_ALIENWARE_M17X, .name = "alienware" }, + { .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" }, {} }; @@ -1975,6 +1988,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { "HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17, "unknown HP", STAC_92HD89XX_HP_FRONT_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_ASUSTEK, 0x83f8, "ASUS AT4NM10", + STAC_92HD73XX_ASUS_MOBO), {} /* terminator */ }; diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index fb0b7e8b08ff..841d05946b88 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -187,6 +187,94 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +/* + * When the bit clock is input, limit the maximum rate according to the + * Serial Clock Ratio Considerations section from the SSC documentation: + * + * The Transmitter and the Receiver can be programmed to operate + * with the clock signals provided on either the TK or RK pins. + * This allows the SSC to support many slave-mode data transfers. + * In this case, the maximum clock speed allowed on the RK pin is: + * - Peripheral clock divided by 2 if Receiver Frame Synchro is input + * - Peripheral clock divided by 3 if Receiver Frame Synchro is output + * In addition, the maximum clock speed allowed on the TK pin is: + * - Peripheral clock divided by 6 if Transmit Frame Synchro is input + * - Peripheral clock divided by 2 if Transmit Frame Synchro is output + * + * When the bit clock is output, limit the rate according to the + * SSC divider restrictions. + */ +static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct atmel_ssc_info *ssc_p = rule->private; + struct ssc_device *ssc = ssc_p->ssc; + struct snd_interval *i = hw_param_interval(params, rule->var); + struct snd_interval t; + struct snd_ratnum r = { + .den_min = 1, + .den_max = 4095, + .den_step = 1, + }; + unsigned int num = 0, den = 0; + int frame_size; + int mck_div = 2; + int ret; + + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) + return frame_size; + + switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFS: + if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE) + && ssc->clk_from_rk_pin) + /* Receiver Frame Synchro (i.e. capture) + * is output (format is _CFS) and the RK pin + * is used for input (format is _CBM_). + */ + mck_div = 3; + break; + + case SND_SOC_DAIFMT_CBM_CFM: + if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK) + && !ssc->clk_from_rk_pin) + /* Transmit Frame Synchro (i.e. playback) + * is input (format is _CFM) and the TK pin + * is used for input (format _CBM_ but not + * using the RK pin). + */ + mck_div = 6; + break; + } + + switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + r.num = ssc_p->mck_rate / mck_div / frame_size; + + ret = snd_interval_ratnum(i, 1, &r, &num, &den); + if (ret >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) { + params->rate_num = num; + params->rate_den = den; + } + break; + + case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBM_CFM: + t.min = 8000; + t.max = ssc_p->mck_rate / mck_div / frame_size; + t.openmin = t.openmax = 0; + t.integer = 0; + ret = snd_interval_refine(i, &t); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} /*-------------------------------------------------------------------------*\ * DAI functions @@ -200,6 +288,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; struct atmel_pcm_dma_params *dma_params; int dir, dir_mask; + int ret; pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", ssc_readl(ssc_p->ssc->regs, SR)); @@ -207,6 +296,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, /* Enable PMC peripheral clock for this SSC */ pr_debug("atmel_ssc_dai: Starting clock\n"); 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)); @@ -219,6 +309,17 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, dir_mask = SSC_DIR_MASK_CAPTURE; } + ret = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + atmel_ssc_hw_rule_rate, + ssc_p, + SNDRV_PCM_HW_PARAM_FRAME_BITS, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (ret < 0) { + dev_err(dai->dev, "Failed to specify rate rule: %d\n", ret); + return ret; + } + dma_params = &ssc_dma_params[dai->id][dir]; dma_params->ssc = ssc_p->ssc; dma_params->substream = substream; @@ -783,8 +884,6 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) # define atmel_ssc_resume NULL #endif /* CONFIG_PM */ -#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000) - #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) @@ -804,12 +903,16 @@ static struct snd_soc_dai_driver atmel_ssc_dai = { .playback = { .channels_min = 1, .channels_max = 2, - .rates = ATMEL_SSC_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, + .rate_max = 384000, .formats = ATMEL_SSC_FORMATS,}, .capture = { .channels_min = 1, .channels_max = 2, - .rates = ATMEL_SSC_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, + .rate_max = 384000, .formats = ATMEL_SSC_FORMATS,}, .ops = &atmel_ssc_dai_ops, }; diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h index b1f08d511495..80b153857a88 100644 --- a/sound/soc/atmel/atmel_ssc_dai.h +++ b/sound/soc/atmel/atmel_ssc_dai.h @@ -115,6 +115,7 @@ struct atmel_ssc_info { unsigned short rcmr_period; struct atmel_pcm_dma_params *dma_params[2]; struct atmel_ssc_state ssc_state; + unsigned long mck_rate; }; int atmel_ssc_set_audio(int ssc_id); diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index f5ad214663f9..8de836165cf2 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -46,8 +46,6 @@ #include <sound/pcm_params.h> #include <sound/soc.h> -#include <asm/mach-types.h> - #include "../codecs/wm8731.h" #include "atmel-pcm.h" #include "atmel_ssc_dai.h" @@ -171,9 +169,7 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev) int ret; if (!np) { - if (!(machine_is_at91sam9g20ek() || - machine_is_at91sam9g20ek_2mmc())) - return -ENODEV; + return -ENODEV; } ret = atmel_ssc_set_audio(0); @@ -210,39 +206,37 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev) card->dev = &pdev->dev; /* Parse device node info */ - if (np) { - ret = snd_soc_of_parse_card_name(card, "atmel,model"); - if (ret) - goto err; - - ret = snd_soc_of_parse_audio_routing(card, - "atmel,audio-routing"); - if (ret) - goto err; - - /* Parse codec info */ - at91sam9g20ek_dai.codec_name = NULL; - codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); - if (!codec_np) { - dev_err(&pdev->dev, "codec info missing\n"); - return -EINVAL; - } - at91sam9g20ek_dai.codec_of_node = codec_np; - - /* Parse dai and platform info */ - at91sam9g20ek_dai.cpu_dai_name = NULL; - at91sam9g20ek_dai.platform_name = NULL; - cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); - if (!cpu_np) { - dev_err(&pdev->dev, "dai and pcm info missing\n"); - return -EINVAL; - } - at91sam9g20ek_dai.cpu_of_node = cpu_np; - at91sam9g20ek_dai.platform_of_node = cpu_np; - - of_node_put(codec_np); - of_node_put(cpu_np); + ret = snd_soc_of_parse_card_name(card, "atmel,model"); + if (ret) + goto err; + + ret = snd_soc_of_parse_audio_routing(card, + "atmel,audio-routing"); + if (ret) + goto err; + + /* Parse codec info */ + at91sam9g20ek_dai.codec_name = NULL; + codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "codec info missing\n"); + return -EINVAL; + } + at91sam9g20ek_dai.codec_of_node = codec_np; + + /* Parse dai and platform info */ + at91sam9g20ek_dai.cpu_dai_name = NULL; + at91sam9g20ek_dai.platform_name = NULL; + cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); + if (!cpu_np) { + dev_err(&pdev->dev, "dai and pcm info missing\n"); + return -EINVAL; } + at91sam9g20ek_dai.cpu_of_node = cpu_np; + at91sam9g20ek_dai.platform_of_node = cpu_np; + + of_node_put(codec_np); + of_node_put(cpu_np); ret = snd_soc_register_card(card); if (ret) { diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig index 7b7fbcd49e5e..c7cd60f009e9 100644 --- a/sound/soc/cirrus/Kconfig +++ b/sound/soc/cirrus/Kconfig @@ -16,7 +16,7 @@ config SND_EP93XX_SOC_AC97 config SND_EP93XX_SOC_SNAPPERCL15 tristate "SoC Audio support for Bluewater Systems Snapper CL15 module" - depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 + depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 && I2C select SND_EP93XX_SOC_I2S select SND_SOC_TLV320AIC23_I2C help diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 064e6c18e109..0bddd929837f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -69,7 +69,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX98088 if I2C select SND_SOC_MAX98090 if I2C select SND_SOC_MAX98095 if I2C - select SND_SOC_MAX98357A + select SND_SOC_MAX98357A if GPIOLIB select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9768 if I2C select SND_SOC_MAX9877 if I2C @@ -141,7 +141,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8770 if SPI_MASTER select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8782 - select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8804_I2C if I2C + select SND_SOC_WM8804_SPI if SPI_MASTER select SND_SOC_WM8900 if I2C select SND_SOC_WM8903 if I2C select SND_SOC_WM8904 if I2C @@ -744,8 +745,19 @@ config SND_SOC_WM8782 tristate config SND_SOC_WM8804 - tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver" - depends on SND_SOC_I2C_AND_SPI + tristate + +config SND_SOC_WM8804_I2C + tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver I2C" + depends on I2C + select SND_SOC_WM8804 + select REGMAP_I2C + +config SND_SOC_WM8804_SPI + tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver SPI" + depends on SPI_MASTER + select SND_SOC_WM8804 + select REGMAP_SPI config SND_SOC_WM8900 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 69b8666d187a..7acb6c174cb4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -145,6 +145,8 @@ snd-soc-wm8770-objs := wm8770.o snd-soc-wm8776-objs := wm8776.o snd-soc-wm8782-objs := wm8782.o snd-soc-wm8804-objs := wm8804.o +snd-soc-wm8804-i2c-objs := wm8804-i2c.o +snd-soc-wm8804-spi-objs := wm8804-spi.o snd-soc-wm8900-objs := wm8900.o snd-soc-wm8903-objs := wm8903.o snd-soc-wm8904-objs := wm8904.o @@ -323,6 +325,8 @@ obj-$(CONFIG_SND_SOC_WM8770) += snd-soc-wm8770.o obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o obj-$(CONFIG_SND_SOC_WM8782) += snd-soc-wm8782.o obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o +obj-$(CONFIG_SND_SOC_WM8804_I2C) += snd-soc-wm8804-i2c.o +obj-$(CONFIG_SND_SOC_WM8804_SPI) += snd-soc-wm8804-spi.o obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index 70ab35744aba..7ad8e156e2df 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -938,22 +938,15 @@ int adau1977_probe(struct device *dev, struct regmap *regmap, adau1977->dvdd_reg = NULL; } - adau1977->reset_gpio = devm_gpiod_get(dev, "reset"); - if (IS_ERR(adau1977->reset_gpio)) { - ret = PTR_ERR(adau1977->reset_gpio); - if (ret != -ENOENT && ret != -ENOSYS) - return PTR_ERR(adau1977->reset_gpio); - adau1977->reset_gpio = NULL; - } + adau1977->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(adau1977->reset_gpio)) + return PTR_ERR(adau1977->reset_gpio); dev_set_drvdata(dev, adau1977); - if (adau1977->reset_gpio) { - ret = gpiod_direction_output(adau1977->reset_gpio, 0); - if (ret) - return ret; + if (adau1977->reset_gpio) ndelay(100); - } ret = adau1977_power_enable(adau1977); if (ret) diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index b67480f1b1aa..4373ada95648 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -317,7 +317,7 @@ static int adav80x_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - unsigned int deemph = ucontrol->value.enumerated.item[0]; + unsigned int deemph = ucontrol->value.integer.value[0]; if (deemph > 1) return -EINVAL; @@ -333,7 +333,7 @@ static int adav80x_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = adav80x->deemph; + ucontrol->value.integer.value[0] = adav80x->deemph; return 0; }; diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 70861c7b1631..81b54a270bd8 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -76,7 +76,7 @@ static int ak4641_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); - int deemph = ucontrol->value.enumerated.item[0]; + int deemph = ucontrol->value.integer.value[0]; if (deemph > 1) return -EINVAL; @@ -92,7 +92,7 @@ static int ak4641_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = ak4641->deemph; + ucontrol->value.integer.value[0] = ak4641->deemph; return 0; }; diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index dde8b49c19ad..fba80f30de4d 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -468,13 +468,13 @@ static struct snd_soc_dai_driver ak4642_dai = { .name = "ak4642-hifi", .playback = { .stream_name = "Playback", - .channels_min = 1, + .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE }, .capture = { .stream_name = "Capture", - .channels_min = 1, + .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE }, diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 632e89f793a7..2a58b1dccd2f 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -343,25 +343,25 @@ static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = { }; static const struct snd_soc_dapm_route ak4671_intercon[] = { - {"DAC Left", "NULL", "PMPLL"}, - {"DAC Right", "NULL", "PMPLL"}, - {"ADC Left", "NULL", "PMPLL"}, - {"ADC Right", "NULL", "PMPLL"}, + {"DAC Left", NULL, "PMPLL"}, + {"DAC Right", NULL, "PMPLL"}, + {"ADC Left", NULL, "PMPLL"}, + {"ADC Right", NULL, "PMPLL"}, /* Outputs */ - {"LOUT1", "NULL", "LOUT1 Mixer"}, - {"ROUT1", "NULL", "ROUT1 Mixer"}, - {"LOUT2", "NULL", "LOUT2 Mix Amp"}, - {"ROUT2", "NULL", "ROUT2 Mix Amp"}, - {"LOUT3", "NULL", "LOUT3 Mixer"}, - {"ROUT3", "NULL", "ROUT3 Mixer"}, + {"LOUT1", NULL, "LOUT1 Mixer"}, + {"ROUT1", NULL, "ROUT1 Mixer"}, + {"LOUT2", NULL, "LOUT2 Mix Amp"}, + {"ROUT2", NULL, "ROUT2 Mix Amp"}, + {"LOUT3", NULL, "LOUT3 Mixer"}, + {"ROUT3", NULL, "ROUT3 Mixer"}, {"LOUT1 Mixer", "DACL", "DAC Left"}, {"ROUT1 Mixer", "DACR", "DAC Right"}, {"LOUT2 Mixer", "DACHL", "DAC Left"}, {"ROUT2 Mixer", "DACHR", "DAC Right"}, - {"LOUT2 Mix Amp", "NULL", "LOUT2 Mixer"}, - {"ROUT2 Mix Amp", "NULL", "ROUT2 Mixer"}, + {"LOUT2 Mix Amp", NULL, "LOUT2 Mixer"}, + {"ROUT2 Mix Amp", NULL, "ROUT2 Mixer"}, {"LOUT3 Mixer", "DACSL", "DAC Left"}, {"ROUT3 Mixer", "DACSR", "DAC Right"}, @@ -381,18 +381,18 @@ static const struct snd_soc_dapm_route ak4671_intercon[] = { {"LIN2", NULL, "Mic Bias"}, {"RIN2", NULL, "Mic Bias"}, - {"ADC Left", "NULL", "LIN MUX"}, - {"ADC Right", "NULL", "RIN MUX"}, + {"ADC Left", NULL, "LIN MUX"}, + {"ADC Right", NULL, "RIN MUX"}, /* Analog Loops */ - {"LIN1 Mixing Circuit", "NULL", "LIN1"}, - {"RIN1 Mixing Circuit", "NULL", "RIN1"}, - {"LIN2 Mixing Circuit", "NULL", "LIN2"}, - {"RIN2 Mixing Circuit", "NULL", "RIN2"}, - {"LIN3 Mixing Circuit", "NULL", "LIN3"}, - {"RIN3 Mixing Circuit", "NULL", "RIN3"}, - {"LIN4 Mixing Circuit", "NULL", "LIN4"}, - {"RIN4 Mixing Circuit", "NULL", "RIN4"}, + {"LIN1 Mixing Circuit", NULL, "LIN1"}, + {"RIN1 Mixing Circuit", NULL, "RIN1"}, + {"LIN2 Mixing Circuit", NULL, "LIN2"}, + {"RIN2 Mixing Circuit", NULL, "RIN2"}, + {"LIN3 Mixing Circuit", NULL, "LIN3"}, + {"RIN3 Mixing Circuit", NULL, "RIN3"}, + {"LIN4 Mixing Circuit", NULL, "LIN4"}, + {"RIN4 Mixing Circuit", NULL, "RIN4"}, {"LOUT1 Mixer", "LINL1", "LIN1 Mixing Circuit"}, {"ROUT1 Mixer", "RINR1", "RIN1 Mixing Circuit"}, diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index f2b8aad21274..60598b230341 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -437,20 +437,13 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, } /* Reset the Device */ - cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev, - "reset-gpios"); - if (IS_ERR(cs35l32->reset_gpio)) { - ret = PTR_ERR(cs35l32->reset_gpio); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - cs35l32->reset_gpio = NULL; - } else { - ret = gpiod_direction_output(cs35l32->reset_gpio, 0); - if (ret) - return ret; + cs35l32->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs35l32->reset_gpio)) + return PTR_ERR(cs35l32->reset_gpio); + + if (cs35l32->reset_gpio) gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); - } /* initialize codec */ ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, ®); diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index ce6086835ebd..cac48ddf3ba6 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -605,21 +605,14 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client, return ret; } - cs4265->reset_gpio = devm_gpiod_get(&i2c_client->dev, - "reset-gpios"); - if (IS_ERR(cs4265->reset_gpio)) { - ret = PTR_ERR(cs4265->reset_gpio); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - cs4265->reset_gpio = NULL; - } else { - ret = gpiod_direction_output(cs4265->reset_gpio, 0); - if (ret) - return ret; + cs4265->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs4265->reset_gpio)) + return PTR_ERR(cs4265->reset_gpio); + + if (cs4265->reset_gpio) { mdelay(1); gpiod_set_value_cansleep(cs4265->reset_gpio, 1); - } i2c_set_clientdata(i2c_client, cs4265); diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 79a4efcb894c..e770ee6f36da 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -286,7 +286,7 @@ static int cs4271_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = cs4271->deemph; + ucontrol->value.integer.value[0] = cs4271->deemph; return 0; } @@ -296,7 +296,7 @@ static int cs4271_put_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); - cs4271->deemph = ucontrol->value.enumerated.item[0]; + cs4271->deemph = ucontrol->value.integer.value[0]; return cs4271_set_deemph(codec); } @@ -561,10 +561,10 @@ static int cs4271_codec_probe(struct snd_soc_codec *codec) if (gpio_is_valid(cs4271->gpio_nreset)) { /* Reset codec */ gpio_direction_output(cs4271->gpio_nreset, 0); - udelay(1); + mdelay(1); gpio_set_value(cs4271->gpio_nreset, 1); /* Give the codec time to wake up */ - udelay(1); + mdelay(1); } ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index ffe96175a8a5..911c26c705fc 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -876,11 +876,11 @@ static const struct snd_soc_dapm_widget da732x_dapm_widgets[] = { static const struct snd_soc_dapm_route da732x_dapm_routes[] = { /* Inputs */ - {"AUX1L PGA", "NULL", "AUX1L"}, - {"AUX1R PGA", "NULL", "AUX1R"}, + {"AUX1L PGA", NULL, "AUX1L"}, + {"AUX1R PGA", NULL, "AUX1R"}, {"MIC1 PGA", NULL, "MIC1"}, - {"MIC2 PGA", "NULL", "MIC2"}, - {"MIC3 PGA", "NULL", "MIC3"}, + {"MIC2 PGA", NULL, "MIC2"}, + {"MIC3 PGA", NULL, "MIC3"}, /* Capture Path */ {"ADC1 Left MUX", "MIC1", "MIC1 PGA"}, diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index f27325155ace..c5f35a07e8e4 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -120,7 +120,7 @@ static int es8328_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = es8328->deemph; + ucontrol->value.integer.value[0] = es8328->deemph; return 0; } @@ -129,7 +129,7 @@ static int es8328_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); - int deemph = ucontrol->value.enumerated.item[0]; + int deemph = ucontrol->value.integer.value[0]; int ret; if (deemph > 1) diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index 1806333ea29e..bf3e933ee895 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -12,11 +12,19 @@ * max98357a.c -- MAX98357A ALSA SoC Codec driver */ -#include <linux/module.h> +#include <linux/device.h> +#include <linux/err.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/kernel.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <sound/pcm.h> #include <sound/soc.h> - -#define DRV_NAME "max98357a" +#include <sound/soc-dai.h> +#include <sound/soc-dapm.h> static int max98357a_daiops_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) @@ -77,9 +85,9 @@ static struct snd_soc_dai_ops max98357a_dai_ops = { }; static struct snd_soc_dai_driver max98357a_dai_driver = { - .name = DRV_NAME, + .name = "HiFi", .playback = { - .stream_name = DRV_NAME "-playback", + .stream_name = "HiFi Playback", .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32, @@ -117,7 +125,7 @@ static int max98357a_platform_remove(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id max98357a_device_id[] = { - { .compatible = "maxim," DRV_NAME, }, + { .compatible = "maxim,max98357a" }, {} }; MODULE_DEVICE_TABLE(of, max98357a_device_id); @@ -125,7 +133,7 @@ MODULE_DEVICE_TABLE(of, max98357a_device_id); static struct platform_driver max98357a_platform_driver = { .driver = { - .name = DRV_NAME, + .name = "max98357a", .of_match_table = of_match_ptr(max98357a_device_id), }, .probe = max98357a_platform_probe, @@ -135,4 +143,3 @@ module_platform_driver(max98357a_platform_driver); MODULE_DESCRIPTION("Maxim MAX98357A Codec Driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index a722a023c262..477e13d30971 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -118,7 +118,7 @@ static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = priv->deemph; + ucontrol->value.integer.value[0] = priv->deemph; return 0; } @@ -129,7 +129,7 @@ static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); - priv->deemph = ucontrol->value.enumerated.item[0]; + priv->deemph = ucontrol->value.integer.value[0]; return pcm1681_set_deemph(codec); } diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 9974f201a08f..5a30fdd0da00 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -54,6 +54,9 @@ struct pcm512x_priv { int pll_d; int pll_p; unsigned long real_pll; + unsigned long overclock_pll; + unsigned long overclock_dac; + unsigned long overclock_dsp; }; /* @@ -224,6 +227,90 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg) } } +static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = pcm512x->overclock_pll; + return 0; +} + +static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + switch (codec->dapm.bias_level) { + case SND_SOC_BIAS_OFF: + case SND_SOC_BIAS_STANDBY: + break; + default: + return -EBUSY; + } + + pcm512x->overclock_pll = ucontrol->value.integer.value[0]; + return 0; +} + +static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = pcm512x->overclock_dsp; + return 0; +} + +static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + switch (codec->dapm.bias_level) { + case SND_SOC_BIAS_OFF: + case SND_SOC_BIAS_STANDBY: + break; + default: + return -EBUSY; + } + + pcm512x->overclock_dsp = ucontrol->value.integer.value[0]; + return 0; +} + +static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = pcm512x->overclock_dac; + return 0; +} + +static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + switch (codec->dapm.bias_level) { + case SND_SOC_BIAS_OFF: + case SND_SOC_BIAS_STANDBY: + break; + default: + return -EBUSY; + } + + pcm512x->overclock_dac = ucontrol->value.integer.value[0]; + return 0; +} + static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0); @@ -304,9 +391,9 @@ static const struct soc_enum pcm512x_veds = static const struct snd_kcontrol_new pcm512x_controls[] = { SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), -SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL, +SOC_DOUBLE_TLV("Analogue Playback Volume", PCM512x_ANALOG_GAIN_CTRL, PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), -SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, +SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, PCM512x_RQMR_SHIFT, 1, 1), @@ -328,6 +415,13 @@ SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf), SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus), SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf), SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds), + +SOC_SINGLE_EXT("Max Overclock PLL", SND_SOC_NOPM, 0, 20, 0, + pcm512x_overclock_pll_get, pcm512x_overclock_pll_put), +SOC_SINGLE_EXT("Max Overclock DSP", SND_SOC_NOPM, 0, 40, 0, + pcm512x_overclock_dsp_get, pcm512x_overclock_dsp_put), +SOC_SINGLE_EXT("Max Overclock DAC", SND_SOC_NOPM, 0, 40, 0, + pcm512x_overclock_dac_get, pcm512x_overclock_dac_put), }; static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = { @@ -346,6 +440,45 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { { "OUTR", NULL, "DACR" }, }; +static unsigned long pcm512x_pll_max(struct pcm512x_priv *pcm512x) +{ + return 25000000 + 25000000 * pcm512x->overclock_pll / 100; +} + +static unsigned long pcm512x_dsp_max(struct pcm512x_priv *pcm512x) +{ + return 50000000 + 50000000 * pcm512x->overclock_dsp / 100; +} + +static unsigned long pcm512x_dac_max(struct pcm512x_priv *pcm512x, + unsigned long rate) +{ + return rate + rate * pcm512x->overclock_dac / 100; +} + +static unsigned long pcm512x_sck_max(struct pcm512x_priv *pcm512x) +{ + if (!pcm512x->pll_out) + return 25000000; + return pcm512x_pll_max(pcm512x); +} + +static unsigned long pcm512x_ncp_target(struct pcm512x_priv *pcm512x, + unsigned long dac_rate) +{ + /* + * If the DAC is not actually overclocked, use the good old + * NCP target rate... + */ + if (dac_rate <= 6144000) + return 1536000; + /* + * ...but if the DAC is in fact overclocked, bump the NCP target + * rate to get the recommended dividers even when overclocking. + */ + return pcm512x_dac_max(pcm512x, 1536000); +} + static const u32 pcm512x_dai_rates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, 384000, @@ -359,6 +492,7 @@ static const struct snd_pcm_hw_constraint_list constraints_slave = { static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { + struct pcm512x_priv *pcm512x = rule->private; struct snd_interval ranges[2]; int frame_size; @@ -377,7 +511,7 @@ static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params, */ memset(ranges, 0, sizeof(ranges)); ranges[0].min = 8000; - ranges[0].max = 25000000 / frame_size / 2; + ranges[0].max = pcm512x_sck_max(pcm512x) / frame_size / 2; ranges[1].min = DIV_ROUND_UP(16000000, frame_size); ranges[1].max = 384000; break; @@ -408,7 +542,7 @@ static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream, return snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, pcm512x_hw_rule_rate, - NULL, + pcm512x, SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1); @@ -517,6 +651,8 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai, unsigned long bclk_rate) { struct device *dev = dai->dev; + struct snd_soc_codec *codec = dai->codec; + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); unsigned long sck_rate; int pow2; @@ -527,9 +663,10 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai, * as many factors of 2 as possible, as that makes it easier * to find a fast DAC rate */ - pow2 = 1 << fls((25000000 - 16000000) / bclk_rate); + pow2 = 1 << fls((pcm512x_pll_max(pcm512x) - 16000000) / bclk_rate); for (; pow2; pow2 >>= 1) { - sck_rate = rounddown(25000000, bclk_rate * pow2); + sck_rate = rounddown(pcm512x_pll_max(pcm512x), + bclk_rate * pow2); if (sck_rate >= 16000000) break; } @@ -576,8 +713,8 @@ static int pcm512x_find_pll_coeff(struct snd_soc_dai *dai, /* pllin_rate / P (or here, den) cannot be greater than 20 MHz */ if (pllin_rate / den > 20000000 && num < 8) { - num *= 20000000 / (pllin_rate / den); - den *= 20000000 / (pllin_rate / den); + num *= DIV_ROUND_UP(pllin_rate / den, 20000000); + den *= DIV_ROUND_UP(pllin_rate / den, 20000000); } dev_dbg(dev, "num / den = %lu / %lu\n", num, den); @@ -678,7 +815,7 @@ static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai, return 0; /* futile, quit early */ /* run DAC no faster than 6144000 Hz */ - for (dac_rate = rounddown(6144000, osr_rate); + for (dac_rate = rounddown(pcm512x_dac_max(pcm512x, 6144000), osr_rate); dac_rate; dac_rate -= osr_rate) { @@ -805,7 +942,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, osr_rate = 16 * sample_rate; /* run DSP no faster than 50 MHz */ - dsp_div = mck_rate > 50000000 ? 2 : 1; + dsp_div = mck_rate > pcm512x_dsp_max(pcm512x) ? 2 : 1; dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate); if (dac_rate) { @@ -836,7 +973,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, dacsrc_rate = pllin_rate; } else { /* run DAC no faster than 6144000 Hz */ - unsigned long dac_mul = 6144000 / osr_rate; + unsigned long dac_mul = pcm512x_dac_max(pcm512x, 6144000) + / osr_rate; unsigned long sck_mul = sck_rate / osr_rate; for (; dac_mul; dac_mul--) { @@ -863,28 +1001,30 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, dacsrc_rate = sck_rate; } + osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate); + if (osr_div > 128) { + dev_err(dev, "Failed to find OSR divider\n"); + return -EINVAL; + } + dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate); if (dac_div > 128) { dev_err(dev, "Failed to find DAC divider\n"); return -EINVAL; } + dac_rate = dacsrc_rate / dac_div; - ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000); - if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) { + ncp_div = DIV_ROUND_CLOSEST(dac_rate, + pcm512x_ncp_target(pcm512x, dac_rate)); + if (ncp_div > 128 || dac_rate / ncp_div > 2048000) { /* run NCP no faster than 2048000 Hz, but why? */ - ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000); + ncp_div = DIV_ROUND_UP(dac_rate, 2048000); if (ncp_div > 128) { dev_err(dev, "Failed to find NCP divider\n"); return -EINVAL; } } - osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate); - if (osr_div > 128) { - dev_err(dev, "Failed to find OSR divider\n"); - return -EINVAL; - } - idac = mck_rate / (dsp_div * sample_rate); ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1); @@ -937,11 +1077,11 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, return ret; } - if (sample_rate <= 48000) + if (sample_rate <= pcm512x_dac_max(pcm512x, 48000)) fssp = PCM512x_FSSP_48KHZ; - else if (sample_rate <= 96000) + else if (sample_rate <= pcm512x_dac_max(pcm512x, 96000)) fssp = PCM512x_FSSP_96KHZ; - else if (sample_rate <= 192000) + else if (sample_rate <= pcm512x_dac_max(pcm512x, 192000)) fssp = PCM512x_FSSP_192KHZ; else fssp = PCM512x_FSSP_384KHZ; @@ -1156,25 +1296,6 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, ret, pcm512x->pll_out); return ret; } - - gpio = PCM512x_G1OE << (4 - 1); - ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN, - gpio, gpio); - if (ret != 0) { - dev_err(codec->dev, "Failed to enable gpio %d: %d\n", - 4, ret); - return ret; - } - - gpio = PCM512x_GPIO_OUTPUT_1 + 4 - 1; - ret = regmap_update_bits(pcm512x->regmap, gpio, - PCM512x_GxSL, PCM512x_GxSL_PLLLK); - if (ret != 0) { - dev_err(codec->dev, - "Failed to output pll lock on %d: %d\n", - ret, 4); - return ret; - } } ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE, diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index f374840a5a7c..826037090c83 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -395,9 +395,20 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) rt286->jack = jack; - /* Send an initial empty report */ - snd_soc_jack_report(rt286->jack, 0, - SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + if (jack) { + /* enable IRQ */ + if (rt286->jack->status | SND_JACK_HEADPHONE) + snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO1"); + regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2); + /* Send an initial empty report */ + snd_soc_jack_report(rt286->jack, rt286->jack->status, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + } else { + /* disable IRQ */ + regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x0); + snd_soc_dapm_disable_pin(&codec->dapm, "LDO1"); + } + snd_soc_dapm_sync(&codec->dapm); return 0; } @@ -1198,7 +1209,7 @@ static struct dmi_system_id dmi_dell_dino[] = { .ident = "Dell Dino", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_BOARD_NAME, "0144P8") + DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343") } }, { } diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index e1a4a45c57e2..fd102613d20d 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -225,7 +225,6 @@ static bool rt5670_volatile_register(struct device *dev, unsigned int reg) case RT5670_ADC_EQ_CTRL1: case RT5670_EQ_CTRL1: case RT5670_ALC_CTRL_1: - case RT5670_IRQ_CTRL1: case RT5670_IRQ_CTRL2: case RT5670_INT_IRQ_ST: case RT5670_IL_CMD: @@ -2703,6 +2702,12 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, regmap_write(rt5670->regmap, RT5670_RESET, 0); + regmap_read(rt5670->regmap, RT5670_VENDOR_ID, &val); + if (val >= 4) + regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0980); + else + regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0d00); + ret = regmap_register_patch(rt5670->regmap, init_list, ARRAY_SIZE(init_list)); if (ret != 0) diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index 21f8e18c13c4..0a67adbcfbc3 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1950,17 +1950,20 @@ enum { }; enum { + RT5670_DMIC1_DISABLED, RT5670_DMIC_DATA_GPIO6, RT5670_DMIC_DATA_IN2P, RT5670_DMIC_DATA_GPIO7, }; enum { + RT5670_DMIC2_DISABLED, RT5670_DMIC_DATA_GPIO8, RT5670_DMIC_DATA_IN3N, }; enum { + RT5670_DMIC3_DISABLED, RT5670_DMIC_DATA_GPIO9, RT5670_DMIC_DATA_GPIO10, RT5670_DMIC_DATA_GPIO5, diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 5d0bb8748dd1..c2a6e4091357 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -718,11 +718,24 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) RT5677_LDO1_SEL_MASK, 0x0); regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, RT5677_PWR_LDO1, RT5677_PWR_LDO1); - regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, - RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC); - regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2, - RT5677_PLL2_PR_SRC_MASK | RT5677_DSP_CLK_SRC_MASK, - RT5677_PLL2_PR_SRC_MCLK2 | RT5677_DSP_CLK_SRC_BYPASS); + switch (rt5677->type) { + case RT5677: + regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, + RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC); + regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2, + RT5677_PLL2_PR_SRC_MASK | + RT5677_DSP_CLK_SRC_MASK, + RT5677_PLL2_PR_SRC_MCLK2 | + RT5677_DSP_CLK_SRC_BYPASS); + break; + case RT5676: + regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2, + RT5677_DSP_CLK_SRC_MASK, + RT5677_DSP_CLK_SRC_BYPASS); + break; + default: + break; + } regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff); regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd); rt5677_set_dsp_mode(codec, true); @@ -3284,8 +3297,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "IB45 Bypass Mux", "Bypass", "IB45 Mux" }, { "IB45 Bypass Mux", "Pass SRC", "IB45 Mux" }, - { "IB6 Mux", "IF1 DAC 6", "IF1 DAC6" }, - { "IB6 Mux", "IF2 DAC 6", "IF2 DAC6" }, + { "IB6 Mux", "IF1 DAC 6", "IF1 DAC6 Mux" }, + { "IB6 Mux", "IF2 DAC 6", "IF2 DAC6 Mux" }, { "IB6 Mux", "SLB DAC 6", "SLB DAC6" }, { "IB6 Mux", "STO4 ADC MIX L", "Stereo4 ADC MIXL" }, { "IB6 Mux", "IF4 DAC L", "IF4 DAC L" }, @@ -3293,8 +3306,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "IB6 Mux", "STO2 ADC MIX L", "Stereo2 ADC MIXL" }, { "IB6 Mux", "STO3 ADC MIX L", "Stereo3 ADC MIXL" }, - { "IB7 Mux", "IF1 DAC 7", "IF1 DAC7" }, - { "IB7 Mux", "IF2 DAC 7", "IF2 DAC7" }, + { "IB7 Mux", "IF1 DAC 7", "IF1 DAC7 Mux" }, + { "IB7 Mux", "IF2 DAC 7", "IF2 DAC7 Mux" }, { "IB7 Mux", "SLB DAC 7", "SLB DAC7" }, { "IB7 Mux", "STO4 ADC MIX R", "Stereo4 ADC MIXR" }, { "IB7 Mux", "IF4 DAC R", "IF4 DAC R" }, @@ -3635,15 +3648,15 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "DAC1 FS", NULL, "DAC1 MIXL" }, { "DAC1 FS", NULL, "DAC1 MIXR" }, - { "DAC2 L Mux", "IF1 DAC 2", "IF1 DAC2" }, - { "DAC2 L Mux", "IF2 DAC 2", "IF2 DAC2" }, + { "DAC2 L Mux", "IF1 DAC 2", "IF1 DAC2 Mux" }, + { "DAC2 L Mux", "IF2 DAC 2", "IF2 DAC2 Mux" }, { "DAC2 L Mux", "IF3 DAC L", "IF3 DAC L" }, { "DAC2 L Mux", "IF4 DAC L", "IF4 DAC L" }, { "DAC2 L Mux", "SLB DAC 2", "SLB DAC2" }, { "DAC2 L Mux", "OB 2", "OutBound2" }, - { "DAC2 R Mux", "IF1 DAC 3", "IF1 DAC3" }, - { "DAC2 R Mux", "IF2 DAC 3", "IF2 DAC3" }, + { "DAC2 R Mux", "IF1 DAC 3", "IF1 DAC3 Mux" }, + { "DAC2 R Mux", "IF2 DAC 3", "IF2 DAC3 Mux" }, { "DAC2 R Mux", "IF3 DAC R", "IF3 DAC R" }, { "DAC2 R Mux", "IF4 DAC R", "IF4 DAC R" }, { "DAC2 R Mux", "SLB DAC 3", "SLB DAC3" }, @@ -3651,29 +3664,29 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "DAC2 R Mux", "Haptic Generator", "Haptic Generator" }, { "DAC2 R Mux", "VAD ADC", "VAD ADC Mux" }, - { "DAC3 L Mux", "IF1 DAC 4", "IF1 DAC4" }, - { "DAC3 L Mux", "IF2 DAC 4", "IF2 DAC4" }, + { "DAC3 L Mux", "IF1 DAC 4", "IF1 DAC4 Mux" }, + { "DAC3 L Mux", "IF2 DAC 4", "IF2 DAC4 Mux" }, { "DAC3 L Mux", "IF3 DAC L", "IF3 DAC L" }, { "DAC3 L Mux", "IF4 DAC L", "IF4 DAC L" }, { "DAC3 L Mux", "SLB DAC 4", "SLB DAC4" }, { "DAC3 L Mux", "OB 4", "OutBound4" }, - { "DAC3 R Mux", "IF1 DAC 5", "IF1 DAC4" }, - { "DAC3 R Mux", "IF2 DAC 5", "IF2 DAC4" }, + { "DAC3 R Mux", "IF1 DAC 5", "IF1 DAC5 Mux" }, + { "DAC3 R Mux", "IF2 DAC 5", "IF2 DAC5 Mux" }, { "DAC3 R Mux", "IF3 DAC R", "IF3 DAC R" }, { "DAC3 R Mux", "IF4 DAC R", "IF4 DAC R" }, { "DAC3 R Mux", "SLB DAC 5", "SLB DAC5" }, { "DAC3 R Mux", "OB 5", "OutBound5" }, - { "DAC4 L Mux", "IF1 DAC 6", "IF1 DAC6" }, - { "DAC4 L Mux", "IF2 DAC 6", "IF2 DAC6" }, + { "DAC4 L Mux", "IF1 DAC 6", "IF1 DAC6 Mux" }, + { "DAC4 L Mux", "IF2 DAC 6", "IF2 DAC6 Mux" }, { "DAC4 L Mux", "IF3 DAC L", "IF3 DAC L" }, { "DAC4 L Mux", "IF4 DAC L", "IF4 DAC L" }, { "DAC4 L Mux", "SLB DAC 6", "SLB DAC6" }, { "DAC4 L Mux", "OB 6", "OutBound6" }, - { "DAC4 R Mux", "IF1 DAC 7", "IF1 DAC7" }, - { "DAC4 R Mux", "IF2 DAC 7", "IF2 DAC7" }, + { "DAC4 R Mux", "IF1 DAC 7", "IF1 DAC7 Mux" }, + { "DAC4 R Mux", "IF2 DAC 7", "IF2 DAC7 Mux" }, { "DAC4 R Mux", "IF3 DAC R", "IF3 DAC R" }, { "DAC4 R Mux", "IF4 DAC R", "IF4 DAC R" }, { "DAC4 R Mux", "SLB DAC 7", "SLB DAC7" }, @@ -4500,10 +4513,10 @@ static int rt5677_suspend(struct snd_soc_codec *codec) if (!rt5677->dsp_vad_en) { regcache_cache_only(rt5677->regmap, true); regcache_mark_dirty(rt5677->regmap); - } - if (gpio_is_valid(rt5677->pow_ldo2)) - gpio_set_value_cansleep(rt5677->pow_ldo2, 0); + if (gpio_is_valid(rt5677->pow_ldo2)) + gpio_set_value_cansleep(rt5677->pow_ldo2, 0); + } return 0; } @@ -4512,12 +4525,12 @@ static int rt5677_resume(struct snd_soc_codec *codec) { struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); - if (gpio_is_valid(rt5677->pow_ldo2)) { - gpio_set_value_cansleep(rt5677->pow_ldo2, 1); - msleep(10); - } - if (!rt5677->dsp_vad_en) { + if (gpio_is_valid(rt5677->pow_ldo2)) { + gpio_set_value_cansleep(rt5677->pow_ldo2, 1); + msleep(10); + } + regcache_cache_only(rt5677->regmap, false); regcache_sync(rt5677->regmap); } @@ -4733,7 +4746,8 @@ static const struct regmap_config rt5677_regmap = { }; static const struct i2c_device_id rt5677_i2c_id[] = { - { "rt5677", 0 }, + { "rt5677", RT5677 }, + { "rt5676", RT5676 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); @@ -4850,6 +4864,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, rt5677); + rt5677->type = id->driver_data; + if (pdata) rt5677->pdata = *pdata; diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index c0a625f290cc..07df96b43f59 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1665,6 +1665,11 @@ enum { RT5677_IRQ_JD3, }; +enum rt5677_type { + RT5677, + RT5676, +}; + struct rt5677_priv { struct snd_soc_codec *codec; struct rt5677_platform_data pdata; @@ -1681,6 +1686,7 @@ struct rt5677_priv { int pll_in; int pll_out; int pow_ldo2; /* POW_LDO2 pin */ + enum rt5677_type type; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; #endif diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index e182e6569bbd..3593a1496056 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1151,13 +1151,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) /* Enable VDDC charge pump */ ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP; } else if (vddio >= 3100 && vdda >= 3100) { - /* - * if vddio and vddd > 3.1v, - * charge pump should be clean before set ana_pwr - */ - snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, - SGTL5000_VDDC_CHRGPMP_POWERUP, 0); - + ana_pwr &= ~SGTL5000_VDDC_CHRGPMP_POWERUP; /* VDDC use VDDIO rail */ lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD; lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO << diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index 47b257e41809..7947c0ebb1ed 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -538,8 +538,8 @@ static const struct snd_soc_dapm_route sn95031_audio_map[] = { /* speaker map */ { "IHFOUTL", NULL, "Speaker Rail"}, { "IHFOUTR", NULL, "Speaker Rail"}, - { "IHFOUTL", "NULL", "Speaker Left Playback"}, - { "IHFOUTR", "NULL", "Speaker Right Playback"}, + { "IHFOUTL", NULL, "Speaker Left Playback"}, + { "IHFOUTR", NULL, "Speaker Right Playback"}, { "Speaker Left Playback", NULL, "Speaker Left Filter"}, { "Speaker Right Playback", NULL, "Speaker Right Filter"}, { "Speaker Left Filter", NULL, "IHFDAC Left"}, @@ -783,19 +783,21 @@ static inline void sn95031_enable_jack_btn(struct snd_soc_codec *codec) snd_soc_write(codec, SN95031_BTNCTRL2, 0x01); } -static int sn95031_get_headset_state(struct snd_soc_jack *mfld_jack) +static int sn95031_get_headset_state(struct snd_soc_codec *codec, + struct snd_soc_jack *mfld_jack) { - int micbias = sn95031_get_mic_bias(mfld_jack->codec); + int micbias = sn95031_get_mic_bias(codec); int jack_type = snd_soc_jack_get_type(mfld_jack, micbias); pr_debug("jack type detected = %d\n", jack_type); if (jack_type == SND_JACK_HEADSET) - sn95031_enable_jack_btn(mfld_jack->codec); + sn95031_enable_jack_btn(codec); return jack_type; } -void sn95031_jack_detection(struct mfld_jack_data *jack_data) +void sn95031_jack_detection(struct snd_soc_codec *codec, + struct mfld_jack_data *jack_data) { unsigned int status; unsigned int mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET; @@ -809,11 +811,11 @@ void sn95031_jack_detection(struct mfld_jack_data *jack_data) status = SND_JACK_HEADSET | SND_JACK_BTN_1; } else if (jack_data->intr_id & 0x4) { pr_debug("headset or headphones inserted\n"); - status = sn95031_get_headset_state(jack_data->mfld_jack); + status = sn95031_get_headset_state(codec, jack_data->mfld_jack); } else if (jack_data->intr_id & 0x8) { pr_debug("headset or headphones removed\n"); status = 0; - sn95031_disable_jack_btn(jack_data->mfld_jack->codec); + sn95031_disable_jack_btn(codec); } else { pr_err("unidentified interrupt\n"); return; diff --git a/sound/soc/codecs/sn95031.h b/sound/soc/codecs/sn95031.h index 20376d234fb8..7651fe4e6a45 100644 --- a/sound/soc/codecs/sn95031.h +++ b/sound/soc/codecs/sn95031.h @@ -127,6 +127,7 @@ struct mfld_jack_data { struct snd_soc_jack *mfld_jack; }; -extern void sn95031_jack_detection(struct mfld_jack_data *jack_data); +extern void sn95031_jack_detection(struct snd_soc_codec *codec, + struct mfld_jack_data *jack_data); #endif diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 3a1343fa109b..007a0e3bc273 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -106,13 +106,11 @@ static const struct reg_default sta32x_regs[] = { }; static const struct regmap_range sta32x_write_regs_range[] = { - regmap_reg_range(STA32X_CONFA, STA32X_AUTO2), - regmap_reg_range(STA32X_C1CFG, STA32X_FDRC2), + regmap_reg_range(STA32X_CONFA, STA32X_FDRC2), }; static const struct regmap_range sta32x_read_regs_range[] = { - regmap_reg_range(STA32X_CONFA, STA32X_AUTO2), - regmap_reg_range(STA32X_C1CFG, STA32X_FDRC2), + regmap_reg_range(STA32X_CONFA, STA32X_FDRC2), }; static const struct regmap_range sta32x_volatile_regs_range[] = { diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index bda2ee18769e..669e3228241e 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -1213,27 +1213,15 @@ static int sta350_i2c_probe(struct i2c_client *i2c, #endif /* GPIOs */ - sta350->gpiod_nreset = devm_gpiod_get(dev, "reset"); - if (IS_ERR(sta350->gpiod_nreset)) { - ret = PTR_ERR(sta350->gpiod_nreset); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - sta350->gpiod_nreset = NULL; - } else { - gpiod_direction_output(sta350->gpiod_nreset, 0); - } - - sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down"); - if (IS_ERR(sta350->gpiod_power_down)) { - ret = PTR_ERR(sta350->gpiod_power_down); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - sta350->gpiod_power_down = NULL; - } else { - gpiod_direction_output(sta350->gpiod_power_down, 0); - } + sta350->gpiod_nreset = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(sta350->gpiod_nreset)) + return PTR_ERR(sta350->gpiod_nreset); + + sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down", + GPIOD_OUT_LOW); + if (IS_ERR(sta350->gpiod_power_down)) + return PTR_ERR(sta350->gpiod_power_down); /* regulators */ for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++) diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index ae23acdd2708..dfb4ff5cc9ea 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -485,16 +485,9 @@ static int tas2552_probe(struct i2c_client *client, if (data == NULL) return -ENOMEM; - data->enable_gpio = devm_gpiod_get(dev, "enable"); - if (IS_ERR(data->enable_gpio)) { - ret = PTR_ERR(data->enable_gpio); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - data->enable_gpio = NULL; - } else { - gpiod_direction_output(data->enable_gpio, 0); - } + data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(data->enable_gpio)) + return PTR_ERR(data->enable_gpio); data->tas2552_client = client; data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config); diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 249ef5c4c762..32942bed34b1 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -281,7 +281,7 @@ static int tas5086_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = priv->deemph; + ucontrol->value.integer.value[0] = priv->deemph; return 0; } @@ -292,7 +292,7 @@ static int tas5086_put_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); - priv->deemph = ucontrol->value.enumerated.item[0]; + priv->deemph = ucontrol->value.integer.value[0]; return tas5086_set_deemph(codec); } diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 8d9de49a5052..21d5402e343f 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -610,7 +610,7 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); - ucontrol->value.enumerated.item[0] = wm2000->anc_active; + ucontrol->value.integer.value[0] = wm2000->anc_active; return 0; } @@ -620,7 +620,7 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); - int anc_active = ucontrol->value.enumerated.item[0]; + int anc_active = ucontrol->value.integer.value[0]; int ret; if (anc_active > 1) @@ -643,7 +643,7 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); - ucontrol->value.enumerated.item[0] = wm2000->spk_ena; + ucontrol->value.integer.value[0] = wm2000->spk_ena; return 0; } @@ -653,7 +653,7 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); - int val = ucontrol->value.enumerated.item[0]; + int val = ucontrol->value.integer.value[0]; int ret; if (val > 1) diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index c81a9eab3e3e..c65e5a75fc1a 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -69,14 +69,14 @@ struct wm8350_data { struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; int fll_freq_out; int fll_freq_in; + struct delayed_work pga_work; }; /* * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown. */ -static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec) +static inline int wm8350_out1_ramp_step(struct wm8350_data *wm8350_data) { - struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out1 = &wm8350_data->out1; struct wm8350 *wm8350 = wm8350_data->wm8350; int left_complete = 0, right_complete = 0; @@ -140,9 +140,8 @@ static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec) /* * Ramp OUT2 PGA volume to minimise pops at stream startup and shutdown. */ -static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec) +static inline int wm8350_out2_ramp_step(struct wm8350_data *wm8350_data) { - struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out2 = &wm8350_data->out2; struct wm8350 *wm8350 = wm8350_data->wm8350; int left_complete = 0, right_complete = 0; @@ -210,10 +209,8 @@ static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec) */ static void wm8350_pga_work(struct work_struct *work) { - struct snd_soc_dapm_context *dapm = - container_of(work, struct snd_soc_dapm_context, delayed_work.work); - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); - struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); + struct wm8350_data *wm8350_data = + container_of(work, struct wm8350_data, pga_work.work); struct wm8350_output *out1 = &wm8350_data->out1, *out2 = &wm8350_data->out2; int i, out1_complete, out2_complete; @@ -226,9 +223,9 @@ static void wm8350_pga_work(struct work_struct *work) for (i = 0; i <= 63; i++) { out1_complete = 1, out2_complete = 1; if (out1->ramp != WM8350_RAMP_NONE) - out1_complete = wm8350_out1_ramp_step(codec); + out1_complete = wm8350_out1_ramp_step(wm8350_data); if (out2->ramp != WM8350_RAMP_NONE) - out2_complete = wm8350_out2_ramp_step(codec); + out2_complete = wm8350_out2_ramp_step(wm8350_data); /* ramp finished ? */ if (out1_complete && out2_complete) @@ -283,7 +280,7 @@ static int pga_event(struct snd_soc_dapm_widget *w, out->ramp = WM8350_RAMP_UP; out->active = 1; - schedule_delayed_work(&codec->dapm.delayed_work, + schedule_delayed_work(&wm8350_data->pga_work, msecs_to_jiffies(1)); break; @@ -291,7 +288,7 @@ static int pga_event(struct snd_soc_dapm_widget *w, out->ramp = WM8350_RAMP_DOWN; out->active = 0; - schedule_delayed_work(&codec->dapm.delayed_work, + schedule_delayed_work(&wm8350_data->pga_work, msecs_to_jiffies(1)); break; } @@ -1492,7 +1489,7 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) /* Put the codec into reset if it wasn't already */ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); - INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8350_pga_work); + INIT_DELAYED_WORK(&priv->pga_work, wm8350_pga_work); INIT_DELAYED_WORK(&priv->hpl.work, wm8350_hpl_work); INIT_DELAYED_WORK(&priv->hpr.work, wm8350_hpr_work); @@ -1578,7 +1575,7 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) /* if there was any work waiting then we run it now and * wait for its completion */ - flush_delayed_work(&codec->dapm.delayed_work); + flush_delayed_work(&priv->pga_work); wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 098c143f44d6..c6d10533e2bd 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -125,7 +125,7 @@ static int wm8731_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = wm8731->deemph; + ucontrol->value.integer.value[0] = wm8731->deemph; return 0; } @@ -135,7 +135,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); - int deemph = ucontrol->value.enumerated.item[0]; + int deemph = ucontrol->value.integer.value[0]; int ret = 0; if (deemph > 1) diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 31bb4801a005..9e71c768966f 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -123,7 +123,7 @@ static struct { }; static const unsigned int rates_11289[] = { - 44100, 88235, + 44100, 88200, }; static const struct snd_pcm_hw_constraint_list constraints_11289 = { @@ -150,7 +150,7 @@ static const struct snd_pcm_hw_constraint_list constraints_16384 = { }; static const unsigned int rates_16934[] = { - 44100, 88235, + 44100, 88200, }; static const struct snd_pcm_hw_constraint_list constraints_16934 = { @@ -168,7 +168,7 @@ static const struct snd_pcm_hw_constraint_list constraints_18432 = { }; static const unsigned int rates_22579[] = { - 44100, 88235, 1764000 + 44100, 88200, 176400 }; static const struct snd_pcm_hw_constraint_list constraints_22579 = { @@ -186,7 +186,7 @@ static const struct snd_pcm_hw_constraint_list constraints_24576 = { }; static const unsigned int rates_36864[] = { - 48000, 96000, 19200 + 48000, 96000, 192000 }; static const struct snd_pcm_hw_constraint_list constraints_36864 = { diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 21ca3a94fc96..c50a5959345f 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -153,6 +153,7 @@ struct wm8753_priv { unsigned int hifi_fmt; int dai_func; + struct delayed_work charge_work; }; #define wm8753_reset(c) snd_soc_write(c, WM8753_RESET, 0) @@ -1326,9 +1327,19 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute) return 0; } +static void wm8753_charge_work(struct work_struct *work) +{ + struct wm8753_priv *wm8753 = + container_of(work, struct wm8753_priv, charge_work.work); + + /* Set to 500k */ + regmap_update_bits(wm8753->regmap, WM8753_PWR1, 0x0180, 0x0100); +} + static int wm8753_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); u16 pwr_reg = snd_soc_read(codec, WM8753_PWR1) & 0xfe3e; switch (level) { @@ -1337,14 +1348,22 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec, snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); break; case SND_SOC_BIAS_PREPARE: - /* set vmid to 5k for quick power up */ - snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); + /* Wait until fully charged */ + flush_delayed_work(&wm8753->charge_work); break; case SND_SOC_BIAS_STANDBY: - /* mute dac and set vmid to 500k, enable VREF */ - snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x0141); + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + /* set vmid to 5k for quick power up */ + snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); + schedule_delayed_work(&wm8753->charge_work, + msecs_to_jiffies(caps_charge)); + } else { + /* mute dac and set vmid to 500k, enable VREF */ + snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x0141); + } break; case SND_SOC_BIAS_OFF: + cancel_delayed_work_sync(&wm8753->charge_work); snd_soc_write(codec, WM8753_PWR1, 0x0001); break; } @@ -1428,38 +1447,12 @@ static struct snd_soc_dai_driver wm8753_dai[] = { }, }; -static void wm8753_work(struct work_struct *work) -{ - struct snd_soc_dapm_context *dapm = - container_of(work, struct snd_soc_dapm_context, - delayed_work.work); - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); - wm8753_set_bias_level(codec, dapm->bias_level); -} - -static int wm8753_suspend(struct snd_soc_codec *codec) -{ - wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static int wm8753_resume(struct snd_soc_codec *codec) { struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); regcache_sync(wm8753->regmap); - wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - /* charge wm8753 caps */ - if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) { - wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - codec->dapm.bias_level = SND_SOC_BIAS_ON; - queue_delayed_work(system_power_efficient_wq, - &codec->dapm.delayed_work, - msecs_to_jiffies(caps_charge)); - } - return 0; } @@ -1468,7 +1461,7 @@ static int wm8753_probe(struct snd_soc_codec *codec) struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); int ret; - INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8753_work); + INIT_DELAYED_WORK(&wm8753->charge_work, wm8753_charge_work); ret = wm8753_reset(codec); if (ret < 0) { @@ -1476,14 +1469,8 @@ static int wm8753_probe(struct snd_soc_codec *codec) return ret; } - wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8753->dai_func = 0; - /* charge output caps */ - wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - schedule_delayed_work(&codec->dapm.delayed_work, - msecs_to_jiffies(caps_charge)); - /* set the update bits */ snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100); @@ -1499,21 +1486,11 @@ static int wm8753_probe(struct snd_soc_codec *codec) return 0; } -/* power down chip */ -static int wm8753_remove(struct snd_soc_codec *codec) -{ - flush_delayed_work(&codec->dapm.delayed_work); - wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8753 = { .probe = wm8753_probe, - .remove = wm8753_remove, - .suspend = wm8753_suspend, .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), diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c new file mode 100644 index 000000000000..5bd4af2b4059 --- /dev/null +++ b/sound/soc/codecs/wm8804-i2c.c @@ -0,0 +1,64 @@ +/* + * wm8804-i2c.c -- WM8804 S/PDIF transceiver driver - I2C + * + * Copyright 2015 Cirrus Logic Inc + * + * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.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/init.h> +#include <linux/module.h> +#include <linux/i2c.h> + +#include "wm8804.h" + +static int wm8804_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return wm8804_probe(&i2c->dev, regmap); +} + +static int wm8804_i2c_remove(struct i2c_client *i2c) +{ + wm8804_remove(&i2c->dev); + return 0; +} + +static const struct i2c_device_id wm8804_i2c_id[] = { + { "wm8804", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id); + +static const struct of_device_id wm8804_of_match[] = { + { .compatible = "wlf,wm8804", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8804_of_match); + +static struct i2c_driver wm8804_i2c_driver = { + .driver = { + .name = "wm8804", + .owner = THIS_MODULE, + .of_match_table = wm8804_of_match, + }, + .probe = wm8804_i2c_probe, + .remove = wm8804_i2c_remove, + .id_table = wm8804_i2c_id +}; + +module_i2c_driver(wm8804_i2c_driver); + +MODULE_DESCRIPTION("ASoC WM8804 driver - I2C"); +MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8804-spi.c b/sound/soc/codecs/wm8804-spi.c new file mode 100644 index 000000000000..287e11e90794 --- /dev/null +++ b/sound/soc/codecs/wm8804-spi.c @@ -0,0 +1,56 @@ +/* + * wm8804-spi.c -- WM8804 S/PDIF transceiver driver - SPI + * + * Copyright 2015 Cirrus Logic Inc + * + * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.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/init.h> +#include <linux/module.h> +#include <linux/spi/spi.h> + +#include "wm8804.h" + +static int wm8804_spi_probe(struct spi_device *spi) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return wm8804_probe(&spi->dev, regmap); +} + +static int wm8804_spi_remove(struct spi_device *spi) +{ + wm8804_remove(&spi->dev); + return 0; +} + +static const struct of_device_id wm8804_of_match[] = { + { .compatible = "wlf,wm8804", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8804_of_match); + +static struct spi_driver wm8804_spi_driver = { + .driver = { + .name = "wm8804", + .owner = THIS_MODULE, + .of_match_table = wm8804_of_match, + }, + .probe = wm8804_spi_probe, + .remove = wm8804_spi_remove +}; + +module_spi_driver(wm8804_spi_driver); + +MODULE_DESCRIPTION("ASoC WM8804 driver - SPI"); +MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index b2b0e68f707e..1bd4ace29594 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -15,10 +15,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> -#include <linux/i2c.h> #include <linux/of_device.h> -#include <linux/spi/spi.h> -#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <sound/core.h> @@ -185,9 +182,9 @@ static bool wm8804_volatile(struct device *dev, unsigned int reg) } } -static int wm8804_reset(struct snd_soc_codec *codec) +static int wm8804_reset(struct wm8804_priv *wm8804) { - return snd_soc_write(codec, WM8804_RST_DEVID1, 0x0); + return regmap_write(wm8804->regmap, WM8804_RST_DEVID1, 0x0); } static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) @@ -518,100 +515,6 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int wm8804_remove(struct snd_soc_codec *codec) -{ - struct wm8804_priv *wm8804; - int i; - - wm8804 = snd_soc_codec_get_drvdata(codec); - - for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) - regulator_unregister_notifier(wm8804->supplies[i].consumer, - &wm8804->disable_nb[i]); - return 0; -} - -static int wm8804_probe(struct snd_soc_codec *codec) -{ - struct wm8804_priv *wm8804; - int i, id1, id2, ret; - - wm8804 = snd_soc_codec_get_drvdata(codec); - - for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) - wm8804->supplies[i].supply = wm8804_supply_names[i]; - - ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies), - wm8804->supplies); - if (ret) { - dev_err(codec->dev, "Failed to request supplies: %d\n", ret); - return ret; - } - - wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0; - wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1; - - /* This should really be moved into the regulator core */ - for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) { - ret = regulator_register_notifier(wm8804->supplies[i].consumer, - &wm8804->disable_nb[i]); - if (ret != 0) { - dev_err(codec->dev, - "Failed to register regulator notifier: %d\n", - ret); - } - } - - ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies), - wm8804->supplies); - if (ret) { - dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); - return ret; - } - - id1 = snd_soc_read(codec, WM8804_RST_DEVID1); - if (id1 < 0) { - dev_err(codec->dev, "Failed to read device ID: %d\n", id1); - ret = id1; - goto err_reg_enable; - } - - id2 = snd_soc_read(codec, WM8804_DEVID2); - if (id2 < 0) { - dev_err(codec->dev, "Failed to read device ID: %d\n", id2); - ret = id2; - goto err_reg_enable; - } - - id2 = (id2 << 8) | id1; - - if (id2 != 0x8805) { - dev_err(codec->dev, "Invalid device ID: %#x\n", id2); - ret = -EINVAL; - goto err_reg_enable; - } - - ret = snd_soc_read(codec, WM8804_DEVREV); - if (ret < 0) { - dev_err(codec->dev, "Failed to read device revision: %d\n", - ret); - goto err_reg_enable; - } - dev_info(codec->dev, "revision %c\n", ret + 'A'); - - ret = wm8804_reset(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset: %d\n", ret); - goto err_reg_enable; - } - - return 0; - -err_reg_enable: - regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies); - return ret; -} - static const struct snd_soc_dai_ops wm8804_dai_ops = { .hw_params = wm8804_hw_params, .set_fmt = wm8804_set_fmt, @@ -649,8 +552,6 @@ static struct snd_soc_dai_driver wm8804_dai = { }; static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = { - .probe = wm8804_probe, - .remove = wm8804_remove, .set_bias_level = wm8804_set_bias_level, .idle_bias_off = true, @@ -658,13 +559,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = { .num_controls = ARRAY_SIZE(wm8804_snd_controls), }; -static const struct of_device_id wm8804_of_match[] = { - { .compatible = "wlf,wm8804", }, - { } -}; -MODULE_DEVICE_TABLE(of, wm8804_of_match); - -static const struct regmap_config wm8804_regmap_config = { +const struct regmap_config wm8804_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -675,128 +570,110 @@ static const struct regmap_config wm8804_regmap_config = { .reg_defaults = wm8804_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults), }; +EXPORT_SYMBOL_GPL(wm8804_regmap_config); -#if defined(CONFIG_SPI_MASTER) -static int wm8804_spi_probe(struct spi_device *spi) +int wm8804_probe(struct device *dev, struct regmap *regmap) { struct wm8804_priv *wm8804; - int ret; + unsigned int id1, id2; + int i, ret; - wm8804 = devm_kzalloc(&spi->dev, sizeof *wm8804, GFP_KERNEL); + wm8804 = devm_kzalloc(dev, sizeof(*wm8804), GFP_KERNEL); if (!wm8804) return -ENOMEM; - wm8804->regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config); - if (IS_ERR(wm8804->regmap)) { - ret = PTR_ERR(wm8804->regmap); + dev_set_drvdata(dev, wm8804); + + wm8804->regmap = regmap; + + for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) + wm8804->supplies[i].supply = wm8804_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8804->supplies), + wm8804->supplies); + if (ret) { + dev_err(dev, "Failed to request supplies: %d\n", ret); return ret; } - spi_set_drvdata(spi, wm8804); + wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0; + wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1; - ret = snd_soc_register_codec(&spi->dev, - &soc_codec_dev_wm8804, &wm8804_dai, 1); + /* This should really be moved into the regulator core */ + for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) { + ret = regulator_register_notifier(wm8804->supplies[i].consumer, + &wm8804->disable_nb[i]); + if (ret != 0) { + dev_err(dev, + "Failed to register regulator notifier: %d\n", + ret); + } + } - return ret; -} + ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies), + wm8804->supplies); + if (ret) { + dev_err(dev, "Failed to enable supplies: %d\n", ret); + goto err_reg_enable; + } -static int wm8804_spi_remove(struct spi_device *spi) -{ - snd_soc_unregister_codec(&spi->dev); - return 0; -} + ret = regmap_read(regmap, WM8804_RST_DEVID1, &id1); + if (ret < 0) { + dev_err(dev, "Failed to read device ID: %d\n", ret); + goto err_reg_enable; + } -static struct spi_driver wm8804_spi_driver = { - .driver = { - .name = "wm8804", - .owner = THIS_MODULE, - .of_match_table = wm8804_of_match, - }, - .probe = wm8804_spi_probe, - .remove = wm8804_spi_remove -}; -#endif + ret = regmap_read(regmap, WM8804_DEVID2, &id2); + if (ret < 0) { + dev_err(dev, "Failed to read device ID: %d\n", ret); + goto err_reg_enable; + } -#if IS_ENABLED(CONFIG_I2C) -static int wm8804_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct wm8804_priv *wm8804; - int ret; + id2 = (id2 << 8) | id1; - wm8804 = devm_kzalloc(&i2c->dev, sizeof *wm8804, GFP_KERNEL); - if (!wm8804) - return -ENOMEM; + if (id2 != 0x8805) { + dev_err(dev, "Invalid device ID: %#x\n", id2); + ret = -EINVAL; + goto err_reg_enable; + } - wm8804->regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config); - if (IS_ERR(wm8804->regmap)) { - ret = PTR_ERR(wm8804->regmap); - return ret; + ret = regmap_read(regmap, WM8804_DEVREV, &id1); + if (ret < 0) { + dev_err(dev, "Failed to read device revision: %d\n", + ret); + goto err_reg_enable; } + dev_info(dev, "revision %c\n", id1 + 'A'); - i2c_set_clientdata(i2c, wm8804); + ret = wm8804_reset(wm8804); + if (ret < 0) { + dev_err(dev, "Failed to issue reset: %d\n", ret); + goto err_reg_enable; + } - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_wm8804, &wm8804_dai, 1); + return snd_soc_register_codec(dev, &soc_codec_dev_wm8804, + &wm8804_dai, 1); + +err_reg_enable: + regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies); return ret; } +EXPORT_SYMBOL_GPL(wm8804_probe); -static int wm8804_i2c_remove(struct i2c_client *i2c) +void wm8804_remove(struct device *dev) { - snd_soc_unregister_codec(&i2c->dev); - return 0; -} - -static const struct i2c_device_id wm8804_i2c_id[] = { - { "wm8804", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id); - -static struct i2c_driver wm8804_i2c_driver = { - .driver = { - .name = "wm8804", - .owner = THIS_MODULE, - .of_match_table = wm8804_of_match, - }, - .probe = wm8804_i2c_probe, - .remove = wm8804_i2c_remove, - .id_table = wm8804_i2c_id -}; -#endif + struct wm8804_priv *wm8804; + int i; -static int __init wm8804_modinit(void) -{ - int ret = 0; + wm8804 = dev_get_drvdata(dev); -#if IS_ENABLED(CONFIG_I2C) - ret = i2c_add_driver(&wm8804_i2c_driver); - if (ret) { - printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n", - ret); - } -#endif -#if defined(CONFIG_SPI_MASTER) - ret = spi_register_driver(&wm8804_spi_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8804 SPI driver: %d\n", - ret); - } -#endif - return ret; -} -module_init(wm8804_modinit); + for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) + regulator_unregister_notifier(wm8804->supplies[i].consumer, + &wm8804->disable_nb[i]); -static void __exit wm8804_exit(void) -{ -#if IS_ENABLED(CONFIG_I2C) - i2c_del_driver(&wm8804_i2c_driver); -#endif -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&wm8804_spi_driver); -#endif + snd_soc_unregister_codec(dev); } -module_exit(wm8804_exit); +EXPORT_SYMBOL_GPL(wm8804_remove); MODULE_DESCRIPTION("ASoC WM8804 driver"); MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm8804.h b/sound/soc/codecs/wm8804.h index e72d4f4ba6b1..a39a2563dc67 100644 --- a/sound/soc/codecs/wm8804.h +++ b/sound/soc/codecs/wm8804.h @@ -13,6 +13,8 @@ #ifndef _WM8804_H #define _WM8804_H +#include <linux/regmap.h> + /* * Register values. */ @@ -62,4 +64,9 @@ #define WM8804_MCLKDIV_256FS 0 #define WM8804_MCLKDIV_128FS 1 +extern const struct regmap_config wm8804_regmap_config; + +int wm8804_probe(struct device *dev, struct regmap *regmap); +void wm8804_remove(struct device *dev); + #endif /* _WM8804_H */ diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index dde462c082be..04b04f8e147c 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -442,7 +442,7 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = wm8903->deemph; + ucontrol->value.integer.value[0] = wm8903->deemph; return 0; } @@ -452,7 +452,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); - int deemph = ucontrol->value.enumerated.item[0]; + int deemph = ucontrol->value.integer.value[0]; int ret = 0; if (deemph > 1) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index d3b3f57668cc..215e93c1ddf0 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -525,7 +525,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = wm8904->deemph; + ucontrol->value.integer.value[0] = wm8904->deemph; return 0; } @@ -534,7 +534,7 @@ static int wm8904_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); - int deemph = ucontrol->value.enumerated.item[0]; + int deemph = ucontrol->value.integer.value[0]; if (deemph > 1) return -EINVAL; diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 1ab2d462afad..00bec915d652 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -393,7 +393,7 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = wm8955->deemph; + ucontrol->value.integer.value[0] = wm8955->deemph; return 0; } @@ -402,7 +402,7 @@ static int wm8955_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); - int deemph = ucontrol->value.enumerated.item[0]; + int deemph = ucontrol->value.integer.value[0]; if (deemph > 1) return -EINVAL; diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index cf8fecf97f2c..3035d9856415 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -184,7 +184,7 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.enumerated.item[0] = wm8960->deemph; + ucontrol->value.integer.value[0] = wm8960->deemph; return 0; } @@ -193,7 +193,7 @@ static int wm8960_put_deemph(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - int deemph = ucontrol->value.enumerated.item[0]; + int deemph = ucontrol->value.integer.value[0]; if (deemph > 1) return -EINVAL; diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 39ddb9b8834c..f9cbabdc6238 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -31,11 +31,11 @@ #define WM8971_REG_COUNT 43 -static struct workqueue_struct *wm8971_workq = NULL; - /* codec private data */ struct wm8971_priv { unsigned int sysclk; + struct delayed_work charge_work; + struct regmap *regmap; }; /* @@ -552,9 +552,19 @@ static int wm8971_mute(struct snd_soc_dai *dai, int mute) return 0; } +static void wm8971_charge_work(struct work_struct *work) +{ + struct wm8971_priv *wm8971 = + container_of(work, struct wm8971_priv, charge_work.work); + + /* Set to 500k */ + regmap_update_bits(wm8971->regmap, WM8971_PWR1, 0x0180, 0x0100); +} + static int wm8971_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); u16 pwr_reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; switch (level) { @@ -563,15 +573,24 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec, snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x00c1); break; case SND_SOC_BIAS_PREPARE: + /* Wait until fully charged */ + flush_delayed_work(&wm8971->charge_work); break; case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { snd_soc_cache_sync(codec); + /* charge output caps - set vmid to 5k for quick power up */ + snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x01c0); + queue_delayed_work(system_power_efficient_wq, + &wm8971->charge_work, msecs_to_jiffies(1000)); + } else { + /* mute dac and set vmid to 500k, enable VREF */ + snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140); + } - /* mute dac and set vmid to 500k, enable VREF */ - snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140); break; case SND_SOC_BIAS_OFF: + cancel_delayed_work_sync(&wm8971->charge_work); snd_soc_write(codec, WM8971_PWR1, 0x0001); break; } @@ -610,58 +629,14 @@ static struct snd_soc_dai_driver wm8971_dai = { .ops = &wm8971_dai_ops, }; -static void wm8971_work(struct work_struct *work) -{ - struct snd_soc_dapm_context *dapm = - container_of(work, struct snd_soc_dapm_context, - delayed_work.work); - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); - wm8971_set_bias_level(codec, codec->dapm.bias_level); -} - -static int wm8971_suspend(struct snd_soc_codec *codec) -{ - wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8971_resume(struct snd_soc_codec *codec) -{ - u16 reg; - - wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - /* charge wm8971 caps */ - if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) { - reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; - snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); - codec->dapm.bias_level = SND_SOC_BIAS_ON; - queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work, - msecs_to_jiffies(1000)); - } - - return 0; -} - static int wm8971_probe(struct snd_soc_codec *codec) { - int ret = 0; - u16 reg; + struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); - INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8971_work); - wm8971_workq = create_workqueue("wm8971"); - if (wm8971_workq == NULL) - return -ENOMEM; + INIT_DELAYED_WORK(&wm8971->charge_work, wm8971_charge_work); wm8971_reset(codec); - /* charge output caps - set vmid to 5k for quick power up */ - reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; - snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); - codec->dapm.bias_level = SND_SOC_BIAS_STANDBY; - queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work, - msecs_to_jiffies(1000)); - /* set the update bits */ snd_soc_update_bits(codec, WM8971_LDAC, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8971_RDAC, 0x0100, 0x0100); @@ -672,26 +647,13 @@ static int wm8971_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8971_LINVOL, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8971_RINVOL, 0x0100, 0x0100); - return ret; -} - - -/* power down chip */ -static int wm8971_remove(struct snd_soc_codec *codec) -{ - wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); - - if (wm8971_workq) - destroy_workqueue(wm8971_workq); return 0; } static struct snd_soc_codec_driver soc_codec_dev_wm8971 = { .probe = wm8971_probe, - .remove = wm8971_remove, - .suspend = wm8971_suspend, - .resume = wm8971_resume, .set_bias_level = wm8971_set_bias_level, + .suspend_bias_off = true, .controls = wm8971_snd_controls, .num_controls = ARRAY_SIZE(wm8971_snd_controls), @@ -715,7 +677,6 @@ static int wm8971_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8971_priv *wm8971; - struct regmap *regmap; int ret; wm8971 = devm_kzalloc(&i2c->dev, sizeof(struct wm8971_priv), @@ -723,9 +684,9 @@ static int wm8971_i2c_probe(struct i2c_client *i2c, if (wm8971 == NULL) return -ENOMEM; - regmap = devm_regmap_init_i2c(i2c, &wm8971_regmap); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + wm8971->regmap = devm_regmap_init_i2c(i2c, &wm8971_regmap); + if (IS_ERR(wm8971->regmap)) + return PTR_ERR(wm8971->regmap); i2c_set_clientdata(i2c, wm8971); diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 9517571e820d..98c9525bd751 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -180,7 +180,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); - unsigned int val = ucontrol->value.enumerated.item[0]; + unsigned int val = ucontrol->value.integer.value[0]; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int mixer, mask, shift, old; @@ -193,7 +193,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol, mutex_lock(&wm9712->lock); old = wm9712->hp_mixer[mixer]; - if (ucontrol->value.enumerated.item[0]) + if (ucontrol->value.integer.value[0]) wm9712->hp_mixer[mixer] |= mask; else wm9712->hp_mixer[mixer] &= ~mask; @@ -231,7 +231,7 @@ static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol, mixer = mc->shift >> 8; shift = mc->shift & 0xff; - ucontrol->value.enumerated.item[0] = + ucontrol->value.integer.value[0] = (wm9712->hp_mixer[mixer] >> shift) & 1; return 0; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 68222917b396..79552953e1bd 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -255,7 +255,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); - unsigned int val = ucontrol->value.enumerated.item[0]; + unsigned int val = ucontrol->value.integer.value[0]; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int mixer, mask, shift, old; @@ -268,7 +268,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, mutex_lock(&wm9713->lock); old = wm9713->hp_mixer[mixer]; - if (ucontrol->value.enumerated.item[0]) + if (ucontrol->value.integer.value[0]) wm9713->hp_mixer[mixer] |= mask; else wm9713->hp_mixer[mixer] &= ~mask; @@ -306,7 +306,7 @@ static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol, mixer = mc->shift >> 8; shift = mc->shift & 0xff; - ucontrol->value.enumerated.item[0] = + ucontrol->value.integer.value[0] = (wm9713->hp_mixer[mixer] >> shift) & 1; return 0; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index ff67b334065b..d01c2095452f 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -420,10 +420,9 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol, memcpy(ctl->cache, p, ctl->len); - if (!ctl->enabled) { - ctl->set = 1; + ctl->set = 1; + if (!ctl->enabled) return 0; - } return wm_coeff_write_control(kcontrol, p, ctl->len); } @@ -1185,7 +1184,6 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) int ret, pos, blocks, type, offset, reg; char *file; struct wm_adsp_buf *buf; - int tmp; file = kzalloc(PAGE_SIZE, GFP_KERNEL); if (file == NULL) @@ -1335,12 +1333,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) } } - tmp = le32_to_cpu(blk->len) % 4; - if (tmp) - pos += le32_to_cpu(blk->len) + (4 - tmp) + sizeof(*blk); - else - pos += le32_to_cpu(blk->len) + sizeof(*blk); - + pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03; blocks++; } diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 2b81ca418d2a..3736d9aabc56 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -1,14 +1,16 @@ config SND_DAVINCI_SOC - tristate "SoC Audio for TI DAVINCI" + tristate depends on ARCH_DAVINCI + select SND_EDMA_SOC config SND_EDMA_SOC - tristate "SoC Audio for Texas Instruments chips using eDMA (AM33XX/43XX)" - depends on SOC_AM33XX || SOC_AM43XX + tristate "SoC Audio for Texas Instruments chips using eDMA" + depends on SOC_AM33XX || SOC_AM43XX || ARCH_DAVINCI select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M here if you want audio support for TI SoC which uses eDMA. The following line of SoCs are supported by this platform driver: + - daVinci devices - AM335x - AM437x/AM438x @@ -17,7 +19,7 @@ config SND_DAVINCI_SOC_I2S config SND_DAVINCI_SOC_MCASP tristate "Multichannel Audio Serial Port (McASP) support" - depends on SND_DAVINCI_SOC || SND_OMAP_SOC || SND_EDMA_SOC + depends on SND_OMAP_SOC || SND_EDMA_SOC help Say Y or M here if you want to have support for McASP IP found in various Texas Instruments SoCs like: @@ -45,7 +47,7 @@ config SND_AM33XX_SOC_EVM config SND_DAVINCI_SOC_EVM tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM" - depends on SND_DAVINCI_SOC && I2C + depends on SND_EDMA_SOC && I2C depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM select SND_DAVINCI_SOC_GENERIC_EVM help @@ -73,7 +75,7 @@ endchoice config SND_DM6467_SOC_EVM tristate "SoC Audio support for DaVinci DM6467 EVM" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM && I2C + depends on SND_EDMA_SOC && MACH_DAVINCI_DM6467_EVM && I2C select SND_DAVINCI_SOC_GENERIC_EVM select SND_SOC_SPDIF @@ -82,7 +84,7 @@ config SND_DM6467_SOC_EVM config SND_DA830_SOC_EVM tristate "SoC Audio support for DA830/OMAP-L137 EVM" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM && I2C + depends on SND_EDMA_SOC && MACH_DAVINCI_DA830_EVM && I2C select SND_DAVINCI_SOC_GENERIC_EVM help @@ -91,7 +93,7 @@ config SND_DA830_SOC_EVM config SND_DA850_SOC_EVM tristate "SoC Audio support for DA850/OMAP-L138 EVM" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM && I2C + depends on SND_EDMA_SOC && MACH_DAVINCI_DA850_EVM && I2C select SND_DAVINCI_SOC_GENERIC_EVM help Say Y if you want to add support for SoC audio on TI diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile index 09bf2ba92d38..f883933c1a19 100644 --- a/sound/soc/davinci/Makefile +++ b/sound/soc/davinci/Makefile @@ -1,11 +1,9 @@ # DAVINCI Platform Support -snd-soc-davinci-objs := davinci-pcm.o snd-soc-edma-objs := edma-pcm.o snd-soc-davinci-i2s-objs := davinci-i2s.o snd-soc-davinci-mcasp-objs:= davinci-mcasp.o snd-soc-davinci-vcif-objs:= davinci-vcif.o -obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o obj-$(CONFIG_SND_EDMA_SOC) += snd-soc-edma.o obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index b6bb5947a8a8..8c2b9be80a9a 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -425,18 +425,8 @@ static int davinci_evm_probe(struct platform_device *pdev) return ret; } -static int davinci_evm_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - snd_soc_unregister_card(card); - - return 0; -} - static struct platform_driver davinci_evm_driver = { .probe = davinci_evm_probe, - .remove = davinci_evm_remove, .driver = { .name = "davinci_evm", .pm = &snd_soc_pm_ops, diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 15fb28fc8e1b..56cb4d95637d 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -23,8 +23,9 @@ #include <sound/pcm_params.h> #include <sound/initval.h> #include <sound/soc.h> +#include <sound/dmaengine_pcm.h> -#include "davinci-pcm.h" +#include "edma-pcm.h" #include "davinci-i2s.h" @@ -122,7 +123,8 @@ static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = { struct davinci_mcbsp_dev { struct device *dev; - struct davinci_pcm_dma_params dma_params[2]; + struct snd_dmaengine_dai_dma_data dma_data[2]; + int dma_request[2]; void __iomem *base; #define MOD_DSP_A 0 #define MOD_DSP_B 1 @@ -419,8 +421,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); - struct davinci_pcm_dma_params *dma_params = - &dev->dma_params[substream->stream]; struct snd_interval *i = NULL; int mcbsp_word_length, master; unsigned int rcr, xcr, srgr, clk_div, freq, framesize; @@ -532,8 +532,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } } - dma_params->acnt = dma_params->data_type = data_type[fmt]; - dma_params->fifo_level = 0; mcbsp_word_length = asp_word_length[fmt]; switch (master) { @@ -600,15 +598,6 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } -static int davinci_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); - - snd_soc_dai_set_dma_data(dai, substream, dev->dma_params); - return 0; -} - static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -620,7 +609,6 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { - .startup = davinci_i2s_startup, .shutdown = davinci_i2s_shutdown, .prepare = davinci_i2s_prepare, .trigger = davinci_i2s_trigger, @@ -630,7 +618,18 @@ static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { }; +static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); + + dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; + dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]; + + return 0; +} + static struct snd_soc_dai_driver davinci_i2s_dai = { + .probe = davinci_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, @@ -651,11 +650,9 @@ static const struct snd_soc_component_driver davinci_i2s_component = { static int davinci_i2s_probe(struct platform_device *pdev) { - struct snd_platform_data *pdata = pdev->dev.platform_data; struct davinci_mcbsp_dev *dev; struct resource *mem, *ioarea, *res; - enum dma_event_q asp_chan_q = EVENTQ_0; - enum dma_event_q ram_chan_q = EVENTQ_1; + int *dma; int ret; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -676,22 +673,6 @@ static int davinci_i2s_probe(struct platform_device *pdev) GFP_KERNEL); if (!dev) return -ENOMEM; - if (pdata) { - dev->enable_channel_combine = pdata->enable_channel_combine; - dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].sram_size = - pdata->sram_size_playback; - dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size = - pdata->sram_size_capture; - dev->clk_input_pin = pdata->clk_input_pin; - dev->i2s_accurate_sck = pdata->i2s_accurate_sck; - asp_chan_q = pdata->asp_chan_q; - ram_chan_q = pdata->ram_chan_q; - } - - dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].asp_chan_q = asp_chan_q; - dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].ram_chan_q = ram_chan_q; - dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].asp_chan_q = asp_chan_q; - dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].ram_chan_q = ram_chan_q; dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) @@ -705,10 +686,10 @@ static int davinci_i2s_probe(struct platform_device *pdev) goto err_release_clk; } - dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr = + dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG); - dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr = + dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG); /* first TX, then RX */ @@ -718,7 +699,9 @@ static int davinci_i2s_probe(struct platform_device *pdev) ret = -ENXIO; goto err_release_clk; } - dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel = res->start; + dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK]; + *dma = res->start; + dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = dma; res = platform_get_resource(pdev, IORESOURCE_DMA, 1); if (!res) { @@ -726,9 +709,11 @@ static int davinci_i2s_probe(struct platform_device *pdev) ret = -ENXIO; goto err_release_clk; } - dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start; - dev->dev = &pdev->dev; + dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE]; + *dma = res->start; + dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = dma; + dev->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, dev); ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component, @@ -736,7 +721,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) if (ret != 0) goto err_release_clk; - ret = davinci_soc_platform_register(&pdev->dev); + ret = edma_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); goto err_unregister_component; diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index de3b155a5011..0c882995a357 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -26,6 +26,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/of_device.h> +#include <linux/platform_data/davinci_asp.h> #include <sound/asoundef.h> #include <sound/core.h> @@ -36,7 +37,6 @@ #include <sound/dmaengine_pcm.h> #include <sound/omap-pcm.h> -#include "davinci-pcm.h" #include "edma-pcm.h" #include "davinci-mcasp.h" @@ -65,7 +65,6 @@ struct davinci_mcasp_context { }; struct davinci_mcasp { - struct davinci_pcm_dma_params dma_params[2]; struct snd_dmaengine_dai_dma_data dma_data[2]; void __iomem *base; u32 fifo_base; @@ -82,6 +81,7 @@ struct davinci_mcasp { u16 bclk_lrclk_ratio; int streams; u32 irq_request[2]; + int dma_request[2]; int sysclk_freq; bool bclk_master; @@ -441,6 +441,18 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); mcasp->bclk_master = 1; break; + case SND_SOC_DAIFMT_CBS_CFM: + /* codec is clock slave and frame master */ + mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); + + mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); + + mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); + mcasp->bclk_master = 1; + break; case SND_SOC_DAIFMT_CBM_CFS: /* codec is clock master and frame slave */ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); @@ -631,7 +643,6 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, int period_words, int channels) { - struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[stream]; struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream]; int i; u8 tx_ser = 0; @@ -699,10 +710,8 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, * For example if three serializers are enabled the DMA * need to transfer three words per DMA request. */ - dma_params->fifo_level = active_serializers; dma_data->maxburst = active_serializers; } else { - dma_params->fifo_level = 0; dma_data->maxburst = 0; } return 0; @@ -734,7 +743,6 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, /* Configure the burst size for platform drivers */ if (numevt == 1) numevt = 0; - dma_params->fifo_level = numevt; dma_data->maxburst = numevt; return 0; @@ -860,8 +868,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); - struct davinci_pcm_dma_params *dma_params = - &mcasp->dma_params[substream->stream]; int word_length; int channels = params_channels(params); int period_size = params_period_size(params); @@ -902,31 +908,26 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_U8: case SNDRV_PCM_FORMAT_S8: - dma_params->data_type = 1; word_length = 8; break; case SNDRV_PCM_FORMAT_U16_LE: case SNDRV_PCM_FORMAT_S16_LE: - dma_params->data_type = 2; word_length = 16; break; case SNDRV_PCM_FORMAT_U24_3LE: case SNDRV_PCM_FORMAT_S24_3LE: - dma_params->data_type = 3; word_length = 24; break; case SNDRV_PCM_FORMAT_U24_LE: case SNDRV_PCM_FORMAT_S24_LE: - dma_params->data_type = 4; word_length = 24; break; case SNDRV_PCM_FORMAT_U32_LE: case SNDRV_PCM_FORMAT_S32_LE: - dma_params->data_type = 4; word_length = 32; break; @@ -935,11 +936,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - if (mcasp->version == MCASP_VERSION_2 && !dma_params->fifo_level) - dma_params->acnt = 4; - else - dma_params->acnt = dma_params->data_type; - davinci_config_channel_size(mcasp, word_length); if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) @@ -1043,17 +1039,8 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); - if (mcasp->version >= MCASP_VERSION_3) { - /* Using dmaengine PCM */ - dai->playback_dma_data = - &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; - dai->capture_dma_data = - &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; - } else { - /* Using davinci-pcm */ - dai->playback_dma_data = mcasp->dma_params; - dai->capture_dma_data = mcasp->dma_params; - } + dai->playback_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; + dai->capture_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; return 0; } @@ -1172,28 +1159,24 @@ static const struct snd_soc_component_driver davinci_mcasp_component = { static struct davinci_mcasp_pdata dm646x_mcasp_pdata = { .tx_dma_offset = 0x400, .rx_dma_offset = 0x400, - .asp_chan_q = EVENTQ_0, .version = MCASP_VERSION_1, }; static struct davinci_mcasp_pdata da830_mcasp_pdata = { .tx_dma_offset = 0x2000, .rx_dma_offset = 0x2000, - .asp_chan_q = EVENTQ_0, .version = MCASP_VERSION_2, }; static struct davinci_mcasp_pdata am33xx_mcasp_pdata = { .tx_dma_offset = 0, .rx_dma_offset = 0, - .asp_chan_q = EVENTQ_0, .version = MCASP_VERSION_3, }; static struct davinci_mcasp_pdata dra7_mcasp_pdata = { .tx_dma_offset = 0x200, .rx_dma_offset = 0x284, - .asp_chan_q = EVENTQ_0, .version = MCASP_VERSION_4, }; @@ -1370,12 +1353,12 @@ nodata: static int davinci_mcasp_probe(struct platform_device *pdev) { - struct davinci_pcm_dma_params *dma_params; struct snd_dmaengine_dai_dma_data *dma_data; struct resource *mem, *ioarea, *res, *dat; struct davinci_mcasp_pdata *pdata; struct davinci_mcasp *mcasp; char *irq_name; + int *dma; int irq; int ret; @@ -1509,59 +1492,45 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (dat) mcasp->dat_port = true; - dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; - dma_params->asp_chan_q = pdata->asp_chan_q; - dma_params->ram_chan_q = pdata->ram_chan_q; - dma_params->sram_pool = pdata->sram_pool; - dma_params->sram_size = pdata->sram_size_playback; if (dat) - dma_params->dma_addr = dat->start; + dma_data->addr = dat->start; else - dma_params->dma_addr = mem->start + pdata->tx_dma_offset; - - /* Unconditional dmaengine stuff */ - dma_data->addr = dma_params->dma_addr; + dma_data->addr = mem->start + pdata->tx_dma_offset; + dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK]; res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (res) - dma_params->channel = res->start; + *dma = res->start; else - dma_params->channel = pdata->tx_dma_channel; + *dma = pdata->tx_dma_channel; /* dmaengine filter data for DT and non-DT boot */ if (pdev->dev.of_node) dma_data->filter_data = "tx"; else - dma_data->filter_data = &dma_params->channel; + dma_data->filter_data = dma; /* RX is not valid in DIT mode */ if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) { - dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE]; dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; - dma_params->asp_chan_q = pdata->asp_chan_q; - dma_params->ram_chan_q = pdata->ram_chan_q; - dma_params->sram_pool = pdata->sram_pool; - dma_params->sram_size = pdata->sram_size_capture; if (dat) - dma_params->dma_addr = dat->start; + dma_data->addr = dat->start; else - dma_params->dma_addr = mem->start + pdata->rx_dma_offset; - - /* Unconditional dmaengine stuff */ - dma_data->addr = dma_params->dma_addr; + dma_data->addr = mem->start + pdata->rx_dma_offset; + dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE]; res = platform_get_resource(pdev, IORESOURCE_DMA, 1); if (res) - dma_params->channel = res->start; + *dma = res->start; else - dma_params->channel = pdata->rx_dma_channel; + *dma = pdata->rx_dma_channel; /* dmaengine filter data for DT and non-DT boot */ if (pdev->dev.of_node) dma_data->filter_data = "rx"; else - dma_data->filter_data = &dma_params->channel; + dma_data->filter_data = dma; } if (mcasp->version < MCASP_VERSION_3) { @@ -1584,17 +1553,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev) goto err; switch (mcasp->version) { -#if IS_BUILTIN(CONFIG_SND_DAVINCI_SOC) || \ - (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ - IS_MODULE(CONFIG_SND_DAVINCI_SOC)) - case MCASP_VERSION_1: - case MCASP_VERSION_2: - ret = davinci_soc_platform_register(&pdev->dev); - break; -#endif #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ IS_MODULE(CONFIG_SND_EDMA_SOC)) + case MCASP_VERSION_1: + case MCASP_VERSION_2: case MCASP_VERSION_3: ret = edma_pcm_platform_register(&pdev->dev); break; diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c deleted file mode 100644 index 7809e9d935fc..000000000000 --- a/sound/soc/davinci/davinci-pcm.c +++ /dev/null @@ -1,861 +0,0 @@ -/* - * ALSA PCM interface for the TI DAVINCI processor - * - * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> - * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> - * added SRAM ping/pong (C) 2008 Troy Kisky <troy.kisky@boundarydevices.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/init.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/dma-mapping.h> -#include <linux/kernel.h> -#include <linux/genalloc.h> -#include <linux/platform_data/edma.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include <asm/dma.h> - -#include "davinci-pcm.h" - -#ifdef DEBUG -static void print_buf_info(int slot, char *name) -{ - struct edmacc_param p; - if (slot < 0) - return; - edma_read_slot(slot, &p); - printk(KERN_DEBUG "%s: 0x%x, opt=%x, src=%x, a_b_cnt=%x dst=%x\n", - name, slot, p.opt, p.src, p.a_b_cnt, p.dst); - printk(KERN_DEBUG " src_dst_bidx=%x link_bcntrld=%x src_dst_cidx=%x ccnt=%x\n", - p.src_dst_bidx, p.link_bcntrld, p.src_dst_cidx, p.ccnt); -} -#else -static void print_buf_info(int slot, char *name) -{ -} -#endif - -static struct snd_pcm_hardware pcm_hardware_playback = { - .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME| - SNDRV_PCM_INFO_BATCH), - .buffer_bytes_max = 128 * 1024, - .period_bytes_min = 32, - .period_bytes_max = 8 * 1024, - .periods_min = 16, - .periods_max = 255, - .fifo_size = 0, -}; - -static struct snd_pcm_hardware pcm_hardware_capture = { - .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_BATCH), - .buffer_bytes_max = 128 * 1024, - .period_bytes_min = 32, - .period_bytes_max = 8 * 1024, - .periods_min = 16, - .periods_max = 255, - .fifo_size = 0, -}; - -/* - * How ping/pong works.... - * - * Playback: - * ram_params - copys 2*ping_size from start of SDRAM to iram, - * links to ram_link2 - * ram_link2 - copys rest of SDRAM to iram in ping_size units, - * links to ram_link - * ram_link - copys entire SDRAM to iram in ping_size uints, - * links to self - * - * asp_params - same as asp_link[0] - * asp_link[0] - copys from lower half of iram to asp port - * links to asp_link[1], triggers iram copy event on completion - * asp_link[1] - copys from upper half of iram to asp port - * links to asp_link[0], triggers iram copy event on completion - * triggers interrupt only needed to let upper SOC levels update position - * in stream on completion - * - * When playback is started: - * ram_params started - * asp_params started - * - * Capture: - * ram_params - same as ram_link, - * links to ram_link - * ram_link - same as playback - * links to self - * - * asp_params - same as playback - * asp_link[0] - same as playback - * asp_link[1] - same as playback - * - * When capture is started: - * asp_params started - */ -struct davinci_runtime_data { - spinlock_t lock; - int period; /* current DMA period */ - int asp_channel; /* Master DMA channel */ - int asp_link[2]; /* asp parameter link channel, ping/pong */ - struct davinci_pcm_dma_params *params; /* DMA params */ - int ram_channel; - int ram_link; - int ram_link2; - struct edmacc_param asp_params; - struct edmacc_param ram_params; -}; - -static void davinci_pcm_period_elapsed(struct snd_pcm_substream *substream) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - - prtd->period++; - if (unlikely(prtd->period >= runtime->periods)) - prtd->period = 0; -} - -static void davinci_pcm_period_reset(struct snd_pcm_substream *substream) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - - prtd->period = 0; -} -/* - * Not used with ping/pong - */ -static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int period_size; - unsigned int dma_offset; - dma_addr_t dma_pos; - dma_addr_t src, dst; - unsigned short src_bidx, dst_bidx; - unsigned short src_cidx, dst_cidx; - unsigned int data_type; - unsigned short acnt; - unsigned int count; - unsigned int fifo_level; - - period_size = snd_pcm_lib_period_bytes(substream); - dma_offset = prtd->period * period_size; - dma_pos = runtime->dma_addr + dma_offset; - fifo_level = prtd->params->fifo_level; - - pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d " - "dma_ptr = %x period_size=%x\n", prtd->asp_link[0], dma_pos, - period_size); - - data_type = prtd->params->data_type; - count = period_size / data_type; - if (fifo_level) - count /= fifo_level; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - src = dma_pos; - dst = prtd->params->dma_addr; - src_bidx = data_type; - dst_bidx = 4; - src_cidx = data_type * fifo_level; - dst_cidx = 0; - } else { - src = prtd->params->dma_addr; - dst = dma_pos; - src_bidx = 0; - dst_bidx = data_type; - src_cidx = 0; - dst_cidx = data_type * fifo_level; - } - - acnt = prtd->params->acnt; - edma_set_src(prtd->asp_link[0], src, INCR, W8BIT); - edma_set_dest(prtd->asp_link[0], dst, INCR, W8BIT); - - edma_set_src_index(prtd->asp_link[0], src_bidx, src_cidx); - edma_set_dest_index(prtd->asp_link[0], dst_bidx, dst_cidx); - - if (!fifo_level) - edma_set_transfer_params(prtd->asp_link[0], acnt, count, 1, 0, - ASYNC); - else - edma_set_transfer_params(prtd->asp_link[0], acnt, - fifo_level, - count, fifo_level, - ABSYNC); -} - -static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) -{ - struct snd_pcm_substream *substream = data; - struct davinci_runtime_data *prtd = substream->runtime->private_data; - - print_buf_info(prtd->ram_channel, "i ram_channel"); - pr_debug("davinci_pcm: link=%d, status=0x%x\n", link, ch_status); - - if (unlikely(ch_status != EDMA_DMA_COMPLETE)) - return; - - if (snd_pcm_running(substream)) { - spin_lock(&prtd->lock); - if (prtd->ram_channel < 0) { - /* No ping/pong must fix up link dma data*/ - davinci_pcm_enqueue_dma(substream); - } - davinci_pcm_period_elapsed(substream); - spin_unlock(&prtd->lock); - snd_pcm_period_elapsed(substream); - } -} - -#ifdef CONFIG_GENERIC_ALLOCATOR -static int allocate_sram(struct snd_pcm_substream *substream, - struct gen_pool *sram_pool, unsigned size, - struct snd_pcm_hardware *ppcm) -{ - struct snd_dma_buffer *buf = &substream->dma_buffer; - struct snd_dma_buffer *iram_dma = NULL; - dma_addr_t iram_phys = 0; - void *iram_virt = NULL; - - if (buf->private_data || !size) - return 0; - - ppcm->period_bytes_max = size; - iram_virt = gen_pool_dma_alloc(sram_pool, size, &iram_phys); - if (!iram_virt) - goto exit1; - iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL); - if (!iram_dma) - goto exit2; - iram_dma->area = iram_virt; - iram_dma->addr = iram_phys; - memset(iram_dma->area, 0, size); - iram_dma->bytes = size; - buf->private_data = iram_dma; - return 0; -exit2: - if (iram_virt) - gen_pool_free(sram_pool, (unsigned)iram_virt, size); -exit1: - return -ENOMEM; -} - -static void davinci_free_sram(struct snd_pcm_substream *substream, - struct snd_dma_buffer *iram_dma) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - struct gen_pool *sram_pool = prtd->params->sram_pool; - - gen_pool_free(sram_pool, (unsigned) iram_dma->area, iram_dma->bytes); -} -#else -static int allocate_sram(struct snd_pcm_substream *substream, - struct gen_pool *sram_pool, unsigned size, - struct snd_pcm_hardware *ppcm) -{ - return 0; -} - -static void davinci_free_sram(struct snd_pcm_substream *substream, - struct snd_dma_buffer *iram_dma) -{ -} -#endif - -/* - * Only used with ping/pong. - * This is called after runtime->dma_addr, period_bytes and data_type are valid - */ -static int ping_pong_dma_setup(struct snd_pcm_substream *substream) -{ - unsigned short ram_src_cidx, ram_dst_cidx; - struct snd_pcm_runtime *runtime = substream->runtime; - struct davinci_runtime_data *prtd = runtime->private_data; - struct snd_dma_buffer *iram_dma = - (struct snd_dma_buffer *)substream->dma_buffer.private_data; - struct davinci_pcm_dma_params *params = prtd->params; - unsigned int data_type = params->data_type; - unsigned int acnt = params->acnt; - /* divide by 2 for ping/pong */ - unsigned int ping_size = snd_pcm_lib_period_bytes(substream) >> 1; - unsigned int fifo_level = prtd->params->fifo_level; - unsigned int count; - if ((data_type == 0) || (data_type > 4)) { - printk(KERN_ERR "%s: data_type=%i\n", __func__, data_type); - return -EINVAL; - } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - dma_addr_t asp_src_pong = iram_dma->addr + ping_size; - ram_src_cidx = ping_size; - ram_dst_cidx = -ping_size; - edma_set_src(prtd->asp_link[1], asp_src_pong, INCR, W8BIT); - - edma_set_src_index(prtd->asp_link[0], data_type, - data_type * fifo_level); - edma_set_src_index(prtd->asp_link[1], data_type, - data_type * fifo_level); - - edma_set_src(prtd->ram_link, runtime->dma_addr, INCR, W32BIT); - } else { - dma_addr_t asp_dst_pong = iram_dma->addr + ping_size; - ram_src_cidx = -ping_size; - ram_dst_cidx = ping_size; - edma_set_dest(prtd->asp_link[1], asp_dst_pong, INCR, W8BIT); - - edma_set_dest_index(prtd->asp_link[0], data_type, - data_type * fifo_level); - edma_set_dest_index(prtd->asp_link[1], data_type, - data_type * fifo_level); - - edma_set_dest(prtd->ram_link, runtime->dma_addr, INCR, W32BIT); - } - - if (!fifo_level) { - count = ping_size / data_type; - edma_set_transfer_params(prtd->asp_link[0], acnt, count, - 1, 0, ASYNC); - edma_set_transfer_params(prtd->asp_link[1], acnt, count, - 1, 0, ASYNC); - } else { - count = ping_size / (data_type * fifo_level); - edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level, - count, fifo_level, ABSYNC); - edma_set_transfer_params(prtd->asp_link[1], acnt, fifo_level, - count, fifo_level, ABSYNC); - } - - edma_set_src_index(prtd->ram_link, ping_size, ram_src_cidx); - edma_set_dest_index(prtd->ram_link, ping_size, ram_dst_cidx); - edma_set_transfer_params(prtd->ram_link, ping_size, 2, - runtime->periods, 2, ASYNC); - - /* init master params */ - edma_read_slot(prtd->asp_link[0], &prtd->asp_params); - edma_read_slot(prtd->ram_link, &prtd->ram_params); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - struct edmacc_param p_ram; - /* Copy entire iram buffer before playback started */ - prtd->ram_params.a_b_cnt = (1 << 16) | (ping_size << 1); - /* 0 dst_bidx */ - prtd->ram_params.src_dst_bidx = (ping_size << 1); - /* 0 dst_cidx */ - prtd->ram_params.src_dst_cidx = (ping_size << 1); - prtd->ram_params.ccnt = 1; - - /* Skip 1st period */ - edma_read_slot(prtd->ram_link, &p_ram); - p_ram.src += (ping_size << 1); - p_ram.ccnt -= 1; - edma_write_slot(prtd->ram_link2, &p_ram); - /* - * When 1st started, ram -> iram dma channel will fill the - * entire iram. Then, whenever a ping/pong asp buffer finishes, - * 1/2 iram will be filled. - */ - prtd->ram_params.link_bcntrld = - EDMA_CHAN_SLOT(prtd->ram_link2) << 5; - } - return 0; -} - -/* 1 asp tx or rx channel using 2 parameter channels - * 1 ram to/from iram channel using 1 parameter channel - * - * Playback - * ram copy channel kicks off first, - * 1st ram copy of entire iram buffer completion kicks off asp channel - * asp tcc always kicks off ram copy of 1/2 iram buffer - * - * Record - * asp channel starts, tcc kicks off ram copy - */ -static int request_ping_pong(struct snd_pcm_substream *substream, - struct davinci_runtime_data *prtd, - struct snd_dma_buffer *iram_dma) -{ - dma_addr_t asp_src_ping; - dma_addr_t asp_dst_ping; - int ret; - struct davinci_pcm_dma_params *params = prtd->params; - - /* Request ram master channel */ - ret = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY, - davinci_pcm_dma_irq, substream, - prtd->params->ram_chan_q); - if (ret < 0) - goto exit1; - - /* Request ram link channel */ - ret = prtd->ram_link = edma_alloc_slot( - EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY); - if (ret < 0) - goto exit2; - - ret = prtd->asp_link[1] = edma_alloc_slot( - EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY); - if (ret < 0) - goto exit3; - - prtd->ram_link2 = -1; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - ret = prtd->ram_link2 = edma_alloc_slot( - EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY); - if (ret < 0) - goto exit4; - } - /* circle ping-pong buffers */ - edma_link(prtd->asp_link[0], prtd->asp_link[1]); - edma_link(prtd->asp_link[1], prtd->asp_link[0]); - /* circle ram buffers */ - edma_link(prtd->ram_link, prtd->ram_link); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - asp_src_ping = iram_dma->addr; - asp_dst_ping = params->dma_addr; /* fifo */ - } else { - asp_src_ping = params->dma_addr; /* fifo */ - asp_dst_ping = iram_dma->addr; - } - /* ping */ - edma_set_src(prtd->asp_link[0], asp_src_ping, INCR, W16BIT); - edma_set_dest(prtd->asp_link[0], asp_dst_ping, INCR, W16BIT); - edma_set_src_index(prtd->asp_link[0], 0, 0); - edma_set_dest_index(prtd->asp_link[0], 0, 0); - - edma_read_slot(prtd->asp_link[0], &prtd->asp_params); - prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN); - prtd->asp_params.opt |= TCCHEN | - EDMA_TCC(prtd->ram_channel & 0x3f); - edma_write_slot(prtd->asp_link[0], &prtd->asp_params); - - /* pong */ - edma_set_src(prtd->asp_link[1], asp_src_ping, INCR, W16BIT); - edma_set_dest(prtd->asp_link[1], asp_dst_ping, INCR, W16BIT); - edma_set_src_index(prtd->asp_link[1], 0, 0); - edma_set_dest_index(prtd->asp_link[1], 0, 0); - - edma_read_slot(prtd->asp_link[1], &prtd->asp_params); - prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f)); - /* interrupt after every pong completion */ - prtd->asp_params.opt |= TCINTEN | TCCHEN | - EDMA_TCC(prtd->ram_channel & 0x3f); - edma_write_slot(prtd->asp_link[1], &prtd->asp_params); - - /* ram */ - edma_set_src(prtd->ram_link, iram_dma->addr, INCR, W32BIT); - edma_set_dest(prtd->ram_link, iram_dma->addr, INCR, W32BIT); - pr_debug("%s: audio dma channels/slots in use for ram:%u %u %u," - "for asp:%u %u %u\n", __func__, - prtd->ram_channel, prtd->ram_link, prtd->ram_link2, - prtd->asp_channel, prtd->asp_link[0], - prtd->asp_link[1]); - return 0; -exit4: - edma_free_channel(prtd->asp_link[1]); - prtd->asp_link[1] = -1; -exit3: - edma_free_channel(prtd->ram_link); - prtd->ram_link = -1; -exit2: - edma_free_channel(prtd->ram_channel); - prtd->ram_channel = -1; -exit1: - return ret; -} - -static int davinci_pcm_dma_request(struct snd_pcm_substream *substream) -{ - struct snd_dma_buffer *iram_dma; - struct davinci_runtime_data *prtd = substream->runtime->private_data; - struct davinci_pcm_dma_params *params = prtd->params; - int ret; - - if (!params) - return -ENODEV; - - /* Request asp master DMA channel */ - ret = prtd->asp_channel = edma_alloc_channel(params->channel, - davinci_pcm_dma_irq, substream, - prtd->params->asp_chan_q); - if (ret < 0) - goto exit1; - - /* Request asp link channels */ - ret = prtd->asp_link[0] = edma_alloc_slot( - EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY); - if (ret < 0) - goto exit2; - - iram_dma = (struct snd_dma_buffer *)substream->dma_buffer.private_data; - if (iram_dma) { - if (request_ping_pong(substream, prtd, iram_dma) == 0) - return 0; - printk(KERN_WARNING "%s: dma channel allocation failed," - "not using sram\n", __func__); - } - - /* Issue transfer completion IRQ when the channel completes a - * transfer, then always reload from the same slot (by a kind - * of loopback link). The completion IRQ handler will update - * the reload slot with a new buffer. - * - * REVISIT save p_ram here after setting up everything except - * the buffer and its length (ccnt) ... use it as a template - * so davinci_pcm_enqueue_dma() takes less time in IRQ. - */ - edma_read_slot(prtd->asp_link[0], &prtd->asp_params); - prtd->asp_params.opt |= TCINTEN | - EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel)); - prtd->asp_params.link_bcntrld = EDMA_CHAN_SLOT(prtd->asp_link[0]) << 5; - edma_write_slot(prtd->asp_link[0], &prtd->asp_params); - return 0; -exit2: - edma_free_channel(prtd->asp_channel); - prtd->asp_channel = -1; -exit1: - return ret; -} - -static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - int ret = 0; - - spin_lock(&prtd->lock); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - edma_start(prtd->asp_channel); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - prtd->ram_channel >= 0) { - /* copy 1st iram buffer */ - edma_start(prtd->ram_channel); - } - break; - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - edma_resume(prtd->asp_channel); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - edma_pause(prtd->asp_channel); - break; - default: - ret = -EINVAL; - break; - } - - spin_unlock(&prtd->lock); - - return ret; -} - -static int davinci_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - - davinci_pcm_period_reset(substream); - if (prtd->ram_channel >= 0) { - int ret = ping_pong_dma_setup(substream); - if (ret < 0) - return ret; - - edma_write_slot(prtd->ram_channel, &prtd->ram_params); - edma_write_slot(prtd->asp_channel, &prtd->asp_params); - - print_buf_info(prtd->ram_channel, "ram_channel"); - print_buf_info(prtd->ram_link, "ram_link"); - print_buf_info(prtd->ram_link2, "ram_link2"); - print_buf_info(prtd->asp_channel, "asp_channel"); - print_buf_info(prtd->asp_link[0], "asp_link[0]"); - print_buf_info(prtd->asp_link[1], "asp_link[1]"); - - /* - * There is a phase offset of 2 periods between the position - * used by dma setup and the position reported in the pointer - * function. - * - * The phase offset, when not using ping-pong buffers, is due to - * the two consecutive calls to davinci_pcm_enqueue_dma() below. - * - * Whereas here, with ping-pong buffers, the phase is due to - * there being an entire buffer transfer complete before the - * first dma completion event triggers davinci_pcm_dma_irq(). - */ - davinci_pcm_period_elapsed(substream); - davinci_pcm_period_elapsed(substream); - - return 0; - } - davinci_pcm_enqueue_dma(substream); - davinci_pcm_period_elapsed(substream); - - /* Copy self-linked parameter RAM entry into master channel */ - edma_read_slot(prtd->asp_link[0], &prtd->asp_params); - edma_write_slot(prtd->asp_channel, &prtd->asp_params); - davinci_pcm_enqueue_dma(substream); - davinci_pcm_period_elapsed(substream); - - return 0; -} - -static snd_pcm_uframes_t -davinci_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct davinci_runtime_data *prtd = runtime->private_data; - unsigned int offset; - int asp_count; - unsigned int period_size = snd_pcm_lib_period_bytes(substream); - - /* - * There is a phase offset of 2 periods between the position used by dma - * setup and the position reported in the pointer function. Either +2 in - * the dma setup or -2 here in the pointer function (with wrapping, - * both) accounts for this offset -- choose the latter since it makes - * the first-time setup clearer. - */ - spin_lock(&prtd->lock); - asp_count = prtd->period - 2; - spin_unlock(&prtd->lock); - - if (asp_count < 0) - asp_count += runtime->periods; - asp_count *= period_size; - - offset = bytes_to_frames(runtime, asp_count); - if (offset >= runtime->buffer_size) - offset = 0; - - return offset; -} - -static int davinci_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct davinci_runtime_data *prtd; - struct snd_pcm_hardware *ppcm; - int ret = 0; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct davinci_pcm_dma_params *pa; - struct davinci_pcm_dma_params *params; - - pa = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - if (!pa) - return -ENODEV; - params = &pa[substream->stream]; - - ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - &pcm_hardware_playback : &pcm_hardware_capture; - allocate_sram(substream, params->sram_pool, params->sram_size, ppcm); - snd_soc_set_runtime_hwparams(substream, ppcm); - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - return ret; - - prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL); - if (prtd == NULL) - return -ENOMEM; - - spin_lock_init(&prtd->lock); - prtd->params = params; - prtd->asp_channel = -1; - prtd->asp_link[0] = prtd->asp_link[1] = -1; - prtd->ram_channel = -1; - prtd->ram_link = -1; - prtd->ram_link2 = -1; - - runtime->private_data = prtd; - - ret = davinci_pcm_dma_request(substream); - if (ret) { - printk(KERN_ERR "davinci_pcm: Failed to get dma channels\n"); - kfree(prtd); - } - - return ret; -} - -static int davinci_pcm_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct davinci_runtime_data *prtd = runtime->private_data; - - if (prtd->ram_channel >= 0) - edma_stop(prtd->ram_channel); - if (prtd->asp_channel >= 0) - edma_stop(prtd->asp_channel); - if (prtd->asp_link[0] >= 0) - edma_unlink(prtd->asp_link[0]); - if (prtd->asp_link[1] >= 0) - edma_unlink(prtd->asp_link[1]); - if (prtd->ram_link >= 0) - edma_unlink(prtd->ram_link); - - if (prtd->asp_link[0] >= 0) - edma_free_slot(prtd->asp_link[0]); - if (prtd->asp_link[1] >= 0) - edma_free_slot(prtd->asp_link[1]); - if (prtd->asp_channel >= 0) - edma_free_channel(prtd->asp_channel); - if (prtd->ram_link >= 0) - edma_free_slot(prtd->ram_link); - if (prtd->ram_link2 >= 0) - edma_free_slot(prtd->ram_link2); - if (prtd->ram_channel >= 0) - edma_free_channel(prtd->ram_channel); - - kfree(prtd); - - return 0; -} - -static int davinci_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - return snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); -} - -static int davinci_pcm_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - -static int davinci_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - return dma_mmap_writecombine(substream->pcm->card->dev, vma, - runtime->dma_area, - runtime->dma_addr, - runtime->dma_bytes); -} - -static struct snd_pcm_ops davinci_pcm_ops = { - .open = davinci_pcm_open, - .close = davinci_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = davinci_pcm_hw_params, - .hw_free = davinci_pcm_hw_free, - .prepare = davinci_pcm_prepare, - .trigger = davinci_pcm_trigger, - .pointer = davinci_pcm_pointer, - .mmap = davinci_pcm_mmap, -}; - -static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream, - size_t size) -{ - struct snd_pcm_substream *substream = pcm->streams[stream].substream; - struct snd_dma_buffer *buf = &substream->dma_buffer; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = pcm->card->dev; - buf->private_data = NULL; - buf->area = dma_alloc_writecombine(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - - pr_debug("davinci_pcm: preallocate_dma_buffer: area=%p, addr=%p, " - "size=%d\n", (void *) buf->area, (void *) buf->addr, size); - - if (!buf->area) - return -ENOMEM; - - buf->bytes = size; - return 0; -} - -static void davinci_pcm_free(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - for (stream = 0; stream < 2; stream++) { - struct snd_dma_buffer *iram_dma; - substream = pcm->streams[stream].substream; - if (!substream) - continue; - - buf = &substream->dma_buffer; - if (!buf->area) - continue; - - dma_free_writecombine(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - iram_dma = buf->private_data; - if (iram_dma) { - davinci_free_sram(substream, iram_dma); - kfree(iram_dma); - } - } -} - -static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_card *card = rtd->card->snd_card; - struct snd_pcm *pcm = rtd->pcm; - int ret; - - ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { - ret = davinci_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK, - pcm_hardware_playback.buffer_bytes_max); - if (ret) - return ret; - } - - if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { - ret = davinci_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE, - pcm_hardware_capture.buffer_bytes_max); - if (ret) - return ret; - } - - return 0; -} - -static struct snd_soc_platform_driver davinci_soc_platform = { - .ops = &davinci_pcm_ops, - .pcm_new = davinci_pcm_new, - .pcm_free = davinci_pcm_free, -}; - -int davinci_soc_platform_register(struct device *dev) -{ - return devm_snd_soc_register_platform(dev, &davinci_soc_platform); -} -EXPORT_SYMBOL_GPL(davinci_soc_platform_register); - -MODULE_AUTHOR("Vladimir Barinov"); -MODULE_DESCRIPTION("TI DAVINCI PCM DMA module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h deleted file mode 100644 index 0fe2346a9aa2..000000000000 --- a/sound/soc/davinci/davinci-pcm.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * ALSA PCM interface for the TI DAVINCI processor - * - * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> - * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.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 _DAVINCI_PCM_H -#define _DAVINCI_PCM_H - -#include <linux/genalloc.h> -#include <linux/platform_data/davinci_asp.h> -#include <linux/platform_data/edma.h> - -struct davinci_pcm_dma_params { - int channel; /* sync dma channel ID */ - unsigned short acnt; - dma_addr_t dma_addr; /* device physical address for DMA */ - unsigned sram_size; - struct gen_pool *sram_pool; /* SRAM gen_pool for ping pong */ - enum dma_event_q asp_chan_q; /* event queue number for ASP channel */ - enum dma_event_q ram_chan_q; /* event queue number for RAM channel */ - unsigned char data_type; /* xfer data type */ - unsigned char convert_mono_stereo; - unsigned int fifo_level; -}; - -#if IS_ENABLED(CONFIG_SND_DAVINCI_SOC) -int davinci_soc_platform_register(struct device *dev); -#else -static inline int davinci_soc_platform_register(struct device *dev) -{ - return 0; -} -#endif /* CONFIG_SND_DAVINCI_SOC */ - -#endif diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index 5bee04279ebe..fabd05f24aeb 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c @@ -33,8 +33,9 @@ #include <sound/pcm_params.h> #include <sound/initval.h> #include <sound/soc.h> +#include <sound/dmaengine_pcm.h> -#include "davinci-pcm.h" +#include "edma-pcm.h" #include "davinci-i2s.h" #define MOD_REG_BIT(val, mask, set) do { \ @@ -47,7 +48,8 @@ struct davinci_vcif_dev { struct davinci_vc *davinci_vc; - struct davinci_pcm_dma_params dma_params[2]; + struct snd_dmaengine_dai_dma_data dma_data[2]; + int dma_request[2]; }; static void davinci_vcif_start(struct snd_pcm_substream *substream) @@ -93,8 +95,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream, { struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai); struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc; - struct davinci_pcm_dma_params *dma_params = - &davinci_vcif_dev->dma_params[substream->stream]; u32 w; /* Restart the codec before setup */ @@ -113,16 +113,12 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream, /* Determine xfer data type */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_U8: - dma_params->data_type = 0; - MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 | DAVINCI_VC_CTRL_RD_UNSIGNED | DAVINCI_VC_CTRL_WD_BITS_8 | DAVINCI_VC_CTRL_WD_UNSIGNED, 1); break; case SNDRV_PCM_FORMAT_S8: - dma_params->data_type = 1; - MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 | DAVINCI_VC_CTRL_WD_BITS_8, 1); @@ -130,8 +126,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream, DAVINCI_VC_CTRL_WD_UNSIGNED, 0); break; case SNDRV_PCM_FORMAT_S16_LE: - dma_params->data_type = 2; - MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 | DAVINCI_VC_CTRL_RD_UNSIGNED | DAVINCI_VC_CTRL_WD_BITS_8 | @@ -142,8 +136,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - dma_params->acnt = dma_params->data_type; - writel(w, davinci_vc->base + DAVINCI_VC_CTRL); return 0; @@ -172,24 +164,25 @@ static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } -static int davinci_vcif_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai); - - snd_soc_dai_set_dma_data(dai, substream, dev->dma_params); - return 0; -} - #define DAVINCI_VCIF_RATES SNDRV_PCM_RATE_8000_48000 static const struct snd_soc_dai_ops davinci_vcif_dai_ops = { - .startup = davinci_vcif_startup, .trigger = davinci_vcif_trigger, .hw_params = davinci_vcif_hw_params, }; +static int davinci_vcif_dai_probe(struct snd_soc_dai *dai) +{ + struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai); + + dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; + dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]; + + return 0; +} + static struct snd_soc_dai_driver davinci_vcif_dai = { + .probe = davinci_vcif_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, @@ -225,16 +218,16 @@ static int davinci_vcif_probe(struct platform_device *pdev) /* DMA tx params */ davinci_vcif_dev->davinci_vc = davinci_vc; - davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel = - davinci_vc->davinci_vcif.dma_tx_channel; - davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr = - davinci_vc->davinci_vcif.dma_tx_addr; + davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = + &davinci_vc->davinci_vcif.dma_tx_channel; + davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = + davinci_vc->davinci_vcif.dma_tx_addr; /* DMA rx params */ - davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = - davinci_vc->davinci_vcif.dma_rx_channel; - davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr = - davinci_vc->davinci_vcif.dma_rx_addr; + davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = + &davinci_vc->davinci_vcif.dma_rx_channel; + davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = + davinci_vc->davinci_vcif.dma_rx_addr; dev_set_drvdata(&pdev->dev, davinci_vcif_dev); @@ -245,7 +238,7 @@ static int davinci_vcif_probe(struct platform_device *pdev) return ret; } - ret = davinci_soc_platform_register(&pdev->dev); + ret = edma_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); snd_soc_unregister_component(&pdev->dev); diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 3f6959c8e2f7..de438871040b 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -512,6 +512,12 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) memcpy(priv->dai_link, fsl_asoc_card_dai, sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link)); + ret = snd_soc_of_parse_audio_routing(&priv->card, "audio-routing"); + if (ret) { + dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret); + goto asrc_fail; + } + /* Normal DAI Link */ priv->dai_link[0].cpu_of_node = cpu_np; priv->dai_link[0].codec_of_node = codec_np; diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 75870c0ea2c9..91eb3aef7f02 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1049,7 +1049,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, enum spdif_txrate index, bool round) { const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; - bool is_sysclk = clk == spdif_priv->sysclk; + bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk); u64 rate_ideal, rate_actual, sub; u32 sysclk_dfmin, sysclk_dfmax; u32 txclk_df, sysclk_df, arate; @@ -1143,7 +1143,7 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, spdif_priv->txclk_src[index], rate[index]); dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n", spdif_priv->txclk_df[index], rate[index]); - if (spdif_priv->txclk[index] == spdif_priv->sysclk) + if (clk_is_match(spdif_priv->txclk[index], spdif_priv->sysclk)) dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n", spdif_priv->sysclk_df[index], rate[index]); dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n", diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 2595611e8a6d..6b0c8f717ec2 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -603,17 +603,20 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, factor = (div2 + 1) * (7 * psr + 1) * 2; for (i = 0; i < 255; i++) { - /* The bclk rate must be smaller than 1/5 sysclk rate */ - if (factor * (i + 1) < 5) - continue; - - tmprate = freq * factor * (i + 2); + tmprate = freq * factor * (i + 1); if (baudclk_is_used) clkrate = clk_get_rate(ssi_private->baudclk); else clkrate = clk_round_rate(ssi_private->baudclk, tmprate); + /* + * Hardware limitation: The bclk rate must be + * never greater than 1/5 IPG clock rate + */ + if (clkrate * 5 > clk_get_rate(ssi_private->clk)) + continue; + clkrate /= factor; afreq = clkrate / (i + 1); @@ -1224,7 +1227,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, ssi_private->dma_params_tx.addr = ssi_private->ssi_phys + CCSR_SSI_STX0; ssi_private->dma_params_rx.addr = ssi_private->ssi_phys + CCSR_SSI_SRX0; - ret = !of_property_read_u32_array(np, "dmas", dmas, 4); + ret = of_property_read_u32_array(np, "dmas", dmas, 4); if (ssi_private->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) { ssi_private->use_dual_fifo = true; /* When using dual fifo mode, we need to keep watermark diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index f8cf10e16ce9..20e7400e2611 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -53,9 +53,9 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) /* Headphone jack detection */ if (gpio_is_valid(data->jack_gpio)) { - ret = snd_soc_jack_new(rtd->codec, "Headphone", - SND_JACK_HEADPHONE | SND_JACK_BTN_0, - &headset_jack); + ret = snd_soc_card_jack_new(rtd->card, "Headphone", + SND_JACK_HEADPHONE | SND_JACK_BTN_0, + &headset_jack, NULL, 0); if (ret) return ret; diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c index a958937ab405..0653aa83c927 100644 --- a/sound/soc/fsl/wm1133-ev1.c +++ b/sound/soc/fsl/wm1133-ev1.c @@ -205,16 +205,14 @@ static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = &codec->dapm; /* Headphone jack detection */ - snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack); - snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), - hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphone", SND_JACK_HEADPHONE, + &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins)); wm8350_hp_jack_detect(codec, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE); /* Microphone jack detection */ - snd_soc_jack_new(codec, "Microphone", - SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack); - snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins), - mic_jack_pins); + snd_soc_card_jack_new(rtd->card, "Microphone", + SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack, + mic_jack_pins, ARRAY_SIZE(mic_jack_pins)); wm8350_mic_jack_detect(codec, &mic_jack, SND_JACK_MICROPHONE, SND_JACK_BTN_0); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index f7c6734bd5da..c49a408fc7a6 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -176,11 +176,11 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return ret; if (gpio_is_valid(priv->gpio_hp_det)) { - snd_soc_jack_new(codec->codec, "Headphones", SND_JACK_HEADPHONE, - &simple_card_hp_jack); - snd_soc_jack_add_pins(&simple_card_hp_jack, - ARRAY_SIZE(simple_card_hp_jack_pins), - simple_card_hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphones", + SND_JACK_HEADPHONE, + &simple_card_hp_jack, + simple_card_hp_jack_pins, + ARRAY_SIZE(simple_card_hp_jack_pins)); simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det; simple_card_hp_jack_gpio.invert = priv->gpio_hp_det_invert; @@ -189,11 +189,11 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) } if (gpio_is_valid(priv->gpio_mic_det)) { - snd_soc_jack_new(codec->codec, "Mic Jack", SND_JACK_MICROPHONE, - &simple_card_mic_jack); - snd_soc_jack_add_pins(&simple_card_mic_jack, - ARRAY_SIZE(simple_card_mic_jack_pins), - simple_card_mic_jack_pins); + snd_soc_card_jack_new(rtd->card, "Mic Jack", + SND_JACK_MICROPHONE, + &simple_card_mic_jack, + simple_card_mic_jack_pins, + ARRAY_SIZE(simple_card_mic_jack_pins)); simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det; simple_card_mic_jack_gpio.invert = priv->gpio_mic_det_invert; snd_soc_jack_add_gpios(&simple_card_mic_jack, 1, @@ -372,6 +372,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, strlen(dai_link->cpu_dai_name) + strlen(dai_link->codec_dai_name) + 2, GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto dai_link_of_err; + } + sprintf(name, "%s-%s", dai_link->cpu_dai_name, dai_link->codec_dai_name); dai_link->name = dai_link->stream_name = name; diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c index 9cf7d01479ad..fc5542034b9b 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/broadwell.c @@ -80,15 +80,9 @@ static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; int ret = 0; - ret = snd_soc_jack_new(codec, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset); - - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&broadwell_headset, - ARRAY_SIZE(broadwell_headset_pins), - broadwell_headset_pins); + ret = snd_soc_card_jack_new(rtd->card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset, + broadwell_headset_pins, ARRAY_SIZE(broadwell_headset_pins)); if (ret) return ret; @@ -110,9 +104,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, 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); + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); return 0; } diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/byt-max98090.c index 9832afe7d22c..d8b1f038da1c 100644 --- a/sound/soc/intel/byt-max98090.c +++ b/sound/soc/intel/byt-max98090.c @@ -84,7 +84,6 @@ static struct snd_soc_jack_gpio hs_jack_gpios[] = { static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime) { int ret; - struct snd_soc_codec *codec = runtime->codec; struct snd_soc_card *card = runtime->card; struct byt_max98090_private *drv = snd_soc_card_get_drvdata(card); struct snd_soc_jack *jack = &drv->jack; @@ -100,13 +99,9 @@ static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime) } /* Enable jack detection */ - ret = snd_soc_jack_new(codec, "Headset", - SND_JACK_LINEOUT | SND_JACK_HEADSET, jack); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(jack, ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); + ret = snd_soc_card_jack_new(runtime->card, "Headset", + SND_JACK_LINEOUT | SND_JACK_HEADSET, jack, + hs_jack_pins, ARRAY_SIZE(hs_jack_pins)); if (ret) return ret; diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/bytcr_dpcm_rt5640.c index 59308629043e..3b262d01c1b3 100644 --- a/sound/soc/intel/bytcr_dpcm_rt5640.c +++ b/sound/soc/intel/bytcr_dpcm_rt5640.c @@ -113,9 +113,7 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; /* set SSP2 to 24-bit */ - snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - - SNDRV_PCM_HW_PARAM_FIRST_MASK], - SNDRV_PCM_FORMAT_S24_LE); + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); return 0; } diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c index bd29617a9ab9..012227997ed9 100644 --- a/sound/soc/intel/cht_bsw_rt5645.c +++ b/sound/soc/intel/cht_bsw_rt5645.c @@ -169,17 +169,17 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) return ret; } - ret = snd_soc_jack_new(codec, "Headphone Jack", - SND_JACK_HEADPHONE, - &ctx->hp_jack); + ret = snd_soc_card_jack_new(runtime->card, "Headphone Jack", + SND_JACK_HEADPHONE, &ctx->hp_jack, + NULL, 0); if (ret) { dev_err(runtime->dev, "HP jack creation failed %d\n", ret); return ret; } - ret = snd_soc_jack_new(codec, "Mic Jack", - SND_JACK_MICROPHONE, - &ctx->mic_jack); + ret = snd_soc_card_jack_new(runtime->card, "Mic Jack", + SND_JACK_MICROPHONE, &ctx->mic_jack, + NULL, 0); if (ret) { dev_err(runtime->dev, "Mic jack creation failed %d\n", ret); return ret; @@ -203,9 +203,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; /* set SSP2 to 24-bit */ - snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - - SNDRV_PCM_HW_PARAM_FIRST_MASK], - SNDRV_PCM_FORMAT_S24_LE); + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); return 0; } diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index ff016621583a..bc8dcacd5e6a 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -178,9 +178,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; /* set SSP2 to 24-bit */ - snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - - SNDRV_PCM_HW_PARAM_FIRST_MASK], - SNDRV_PCM_FORMAT_S24_LE); + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); return 0; } @@ -217,7 +215,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", .platform_name = "sst-mfld-platform", - .ignore_suspend = 1, + .nonatomic = true, .dynamic = 1, .dpcm_playback = 1, .dpcm_capture = 1, @@ -240,13 +238,13 @@ static struct snd_soc_dai_link cht_dailink[] = { .cpu_dai_name = "ssp2-port", .platform_name = "sst-mfld-platform", .no_pcm = 1, + .nonatomic = true, .codec_dai_name = "rt5670-aif1", .codec_name = "i2c-10EC5670:00", .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .ignore_suspend = 1, .dpcm_playback = 1, .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, @@ -285,7 +283,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) static struct platform_driver snd_cht_mc_driver = { .driver = { .name = "cht-bsw-rt5672", - .pm = &snd_soc_pm_ops, }, .probe = snd_cht_mc_probe, }; diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c index 35edf51a52aa..00fddd3f5dfb 100644 --- a/sound/soc/intel/haswell.c +++ b/sound/soc/intel/haswell.c @@ -56,9 +56,7 @@ static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, 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); + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); return 0; } diff --git a/sound/soc/intel/mfld_machine.c b/sound/soc/intel/mfld_machine.c index 90b7a57713a0..49c09a0add79 100644 --- a/sound/soc/intel/mfld_machine.c +++ b/sound/soc/intel/mfld_machine.c @@ -228,10 +228,13 @@ static void mfld_jack_check(unsigned int intr_status) { struct mfld_jack_data jack_data; + if (!mfld_codec) + return; + jack_data.mfld_jack = &mfld_jack; jack_data.intr_id = intr_status; - sn95031_jack_detection(&jack_data); + sn95031_jack_detection(mfld_codec, &jack_data); /* TODO: add american headset detection post gpiolib support */ } @@ -240,8 +243,6 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_dapm_context *dapm = &runtime->card->dapm; int ret_val; - mfld_codec = runtime->codec; - /* default is earpiece pin, userspace sets it explcitly */ snd_soc_dapm_disable_pin(dapm, "Headphones"); /* default is lineout NC, userspace sets it explcitly */ @@ -254,20 +255,15 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime) snd_soc_dapm_disable_pin(dapm, "LINEINR"); /* Headset and button jack detection */ - ret_val = snd_soc_jack_new(mfld_codec, "Intel(R) MID Audio Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1, &mfld_jack); + ret_val = snd_soc_card_jack_new(runtime->card, + "Intel(R) MID Audio Jack", SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1, &mfld_jack, + mfld_jack_pins, ARRAY_SIZE(mfld_jack_pins)); if (ret_val) { pr_err("jack creation failed\n"); return ret_val; } - ret_val = snd_soc_jack_add_pins(&mfld_jack, - ARRAY_SIZE(mfld_jack_pins), mfld_jack_pins); - if (ret_val) { - pr_err("adding jack pins failed\n"); - return ret_val; - } ret_val = snd_soc_jack_add_zones(&mfld_jack, ARRAY_SIZE(mfld_zones), mfld_zones); if (ret_val) { @@ -275,6 +271,8 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime) return ret_val; } + mfld_codec = runtime->codec; + /* we want to check if anything is inserted at boot, * so send a fake event to codec and it will read adc * to find if anything is there or not */ @@ -359,8 +357,6 @@ static irqreturn_t snd_mfld_jack_detection(int irq, void *data) { struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data; - if (mfld_jack.codec == NULL) - return IRQ_HANDLED; mfld_jack_check(mc_drv_ctx->interrupt_status); return IRQ_HANDLED; diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c index b3d84560fbb5..42f293f9c6e2 100644 --- a/sound/soc/intel/sst-acpi.c +++ b/sound/soc/intel/sst-acpi.c @@ -142,6 +142,7 @@ static int sst_acpi_probe(struct platform_device *pdev) sst_acpi->desc = desc; sst_acpi->mach = mach; + sst_pdata->resindex_dma_base = desc->resindex_dma_base; if (desc->resindex_dma_base >= 0) { sst_pdata->dma_engine = desc->dma_engine; sst_pdata->dma_base = desc->resindex_dma_base; diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h index dfebfdd5eb2a..daecc58f28af 100644 --- a/sound/soc/intel/sst-atom-controls.h +++ b/sound/soc/intel/sst-atom-controls.h @@ -150,7 +150,7 @@ enum sst_cmd_type { enum sst_task { SST_TASK_SBA = 1, - SST_TASK_MMX, + SST_TASK_MMX = 3, }; enum sst_type { diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h index f291e32f0077..148d8c589a43 100644 --- a/sound/soc/intel/sst-dsp.h +++ b/sound/soc/intel/sst-dsp.h @@ -206,6 +206,7 @@ struct sst_pdata { const struct firmware *fw; /* DMA */ + int resindex_dma_base; /* other fields invalid if equals to -1 */ u32 dma_base; u32 dma_size; int dma_engine; diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index 5f71ef607a57..4a993d16a235 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c @@ -271,6 +271,10 @@ int sst_dma_new(struct sst_dsp *sst) const char *dma_dev_name; int ret = 0; + if (sst->pdata->resindex_dma_base == -1) + /* DMA is not used, return and squelsh error messages */ + return 0; + /* configure the correct platform data for whatever DMA engine * is attached to the ADSP IP. */ switch (sst->pdata->dma_engine) { diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index c42ffae5fe9f..402b728c0a06 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c @@ -207,9 +207,6 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw) module = (void *)module + sizeof(*module) + module->mod_size; } - /* allocate scratch mem regions */ - sst_block_alloc_scratch(dsp); - return 0; } diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 394af5684c05..863a9ca34b8e 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -1732,6 +1732,7 @@ static void sst_hsw_drop_all(struct sst_hsw *hsw) int sst_hsw_dsp_load(struct sst_hsw *hsw) { struct sst_dsp *dsp = hsw->dsp; + struct sst_fw *sst_fw, *t; int ret; dev_dbg(hsw->dev, "loading audio DSP...."); @@ -1748,12 +1749,17 @@ int sst_hsw_dsp_load(struct sst_hsw *hsw) return ret; } - ret = sst_fw_reload(hsw->sst_fw); - if (ret < 0) { - dev_err(hsw->dev, "error: SST FW reload failed\n"); - sst_dsp_dma_put_channel(dsp); - return -ENOMEM; + list_for_each_entry_safe_reverse(sst_fw, t, &dsp->fw_list, list) { + ret = sst_fw_reload(sst_fw); + if (ret < 0) { + dev_err(hsw->dev, "error: SST FW reload failed\n"); + sst_dsp_dma_put_channel(dsp); + return -ENOMEM; + } } + ret = sst_block_alloc_scratch(hsw->dsp); + if (ret < 0) + return -EINVAL; sst_dsp_dma_put_channel(dsp); return 0; @@ -1809,12 +1815,17 @@ int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw) int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw) { - sst_fw_unload(hsw->sst_fw); - sst_block_free_scratch(hsw->dsp); + struct sst_fw *sst_fw, *t; + struct sst_dsp *dsp = hsw->dsp; + + list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) { + sst_fw_unload(sst_fw); + } + sst_block_free_scratch(dsp); hsw->boot_complete = false; - sst_dsp_sleep(hsw->dsp); + sst_dsp_sleep(dsp); return 0; } @@ -1943,6 +1954,11 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) goto fw_err; } + /* allocate scratch mem regions */ + ret = sst_block_alloc_scratch(hsw->dsp); + if (ret < 0) + goto boot_err; + /* wait for DSP boot completion */ sst_dsp_boot(hsw->dsp); ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 7523cbef8780..2fbaf2c75d17 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -594,11 +594,13 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, ret_val = stream->ops->stream_drop(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: dev_dbg(rtd->dev, "sst: in pause\n"); status = SST_PLATFORM_PAUSED; ret_val = stream->ops->stream_pause(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: dev_dbg(rtd->dev, "sst: in pause release\n"); status = SST_PLATFORM_RUNNING; ret_val = stream->ops->stream_pause_release(sst->dev, str_id); @@ -665,6 +667,9 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) static int sst_soc_probe(struct snd_soc_platform *platform) { + struct sst_data *drv = dev_get_drvdata(platform->dev); + + drv->soc_card = platform->component.card; return sst_dsp_init_v2_dpcm(platform); } @@ -727,9 +732,64 @@ static int sst_platform_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP + +static int sst_soc_prepare(struct device *dev) +{ + struct sst_data *drv = dev_get_drvdata(dev); + int i; + + /* suspend all pcms first */ + snd_soc_suspend(drv->soc_card->dev); + snd_soc_poweroff(drv->soc_card->dev); + + /* set the SSPs to idle */ + for (i = 0; i < drv->soc_card->num_rtd; i++) { + struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; + + if (dai->active) { + send_ssp_cmd(dai, dai->name, 0); + sst_handle_vb_timer(dai, false); + } + } + + return 0; +} + +static void sst_soc_complete(struct device *dev) +{ + struct sst_data *drv = dev_get_drvdata(dev); + int i; + + /* restart SSPs */ + for (i = 0; i < drv->soc_card->num_rtd; i++) { + struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; + + if (dai->active) { + sst_handle_vb_timer(dai, true); + send_ssp_cmd(dai, dai->name, 1); + } + } + snd_soc_resume(drv->soc_card->dev); +} + +#else + +#define sst_soc_prepare NULL +#define sst_soc_complete NULL + +#endif + + +static const struct dev_pm_ops sst_platform_pm = { + .prepare = sst_soc_prepare, + .complete = sst_soc_complete, +}; + static struct platform_driver sst_platform_driver = { .driver = { .name = "sst-mfld-platform", + .pm = &sst_platform_pm, }, .probe = sst_platform_probe, .remove = sst_platform_remove, diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 79c8d1246a8f..9094314be2b0 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -174,6 +174,7 @@ struct sst_data { struct sst_platform_data *pdata; struct snd_sst_bytes_v2 *byte_stream; struct mutex lock; + struct snd_soc_card *soc_card; }; int sst_register_dsp(struct sst_device *sst); int sst_unregister_dsp(struct sst_device *sst); diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c index 8a8d56a146e7..1a7eeec444b1 100644 --- a/sound/soc/intel/sst/sst.c +++ b/sound/soc/intel/sst/sst.c @@ -350,7 +350,9 @@ static inline void sst_save_shim64(struct intel_sst_drv *ctx, spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); - shim_regs->imrx = sst_shim_read64(shim, SST_IMRX), + shim_regs->imrx = sst_shim_read64(shim, SST_IMRX); + shim_regs->csr = sst_shim_read64(shim, SST_CSR); + spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); } @@ -367,6 +369,7 @@ static inline void sst_restore_shim64(struct intel_sst_drv *ctx, */ spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); sst_shim_write64(shim, SST_IMRX, shim_regs->imrx), + sst_shim_write64(shim, SST_CSR, shim_regs->csr), spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); } @@ -379,6 +382,10 @@ void sst_configure_runtime_pm(struct intel_sst_drv *ctx) * initially active. So change the state to active before * enabling the pm */ + + if (!acpi_disabled) + pm_runtime_set_active(ctx->dev); + pm_runtime_enable(ctx->dev); if (acpi_disabled) @@ -409,29 +416,142 @@ static int intel_sst_runtime_suspend(struct device *dev) synchronize_irq(ctx->irq_num); flush_workqueue(ctx->post_msg_wq); + ctx->ops->reset(ctx); /* save the shim registers because PMC doesn't save state */ sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64); return ret; } -static int intel_sst_runtime_resume(struct device *dev) +static int intel_sst_suspend(struct device *dev) { - int ret = 0; struct intel_sst_drv *ctx = dev_get_drvdata(dev); + struct sst_fw_save *fw_save; + int i, ret = 0; - if (ctx->sst_state == SST_RESET) { - ret = sst_load_fw(ctx); - if (ret) { - dev_err(dev, "FW download fail %d\n", ret); - sst_set_fw_state_locked(ctx, SST_RESET); + /* check first if we are already in SW reset */ + if (ctx->sst_state == SST_RESET) + return 0; + + /* + * check if any stream is active and running + * they should already by suspend by soc_suspend + */ + for (i = 1; i <= ctx->info.max_streams; i++) { + struct stream_info *stream = &ctx->streams[i]; + + if (stream->status == STREAM_RUNNING) { + dev_err(dev, "stream %d is running, cant susupend, abort\n", i); + return -EBUSY; } } + synchronize_irq(ctx->irq_num); + flush_workqueue(ctx->post_msg_wq); + + /* Move the SST state to Reset */ + sst_set_fw_state_locked(ctx, SST_RESET); + + /* tell DSP we are suspending */ + if (ctx->ops->save_dsp_context(ctx)) + return -EBUSY; + + /* save the memories */ + fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL); + if (!fw_save) + return -ENOMEM; + fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL); + if (!fw_save->iram) { + ret = -ENOMEM; + goto iram; + } + fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL); + if (!fw_save->dram) { + ret = -ENOMEM; + goto dram; + } + fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL); + if (!fw_save->sram) { + ret = -ENOMEM; + goto sram; + } + + fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL); + if (!fw_save->ddr) { + ret = -ENOMEM; + goto ddr; + } + + memcpy32_fromio(fw_save->iram, ctx->iram, ctx->iram_end - ctx->iram_base); + memcpy32_fromio(fw_save->dram, ctx->dram, ctx->dram_end - ctx->dram_base); + memcpy32_fromio(fw_save->sram, ctx->mailbox, SST_MAILBOX_SIZE); + memcpy32_fromio(fw_save->ddr, ctx->ddr, ctx->ddr_end - ctx->ddr_base); + + ctx->fw_save = fw_save; + ctx->ops->reset(ctx); + return 0; +ddr: + kfree(fw_save->sram); +sram: + kfree(fw_save->dram); +dram: + kfree(fw_save->iram); +iram: + kfree(fw_save); + return ret; +} + +static int intel_sst_resume(struct device *dev) +{ + struct intel_sst_drv *ctx = dev_get_drvdata(dev); + struct sst_fw_save *fw_save = ctx->fw_save; + int ret = 0; + struct sst_block *block; + + if (!fw_save) + return 0; + + sst_set_fw_state_locked(ctx, SST_FW_LOADING); + + /* we have to restore the memory saved */ + ctx->ops->reset(ctx); + + ctx->fw_save = NULL; + + memcpy32_toio(ctx->iram, fw_save->iram, ctx->iram_end - ctx->iram_base); + memcpy32_toio(ctx->dram, fw_save->dram, ctx->dram_end - ctx->dram_base); + memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE); + memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base); + + kfree(fw_save->sram); + kfree(fw_save->dram); + kfree(fw_save->iram); + kfree(fw_save->ddr); + kfree(fw_save); + + block = sst_create_block(ctx, 0, FW_DWNL_ID); + if (block == NULL) + return -ENOMEM; + + + /* start and wait for ack */ + ctx->ops->start(ctx); + ret = sst_wait_timeout(ctx, block); + if (ret) { + dev_err(ctx->dev, "fw download failed %d\n", ret); + /* FW download failed due to timeout */ + ret = -EBUSY; + + } else { + sst_set_fw_state_locked(ctx, SST_FW_RUNNING); + } + + sst_free_block(ctx, block); return ret; } const struct dev_pm_ops intel_sst_pm = { + .suspend = intel_sst_suspend, + .resume = intel_sst_resume, .runtime_suspend = intel_sst_runtime_suspend, - .runtime_resume = intel_sst_runtime_resume, }; EXPORT_SYMBOL_GPL(intel_sst_pm); diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h index 562bc483d6b7..3f493862e98d 100644 --- a/sound/soc/intel/sst/sst.h +++ b/sound/soc/intel/sst/sst.h @@ -337,6 +337,13 @@ struct sst_shim_regs64 { u64 csr2; }; +struct sst_fw_save { + void *iram; + void *dram; + void *sram; + void *ddr; +}; + /** * struct intel_sst_drv - driver ops * @@ -428,6 +435,8 @@ struct intel_sst_drv { * persistent till worker thread gets called */ char firmware_name[FW_NAME_SIZE]; + + struct sst_fw_save *fw_save; }; /* misc definitions */ @@ -544,4 +553,7 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx, int sst_context_init(struct intel_sst_drv *ctx); void sst_context_cleanup(struct intel_sst_drv *ctx); void sst_configure_runtime_pm(struct intel_sst_drv *ctx); +void memcpy32_toio(void __iomem *dst, const void *src, int count); +void memcpy32_fromio(void *dst, const void __iomem *src, int count); + #endif diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c index b782dfdcdbba..b536ddd2517d 100644 --- a/sound/soc/intel/sst/sst_acpi.c +++ b/sound/soc/intel/sst/sst_acpi.c @@ -309,7 +309,7 @@ static int sst_acpi_probe(struct platform_device *pdev) ctx->shim_regs64 = devm_kzalloc(ctx->dev, sizeof(*ctx->shim_regs64), GFP_KERNEL); if (!ctx->shim_regs64) { - return -ENOMEM; + ret = -ENOMEM; goto do_sst_cleanup; } diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/sst/sst_drv_interface.c index 5f75ef3cdd22..f0e4b99b3aeb 100644 --- a/sound/soc/intel/sst/sst_drv_interface.c +++ b/sound/soc/intel/sst/sst_drv_interface.c @@ -138,12 +138,36 @@ int sst_get_stream(struct intel_sst_drv *ctx, static int sst_power_control(struct device *dev, bool state) { struct intel_sst_drv *ctx = dev_get_drvdata(dev); - - dev_dbg(ctx->dev, "state:%d", state); - if (state == true) - return pm_runtime_get_sync(dev); - else + int ret = 0; + int usage_count = 0; + +#ifdef CONFIG_PM + usage_count = atomic_read(&dev->power.usage_count); +#else + usage_count = 1; +#endif + + if (state == true) { + ret = pm_runtime_get_sync(dev); + + dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count); + if (ret < 0) { + dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret); + return ret; + } + if ((ctx->sst_state == SST_RESET) && (usage_count == 1)) { + ret = sst_load_fw(ctx); + if (ret) { + dev_err(dev, "FW download fail %d\n", ret); + sst_set_fw_state_locked(ctx, SST_RESET); + ret = sst_pm_runtime_put(ctx); + } + } + } else { + dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", usage_count); return sst_pm_runtime_put(ctx); + } + return ret; } /* @@ -572,6 +596,35 @@ static int sst_stream_drop(struct device *dev, int str_id) return sst_drop_stream(ctx, str_id); } +static int sst_stream_pause(struct device *dev, int str_id) +{ + struct stream_info *str_info; + struct intel_sst_drv *ctx = dev_get_drvdata(dev); + + if (ctx->sst_state != SST_FW_RUNNING) + return 0; + + str_info = get_stream_info(ctx, str_id); + if (!str_info) + return -EINVAL; + + return sst_pause_stream(ctx, str_id); +} + +static int sst_stream_resume(struct device *dev, int str_id) +{ + struct stream_info *str_info; + struct intel_sst_drv *ctx = dev_get_drvdata(dev); + + if (ctx->sst_state != SST_FW_RUNNING) + return 0; + + str_info = get_stream_info(ctx, str_id); + if (!str_info) + return -EINVAL; + return sst_resume_stream(ctx, str_id); +} + static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info) { int str_id = 0; @@ -633,6 +686,8 @@ static struct sst_ops pcm_ops = { .stream_init = sst_stream_init, .stream_start = sst_stream_start, .stream_drop = sst_stream_drop, + .stream_pause = sst_stream_pause, + .stream_pause_release = sst_stream_resume, .stream_read_tstamp = sst_read_timestamp, .send_byte_stream = sst_send_byte_stream, .close = sst_close_pcm_stream, diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c index 7888cd707853..e88907ae8b15 100644 --- a/sound/soc/intel/sst/sst_loader.c +++ b/sound/soc/intel/sst/sst_loader.c @@ -39,7 +39,15 @@ #include "sst.h" #include "../sst-dsp.h" -static inline void memcpy32_toio(void __iomem *dst, const void *src, int count) +void memcpy32_toio(void __iomem *dst, const void *src, int count) +{ + /* __iowrite32_copy uses 32-bit count values so divide by 4 for + * right count in words + */ + __iowrite32_copy(dst, src, count/4); +} + +void memcpy32_fromio(void *dst, const void __iomem *src, int count) { /* __iowrite32_copy uses 32-bit count values so divide by 4 for * right count in words diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index def7d8260c4e..d19483081f9b 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -579,7 +579,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) if (PTR_ERR(priv->extclk) == -EPROBE_DEFER) return -EPROBE_DEFER; } else { - if (priv->extclk == priv->clk) { + if (clk_is_match(priv->extclk, priv->clk)) { devm_clk_put(&pdev->dev, priv->extclk); priv->extclk = ERR_PTR(-EINVAL); } else { diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index a2cd3486ac55..e7c78b0406b5 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -100,17 +100,19 @@ config SND_OMAP_SOC_OMAP_TWL4030 config SND_OMAP_SOC_OMAP_ABE_TWL6040 tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" - depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || COMPILE_TEST) + depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST) select SND_OMAP_SOC_DMIC select SND_OMAP_SOC_MCPDM select SND_SOC_TWL6040 select SND_SOC_DMIC + select COMMON_CLK_PALMAS if SOC_OMAP5 help Say Y if you want to add support for SoC audio on OMAP boards using ABE and twl6040 codec. This driver currently supports: - SDP4430/Blaze boards - PandaBoard (4430) - PandaBoardES (4460) + - omap5-uevm (5432) config SND_OMAP_SOC_OMAP3_PANDORA tristate "SoC Audio support for OMAP3 Pandora" diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 706613077c15..16cc95fa4573 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -479,8 +479,8 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd) /* Add hook switch - can be used to control the codec from userspace * even if line discipline fails */ - ret = snd_soc_jack_new(rtd->codec, "hook_switch", - SND_JACK_HEADSET, &ams_delta_hook_switch); + ret = snd_soc_card_jack_new(card, "hook_switch", SND_JACK_HEADSET, + &ams_delta_hook_switch, NULL, 0); if (ret) dev_warn(card->dev, "Failed to allocate resources for hook switch, " diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index b9c65f1ad5a8..0843a68f277c 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -182,17 +182,17 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) /* Headset jack detection only if it is supported */ if (priv->jack_detection) { - ret = snd_soc_jack_new(codec, "Headset Jack", - SND_JACK_HEADSET, &hs_jack); + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET, &hs_jack, + hs_jack_pins, + ARRAY_SIZE(hs_jack_pins)); if (ret) return ret; - ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET); } - return ret; + return 0; } static const struct snd_soc_dapm_route dmic_audio_map[] = { diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index ccfb41c22e53..f7eb42aa3f38 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -352,6 +352,9 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) return ret; card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + card->name = devm_kasprintf(dev, GFP_KERNEL, "HDMI %s", dev_name(ad->dssdev)); card->owner = THIS_MODULE; diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index c7eb9dd67f60..fd99d89de6a8 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -530,8 +530,19 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, case OMAP_MCBSP_SYSCLK_CLKX_EXT: regs->srgr2 |= CLKSM; + regs->pcr0 |= SCLKME; + /* + * If McBSP is master but yet the CLKX/CLKR pin drives the SRG, + * disable output on those pins. This enables to inject the + * reference clock through CLKX/CLKR. For this to work + * set_dai_sysclk() _needs_ to be called after set_dai_fmt(). + */ + regs->pcr0 &= ~CLKXM; + break; case OMAP_MCBSP_SYSCLK_CLKR_EXT: regs->pcr0 |= SCLKME; + /* Disable ouput on CLKR pin in master mode */ + regs->pcr0 &= ~CLKRM; break; default: err = -ENODEV; diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index f4b05bc23e4b..6bb623a2a4df 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -39,7 +39,7 @@ #define pcm_omap1510() 0 #endif -static const struct snd_pcm_hardware omap_pcm_hardware = { +static struct snd_pcm_hardware omap_pcm_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | @@ -53,6 +53,24 @@ static const struct snd_pcm_hardware omap_pcm_hardware = { .buffer_bytes_max = 128 * 1024, }; +/* sDMA supports only 1, 2, and 4 byte transfer elements. */ +static void omap_pcm_limit_supported_formats(void) +{ + int i; + + for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { + switch (snd_pcm_format_physical_width(i)) { + case 8: + case 16: + case 32: + omap_pcm_hardware.formats |= (1LL << i); + break; + default: + break; + } + } +} + /* this may get called several times by oss emulation */ static int omap_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -201,7 +219,7 @@ static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd) struct snd_pcm *pcm = rtd->pcm; int ret; - ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(64)); + ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); if (ret) return ret; @@ -235,6 +253,7 @@ static struct snd_soc_platform_driver omap_soc_platform = { int omap_pcm_platform_register(struct device *dev) { + omap_pcm_limit_supported_formats(); return devm_snd_soc_register_platform(dev, &omap_soc_platform); } EXPORT_SYMBOL_GPL(omap_pcm_platform_register); diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c index fb1f6bb87cd4..3673ada43bfb 100644 --- a/sound/soc/omap/omap-twl4030.c +++ b/sound/soc/omap/omap-twl4030.c @@ -170,14 +170,10 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) if (priv->jack_detect > 0) { hs_jack_gpios[0].gpio = priv->jack_detect; - ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, - &priv->hs_jack); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&priv->hs_jack, - ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET, &priv->hs_jack, + hs_jack_pins, + ARRAY_SIZE(hs_jack_pins)); if (ret) return ret; diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 7f299357c2d2..c2ddf0fbfa28 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c @@ -311,9 +311,9 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) } /* AV jack detection */ - err = snd_soc_jack_new(codec, "AV Jack", - SND_JACK_HEADSET | SND_JACK_VIDEOOUT, - &rx51_av_jack); + err = snd_soc_card_jack_new(rtd->card, "AV Jack", + SND_JACK_HEADSET | SND_JACK_VIDEOOUT, + &rx51_av_jack, NULL, 0); if (err) { dev_err(card->dev, "Failed to add AV Jack\n"); return err; diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c index 73eb5ddf9753..9f8be7cd567e 100644 --- a/sound/soc/pxa/hx4700.c +++ b/sound/soc/pxa/hx4700.c @@ -126,17 +126,12 @@ static const struct snd_soc_dapm_route hx4700_audio_map[] = { */ static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; int err; /* Jack detection API stuff */ - err = snd_soc_jack_new(codec, "Headphone Jack", - SND_JACK_HEADPHONE, &hs_jack); - if (err) - return err; - - err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pin), - hs_jack_pin); + err = snd_soc_card_jack_new(rtd->card, "Headphone Jack", + SND_JACK_HEADPHONE, &hs_jack, hs_jack_pin, + ARRAY_SIZE(hs_jack_pin)); if (err) return err; diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index 910336c5ebeb..c20bbc042425 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -75,17 +75,12 @@ static struct snd_soc_card palm27x_asoc; static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; int err; /* Jack detection API stuff */ - err = snd_soc_jack_new(codec, "Headphone Jack", - SND_JACK_HEADPHONE, &hs_jack); - if (err) - return err; - - err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); + err = snd_soc_card_jack_new(rtd->card, "Headphone Jack", + SND_JACK_HEADPHONE, &hs_jack, hs_jack_pins, + ARRAY_SIZE(hs_jack_pins)); if (err) return err; diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c index 5001dbb9b257..1753c7d9e760 100644 --- a/sound/soc/pxa/ttc-dkb.c +++ b/sound/soc/pxa/ttc-dkb.c @@ -78,15 +78,12 @@ static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_codec *codec = rtd->codec; /* Headset jack detection */ - snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE - | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, - &hs_jack); - snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); - snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE, - &mic_jack); - snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins), - mic_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, + &hs_jack, hs_jack_pins, ARRAY_SIZE(hs_jack_pins)); + snd_soc_card_jack_new(rtd->card, "Microphone Jack", SND_JACK_MICROPHONE, + &mic_jack, mic_jack_pins, + ARRAY_SIZE(mic_jack_pins)); /* headphone, microphone detection & headset short detection */ pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE, diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c index 76ccb172d0a7..bcbfbe8303f7 100644 --- a/sound/soc/pxa/z2.c +++ b/sound/soc/pxa/z2.c @@ -143,13 +143,9 @@ static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_disable_pin(dapm, "MONO1"); /* Jack detection API stuff */ - ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, - &hs_jack); - if (ret) - goto err; - - ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET, + &hs_jack, hs_jack_pins, + ARRAY_SIZE(hs_jack_pins)); if (ret) goto err; diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 3cebf6ca03df..0632a36852c8 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -174,7 +174,7 @@ config SND_SOC_SMDK_WM8994_PCM config SND_SOC_SPEYSIDE tristate "Audio support for Wolfson Speyside" - depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 + depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C && SPI_MASTER select SND_SAMSUNG_I2S select SND_SOC_WM8996 select SND_SOC_WM9081 @@ -189,7 +189,7 @@ config SND_SOC_TOBERMORY config SND_SOC_BELLS tristate "Audio support for Wolfson Bells" - depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA + depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA && I2C && SPI_MASTER select SND_SAMSUNG_I2S select SND_SOC_WM5102 select SND_SOC_WM5110 @@ -206,7 +206,7 @@ config SND_SOC_LOWLAND config SND_SOC_LITTLEMILL tristate "Audio support for Wolfson Littlemill" - depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 + depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C select SND_SAMSUNG_I2S select MFD_WM8994 select SND_SOC_WM8994 @@ -223,7 +223,7 @@ config SND_SOC_SNOW config SND_SOC_ODROIDX2 tristate "Audio support for Odroid-X2 and Odroid-U3" - depends on SND_SOC_SAMSUNG + depends on SND_SOC_SAMSUNG && I2C select SND_SOC_MAX98090 select SND_SAMSUNG_I2S help @@ -231,6 +231,6 @@ config SND_SOC_ODROIDX2 config SND_SOC_ARNDALE_RT5631_ALC5631 tristate "Audio support for RT5631(ALC5631) on Arndale Board" - depends on SND_SOC_SAMSUNG + depends on SND_SOC_SAMSUNG && I2C select SND_SAMSUNG_I2S select SND_SOC_RT5631 diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c index 59b044255b78..c72e9fb26658 100644 --- a/sound/soc/samsung/h1940_uda1380.c +++ b/sound/soc/samsung/h1940_uda1380.c @@ -162,13 +162,8 @@ static struct platform_device *s3c24xx_snd_device; static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - - snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, - &hp_jack); - - snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), - hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE, + &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins)); snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), hp_jack_gpios); diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index 141519c21e21..31a820eb0ac3 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -260,12 +260,12 @@ static int littlemill_late_probe(struct snd_soc_card *card) if (ret < 0) return ret; - ret = snd_soc_jack_new(codec, "Headset", - SND_JACK_HEADSET | SND_JACK_MECHANICAL | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_BTN_4 | SND_JACK_BTN_5, - &littlemill_headset); + ret = snd_soc_card_jack_new(card, "Headset", + SND_JACK_HEADSET | SND_JACK_MECHANICAL | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_BTN_4 | SND_JACK_BTN_5, + &littlemill_headset, NULL, 0); if (ret) return ret; diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c index 243dea7ba38f..5f156093101e 100644 --- a/sound/soc/samsung/lowland.c +++ b/sound/soc/samsung/lowland.c @@ -56,16 +56,10 @@ static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_jack_new(codec, "Headset", - SND_JACK_LINEOUT | SND_JACK_HEADSET | - SND_JACK_BTN_0, - &lowland_headset); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&lowland_headset, - ARRAY_SIZE(lowland_headset_pins), - lowland_headset_pins); + ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT | + SND_JACK_HEADSET | SND_JACK_BTN_0, + &lowland_headset, lowland_headset_pins, + ARRAY_SIZE(lowland_headset_pins)); if (ret) return ret; diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c index 873f2cb4bebe..35e37c457f1f 100644 --- a/sound/soc/samsung/rx1950_uda1380.c +++ b/sound/soc/samsung/rx1950_uda1380.c @@ -211,13 +211,8 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream, static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - - snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, - &hp_jack); - - snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), - hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE, + &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins)); snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), hp_jack_gpios); diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c index 8291d2a5f152..dfbe2db1c407 100644 --- a/sound/soc/samsung/smartq_wm8987.c +++ b/sound/soc/samsung/smartq_wm8987.c @@ -151,13 +151,10 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); /* Headphone jack detection */ - err = snd_soc_jack_new(codec, "Headphone Jack", - SND_JACK_HEADPHONE, &smartq_jack); - if (err) - return err; - - err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins), - smartq_jack_pins); + err = snd_soc_card_jack_new(rtd->card, "Headphone Jack", + SND_JACK_HEADPHONE, &smartq_jack, + smartq_jack_pins, + ARRAY_SIZE(smartq_jack_pins)); if (err) return err; diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 5ec7c52282f2..2dcb988bdff2 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -153,16 +153,10 @@ static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd) pr_err("Failed to request HP_SEL GPIO: %d\n", ret); gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity); - ret = snd_soc_jack_new(codec, "Headset", - SND_JACK_LINEOUT | SND_JACK_HEADSET | - SND_JACK_BTN_0, - &speyside_headset); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&speyside_headset, - ARRAY_SIZE(speyside_headset_pins), - speyside_headset_pins); + ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT | + SND_JACK_HEADSET | SND_JACK_BTN_0, + &speyside_headset, speyside_headset_pins, + ARRAY_SIZE(speyside_headset_pins)); if (ret) return ret; diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c index 9c80506527c4..85ccfb7188cb 100644 --- a/sound/soc/samsung/tobermory.c +++ b/sound/soc/samsung/tobermory.c @@ -179,15 +179,10 @@ static int tobermory_late_probe(struct snd_soc_card *card) if (ret < 0) return ret; - ret = snd_soc_jack_new(codec, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &tobermory_headset); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&tobermory_headset, - ARRAY_SIZE(tobermory_headset_pins), - tobermory_headset_pins); + ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET | + SND_JACK_BTN_0, &tobermory_headset, + tobermory_headset_pins, + ARRAY_SIZE(tobermory_headset_pins)); if (ret) return ret; diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1b53605f7154..31202e95be1e 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -149,16 +149,29 @@ char *rsnd_mod_dma_name(struct rsnd_mod *mod) return mod->ops->dma_name(mod); } -void rsnd_mod_init(struct rsnd_mod *mod, +int rsnd_mod_init(struct rsnd_mod *mod, struct rsnd_mod_ops *ops, struct clk *clk, enum rsnd_mod_type type, int id) { + int ret = clk_prepare(clk); + + if (ret) + return ret; + mod->id = id; mod->ops = ops; mod->type = type; mod->clk = clk; + + return ret; +} + +void rsnd_mod_quit(struct rsnd_mod *mod) +{ + if (mod->clk) + clk_unprepare(mod->clk); } /* @@ -1252,6 +1265,8 @@ static int rsnd_probe(struct platform_device *pdev) goto exit_snd_probe; } + dev_set_drvdata(dev, priv); + /* * asoc register */ @@ -1268,8 +1283,6 @@ static int rsnd_probe(struct platform_device *pdev) goto exit_snd_soc; } - dev_set_drvdata(dev, priv); - pm_runtime_enable(dev); dev_info(dev, "probed\n"); @@ -1290,6 +1303,12 @@ static int rsnd_remove(struct platform_device *pdev) { struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); struct rsnd_dai *rdai; + void (*remove_func[])(struct platform_device *pdev, + struct rsnd_priv *priv) = { + rsnd_ssi_remove, + rsnd_src_remove, + rsnd_dvc_remove, + }; int ret = 0, i; pm_runtime_disable(&pdev->dev); @@ -1299,6 +1318,9 @@ static int rsnd_remove(struct platform_device *pdev) ret |= rsnd_dai_call(remove, &rdai->capture, priv); } + for (i = 0; i < ARRAY_SIZE(remove_func); i++) + remove_func[i](pdev, priv); + snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index d7f9ed959c4e..261997a3f589 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -333,7 +333,7 @@ int rsnd_dvc_probe(struct platform_device *pdev, struct rsnd_dvc *dvc; struct clk *clk; char name[RSND_DVC_NAME_SIZE]; - int i, nr; + int i, nr, ret; rsnd_of_parse_dvc(pdev, of_data, priv); @@ -366,11 +366,24 @@ int rsnd_dvc_probe(struct platform_device *pdev, dvc->info = &info->dvc_info[i]; - rsnd_mod_init(&dvc->mod, &rsnd_dvc_ops, + ret = rsnd_mod_init(&dvc->mod, &rsnd_dvc_ops, clk, RSND_MOD_DVC, i); + if (ret) + return ret; dev_dbg(dev, "CMD%d probed\n", i); } return 0; } + +void rsnd_dvc_remove(struct platform_device *pdev, + struct rsnd_priv *priv) +{ + struct rsnd_dvc *dvc; + int i; + + for_each_rsnd_dvc(dvc, priv, i) { + rsnd_mod_quit(&dvc->mod); + } +} diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index e7914bd610e2..1bccc5515b5a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -260,14 +260,15 @@ struct rsnd_mod { #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) #define rsnd_mod_to_io(mod) ((mod)->io) #define rsnd_mod_id(mod) ((mod)->id) -#define rsnd_mod_hw_start(mod) clk_prepare_enable((mod)->clk) -#define rsnd_mod_hw_stop(mod) clk_disable_unprepare((mod)->clk) +#define rsnd_mod_hw_start(mod) clk_enable((mod)->clk) +#define rsnd_mod_hw_stop(mod) clk_disable((mod)->clk) -void rsnd_mod_init(struct rsnd_mod *mod, +int rsnd_mod_init(struct rsnd_mod *mod, struct rsnd_mod_ops *ops, struct clk *clk, enum rsnd_mod_type type, int id); +void rsnd_mod_quit(struct rsnd_mod *mod); char *rsnd_mod_name(struct rsnd_mod *mod); char *rsnd_mod_dma_name(struct rsnd_mod *mod); @@ -480,6 +481,8 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod, int rsnd_src_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv); +void rsnd_src_remove(struct platform_device *pdev, + struct rsnd_priv *priv); struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, struct rsnd_dai_stream *io, @@ -498,6 +501,8 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod); int rsnd_ssi_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv); +void rsnd_ssi_remove(struct platform_device *pdev, + struct rsnd_priv *priv); struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 81c182b4bad5..c77d059edc84 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -850,7 +850,7 @@ int rsnd_src_probe(struct platform_device *pdev, struct rsnd_mod_ops *ops; struct clk *clk; char name[RSND_SRC_NAME_SIZE]; - int i, nr; + int i, nr, ret; ops = NULL; if (rsnd_is_gen1(priv)) @@ -890,10 +890,23 @@ int rsnd_src_probe(struct platform_device *pdev, src->info = &info->src_info[i]; - rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i); + ret = rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i); + if (ret) + return ret; dev_dbg(dev, "SRC%d probed\n", i); } return 0; } + +void rsnd_src_remove(struct platform_device *pdev, + struct rsnd_priv *priv) +{ + struct rsnd_src *src; + int i; + + for_each_rsnd_src(src, priv, i) { + rsnd_mod_quit(&src->mod); + } +} diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 9e7b627c08e2..f7cb1fd635a0 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -697,7 +697,7 @@ int rsnd_ssi_probe(struct platform_device *pdev, struct clk *clk; struct rsnd_ssi *ssi; char name[RSND_SSI_NAME_SIZE]; - int i, nr; + int i, nr, ret; rsnd_of_parse_ssi(pdev, of_data, priv); @@ -732,10 +732,23 @@ int rsnd_ssi_probe(struct platform_device *pdev, else if (rsnd_ssi_pio_available(ssi)) ops = &rsnd_ssi_pio_ops; - rsnd_mod_init(&ssi->mod, ops, clk, RSND_MOD_SSI, i); + ret = rsnd_mod_init(&ssi->mod, ops, clk, RSND_MOD_SSI, i); + if (ret) + return ret; rsnd_ssi_parent_clk_setup(priv, ssi); } return 0; } + +void rsnd_ssi_remove(struct platform_device *pdev, + struct rsnd_priv *priv) +{ + struct rsnd_ssi *ssi; + int i; + + for_each_rsnd_ssi(ssi, priv, i) { + rsnd_mod_quit(&ssi->mod); + } +} diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 30579ca5bacb..2fb3bf738b5b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -292,6 +292,9 @@ static const struct file_operations codec_reg_fops = { static void soc_init_component_debugfs(struct snd_soc_component *component) { + if (!component->card->debugfs_card_root) + return; + if (component->debugfs_prefix) { char *name; @@ -347,6 +350,8 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, if (!buf) return -ENOMEM; + mutex_lock(&client_mutex); + list_for_each_entry(codec, &codec_list, list) { len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", codec->component.name); @@ -358,6 +363,8 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, } } + mutex_unlock(&client_mutex); + if (ret >= 0) ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); @@ -382,6 +389,8 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf, if (!buf) return -ENOMEM; + mutex_lock(&client_mutex); + list_for_each_entry(component, &component_list, list) { list_for_each_entry(dai, &component->dai_list, list) { len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", @@ -395,6 +404,8 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf, } } + mutex_unlock(&client_mutex); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); kfree(buf); @@ -418,6 +429,8 @@ static ssize_t platform_list_read_file(struct file *file, if (!buf) return -ENOMEM; + mutex_lock(&client_mutex); + list_for_each_entry(platform, &platform_list, list) { len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", platform->component.name); @@ -429,6 +442,8 @@ static ssize_t platform_list_read_file(struct file *file, } } + mutex_unlock(&client_mutex); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); kfree(buf); @@ -443,6 +458,9 @@ static const struct file_operations platform_list_fops = { static void soc_init_card_debugfs(struct snd_soc_card *card) { + if (!snd_soc_debugfs_root) + return; + card->debugfs_card_root = debugfs_create_dir(card->name, snd_soc_debugfs_root); if (!card->debugfs_card_root) { @@ -464,6 +482,34 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card) debugfs_remove_recursive(card->debugfs_card_root); } + +static void snd_soc_debugfs_init(void) +{ + snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL); + if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) { + pr_warn("ASoC: Failed to create debugfs directory\n"); + snd_soc_debugfs_root = NULL; + return; + } + + if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL, + &codec_list_fops)) + pr_warn("ASoC: Failed to create CODEC list debugfs file\n"); + + if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL, + &dai_list_fops)) + pr_warn("ASoC: Failed to create DAI list debugfs file\n"); + + if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL, + &platform_list_fops)) + pr_warn("ASoC: Failed to create platform list debugfs file\n"); +} + +static void snd_soc_debugfs_exit(void) +{ + debugfs_remove_recursive(snd_soc_debugfs_root); +} + #else #define soc_init_codec_debugfs NULL @@ -485,6 +531,15 @@ static inline void soc_init_card_debugfs(struct snd_soc_card *card) static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card) { } + +static inline void snd_soc_debugfs_init(void) +{ +} + +static inline void snd_soc_debugfs_exit(void) +{ +} + #endif struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, @@ -583,15 +638,9 @@ int snd_soc_suspend(struct device *dev) cpu_dai->driver->suspend(cpu_dai); } - /* close any waiting streams and save state */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai **codec_dais = card->rtd[i].codec_dais; + /* close any waiting streams */ + for (i = 0; i < card->num_rtd; i++) flush_delayed_work(&card->rtd[i].delayed_work); - for (j = 0; j < card->rtd[i].num_codecs; j++) { - codec_dais[j]->codec->dapm.suspend_bias_level = - codec_dais[j]->codec->dapm.bias_level; - } - } for (i = 0; i < card->num_rtd; i++) { @@ -836,6 +885,8 @@ static struct snd_soc_component *soc_find_component( { struct snd_soc_component *component; + lockdep_assert_held(&client_mutex); + list_for_each_entry(component, &component_list, list) { if (of_node) { if (component->dev->of_node == of_node) @@ -854,6 +905,8 @@ static struct snd_soc_dai *snd_soc_find_dai( struct snd_soc_component *component; struct snd_soc_dai *dai; + lockdep_assert_held(&client_mutex); + /* Find CPU DAI from registered DAIs*/ list_for_each_entry(component, &component_list, list) { if (dlc->of_node && component->dev->of_node != dlc->of_node) @@ -1306,21 +1359,17 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) } } + if (dai_link->dai_fmt) + snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt); + ret = soc_post_component_init(rtd, dai_link->name); if (ret) return ret; #ifdef CONFIG_DEBUG_FS /* add DPCM sysfs entries */ - if (dai_link->dynamic) { - ret = soc_dpcm_debugfs_add(rtd); - if (ret < 0) { - dev_err(rtd->dev, - "ASoC: failed to add dpcm sysfs entries: %d\n", - ret); - return ret; - } - } + if (dai_link->dynamic) + soc_dpcm_debugfs_add(rtd); #endif if (cpu_dai->driver->compress_dai) { @@ -1410,7 +1459,6 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) /* unregister the rtd device */ if (rtd->dev_registered) { - device_remove_file(rtd->dev, &dev_attr_codec_reg); device_unregister(rtd->dev); rtd->dev_registered = 0; } @@ -1508,6 +1556,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) struct snd_soc_codec *codec; int ret, i, order; + mutex_lock(&client_mutex); mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); /* bind DAIs */ @@ -1543,6 +1592,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) goto base_error; } + soc_init_card_debugfs(card); + card->dapm.bias_level = SND_SOC_BIAS_OFF; card->dapm.dev = card->dev; card->dapm.card = card; @@ -1561,6 +1612,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, card->num_dapm_widgets); + if (card->of_dapm_widgets) + snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets, + card->num_of_dapm_widgets); + /* initialise the sound card only once */ if (card->probe) { ret = card->probe(card); @@ -1616,11 +1671,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, card->num_dapm_routes); - for (i = 0; i < card->num_links; i++) { - if (card->dai_link[i].dai_fmt) - snd_soc_runtime_set_dai_fmt(&card->rtd[i], - card->dai_link[i].dai_fmt); - } + if (card->of_dapm_routes) + snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes, + card->num_of_dapm_routes); snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), "%s", card->name); @@ -1662,6 +1715,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) card->instantiated = 1; snd_soc_dapm_sync(&card->dapm); mutex_unlock(&card->mutex); + mutex_unlock(&client_mutex); return 0; @@ -1676,10 +1730,12 @@ card_probe_error: if (card->remove) card->remove(card); + soc_cleanup_card_debugfs(card); snd_card_free(card->snd_card); base_error: mutex_unlock(&card->mutex); + mutex_unlock(&client_mutex); return ret; } @@ -2353,8 +2409,6 @@ int snd_soc_register_card(struct snd_soc_card *card) snd_soc_initialize_card_lists(card); - soc_init_card_debugfs(card); - card->rtd = devm_kzalloc(card->dev, sizeof(struct snd_soc_pcm_runtime) * (card->num_links + card->num_aux_devs), @@ -2385,7 +2439,7 @@ int snd_soc_register_card(struct snd_soc_card *card) ret = snd_soc_instantiate_card(card); if (ret != 0) - soc_cleanup_card_debugfs(card); + return ret; /* deactivate pins to sleep state */ for (i = 0; i < card->num_rtd; i++) { @@ -2713,13 +2767,6 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component) list_del(&component->list); } -static void snd_soc_component_del(struct snd_soc_component *component) -{ - mutex_lock(&client_mutex); - snd_soc_component_del_unlocked(component); - mutex_unlock(&client_mutex); -} - int snd_soc_register_component(struct device *dev, const struct snd_soc_component_driver *cmpnt_drv, struct snd_soc_dai_driver *dai_drv, @@ -2767,14 +2814,17 @@ void snd_soc_unregister_component(struct device *dev) { struct snd_soc_component *cmpnt; + mutex_lock(&client_mutex); list_for_each_entry(cmpnt, &component_list, list) { if (dev == cmpnt->dev && cmpnt->registered_as_component) goto found; } + mutex_unlock(&client_mutex); return; found: - snd_soc_component_del(cmpnt); + snd_soc_component_del_unlocked(cmpnt); + mutex_unlock(&client_mutex); snd_soc_component_cleanup(cmpnt); kfree(cmpnt); } @@ -2882,10 +2932,14 @@ struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev) { struct snd_soc_platform *platform; + mutex_lock(&client_mutex); list_for_each_entry(platform, &platform_list, list) { - if (dev == platform->dev) + if (dev == platform->dev) { + mutex_unlock(&client_mutex); return platform; + } } + mutex_unlock(&client_mutex); return NULL; } @@ -3090,15 +3144,15 @@ void snd_soc_unregister_codec(struct device *dev) { struct snd_soc_codec *codec; + mutex_lock(&client_mutex); list_for_each_entry(codec, &codec_list, list) { if (dev == codec->dev) goto found; } + mutex_unlock(&client_mutex); return; found: - - mutex_lock(&client_mutex); list_del(&codec->list); snd_soc_component_del_unlocked(&codec->component); mutex_unlock(&client_mutex); @@ -3223,8 +3277,8 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, widgets[i].name = wname; } - card->dapm_widgets = widgets; - card->num_dapm_widgets = num_widgets; + card->of_dapm_widgets = widgets; + card->num_of_dapm_widgets = num_widgets; return 0; } @@ -3308,8 +3362,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, } } - card->num_dapm_routes = num_routes; - card->dapm_routes = routes; + card->num_of_dapm_routes = num_routes; + card->of_dapm_routes = routes; return 0; } @@ -3568,26 +3622,7 @@ EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs); static int __init snd_soc_init(void) { -#ifdef CONFIG_DEBUG_FS - snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL); - if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) { - pr_warn("ASoC: Failed to create debugfs directory\n"); - snd_soc_debugfs_root = NULL; - } - - if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL, - &codec_list_fops)) - pr_warn("ASoC: Failed to create CODEC list debugfs file\n"); - - if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL, - &dai_list_fops)) - pr_warn("ASoC: Failed to create DAI list debugfs file\n"); - - if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL, - &platform_list_fops)) - pr_warn("ASoC: Failed to create platform list debugfs file\n"); -#endif - + snd_soc_debugfs_init(); snd_soc_util_init(); return platform_driver_register(&soc_driver); @@ -3597,9 +3632,9 @@ module_init(snd_soc_init); static void __exit snd_soc_exit(void) { snd_soc_util_exit(); + snd_soc_debugfs_exit(); #ifdef CONFIG_DEBUG_FS - debugfs_remove_recursive(snd_soc_debugfs_root); #endif platform_driver_unregister(&soc_driver); } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 95337c832258..dc05469e2ccf 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1888,6 +1888,9 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, { struct dentry *d; + if (!parent) + return; + dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); if (!dapm->debugfs_dapm) { diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 4380dcc064a5..9f60c25c4568 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -22,30 +22,42 @@ #include <trace/events/asoc.h> /** - * snd_soc_jack_new - Create a new jack - * @codec: ASoC codec + * snd_soc_card_jack_new - Create a new jack + * @card: ASoC card * @id: an identifying string for this jack * @type: a bitmask of enum snd_jack_type values that can be detected by * this jack * @jack: structure to use for the jack + * @pins: Array of jack pins to be added to the jack or NULL + * @num_pins: Number of elements in the @pins array * * Creates a new jack object. * * Returns zero if successful, or a negative error code on failure. * On success jack will be initialised. */ -int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type, - struct snd_soc_jack *jack) +int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type, + struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins, + unsigned int num_pins) { + int ret; + mutex_init(&jack->mutex); - jack->codec = codec; + jack->card = card; INIT_LIST_HEAD(&jack->pins); INIT_LIST_HEAD(&jack->jack_zones); BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier); - return snd_jack_new(codec->component.card->snd_card, id, type, &jack->jack); + ret = snd_jack_new(card->snd_card, id, type, &jack->jack); + if (ret) + return ret; + + if (num_pins) + return snd_soc_jack_add_pins(jack, num_pins, pins); + + return 0; } -EXPORT_SYMBOL_GPL(snd_soc_jack_new); +EXPORT_SYMBOL_GPL(snd_soc_card_jack_new); /** * snd_soc_jack_report - Report the current status for a jack @@ -63,7 +75,6 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_new); */ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) { - struct snd_soc_codec *codec; struct snd_soc_dapm_context *dapm; struct snd_soc_jack_pin *pin; unsigned int sync = 0; @@ -74,8 +85,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) if (!jack) return; - codec = jack->codec; - dapm = &codec->dapm; + dapm = &jack->card->dapm; mutex_lock(&jack->mutex); @@ -175,12 +185,12 @@ int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, for (i = 0; i < count; i++) { if (!pins[i].pin) { - dev_err(jack->codec->dev, "ASoC: No name for pin %d\n", + dev_err(jack->card->dev, "ASoC: No name for pin %d\n", i); return -EINVAL; } if (!pins[i].mask) { - dev_err(jack->codec->dev, "ASoC: No mask for pin %d" + dev_err(jack->card->dev, "ASoC: No mask for pin %d" " (%s)\n", i, pins[i].pin); return -EINVAL; } @@ -260,7 +270,7 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio) static irqreturn_t gpio_handler(int irq, void *data) { struct snd_soc_jack_gpio *gpio = data; - struct device *dev = gpio->jack->codec->component.card->dev; + struct device *dev = gpio->jack->card->dev; trace_snd_soc_jack_irq(gpio->name); @@ -299,7 +309,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, for (i = 0; i < count; i++) { if (!gpios[i].name) { - dev_err(jack->codec->dev, + dev_err(jack->card->dev, "ASoC: No name for gpio at index %d\n", i); ret = -EINVAL; goto undo; @@ -320,7 +330,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, } else { /* legacy GPIO number */ if (!gpio_is_valid(gpios[i].gpio)) { - dev_err(jack->codec->dev, + dev_err(jack->card->dev, "ASoC: Invalid gpio %d\n", gpios[i].gpio); ret = -EINVAL; @@ -350,7 +360,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, if (gpios[i].wake) { ret = irq_set_irq_wake(gpiod_to_irq(gpios[i].desc), 1); if (ret != 0) - dev_err(jack->codec->dev, + dev_err(jack->card->dev, "ASoC: Failed to mark GPIO at index %d as wake source: %d\n", i, ret); } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 6b0136e7cb88..35fe58f4fa86 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1097,8 +1097,9 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, stream ? "<-" : "->", be->dai_link->name); #ifdef CONFIG_DEBUG_FS - dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644, - fe->debugfs_dpcm_root, &dpcm->state); + if (fe->debugfs_dpcm_root) + dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644, + fe->debugfs_dpcm_root, &dpcm->state); #endif return 1; } @@ -2511,6 +2512,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) /* DAPM dai link stream work */ INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); + pcm->nonatomic = rtd->dai_link->nonatomic; rtd->pcm = pcm; pcm->private_data = rtd; @@ -2802,10 +2804,13 @@ static const struct file_operations dpcm_state_fops = { .llseek = default_llseek, }; -int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) +void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) { if (!rtd->dai_link) - return 0; + return; + + if (!rtd->card->debugfs_card_root) + return; rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name, rtd->card->debugfs_card_root); @@ -2813,13 +2818,11 @@ int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) dev_dbg(rtd->dev, "ASoC: Failed to create dpcm debugfs directory %s\n", rtd->dai_link->name); - return -EINVAL; + return; } rtd->debugfs_dpcm_state = debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root, rtd, &dpcm_state_fops); - - return 0; } #endif diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index 769aca2fc5f5..6dcd06a966c7 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -106,11 +106,10 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = &codec->dapm; struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(rtd->card); - snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, - &tegra_alc5632_hs_jack); - snd_soc_jack_add_pins(&tegra_alc5632_hs_jack, - ARRAY_SIZE(tegra_alc5632_hs_jack_pins), - tegra_alc5632_hs_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET, + &tegra_alc5632_hs_jack, + tegra_alc5632_hs_jack_pins, + ARRAY_SIZE(tegra_alc5632_hs_jack_pins)); if (gpio_is_valid(machine->gpio_hp_det)) { tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det; diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index af3fb997b752..902da36581d1 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c @@ -133,24 +133,26 @@ static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), }; static const struct snd_kcontrol_new tegra_max98090_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), + SOC_DAPM_PIN_SWITCH("Int Mic"), }; static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; struct tegra_max98090 *machine = snd_soc_card_get_drvdata(rtd->card); if (gpio_is_valid(machine->gpio_hp_det)) { - snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE, - &tegra_max98090_hp_jack); - snd_soc_jack_add_pins(&tegra_max98090_hp_jack, - ARRAY_SIZE(tegra_max98090_hp_jack_pins), - tegra_max98090_hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphones", + SND_JACK_HEADPHONE, + &tegra_max98090_hp_jack, + tegra_max98090_hp_jack_pins, + ARRAY_SIZE(tegra_max98090_hp_jack_pins)); tegra_max98090_hp_jack_gpio.gpio = machine->gpio_hp_det; snd_soc_jack_add_gpios(&tegra_max98090_hp_jack, @@ -159,11 +161,11 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd) } if (gpio_is_valid(machine->gpio_mic_det)) { - snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, - &tegra_max98090_mic_jack); - snd_soc_jack_add_pins(&tegra_max98090_mic_jack, - ARRAY_SIZE(tegra_max98090_mic_jack_pins), - tegra_max98090_mic_jack_pins); + snd_soc_card_jack_new(rtd->card, "Mic Jack", + SND_JACK_MICROPHONE, + &tegra_max98090_mic_jack, + tegra_max98090_mic_jack_pins, + ARRAY_SIZE(tegra_max98090_mic_jack_pins)); tegra_max98090_mic_jack_gpio.gpio = machine->gpio_mic_det; snd_soc_jack_add_gpios(&tegra_max98090_mic_jack, diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index ed759a3076b8..773daecaa5e8 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -108,15 +108,11 @@ static const struct snd_kcontrol_new tegra_rt5640_controls[] = { static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(rtd->card); - snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE, - &tegra_rt5640_hp_jack); - snd_soc_jack_add_pins(&tegra_rt5640_hp_jack, - ARRAY_SIZE(tegra_rt5640_hp_jack_pins), - tegra_rt5640_hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphones", SND_JACK_HEADPHONE, + &tegra_rt5640_hp_jack, tegra_rt5640_hp_jack_pins, + ARRAY_SIZE(tegra_rt5640_hp_jack_pins)); if (gpio_is_valid(machine->gpio_hp_det)) { tegra_rt5640_hp_jack_gpio.gpio = machine->gpio_hp_det; diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c index e4cf978a6e3a..68d8b67e79c1 100644 --- a/sound/soc/tegra/tegra_rt5677.c +++ b/sound/soc/tegra/tegra_rt5677.c @@ -146,10 +146,9 @@ static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = &codec->dapm; struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(rtd->card); - snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, - &tegra_rt5677_hp_jack); - snd_soc_jack_add_pins(&tegra_rt5677_hp_jack, 1, - &tegra_rt5677_hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE, + &tegra_rt5677_hp_jack, + &tegra_rt5677_hp_jack_pins, 1); if (gpio_is_valid(machine->gpio_hp_det)) { tegra_rt5677_hp_jack_gpio.gpio = machine->gpio_hp_det; @@ -158,10 +157,9 @@ static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd) } - snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, - &tegra_rt5677_mic_jack); - snd_soc_jack_add_pins(&tegra_rt5677_mic_jack, 1, - &tegra_rt5677_mic_jack_pins); + snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE, + &tegra_rt5677_mic_jack, + &tegra_rt5677_mic_jack_pins, 1); if (gpio_is_valid(machine->gpio_mic_present)) { tegra_rt5677_mic_jack_gpio.gpio = machine->gpio_mic_present; diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index e52420dae2b4..4a95b70f0cf0 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -177,21 +177,19 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) if (gpio_is_valid(machine->gpio_hp_det)) { tegra_wm8903_hp_jack_gpio.gpio = machine->gpio_hp_det; - snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, - &tegra_wm8903_hp_jack); - snd_soc_jack_add_pins(&tegra_wm8903_hp_jack, - ARRAY_SIZE(tegra_wm8903_hp_jack_pins), - tegra_wm8903_hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphone Jack", + SND_JACK_HEADPHONE, &tegra_wm8903_hp_jack, + tegra_wm8903_hp_jack_pins, + ARRAY_SIZE(tegra_wm8903_hp_jack_pins)); snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, 1, &tegra_wm8903_hp_jack_gpio); } - snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, - &tegra_wm8903_mic_jack); - snd_soc_jack_add_pins(&tegra_wm8903_mic_jack, - ARRAY_SIZE(tegra_wm8903_mic_jack_pins), - tegra_wm8903_mic_jack_pins); + snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE, + &tegra_wm8903_mic_jack, + tegra_wm8903_mic_jack_pins, + ARRAY_SIZE(tegra_wm8903_mic_jack_pins)); wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE, 0); diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 05dee690f487..97ed593f6010 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -39,7 +39,7 @@ static void change_volume(struct urb *urb_out, int volume[], for (; p < buf_end; ++p) { short pv = le16_to_cpu(*p); int val = (pv * volume[chn & 1]) >> 8; - pv = clamp(val, 0x7fff, -0x8000); + pv = clamp(val, -0x8000, 0x7fff); *p = cpu_to_le16(pv); ++chn; } @@ -54,7 +54,7 @@ static void change_volume(struct urb *urb_out, int volume[], val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16); val = (val * volume[chn & 1]) >> 8; - val = clamp(val, 0x7fffff, -0x800000); + val = clamp(val, -0x800000, 0x7fffff); p[0] = val; p[1] = val >> 8; p[2] = val >> 16; @@ -126,7 +126,7 @@ static void add_monitor_signal(struct urb *urb_out, unsigned char *signal, short pov = le16_to_cpu(*po); short piv = le16_to_cpu(*pi); int val = pov + ((piv * volume) >> 8); - pov = clamp(val, 0x7fff, -0x8000); + pov = clamp(val, -0x8000, 0x7fff); *po = cpu_to_le16(pov); } } diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 67d476548dcf..07f984d5f516 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1773,6 +1773,36 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + USB_DEVICE(0x0582, 0x0159), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Roland", */ + /* .product_name = "UA-22", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, /* this catches most recent vendor-specific Roland devices */ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR | |