162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* -*- linux-c -*- * 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * ALSA driver for the digigram lx6464es interface 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 2008, 2009 Tim Blechmann <tim@klingt.org> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/pci.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <sound/initval.h> 1662306a36Sopenharmony_ci#include <sound/control.h> 1762306a36Sopenharmony_ci#include <sound/info.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "lx6464es.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciMODULE_AUTHOR("Tim Blechmann"); 2262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2362306a36Sopenharmony_ciMODULE_DESCRIPTION("digigram lx6464es"); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 2662306a36Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 2762306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 3062306a36Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for Digigram LX6464ES interface."); 3162306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 3262306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for Digigram LX6464ES interface."); 3362306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 3462306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable/disable specific Digigram LX6464ES soundcards."); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic const char card_name[] = "LX6464ES"; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic const struct pci_device_id snd_lx6464es_ids[] = { 4262306a36Sopenharmony_ci { PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES, 4362306a36Sopenharmony_ci PCI_VENDOR_ID_DIGIGRAM, 4462306a36Sopenharmony_ci PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM), 4562306a36Sopenharmony_ci }, /* LX6464ES */ 4662306a36Sopenharmony_ci { PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES, 4762306a36Sopenharmony_ci PCI_VENDOR_ID_DIGIGRAM, 4862306a36Sopenharmony_ci PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM), 4962306a36Sopenharmony_ci }, /* LX6464ES-CAE */ 5062306a36Sopenharmony_ci { PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES, 5162306a36Sopenharmony_ci PCI_VENDOR_ID_DIGIGRAM, 5262306a36Sopenharmony_ci PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ESE_SERIAL_SUBSYSTEM), 5362306a36Sopenharmony_ci }, /* LX6464ESe */ 5462306a36Sopenharmony_ci { PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES, 5562306a36Sopenharmony_ci PCI_VENDOR_ID_DIGIGRAM, 5662306a36Sopenharmony_ci PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ESE_CAE_SERIAL_SUBSYSTEM), 5762306a36Sopenharmony_ci }, /* LX6464ESe-CAE */ 5862306a36Sopenharmony_ci { 0, }, 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_lx6464es_ids); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* PGO pour USERo dans le registre pci_0x06/loc_0xEC */ 6662306a36Sopenharmony_ci#define CHIPSC_RESET_XILINX (1L<<16) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* alsa callbacks */ 7062306a36Sopenharmony_cistatic const struct snd_pcm_hardware lx_caps = { 7162306a36Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | 7262306a36Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 7362306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 7462306a36Sopenharmony_ci SNDRV_PCM_INFO_SYNC_START), 7562306a36Sopenharmony_ci .formats = (SNDRV_PCM_FMTBIT_S16_LE | 7662306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_BE | 7762306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE | 7862306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3BE), 7962306a36Sopenharmony_ci .rates = (SNDRV_PCM_RATE_CONTINUOUS | 8062306a36Sopenharmony_ci SNDRV_PCM_RATE_8000_192000), 8162306a36Sopenharmony_ci .rate_min = 8000, 8262306a36Sopenharmony_ci .rate_max = 192000, 8362306a36Sopenharmony_ci .channels_min = 2, 8462306a36Sopenharmony_ci .channels_max = 64, 8562306a36Sopenharmony_ci .buffer_bytes_max = 64*2*3*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER, 8662306a36Sopenharmony_ci .period_bytes_min = (2*2*MICROBLAZE_IBL_MIN*2), 8762306a36Sopenharmony_ci .period_bytes_max = (4*64*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER), 8862306a36Sopenharmony_ci .periods_min = 2, 8962306a36Sopenharmony_ci .periods_max = MAX_STREAM_BUFFER, 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic int lx_set_granularity(struct lx6464es *chip, u32 gran); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int lx_hardware_open(struct lx6464es *chip, 9662306a36Sopenharmony_ci struct snd_pcm_substream *substream) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci int err = 0; 9962306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 10062306a36Sopenharmony_ci int channels = runtime->channels; 10162306a36Sopenharmony_ci int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci snd_pcm_uframes_t period_size = runtime->period_size; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci dev_dbg(chip->card->dev, "allocating pipe for %d channels\n", channels); 10662306a36Sopenharmony_ci err = lx_pipe_allocate(chip, 0, is_capture, channels); 10762306a36Sopenharmony_ci if (err < 0) { 10862306a36Sopenharmony_ci dev_err(chip->card->dev, LXP "allocating pipe failed\n"); 10962306a36Sopenharmony_ci return err; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci err = lx_set_granularity(chip, period_size); 11362306a36Sopenharmony_ci if (err < 0) { 11462306a36Sopenharmony_ci dev_err(chip->card->dev, "setting granularity to %ld failed\n", 11562306a36Sopenharmony_ci period_size); 11662306a36Sopenharmony_ci return err; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic int lx_hardware_start(struct lx6464es *chip, 12362306a36Sopenharmony_ci struct snd_pcm_substream *substream) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci int err = 0; 12662306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 12762306a36Sopenharmony_ci int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci dev_dbg(chip->card->dev, "setting stream format\n"); 13062306a36Sopenharmony_ci err = lx_stream_set_format(chip, runtime, 0, is_capture); 13162306a36Sopenharmony_ci if (err < 0) { 13262306a36Sopenharmony_ci dev_err(chip->card->dev, "setting stream format failed\n"); 13362306a36Sopenharmony_ci return err; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci dev_dbg(chip->card->dev, "starting pipe\n"); 13762306a36Sopenharmony_ci err = lx_pipe_start(chip, 0, is_capture); 13862306a36Sopenharmony_ci if (err < 0) { 13962306a36Sopenharmony_ci dev_err(chip->card->dev, "starting pipe failed\n"); 14062306a36Sopenharmony_ci return err; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci dev_dbg(chip->card->dev, "waiting for pipe to start\n"); 14462306a36Sopenharmony_ci err = lx_pipe_wait_for_start(chip, 0, is_capture); 14562306a36Sopenharmony_ci if (err < 0) { 14662306a36Sopenharmony_ci dev_err(chip->card->dev, "waiting for pipe failed\n"); 14762306a36Sopenharmony_ci return err; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return err; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic int lx_hardware_stop(struct lx6464es *chip, 15562306a36Sopenharmony_ci struct snd_pcm_substream *substream) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci int err = 0; 15862306a36Sopenharmony_ci int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci dev_dbg(chip->card->dev, "pausing pipe\n"); 16162306a36Sopenharmony_ci err = lx_pipe_pause(chip, 0, is_capture); 16262306a36Sopenharmony_ci if (err < 0) { 16362306a36Sopenharmony_ci dev_err(chip->card->dev, "pausing pipe failed\n"); 16462306a36Sopenharmony_ci return err; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci dev_dbg(chip->card->dev, "waiting for pipe to become idle\n"); 16862306a36Sopenharmony_ci err = lx_pipe_wait_for_idle(chip, 0, is_capture); 16962306a36Sopenharmony_ci if (err < 0) { 17062306a36Sopenharmony_ci dev_err(chip->card->dev, "waiting for pipe failed\n"); 17162306a36Sopenharmony_ci return err; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci dev_dbg(chip->card->dev, "stopping pipe\n"); 17562306a36Sopenharmony_ci err = lx_pipe_stop(chip, 0, is_capture); 17662306a36Sopenharmony_ci if (err < 0) { 17762306a36Sopenharmony_ci dev_err(chip->card->dev, "stopping pipe failed\n"); 17862306a36Sopenharmony_ci return err; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return err; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int lx_hardware_close(struct lx6464es *chip, 18662306a36Sopenharmony_ci struct snd_pcm_substream *substream) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci int err = 0; 18962306a36Sopenharmony_ci int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci dev_dbg(chip->card->dev, "releasing pipe\n"); 19262306a36Sopenharmony_ci err = lx_pipe_release(chip, 0, is_capture); 19362306a36Sopenharmony_ci if (err < 0) { 19462306a36Sopenharmony_ci dev_err(chip->card->dev, "releasing pipe failed\n"); 19562306a36Sopenharmony_ci return err; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return err; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic int lx_pcm_open(struct snd_pcm_substream *substream) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct lx6464es *chip = snd_pcm_substream_chip(substream); 20562306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 20662306a36Sopenharmony_ci int err = 0; 20762306a36Sopenharmony_ci int board_rate; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci dev_dbg(chip->card->dev, "->lx_pcm_open\n"); 21062306a36Sopenharmony_ci mutex_lock(&chip->setup_mutex); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* copy the struct snd_pcm_hardware struct */ 21362306a36Sopenharmony_ci runtime->hw = lx_caps; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci#if 0 21662306a36Sopenharmony_ci /* buffer-size should better be multiple of period-size */ 21762306a36Sopenharmony_ci err = snd_pcm_hw_constraint_integer(runtime, 21862306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS); 21962306a36Sopenharmony_ci if (err < 0) { 22062306a36Sopenharmony_ci dev_warn(chip->card->dev, "could not constrain periods\n"); 22162306a36Sopenharmony_ci goto exit; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci#endif 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* the clock rate cannot be changed */ 22662306a36Sopenharmony_ci board_rate = chip->board_sample_rate; 22762306a36Sopenharmony_ci err = snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_RATE, 22862306a36Sopenharmony_ci board_rate); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (err < 0) { 23162306a36Sopenharmony_ci dev_warn(chip->card->dev, "could not constrain periods\n"); 23262306a36Sopenharmony_ci goto exit; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* constrain period size */ 23662306a36Sopenharmony_ci err = snd_pcm_hw_constraint_minmax(runtime, 23762306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 23862306a36Sopenharmony_ci MICROBLAZE_IBL_MIN, 23962306a36Sopenharmony_ci MICROBLAZE_IBL_MAX); 24062306a36Sopenharmony_ci if (err < 0) { 24162306a36Sopenharmony_ci dev_warn(chip->card->dev, 24262306a36Sopenharmony_ci "could not constrain period size\n"); 24362306a36Sopenharmony_ci goto exit; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci snd_pcm_hw_constraint_step(runtime, 0, 24762306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci snd_pcm_set_sync(substream); 25062306a36Sopenharmony_ci err = 0; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ciexit: 25362306a36Sopenharmony_ci runtime->private_data = chip; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci mutex_unlock(&chip->setup_mutex); 25662306a36Sopenharmony_ci dev_dbg(chip->card->dev, "<-lx_pcm_open, %d\n", err); 25762306a36Sopenharmony_ci return err; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int lx_pcm_close(struct snd_pcm_substream *substream) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci dev_dbg(substream->pcm->card->dev, "->lx_pcm_close\n"); 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream 26762306a36Sopenharmony_ci *substream) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct lx6464es *chip = snd_pcm_substream_chip(substream); 27062306a36Sopenharmony_ci snd_pcm_uframes_t pos; 27162306a36Sopenharmony_ci int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci struct lx_stream *lx_stream = is_capture ? &chip->capture_stream : 27462306a36Sopenharmony_ci &chip->playback_stream; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci dev_dbg(chip->card->dev, "->lx_pcm_stream_pointer\n"); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci mutex_lock(&chip->lock); 27962306a36Sopenharmony_ci pos = lx_stream->frame_pos * substream->runtime->period_size; 28062306a36Sopenharmony_ci mutex_unlock(&chip->lock); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci dev_dbg(chip->card->dev, "stream_pointer at %ld\n", pos); 28362306a36Sopenharmony_ci return pos; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int lx_pcm_prepare(struct snd_pcm_substream *substream) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct lx6464es *chip = snd_pcm_substream_chip(substream); 28962306a36Sopenharmony_ci int err = 0; 29062306a36Sopenharmony_ci const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci dev_dbg(chip->card->dev, "->lx_pcm_prepare\n"); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci mutex_lock(&chip->setup_mutex); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (chip->hardware_running[is_capture]) { 29762306a36Sopenharmony_ci err = lx_hardware_stop(chip, substream); 29862306a36Sopenharmony_ci if (err < 0) { 29962306a36Sopenharmony_ci dev_err(chip->card->dev, "failed to stop hardware. " 30062306a36Sopenharmony_ci "Error code %d\n", err); 30162306a36Sopenharmony_ci goto exit; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci err = lx_hardware_close(chip, substream); 30562306a36Sopenharmony_ci if (err < 0) { 30662306a36Sopenharmony_ci dev_err(chip->card->dev, "failed to close hardware. " 30762306a36Sopenharmony_ci "Error code %d\n", err); 30862306a36Sopenharmony_ci goto exit; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci dev_dbg(chip->card->dev, "opening hardware\n"); 31362306a36Sopenharmony_ci err = lx_hardware_open(chip, substream); 31462306a36Sopenharmony_ci if (err < 0) { 31562306a36Sopenharmony_ci dev_err(chip->card->dev, "failed to open hardware. " 31662306a36Sopenharmony_ci "Error code %d\n", err); 31762306a36Sopenharmony_ci goto exit; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci err = lx_hardware_start(chip, substream); 32162306a36Sopenharmony_ci if (err < 0) { 32262306a36Sopenharmony_ci dev_err(chip->card->dev, "failed to start hardware. " 32362306a36Sopenharmony_ci "Error code %d\n", err); 32462306a36Sopenharmony_ci goto exit; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci chip->hardware_running[is_capture] = 1; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (chip->board_sample_rate != substream->runtime->rate) { 33062306a36Sopenharmony_ci if (!err) 33162306a36Sopenharmony_ci chip->board_sample_rate = substream->runtime->rate; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ciexit: 33562306a36Sopenharmony_ci mutex_unlock(&chip->setup_mutex); 33662306a36Sopenharmony_ci return err; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic int lx_pcm_hw_params(struct snd_pcm_substream *substream, 34062306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params, int is_capture) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct lx6464es *chip = snd_pcm_substream_chip(substream); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci dev_dbg(chip->card->dev, "->lx_pcm_hw_params\n"); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci mutex_lock(&chip->setup_mutex); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (is_capture) 34962306a36Sopenharmony_ci chip->capture_stream.stream = substream; 35062306a36Sopenharmony_ci else 35162306a36Sopenharmony_ci chip->playback_stream.stream = substream; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci mutex_unlock(&chip->setup_mutex); 35462306a36Sopenharmony_ci return 0; 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic int lx_pcm_hw_params_playback(struct snd_pcm_substream *substream, 35862306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci return lx_pcm_hw_params(substream, hw_params, 0); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic int lx_pcm_hw_params_capture(struct snd_pcm_substream *substream, 36462306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci return lx_pcm_hw_params(substream, hw_params, 1); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic int lx_pcm_hw_free(struct snd_pcm_substream *substream) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct lx6464es *chip = snd_pcm_substream_chip(substream); 37262306a36Sopenharmony_ci int err = 0; 37362306a36Sopenharmony_ci int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci dev_dbg(chip->card->dev, "->lx_pcm_hw_free\n"); 37662306a36Sopenharmony_ci mutex_lock(&chip->setup_mutex); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (chip->hardware_running[is_capture]) { 37962306a36Sopenharmony_ci err = lx_hardware_stop(chip, substream); 38062306a36Sopenharmony_ci if (err < 0) { 38162306a36Sopenharmony_ci dev_err(chip->card->dev, "failed to stop hardware. " 38262306a36Sopenharmony_ci "Error code %d\n", err); 38362306a36Sopenharmony_ci goto exit; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci err = lx_hardware_close(chip, substream); 38762306a36Sopenharmony_ci if (err < 0) { 38862306a36Sopenharmony_ci dev_err(chip->card->dev, "failed to close hardware. " 38962306a36Sopenharmony_ci "Error code %d\n", err); 39062306a36Sopenharmony_ci goto exit; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci chip->hardware_running[is_capture] = 0; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (is_capture) 39762306a36Sopenharmony_ci chip->capture_stream.stream = NULL; 39862306a36Sopenharmony_ci else 39962306a36Sopenharmony_ci chip->playback_stream.stream = NULL; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ciexit: 40262306a36Sopenharmony_ci mutex_unlock(&chip->setup_mutex); 40362306a36Sopenharmony_ci return err; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct snd_pcm_substream *substream = lx_stream->stream; 40962306a36Sopenharmony_ci const unsigned int is_capture = lx_stream->is_capture; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci int err; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci const u32 channels = substream->runtime->channels; 41462306a36Sopenharmony_ci const u32 bytes_per_frame = channels * 3; 41562306a36Sopenharmony_ci const u32 period_size = substream->runtime->period_size; 41662306a36Sopenharmony_ci const u32 periods = substream->runtime->periods; 41762306a36Sopenharmony_ci const u32 period_bytes = period_size * bytes_per_frame; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci dma_addr_t buf = substream->dma_buffer.addr; 42062306a36Sopenharmony_ci int i; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci u32 needed, freed; 42362306a36Sopenharmony_ci u32 size_array[5]; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci for (i = 0; i != periods; ++i) { 42662306a36Sopenharmony_ci u32 buffer_index = 0; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, 42962306a36Sopenharmony_ci size_array); 43062306a36Sopenharmony_ci dev_dbg(chip->card->dev, "starting: needed %d, freed %d\n", 43162306a36Sopenharmony_ci needed, freed); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci err = lx_buffer_give(chip, 0, is_capture, period_bytes, 43462306a36Sopenharmony_ci lower_32_bits(buf), upper_32_bits(buf), 43562306a36Sopenharmony_ci &buffer_index); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci dev_dbg(chip->card->dev, "starting: buffer index %x on 0x%lx (%d bytes)\n", 43862306a36Sopenharmony_ci buffer_index, (unsigned long)buf, period_bytes); 43962306a36Sopenharmony_ci buf += period_bytes; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); 44362306a36Sopenharmony_ci dev_dbg(chip->card->dev, "starting: needed %d, freed %d\n", needed, freed); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci dev_dbg(chip->card->dev, "starting: starting stream\n"); 44662306a36Sopenharmony_ci err = lx_stream_start(chip, 0, is_capture); 44762306a36Sopenharmony_ci if (err < 0) 44862306a36Sopenharmony_ci dev_err(chip->card->dev, "couldn't start stream\n"); 44962306a36Sopenharmony_ci else 45062306a36Sopenharmony_ci lx_stream->status = LX_STREAM_STATUS_RUNNING; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci lx_stream->frame_pos = 0; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci const unsigned int is_capture = lx_stream->is_capture; 45862306a36Sopenharmony_ci int err; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci dev_dbg(chip->card->dev, "stopping: stopping stream\n"); 46162306a36Sopenharmony_ci err = lx_stream_stop(chip, 0, is_capture); 46262306a36Sopenharmony_ci if (err < 0) 46362306a36Sopenharmony_ci dev_err(chip->card->dev, "couldn't stop stream\n"); 46462306a36Sopenharmony_ci else 46562306a36Sopenharmony_ci lx_stream->status = LX_STREAM_STATUS_FREE; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic void lx_trigger_dispatch_stream(struct lx6464es *chip, 47062306a36Sopenharmony_ci struct lx_stream *lx_stream) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci switch (lx_stream->status) { 47362306a36Sopenharmony_ci case LX_STREAM_STATUS_SCHEDULE_RUN: 47462306a36Sopenharmony_ci lx_trigger_start(chip, lx_stream); 47562306a36Sopenharmony_ci break; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci case LX_STREAM_STATUS_SCHEDULE_STOP: 47862306a36Sopenharmony_ci lx_trigger_stop(chip, lx_stream); 47962306a36Sopenharmony_ci break; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci default: 48262306a36Sopenharmony_ci break; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic int lx_pcm_trigger_dispatch(struct lx6464es *chip, 48762306a36Sopenharmony_ci struct lx_stream *lx_stream, int cmd) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci int err = 0; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci mutex_lock(&chip->lock); 49262306a36Sopenharmony_ci switch (cmd) { 49362306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 49462306a36Sopenharmony_ci lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN; 49562306a36Sopenharmony_ci break; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 49862306a36Sopenharmony_ci lx_stream->status = LX_STREAM_STATUS_SCHEDULE_STOP; 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci default: 50262306a36Sopenharmony_ci err = -EINVAL; 50362306a36Sopenharmony_ci goto exit; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci lx_trigger_dispatch_stream(chip, &chip->capture_stream); 50762306a36Sopenharmony_ci lx_trigger_dispatch_stream(chip, &chip->playback_stream); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ciexit: 51062306a36Sopenharmony_ci mutex_unlock(&chip->lock); 51162306a36Sopenharmony_ci return err; 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic int lx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci struct lx6464es *chip = snd_pcm_substream_chip(substream); 51862306a36Sopenharmony_ci const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); 51962306a36Sopenharmony_ci struct lx_stream *stream = is_capture ? &chip->capture_stream : 52062306a36Sopenharmony_ci &chip->playback_stream; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci dev_dbg(chip->card->dev, "->lx_pcm_trigger\n"); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci return lx_pcm_trigger_dispatch(chip, stream, cmd); 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic void snd_lx6464es_free(struct snd_card *card) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci struct lx6464es *chip = card->private_data; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci lx_irq_disable(chip); 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci/* reset the dsp during initialization */ 53562306a36Sopenharmony_cistatic int lx_init_xilinx_reset(struct lx6464es *chip) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci int i; 53862306a36Sopenharmony_ci u32 plx_reg = lx_plx_reg_read(chip, ePLX_CHIPSC); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci dev_dbg(chip->card->dev, "->lx_init_xilinx_reset\n"); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* activate reset of xilinx */ 54362306a36Sopenharmony_ci plx_reg &= ~CHIPSC_RESET_XILINX; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); 54662306a36Sopenharmony_ci msleep(1); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci lx_plx_reg_write(chip, ePLX_MBOX3, 0); 54962306a36Sopenharmony_ci msleep(1); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci plx_reg |= CHIPSC_RESET_XILINX; 55262306a36Sopenharmony_ci lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* deactivate reset of xilinx */ 55562306a36Sopenharmony_ci for (i = 0; i != 100; ++i) { 55662306a36Sopenharmony_ci u32 reg_mbox3; 55762306a36Sopenharmony_ci msleep(10); 55862306a36Sopenharmony_ci reg_mbox3 = lx_plx_reg_read(chip, ePLX_MBOX3); 55962306a36Sopenharmony_ci if (reg_mbox3) { 56062306a36Sopenharmony_ci dev_dbg(chip->card->dev, "xilinx reset done\n"); 56162306a36Sopenharmony_ci dev_dbg(chip->card->dev, "xilinx took %d loops\n", i); 56262306a36Sopenharmony_ci break; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* todo: add some error handling? */ 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* clear mr */ 56962306a36Sopenharmony_ci lx_dsp_reg_write(chip, eReg_CSM, 0); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* le xilinx ES peut ne pas etre encore pret, on attend. */ 57262306a36Sopenharmony_ci msleep(600); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci return 0; 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic int lx_init_xilinx_test(struct lx6464es *chip) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci u32 reg; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci dev_dbg(chip->card->dev, "->lx_init_xilinx_test\n"); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /* TEST if we have access to Xilinx/MicroBlaze */ 58462306a36Sopenharmony_ci lx_dsp_reg_write(chip, eReg_CSM, 0); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci reg = lx_dsp_reg_read(chip, eReg_CSM); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (reg) { 58962306a36Sopenharmony_ci dev_err(chip->card->dev, "Problem: Reg_CSM %x.\n", reg); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* PCI9056_SPACE0_REMAP */ 59262306a36Sopenharmony_ci lx_plx_reg_write(chip, ePLX_PCICR, 1); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci reg = lx_dsp_reg_read(chip, eReg_CSM); 59562306a36Sopenharmony_ci if (reg) { 59662306a36Sopenharmony_ci dev_err(chip->card->dev, "Error: Reg_CSM %x.\n", reg); 59762306a36Sopenharmony_ci return -EAGAIN; /* seems to be appropriate */ 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci dev_dbg(chip->card->dev, "Xilinx/MicroBlaze access test successful\n"); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci return 0; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci/* initialize ethersound */ 60762306a36Sopenharmony_cistatic int lx_init_ethersound_config(struct lx6464es *chip) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci int i; 61062306a36Sopenharmony_ci u32 orig_conf_es = lx_dsp_reg_read(chip, eReg_CONFES); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* configure 64 io channels */ 61362306a36Sopenharmony_ci u32 conf_es = (orig_conf_es & CONFES_READ_PART_MASK) | 61462306a36Sopenharmony_ci (64 << IOCR_INPUTS_OFFSET) | 61562306a36Sopenharmony_ci (64 << IOCR_OUTPUTS_OFFSET) | 61662306a36Sopenharmony_ci (FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci dev_dbg(chip->card->dev, "->lx_init_ethersound\n"); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci chip->freq_ratio = FREQ_RATIO_SINGLE_MODE; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* 62362306a36Sopenharmony_ci * write it to the card ! 62462306a36Sopenharmony_ci * this actually kicks the ES xilinx, the first time since poweron. 62562306a36Sopenharmony_ci * the MAC address in the Reg_ADMACESMSB Reg_ADMACESLSB registers 62662306a36Sopenharmony_ci * is not ready before this is done, and the bit 2 in Reg_CSES is set. 62762306a36Sopenharmony_ci * */ 62862306a36Sopenharmony_ci lx_dsp_reg_write(chip, eReg_CONFES, conf_es); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci for (i = 0; i != 1000; ++i) { 63162306a36Sopenharmony_ci if (lx_dsp_reg_read(chip, eReg_CSES) & 4) { 63262306a36Sopenharmony_ci dev_dbg(chip->card->dev, "ethersound initialized after %dms\n", 63362306a36Sopenharmony_ci i); 63462306a36Sopenharmony_ci goto ethersound_initialized; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci msleep(1); 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci dev_warn(chip->card->dev, 63962306a36Sopenharmony_ci "ethersound could not be initialized after %dms\n", i); 64062306a36Sopenharmony_ci return -ETIMEDOUT; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci ethersound_initialized: 64362306a36Sopenharmony_ci dev_dbg(chip->card->dev, "ethersound initialized\n"); 64462306a36Sopenharmony_ci return 0; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic int lx_init_get_version_features(struct lx6464es *chip) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci u32 dsp_version; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci int err; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci dev_dbg(chip->card->dev, "->lx_init_get_version_features\n"); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci err = lx_dsp_get_version(chip, &dsp_version); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (err == 0) { 65862306a36Sopenharmony_ci u32 freq; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci dev_info(chip->card->dev, "DSP version: V%02d.%02d #%d\n", 66162306a36Sopenharmony_ci (dsp_version>>16) & 0xff, (dsp_version>>8) & 0xff, 66262306a36Sopenharmony_ci dsp_version & 0xff); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* later: what firmware version do we expect? */ 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* retrieve Play/Rec features */ 66762306a36Sopenharmony_ci /* done here because we may have to handle alternate 66862306a36Sopenharmony_ci * DSP files. */ 66962306a36Sopenharmony_ci /* later */ 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* init the EtherSound sample rate */ 67262306a36Sopenharmony_ci err = lx_dsp_get_clock_frequency(chip, &freq); 67362306a36Sopenharmony_ci if (err == 0) 67462306a36Sopenharmony_ci chip->board_sample_rate = freq; 67562306a36Sopenharmony_ci dev_dbg(chip->card->dev, "actual clock frequency %d\n", freq); 67662306a36Sopenharmony_ci } else { 67762306a36Sopenharmony_ci dev_err(chip->card->dev, "DSP corrupted \n"); 67862306a36Sopenharmony_ci err = -EAGAIN; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci return err; 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic int lx_set_granularity(struct lx6464es *chip, u32 gran) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci int err = 0; 68762306a36Sopenharmony_ci u32 snapped_gran = MICROBLAZE_IBL_MIN; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci dev_dbg(chip->card->dev, "->lx_set_granularity\n"); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci /* blocksize is a power of 2 */ 69262306a36Sopenharmony_ci while ((snapped_gran < gran) && 69362306a36Sopenharmony_ci (snapped_gran < MICROBLAZE_IBL_MAX)) { 69462306a36Sopenharmony_ci snapped_gran *= 2; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (snapped_gran == chip->pcm_granularity) 69862306a36Sopenharmony_ci return 0; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci err = lx_dsp_set_granularity(chip, snapped_gran); 70162306a36Sopenharmony_ci if (err < 0) { 70262306a36Sopenharmony_ci dev_warn(chip->card->dev, "could not set granularity\n"); 70362306a36Sopenharmony_ci err = -EAGAIN; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (snapped_gran != gran) 70762306a36Sopenharmony_ci dev_err(chip->card->dev, "snapped blocksize to %d\n", snapped_gran); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci dev_dbg(chip->card->dev, "set blocksize on board %d\n", snapped_gran); 71062306a36Sopenharmony_ci chip->pcm_granularity = snapped_gran; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return err; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci/* initialize and test the xilinx dsp chip */ 71662306a36Sopenharmony_cistatic int lx_init_dsp(struct lx6464es *chip) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci int err; 71962306a36Sopenharmony_ci int i; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci dev_dbg(chip->card->dev, "->lx_init_dsp\n"); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci dev_dbg(chip->card->dev, "initialize board\n"); 72462306a36Sopenharmony_ci err = lx_init_xilinx_reset(chip); 72562306a36Sopenharmony_ci if (err) 72662306a36Sopenharmony_ci return err; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci dev_dbg(chip->card->dev, "testing board\n"); 72962306a36Sopenharmony_ci err = lx_init_xilinx_test(chip); 73062306a36Sopenharmony_ci if (err) 73162306a36Sopenharmony_ci return err; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci dev_dbg(chip->card->dev, "initialize ethersound configuration\n"); 73462306a36Sopenharmony_ci err = lx_init_ethersound_config(chip); 73562306a36Sopenharmony_ci if (err) 73662306a36Sopenharmony_ci return err; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci lx_irq_enable(chip); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /** \todo the mac address should be ready by not, but it isn't, 74162306a36Sopenharmony_ci * so we wait for it */ 74262306a36Sopenharmony_ci for (i = 0; i != 1000; ++i) { 74362306a36Sopenharmony_ci err = lx_dsp_get_mac(chip); 74462306a36Sopenharmony_ci if (err) 74562306a36Sopenharmony_ci return err; 74662306a36Sopenharmony_ci if (chip->mac_address[0] || chip->mac_address[1] || chip->mac_address[2] || 74762306a36Sopenharmony_ci chip->mac_address[3] || chip->mac_address[4] || chip->mac_address[5]) 74862306a36Sopenharmony_ci goto mac_ready; 74962306a36Sopenharmony_ci msleep(1); 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci return -ETIMEDOUT; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cimac_ready: 75462306a36Sopenharmony_ci dev_dbg(chip->card->dev, "mac address ready read after: %dms\n", i); 75562306a36Sopenharmony_ci dev_info(chip->card->dev, 75662306a36Sopenharmony_ci "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n", 75762306a36Sopenharmony_ci chip->mac_address[0], chip->mac_address[1], chip->mac_address[2], 75862306a36Sopenharmony_ci chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci err = lx_init_get_version_features(chip); 76162306a36Sopenharmony_ci if (err) 76262306a36Sopenharmony_ci return err; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci lx_set_granularity(chip, MICROBLAZE_IBL_DEFAULT); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci chip->playback_mute = 0; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci return err; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic const struct snd_pcm_ops lx_ops_playback = { 77262306a36Sopenharmony_ci .open = lx_pcm_open, 77362306a36Sopenharmony_ci .close = lx_pcm_close, 77462306a36Sopenharmony_ci .prepare = lx_pcm_prepare, 77562306a36Sopenharmony_ci .hw_params = lx_pcm_hw_params_playback, 77662306a36Sopenharmony_ci .hw_free = lx_pcm_hw_free, 77762306a36Sopenharmony_ci .trigger = lx_pcm_trigger, 77862306a36Sopenharmony_ci .pointer = lx_pcm_stream_pointer, 77962306a36Sopenharmony_ci}; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic const struct snd_pcm_ops lx_ops_capture = { 78262306a36Sopenharmony_ci .open = lx_pcm_open, 78362306a36Sopenharmony_ci .close = lx_pcm_close, 78462306a36Sopenharmony_ci .prepare = lx_pcm_prepare, 78562306a36Sopenharmony_ci .hw_params = lx_pcm_hw_params_capture, 78662306a36Sopenharmony_ci .hw_free = lx_pcm_hw_free, 78762306a36Sopenharmony_ci .trigger = lx_pcm_trigger, 78862306a36Sopenharmony_ci .pointer = lx_pcm_stream_pointer, 78962306a36Sopenharmony_ci}; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic int lx_pcm_create(struct lx6464es *chip) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci int err; 79462306a36Sopenharmony_ci struct snd_pcm *pcm; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci u32 size = 64 * /* channels */ 79762306a36Sopenharmony_ci 3 * /* 24 bit samples */ 79862306a36Sopenharmony_ci MAX_STREAM_BUFFER * /* periods */ 79962306a36Sopenharmony_ci MICROBLAZE_IBL_MAX * /* frames per period */ 80062306a36Sopenharmony_ci 2; /* duplex */ 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci size = PAGE_ALIGN(size); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* hardcoded device name & channel count */ 80562306a36Sopenharmony_ci err = snd_pcm_new(chip->card, (char *)card_name, 0, 80662306a36Sopenharmony_ci 1, 1, &pcm); 80762306a36Sopenharmony_ci if (err < 0) 80862306a36Sopenharmony_ci return err; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci pcm->private_data = chip; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &lx_ops_playback); 81362306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &lx_ops_capture); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci pcm->info_flags = 0; 81662306a36Sopenharmony_ci pcm->nonatomic = true; 81762306a36Sopenharmony_ci strcpy(pcm->name, card_name); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 82062306a36Sopenharmony_ci &chip->pci->dev, size, size); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci chip->pcm = pcm; 82362306a36Sopenharmony_ci chip->capture_stream.is_capture = 1; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci return 0; 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic int lx_control_playback_info(struct snd_kcontrol *kcontrol, 82962306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 83262306a36Sopenharmony_ci uinfo->count = 1; 83362306a36Sopenharmony_ci uinfo->value.integer.min = 0; 83462306a36Sopenharmony_ci uinfo->value.integer.max = 1; 83562306a36Sopenharmony_ci return 0; 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic int lx_control_playback_get(struct snd_kcontrol *kcontrol, 83962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci struct lx6464es *chip = snd_kcontrol_chip(kcontrol); 84262306a36Sopenharmony_ci ucontrol->value.integer.value[0] = chip->playback_mute; 84362306a36Sopenharmony_ci return 0; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic int lx_control_playback_put(struct snd_kcontrol *kcontrol, 84762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci struct lx6464es *chip = snd_kcontrol_chip(kcontrol); 85062306a36Sopenharmony_ci int changed = 0; 85162306a36Sopenharmony_ci int current_value = chip->playback_mute; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (current_value != ucontrol->value.integer.value[0]) { 85462306a36Sopenharmony_ci lx_level_unmute(chip, 0, !current_value); 85562306a36Sopenharmony_ci chip->playback_mute = !current_value; 85662306a36Sopenharmony_ci changed = 1; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci return changed; 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic const struct snd_kcontrol_new lx_control_playback_switch = { 86262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 86362306a36Sopenharmony_ci .name = "PCM Playback Switch", 86462306a36Sopenharmony_ci .index = 0, 86562306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 86662306a36Sopenharmony_ci .private_value = 0, 86762306a36Sopenharmony_ci .info = lx_control_playback_info, 86862306a36Sopenharmony_ci .get = lx_control_playback_get, 86962306a36Sopenharmony_ci .put = lx_control_playback_put 87062306a36Sopenharmony_ci}; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_cistatic void lx_proc_levels_read(struct snd_info_entry *entry, 87562306a36Sopenharmony_ci struct snd_info_buffer *buffer) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci u32 levels[64]; 87862306a36Sopenharmony_ci int err; 87962306a36Sopenharmony_ci int i, j; 88062306a36Sopenharmony_ci struct lx6464es *chip = entry->private_data; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci snd_iprintf(buffer, "capture levels:\n"); 88362306a36Sopenharmony_ci err = lx_level_peaks(chip, 1, 64, levels); 88462306a36Sopenharmony_ci if (err < 0) 88562306a36Sopenharmony_ci return; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci for (i = 0; i != 8; ++i) { 88862306a36Sopenharmony_ci for (j = 0; j != 8; ++j) 88962306a36Sopenharmony_ci snd_iprintf(buffer, "%08x ", levels[i*8+j]); 89062306a36Sopenharmony_ci snd_iprintf(buffer, "\n"); 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci snd_iprintf(buffer, "\nplayback levels:\n"); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci err = lx_level_peaks(chip, 0, 64, levels); 89662306a36Sopenharmony_ci if (err < 0) 89762306a36Sopenharmony_ci return; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci for (i = 0; i != 8; ++i) { 90062306a36Sopenharmony_ci for (j = 0; j != 8; ++j) 90162306a36Sopenharmony_ci snd_iprintf(buffer, "%08x ", levels[i*8+j]); 90262306a36Sopenharmony_ci snd_iprintf(buffer, "\n"); 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci snd_iprintf(buffer, "\n"); 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_cistatic int lx_proc_create(struct snd_card *card, struct lx6464es *chip) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci return snd_card_ro_proc_new(card, "levels", chip, lx_proc_levels_read); 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic int snd_lx6464es_create(struct snd_card *card, 91562306a36Sopenharmony_ci struct pci_dev *pci) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci struct lx6464es *chip = card->private_data; 91862306a36Sopenharmony_ci int err; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci dev_dbg(card->dev, "->snd_lx6464es_create\n"); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci /* enable PCI device */ 92362306a36Sopenharmony_ci err = pcim_enable_device(pci); 92462306a36Sopenharmony_ci if (err < 0) 92562306a36Sopenharmony_ci return err; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci pci_set_master(pci); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci /* check if we can restrict PCI DMA transfers to 32 bits */ 93062306a36Sopenharmony_ci err = dma_set_mask(&pci->dev, DMA_BIT_MASK(32)); 93162306a36Sopenharmony_ci if (err < 0) { 93262306a36Sopenharmony_ci dev_err(card->dev, 93362306a36Sopenharmony_ci "architecture does not support 32bit PCI busmaster DMA\n"); 93462306a36Sopenharmony_ci return -ENXIO; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci chip->card = card; 93862306a36Sopenharmony_ci chip->pci = pci; 93962306a36Sopenharmony_ci chip->irq = -1; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* initialize synchronization structs */ 94262306a36Sopenharmony_ci mutex_init(&chip->lock); 94362306a36Sopenharmony_ci mutex_init(&chip->msg_lock); 94462306a36Sopenharmony_ci mutex_init(&chip->setup_mutex); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci /* request resources */ 94762306a36Sopenharmony_ci err = pci_request_regions(pci, card_name); 94862306a36Sopenharmony_ci if (err < 0) 94962306a36Sopenharmony_ci return err; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci /* plx port */ 95262306a36Sopenharmony_ci chip->port_plx = pci_resource_start(pci, 1); 95362306a36Sopenharmony_ci chip->port_plx_remapped = devm_ioport_map(&pci->dev, chip->port_plx, 95462306a36Sopenharmony_ci pci_resource_len(pci, 1)); 95562306a36Sopenharmony_ci if (!chip->port_plx_remapped) 95662306a36Sopenharmony_ci return -ENOMEM; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /* dsp port */ 95962306a36Sopenharmony_ci chip->port_dsp_bar = pcim_iomap(pci, 2, 0); 96062306a36Sopenharmony_ci if (!chip->port_dsp_bar) 96162306a36Sopenharmony_ci return -ENOMEM; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci err = devm_request_threaded_irq(&pci->dev, pci->irq, lx_interrupt, 96462306a36Sopenharmony_ci lx_threaded_irq, IRQF_SHARED, 96562306a36Sopenharmony_ci KBUILD_MODNAME, chip); 96662306a36Sopenharmony_ci if (err) { 96762306a36Sopenharmony_ci dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); 96862306a36Sopenharmony_ci return err; 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci chip->irq = pci->irq; 97162306a36Sopenharmony_ci card->sync_irq = chip->irq; 97262306a36Sopenharmony_ci card->private_free = snd_lx6464es_free; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci err = lx_init_dsp(chip); 97562306a36Sopenharmony_ci if (err < 0) { 97662306a36Sopenharmony_ci dev_err(card->dev, "error during DSP initialization\n"); 97762306a36Sopenharmony_ci return err; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci err = lx_pcm_create(chip); 98162306a36Sopenharmony_ci if (err < 0) 98262306a36Sopenharmony_ci return err; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci err = lx_proc_create(card, chip); 98562306a36Sopenharmony_ci if (err < 0) 98662306a36Sopenharmony_ci return err; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci err = snd_ctl_add(card, snd_ctl_new1(&lx_control_playback_switch, 98962306a36Sopenharmony_ci chip)); 99062306a36Sopenharmony_ci if (err < 0) 99162306a36Sopenharmony_ci return err; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci return 0; 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_cistatic int snd_lx6464es_probe(struct pci_dev *pci, 99762306a36Sopenharmony_ci const struct pci_device_id *pci_id) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci static int dev; 100062306a36Sopenharmony_ci struct snd_card *card; 100162306a36Sopenharmony_ci struct lx6464es *chip; 100262306a36Sopenharmony_ci int err; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci dev_dbg(&pci->dev, "->snd_lx6464es_probe\n"); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci if (dev >= SNDRV_CARDS) 100762306a36Sopenharmony_ci return -ENODEV; 100862306a36Sopenharmony_ci if (!enable[dev]) { 100962306a36Sopenharmony_ci dev++; 101062306a36Sopenharmony_ci return -ENOENT; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 101462306a36Sopenharmony_ci sizeof(*chip), &card); 101562306a36Sopenharmony_ci if (err < 0) 101662306a36Sopenharmony_ci return err; 101762306a36Sopenharmony_ci chip = card->private_data; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci err = snd_lx6464es_create(card, pci); 102062306a36Sopenharmony_ci if (err < 0) { 102162306a36Sopenharmony_ci dev_err(card->dev, "error during snd_lx6464es_create\n"); 102262306a36Sopenharmony_ci goto error; 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci strcpy(card->driver, "LX6464ES"); 102662306a36Sopenharmony_ci sprintf(card->id, "LX6464ES_%02X%02X%02X", 102762306a36Sopenharmony_ci chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci sprintf(card->shortname, "LX6464ES %02X.%02X.%02X.%02X.%02X.%02X", 103062306a36Sopenharmony_ci chip->mac_address[0], chip->mac_address[1], chip->mac_address[2], 103162306a36Sopenharmony_ci chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i", 103462306a36Sopenharmony_ci card->shortname, chip->port_plx, 103562306a36Sopenharmony_ci chip->port_dsp_bar, chip->irq); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci err = snd_card_register(card); 103862306a36Sopenharmony_ci if (err < 0) 103962306a36Sopenharmony_ci goto error; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci dev_dbg(chip->card->dev, "initialization successful\n"); 104262306a36Sopenharmony_ci pci_set_drvdata(pci, card); 104362306a36Sopenharmony_ci dev++; 104462306a36Sopenharmony_ci return 0; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci error: 104762306a36Sopenharmony_ci snd_card_free(card); 104862306a36Sopenharmony_ci return err; 104962306a36Sopenharmony_ci} 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_cistatic struct pci_driver lx6464es_driver = { 105262306a36Sopenharmony_ci .name = KBUILD_MODNAME, 105362306a36Sopenharmony_ci .id_table = snd_lx6464es_ids, 105462306a36Sopenharmony_ci .probe = snd_lx6464es_probe, 105562306a36Sopenharmony_ci}; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_cimodule_pci_driver(lx6464es_driver); 1058