162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for AT73C213 16-bit stereo DAC connected to Atmel SSC 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2006-2007 Atmel Norway 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/*#define DEBUG*/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/device.h> 1462306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/mutex.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/io.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <sound/initval.h> 2362306a36Sopenharmony_ci#include <sound/control.h> 2462306a36Sopenharmony_ci#include <sound/core.h> 2562306a36Sopenharmony_ci#include <sound/pcm.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <linux/atmel-ssc.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/spi/spi.h> 3062306a36Sopenharmony_ci#include <linux/spi/at73c213.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "at73c213.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define BITRATE_MIN 8000 /* Hardware limit? */ 3562306a36Sopenharmony_ci#define BITRATE_TARGET CONFIG_SND_AT73C213_TARGET_BITRATE 3662306a36Sopenharmony_ci#define BITRATE_MAX 50000 /* Hardware limit. */ 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* Initial (hardware reset) AT73C213 register values. */ 3962306a36Sopenharmony_cistatic const u8 snd_at73c213_original_image[18] = 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci 0x00, /* 00 - CTRL */ 4262306a36Sopenharmony_ci 0x05, /* 01 - LLIG */ 4362306a36Sopenharmony_ci 0x05, /* 02 - RLIG */ 4462306a36Sopenharmony_ci 0x08, /* 03 - LPMG */ 4562306a36Sopenharmony_ci 0x08, /* 04 - RPMG */ 4662306a36Sopenharmony_ci 0x00, /* 05 - LLOG */ 4762306a36Sopenharmony_ci 0x00, /* 06 - RLOG */ 4862306a36Sopenharmony_ci 0x22, /* 07 - OLC */ 4962306a36Sopenharmony_ci 0x09, /* 08 - MC */ 5062306a36Sopenharmony_ci 0x00, /* 09 - CSFC */ 5162306a36Sopenharmony_ci 0x00, /* 0A - MISC */ 5262306a36Sopenharmony_ci 0x00, /* 0B - */ 5362306a36Sopenharmony_ci 0x00, /* 0C - PRECH */ 5462306a36Sopenharmony_ci 0x05, /* 0D - AUXG */ 5562306a36Sopenharmony_ci 0x00, /* 0E - */ 5662306a36Sopenharmony_ci 0x00, /* 0F - */ 5762306a36Sopenharmony_ci 0x00, /* 10 - RST */ 5862306a36Sopenharmony_ci 0x00, /* 11 - PA_CTRL */ 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistruct snd_at73c213 { 6262306a36Sopenharmony_ci struct snd_card *card; 6362306a36Sopenharmony_ci struct snd_pcm *pcm; 6462306a36Sopenharmony_ci struct snd_pcm_substream *substream; 6562306a36Sopenharmony_ci struct at73c213_board_info *board; 6662306a36Sopenharmony_ci int irq; 6762306a36Sopenharmony_ci int period; 6862306a36Sopenharmony_ci unsigned long bitrate; 6962306a36Sopenharmony_ci struct ssc_device *ssc; 7062306a36Sopenharmony_ci struct spi_device *spi; 7162306a36Sopenharmony_ci u8 spi_wbuffer[2]; 7262306a36Sopenharmony_ci u8 spi_rbuffer[2]; 7362306a36Sopenharmony_ci /* Image of the SPI registers in AT73C213. */ 7462306a36Sopenharmony_ci u8 reg_image[18]; 7562306a36Sopenharmony_ci /* Protect SSC registers against concurrent access. */ 7662306a36Sopenharmony_ci spinlock_t lock; 7762306a36Sopenharmony_ci /* Protect mixer registers against concurrent access. */ 7862306a36Sopenharmony_ci struct mutex mixer_lock; 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define get_chip(card) ((struct snd_at73c213 *)card->private_data) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic int 8462306a36Sopenharmony_cisnd_at73c213_write_reg(struct snd_at73c213 *chip, u8 reg, u8 val) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct spi_message msg; 8762306a36Sopenharmony_ci struct spi_transfer msg_xfer = { 8862306a36Sopenharmony_ci .len = 2, 8962306a36Sopenharmony_ci .cs_change = 0, 9062306a36Sopenharmony_ci }; 9162306a36Sopenharmony_ci int retval; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci spi_message_init(&msg); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci chip->spi_wbuffer[0] = reg; 9662306a36Sopenharmony_ci chip->spi_wbuffer[1] = val; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci msg_xfer.tx_buf = chip->spi_wbuffer; 9962306a36Sopenharmony_ci msg_xfer.rx_buf = chip->spi_rbuffer; 10062306a36Sopenharmony_ci spi_message_add_tail(&msg_xfer, &msg); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci retval = spi_sync(chip->spi, &msg); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (!retval) 10562306a36Sopenharmony_ci chip->reg_image[reg] = val; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci return retval; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic struct snd_pcm_hardware snd_at73c213_playback_hw = { 11162306a36Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | 11262306a36Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER, 11362306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_BE, 11462306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS, 11562306a36Sopenharmony_ci .rate_min = 8000, /* Replaced by chip->bitrate later. */ 11662306a36Sopenharmony_ci .rate_max = 50000, /* Replaced by chip->bitrate later. */ 11762306a36Sopenharmony_ci .channels_min = 1, 11862306a36Sopenharmony_ci .channels_max = 2, 11962306a36Sopenharmony_ci .buffer_bytes_max = 64 * 1024 - 1, 12062306a36Sopenharmony_ci .period_bytes_min = 512, 12162306a36Sopenharmony_ci .period_bytes_max = 64 * 1024 - 1, 12262306a36Sopenharmony_ci .periods_min = 4, 12362306a36Sopenharmony_ci .periods_max = 1024, 12462306a36Sopenharmony_ci}; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* 12762306a36Sopenharmony_ci * Calculate and set bitrate and divisions. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_cistatic int snd_at73c213_set_bitrate(struct snd_at73c213 *chip) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci unsigned long ssc_rate = clk_get_rate(chip->ssc->clk); 13262306a36Sopenharmony_ci unsigned long dac_rate_new, ssc_div; 13362306a36Sopenharmony_ci int status; 13462306a36Sopenharmony_ci unsigned long ssc_div_max, ssc_div_min; 13562306a36Sopenharmony_ci int max_tries; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * We connect two clocks here, picking divisors so the I2S clocks 13962306a36Sopenharmony_ci * out data at the same rate the DAC clocks it in ... and as close 14062306a36Sopenharmony_ci * as practical to the desired target rate. 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * The DAC master clock (MCLK) is programmable, and is either 256 14362306a36Sopenharmony_ci * or (not here) 384 times the I2S output clock (BCLK). 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* SSC clock / (bitrate * stereo * 16-bit). */ 14762306a36Sopenharmony_ci ssc_div = ssc_rate / (BITRATE_TARGET * 2 * 16); 14862306a36Sopenharmony_ci ssc_div_min = ssc_rate / (BITRATE_MAX * 2 * 16); 14962306a36Sopenharmony_ci ssc_div_max = ssc_rate / (BITRATE_MIN * 2 * 16); 15062306a36Sopenharmony_ci max_tries = (ssc_div_max - ssc_div_min) / 2; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (max_tries < 1) 15362306a36Sopenharmony_ci max_tries = 1; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* ssc_div must be even. */ 15662306a36Sopenharmony_ci ssc_div = (ssc_div + 1) & ~1UL; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) { 15962306a36Sopenharmony_ci ssc_div -= 2; 16062306a36Sopenharmony_ci if ((ssc_rate / (ssc_div * 2 * 16)) > BITRATE_MAX) 16162306a36Sopenharmony_ci return -ENXIO; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Search for a possible bitrate. */ 16562306a36Sopenharmony_ci do { 16662306a36Sopenharmony_ci /* SSC clock / (ssc divider * 16-bit * stereo). */ 16762306a36Sopenharmony_ci if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) 16862306a36Sopenharmony_ci return -ENXIO; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* 256 / (2 * 16) = 8 */ 17162306a36Sopenharmony_ci dac_rate_new = 8 * (ssc_rate / ssc_div); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci status = clk_round_rate(chip->board->dac_clk, dac_rate_new); 17462306a36Sopenharmony_ci if (status <= 0) 17562306a36Sopenharmony_ci return status; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* Ignore difference smaller than 256 Hz. */ 17862306a36Sopenharmony_ci if ((status/256) == (dac_rate_new/256)) 17962306a36Sopenharmony_ci goto set_rate; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci ssc_div += 2; 18262306a36Sopenharmony_ci } while (--max_tries); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* Not able to find a valid bitrate. */ 18562306a36Sopenharmony_ci return -ENXIO; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ciset_rate: 18862306a36Sopenharmony_ci status = clk_set_rate(chip->board->dac_clk, status); 18962306a36Sopenharmony_ci if (status < 0) 19062306a36Sopenharmony_ci return status; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* Set divider in SSC device. */ 19362306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, CMR, ssc_div/2); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* SSC clock / (ssc divider * 16-bit * stereo). */ 19662306a36Sopenharmony_ci chip->bitrate = ssc_rate / (ssc_div * 16 * 2); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci dev_info(&chip->spi->dev, 19962306a36Sopenharmony_ci "at73c213: supported bitrate is %lu (%lu divider)\n", 20062306a36Sopenharmony_ci chip->bitrate, ssc_div); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic int snd_at73c213_pcm_open(struct snd_pcm_substream *substream) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); 20862306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 20962306a36Sopenharmony_ci int err; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* ensure buffer_size is a multiple of period_size */ 21262306a36Sopenharmony_ci err = snd_pcm_hw_constraint_integer(runtime, 21362306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS); 21462306a36Sopenharmony_ci if (err < 0) 21562306a36Sopenharmony_ci return err; 21662306a36Sopenharmony_ci snd_at73c213_playback_hw.rate_min = chip->bitrate; 21762306a36Sopenharmony_ci snd_at73c213_playback_hw.rate_max = chip->bitrate; 21862306a36Sopenharmony_ci runtime->hw = snd_at73c213_playback_hw; 21962306a36Sopenharmony_ci chip->substream = substream; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci err = clk_enable(chip->ssc->clk); 22262306a36Sopenharmony_ci if (err) 22362306a36Sopenharmony_ci return err; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return 0; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic int snd_at73c213_pcm_close(struct snd_pcm_substream *substream) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); 23162306a36Sopenharmony_ci chip->substream = NULL; 23262306a36Sopenharmony_ci clk_disable(chip->ssc->clk); 23362306a36Sopenharmony_ci return 0; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int snd_at73c213_pcm_hw_params(struct snd_pcm_substream *substream, 23762306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); 24062306a36Sopenharmony_ci int channels = params_channels(hw_params); 24162306a36Sopenharmony_ci int val; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci val = ssc_readl(chip->ssc->regs, TFMR); 24462306a36Sopenharmony_ci val = SSC_BFINS(TFMR_DATNB, channels - 1, val); 24562306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, TFMR, val); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int snd_at73c213_pcm_prepare(struct snd_pcm_substream *substream) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); 25362306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 25462306a36Sopenharmony_ci int block_size; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci block_size = frames_to_bytes(runtime, runtime->period_size); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci chip->period = 0; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_TPR, 26162306a36Sopenharmony_ci (long)runtime->dma_addr); 26262306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_TCR, 26362306a36Sopenharmony_ci runtime->period_size * runtime->channels); 26462306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_TNPR, 26562306a36Sopenharmony_ci (long)runtime->dma_addr + block_size); 26662306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_TNCR, 26762306a36Sopenharmony_ci runtime->period_size * runtime->channels); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int snd_at73c213_pcm_trigger(struct snd_pcm_substream *substream, 27362306a36Sopenharmony_ci int cmd) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); 27662306a36Sopenharmony_ci int retval = 0; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci spin_lock(&chip->lock); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci switch (cmd) { 28162306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 28262306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, IER, SSC_BIT(IER_ENDTX)); 28362306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTEN)); 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 28662306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTDIS)); 28762306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, IDR, SSC_BIT(IDR_ENDTX)); 28862306a36Sopenharmony_ci break; 28962306a36Sopenharmony_ci default: 29062306a36Sopenharmony_ci dev_dbg(&chip->spi->dev, "spurious command %x\n", cmd); 29162306a36Sopenharmony_ci retval = -EINVAL; 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci spin_unlock(&chip->lock); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return retval; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic snd_pcm_uframes_t 30162306a36Sopenharmony_cisnd_at73c213_pcm_pointer(struct snd_pcm_substream *substream) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); 30462306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 30562306a36Sopenharmony_ci snd_pcm_uframes_t pos; 30662306a36Sopenharmony_ci unsigned long bytes; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci bytes = ssc_readl(chip->ssc->regs, PDC_TPR) 30962306a36Sopenharmony_ci - (unsigned long)runtime->dma_addr; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci pos = bytes_to_frames(runtime, bytes); 31262306a36Sopenharmony_ci if (pos >= runtime->buffer_size) 31362306a36Sopenharmony_ci pos -= runtime->buffer_size; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return pos; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic const struct snd_pcm_ops at73c213_playback_ops = { 31962306a36Sopenharmony_ci .open = snd_at73c213_pcm_open, 32062306a36Sopenharmony_ci .close = snd_at73c213_pcm_close, 32162306a36Sopenharmony_ci .hw_params = snd_at73c213_pcm_hw_params, 32262306a36Sopenharmony_ci .prepare = snd_at73c213_pcm_prepare, 32362306a36Sopenharmony_ci .trigger = snd_at73c213_pcm_trigger, 32462306a36Sopenharmony_ci .pointer = snd_at73c213_pcm_pointer, 32562306a36Sopenharmony_ci}; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic int snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct snd_pcm *pcm; 33062306a36Sopenharmony_ci int retval; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci retval = snd_pcm_new(chip->card, chip->card->shortname, 33362306a36Sopenharmony_ci device, 1, 0, &pcm); 33462306a36Sopenharmony_ci if (retval < 0) 33562306a36Sopenharmony_ci goto out; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci pcm->private_data = chip; 33862306a36Sopenharmony_ci pcm->info_flags = SNDRV_PCM_INFO_BLOCK_TRANSFER; 33962306a36Sopenharmony_ci strcpy(pcm->name, "at73c213"); 34062306a36Sopenharmony_ci chip->pcm = pcm; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &at73c213_playback_ops); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(chip->pcm, 34562306a36Sopenharmony_ci SNDRV_DMA_TYPE_DEV, &chip->ssc->pdev->dev, 34662306a36Sopenharmony_ci 64 * 1024, 64 * 1024); 34762306a36Sopenharmony_ciout: 34862306a36Sopenharmony_ci return retval; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic irqreturn_t snd_at73c213_interrupt(int irq, void *dev_id) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct snd_at73c213 *chip = dev_id; 35462306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = chip->substream->runtime; 35562306a36Sopenharmony_ci u32 status; 35662306a36Sopenharmony_ci int offset; 35762306a36Sopenharmony_ci int block_size; 35862306a36Sopenharmony_ci int next_period; 35962306a36Sopenharmony_ci int retval = IRQ_NONE; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci spin_lock(&chip->lock); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci block_size = frames_to_bytes(runtime, runtime->period_size); 36462306a36Sopenharmony_ci status = ssc_readl(chip->ssc->regs, IMR); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (status & SSC_BIT(IMR_ENDTX)) { 36762306a36Sopenharmony_ci chip->period++; 36862306a36Sopenharmony_ci if (chip->period == runtime->periods) 36962306a36Sopenharmony_ci chip->period = 0; 37062306a36Sopenharmony_ci next_period = chip->period + 1; 37162306a36Sopenharmony_ci if (next_period == runtime->periods) 37262306a36Sopenharmony_ci next_period = 0; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci offset = block_size * next_period; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_TNPR, 37762306a36Sopenharmony_ci (long)runtime->dma_addr + offset); 37862306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_TNCR, 37962306a36Sopenharmony_ci runtime->period_size * runtime->channels); 38062306a36Sopenharmony_ci retval = IRQ_HANDLED; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci ssc_readl(chip->ssc->regs, IMR); 38462306a36Sopenharmony_ci spin_unlock(&chip->lock); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (status & SSC_BIT(IMR_ENDTX)) 38762306a36Sopenharmony_ci snd_pcm_period_elapsed(chip->substream); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return retval; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci/* 39362306a36Sopenharmony_ci * Mixer functions. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_cistatic int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol, 39662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); 39962306a36Sopenharmony_ci int reg = kcontrol->private_value & 0xff; 40062306a36Sopenharmony_ci int shift = (kcontrol->private_value >> 8) & 0xff; 40162306a36Sopenharmony_ci int mask = (kcontrol->private_value >> 16) & 0xff; 40262306a36Sopenharmony_ci int invert = (kcontrol->private_value >> 24) & 0xff; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci mutex_lock(&chip->mixer_lock); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 40762306a36Sopenharmony_ci (chip->reg_image[reg] >> shift) & mask; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (invert) 41062306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 41162306a36Sopenharmony_ci mask - ucontrol->value.integer.value[0]; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic int snd_at73c213_mono_put(struct snd_kcontrol *kcontrol, 41962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); 42262306a36Sopenharmony_ci int reg = kcontrol->private_value & 0xff; 42362306a36Sopenharmony_ci int shift = (kcontrol->private_value >> 8) & 0xff; 42462306a36Sopenharmony_ci int mask = (kcontrol->private_value >> 16) & 0xff; 42562306a36Sopenharmony_ci int invert = (kcontrol->private_value >> 24) & 0xff; 42662306a36Sopenharmony_ci int change, retval; 42762306a36Sopenharmony_ci unsigned short val; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci val = (ucontrol->value.integer.value[0] & mask); 43062306a36Sopenharmony_ci if (invert) 43162306a36Sopenharmony_ci val = mask - val; 43262306a36Sopenharmony_ci val <<= shift; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci mutex_lock(&chip->mixer_lock); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci val = (chip->reg_image[reg] & ~(mask << shift)) | val; 43762306a36Sopenharmony_ci change = val != chip->reg_image[reg]; 43862306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, reg, val); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (retval) 44362306a36Sopenharmony_ci return retval; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return change; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic int snd_at73c213_stereo_info(struct snd_kcontrol *kcontrol, 44962306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci int mask = (kcontrol->private_value >> 24) & 0xff; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (mask == 1) 45462306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 45562306a36Sopenharmony_ci else 45662306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci uinfo->count = 2; 45962306a36Sopenharmony_ci uinfo->value.integer.min = 0; 46062306a36Sopenharmony_ci uinfo->value.integer.max = mask; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return 0; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol, 46662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); 46962306a36Sopenharmony_ci int left_reg = kcontrol->private_value & 0xff; 47062306a36Sopenharmony_ci int right_reg = (kcontrol->private_value >> 8) & 0xff; 47162306a36Sopenharmony_ci int shift_left = (kcontrol->private_value >> 16) & 0x07; 47262306a36Sopenharmony_ci int shift_right = (kcontrol->private_value >> 19) & 0x07; 47362306a36Sopenharmony_ci int mask = (kcontrol->private_value >> 24) & 0xff; 47462306a36Sopenharmony_ci int invert = (kcontrol->private_value >> 22) & 1; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci mutex_lock(&chip->mixer_lock); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 47962306a36Sopenharmony_ci (chip->reg_image[left_reg] >> shift_left) & mask; 48062306a36Sopenharmony_ci ucontrol->value.integer.value[1] = 48162306a36Sopenharmony_ci (chip->reg_image[right_reg] >> shift_right) & mask; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (invert) { 48462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 48562306a36Sopenharmony_ci mask - ucontrol->value.integer.value[0]; 48662306a36Sopenharmony_ci ucontrol->value.integer.value[1] = 48762306a36Sopenharmony_ci mask - ucontrol->value.integer.value[1]; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci return 0; 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol, 49662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); 49962306a36Sopenharmony_ci int left_reg = kcontrol->private_value & 0xff; 50062306a36Sopenharmony_ci int right_reg = (kcontrol->private_value >> 8) & 0xff; 50162306a36Sopenharmony_ci int shift_left = (kcontrol->private_value >> 16) & 0x07; 50262306a36Sopenharmony_ci int shift_right = (kcontrol->private_value >> 19) & 0x07; 50362306a36Sopenharmony_ci int mask = (kcontrol->private_value >> 24) & 0xff; 50462306a36Sopenharmony_ci int invert = (kcontrol->private_value >> 22) & 1; 50562306a36Sopenharmony_ci int change, retval; 50662306a36Sopenharmony_ci unsigned short val1, val2; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci val1 = ucontrol->value.integer.value[0] & mask; 50962306a36Sopenharmony_ci val2 = ucontrol->value.integer.value[1] & mask; 51062306a36Sopenharmony_ci if (invert) { 51162306a36Sopenharmony_ci val1 = mask - val1; 51262306a36Sopenharmony_ci val2 = mask - val2; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci val1 <<= shift_left; 51562306a36Sopenharmony_ci val2 <<= shift_right; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci mutex_lock(&chip->mixer_lock); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci val1 = (chip->reg_image[left_reg] & ~(mask << shift_left)) | val1; 52062306a36Sopenharmony_ci val2 = (chip->reg_image[right_reg] & ~(mask << shift_right)) | val2; 52162306a36Sopenharmony_ci change = val1 != chip->reg_image[left_reg] 52262306a36Sopenharmony_ci || val2 != chip->reg_image[right_reg]; 52362306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, left_reg, val1); 52462306a36Sopenharmony_ci if (retval) { 52562306a36Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 52662306a36Sopenharmony_ci goto out; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, right_reg, val2); 52962306a36Sopenharmony_ci if (retval) { 53062306a36Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 53162306a36Sopenharmony_ci goto out; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return change; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ciout: 53962306a36Sopenharmony_ci return retval; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci#define snd_at73c213_mono_switch_info snd_ctl_boolean_mono_info 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, 54562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); 54862306a36Sopenharmony_ci int reg = kcontrol->private_value & 0xff; 54962306a36Sopenharmony_ci int shift = (kcontrol->private_value >> 8) & 0xff; 55062306a36Sopenharmony_ci int invert = (kcontrol->private_value >> 24) & 0xff; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci mutex_lock(&chip->mixer_lock); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 55562306a36Sopenharmony_ci (chip->reg_image[reg] >> shift) & 0x01; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (invert) 55862306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 55962306a36Sopenharmony_ci 0x01 - ucontrol->value.integer.value[0]; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci return 0; 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol, 56762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); 57062306a36Sopenharmony_ci int reg = kcontrol->private_value & 0xff; 57162306a36Sopenharmony_ci int shift = (kcontrol->private_value >> 8) & 0xff; 57262306a36Sopenharmony_ci int mask = (kcontrol->private_value >> 16) & 0xff; 57362306a36Sopenharmony_ci int invert = (kcontrol->private_value >> 24) & 0xff; 57462306a36Sopenharmony_ci int change, retval; 57562306a36Sopenharmony_ci unsigned short val; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (ucontrol->value.integer.value[0]) 57862306a36Sopenharmony_ci val = mask; 57962306a36Sopenharmony_ci else 58062306a36Sopenharmony_ci val = 0; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (invert) 58362306a36Sopenharmony_ci val = mask - val; 58462306a36Sopenharmony_ci val <<= shift; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci mutex_lock(&chip->mixer_lock); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci val |= (chip->reg_image[reg] & ~(mask << shift)); 58962306a36Sopenharmony_ci change = val != chip->reg_image[reg]; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, reg, val); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (retval) 59662306a36Sopenharmony_ci return retval; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return change; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic int snd_at73c213_pa_volume_info(struct snd_kcontrol *kcontrol, 60262306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 60562306a36Sopenharmony_ci uinfo->count = 1; 60662306a36Sopenharmony_ci uinfo->value.integer.min = 0; 60762306a36Sopenharmony_ci uinfo->value.integer.max = ((kcontrol->private_value >> 16) & 0xff) - 1; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci return 0; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic int snd_at73c213_line_capture_volume_info( 61362306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, 61462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 61762306a36Sopenharmony_ci uinfo->count = 2; 61862306a36Sopenharmony_ci /* When inverted will give values 0x10001 => 0. */ 61962306a36Sopenharmony_ci uinfo->value.integer.min = 14; 62062306a36Sopenharmony_ci uinfo->value.integer.max = 31; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return 0; 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic int snd_at73c213_aux_capture_volume_info( 62662306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, 62762306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 63062306a36Sopenharmony_ci uinfo->count = 1; 63162306a36Sopenharmony_ci /* When inverted will give values 0x10001 => 0. */ 63262306a36Sopenharmony_ci uinfo->value.integer.min = 14; 63362306a36Sopenharmony_ci uinfo->value.integer.max = 31; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci return 0; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci#define AT73C213_MONO_SWITCH(xname, xindex, reg, shift, mask, invert) \ 63962306a36Sopenharmony_ci{ \ 64062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 64162306a36Sopenharmony_ci .name = xname, \ 64262306a36Sopenharmony_ci .index = xindex, \ 64362306a36Sopenharmony_ci .info = snd_at73c213_mono_switch_info, \ 64462306a36Sopenharmony_ci .get = snd_at73c213_mono_switch_get, \ 64562306a36Sopenharmony_ci .put = snd_at73c213_mono_switch_put, \ 64662306a36Sopenharmony_ci .private_value = (reg | (shift << 8) | (mask << 16) | (invert << 24)) \ 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci#define AT73C213_STEREO(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ 65062306a36Sopenharmony_ci{ \ 65162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 65262306a36Sopenharmony_ci .name = xname, \ 65362306a36Sopenharmony_ci .index = xindex, \ 65462306a36Sopenharmony_ci .info = snd_at73c213_stereo_info, \ 65562306a36Sopenharmony_ci .get = snd_at73c213_stereo_get, \ 65662306a36Sopenharmony_ci .put = snd_at73c213_stereo_put, \ 65762306a36Sopenharmony_ci .private_value = (left_reg | (right_reg << 8) \ 65862306a36Sopenharmony_ci | (shift_left << 16) | (shift_right << 19) \ 65962306a36Sopenharmony_ci | (mask << 24) | (invert << 22)) \ 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_at73c213_controls[] = { 66362306a36Sopenharmony_ciAT73C213_STEREO("Master Playback Volume", 0, DAC_LMPG, DAC_RMPG, 0, 0, 0x1f, 1), 66462306a36Sopenharmony_ciAT73C213_STEREO("Master Playback Switch", 0, DAC_LMPG, DAC_RMPG, 5, 5, 1, 1), 66562306a36Sopenharmony_ciAT73C213_STEREO("PCM Playback Volume", 0, DAC_LLOG, DAC_RLOG, 0, 0, 0x1f, 1), 66662306a36Sopenharmony_ciAT73C213_STEREO("PCM Playback Switch", 0, DAC_LLOG, DAC_RLOG, 5, 5, 1, 1), 66762306a36Sopenharmony_ciAT73C213_MONO_SWITCH("Mono PA Playback Switch", 0, DAC_CTRL, DAC_CTRL_ONPADRV, 66862306a36Sopenharmony_ci 0x01, 0), 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 67162306a36Sopenharmony_ci .name = "PA Playback Volume", 67262306a36Sopenharmony_ci .index = 0, 67362306a36Sopenharmony_ci .info = snd_at73c213_pa_volume_info, 67462306a36Sopenharmony_ci .get = snd_at73c213_mono_get, 67562306a36Sopenharmony_ci .put = snd_at73c213_mono_put, 67662306a36Sopenharmony_ci .private_value = PA_CTRL | (PA_CTRL_APAGAIN << 8) | \ 67762306a36Sopenharmony_ci (0x0f << 16) | (1 << 24), 67862306a36Sopenharmony_ci}, 67962306a36Sopenharmony_ciAT73C213_MONO_SWITCH("PA High Gain Playback Switch", 0, PA_CTRL, PA_CTRL_APALP, 68062306a36Sopenharmony_ci 0x01, 1), 68162306a36Sopenharmony_ciAT73C213_MONO_SWITCH("PA Playback Switch", 0, PA_CTRL, PA_CTRL_APAON, 0x01, 0), 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 68462306a36Sopenharmony_ci .name = "Aux Capture Volume", 68562306a36Sopenharmony_ci .index = 0, 68662306a36Sopenharmony_ci .info = snd_at73c213_aux_capture_volume_info, 68762306a36Sopenharmony_ci .get = snd_at73c213_mono_get, 68862306a36Sopenharmony_ci .put = snd_at73c213_mono_put, 68962306a36Sopenharmony_ci .private_value = DAC_AUXG | (0 << 8) | (0x1f << 16) | (1 << 24), 69062306a36Sopenharmony_ci}, 69162306a36Sopenharmony_ciAT73C213_MONO_SWITCH("Aux Capture Switch", 0, DAC_CTRL, DAC_CTRL_ONAUXIN, 69262306a36Sopenharmony_ci 0x01, 0), 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 69562306a36Sopenharmony_ci .name = "Line Capture Volume", 69662306a36Sopenharmony_ci .index = 0, 69762306a36Sopenharmony_ci .info = snd_at73c213_line_capture_volume_info, 69862306a36Sopenharmony_ci .get = snd_at73c213_stereo_get, 69962306a36Sopenharmony_ci .put = snd_at73c213_stereo_put, 70062306a36Sopenharmony_ci .private_value = DAC_LLIG | (DAC_RLIG << 8) | (0 << 16) | (0 << 19) 70162306a36Sopenharmony_ci | (0x1f << 24) | (1 << 22), 70262306a36Sopenharmony_ci}, 70362306a36Sopenharmony_ciAT73C213_MONO_SWITCH("Line Capture Switch", 0, DAC_CTRL, 0, 0x03, 0), 70462306a36Sopenharmony_ci}; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic int snd_at73c213_mixer(struct snd_at73c213 *chip) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct snd_card *card; 70962306a36Sopenharmony_ci int errval, idx; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (chip == NULL || chip->pcm == NULL) 71262306a36Sopenharmony_ci return -EINVAL; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci card = chip->card; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci strcpy(card->mixername, chip->pcm->name); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(snd_at73c213_controls); idx++) { 71962306a36Sopenharmony_ci errval = snd_ctl_add(card, 72062306a36Sopenharmony_ci snd_ctl_new1(&snd_at73c213_controls[idx], 72162306a36Sopenharmony_ci chip)); 72262306a36Sopenharmony_ci if (errval < 0) 72362306a36Sopenharmony_ci goto cleanup; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci return 0; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cicleanup: 72962306a36Sopenharmony_ci for (idx = 1; idx < ARRAY_SIZE(snd_at73c213_controls) + 1; idx++) { 73062306a36Sopenharmony_ci struct snd_kcontrol *kctl; 73162306a36Sopenharmony_ci kctl = snd_ctl_find_numid(card, idx); 73262306a36Sopenharmony_ci if (kctl) 73362306a36Sopenharmony_ci snd_ctl_remove(card, kctl); 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci return errval; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci/* 73962306a36Sopenharmony_ci * Device functions 74062306a36Sopenharmony_ci */ 74162306a36Sopenharmony_cistatic int snd_at73c213_ssc_init(struct snd_at73c213 *chip) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci /* 74462306a36Sopenharmony_ci * Continuous clock output. 74562306a36Sopenharmony_ci * Starts on falling TF. 74662306a36Sopenharmony_ci * Delay 1 cycle (1 bit). 74762306a36Sopenharmony_ci * Periode is 16 bit (16 - 1). 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, TCMR, 75062306a36Sopenharmony_ci SSC_BF(TCMR_CKO, 1) 75162306a36Sopenharmony_ci | SSC_BF(TCMR_START, 4) 75262306a36Sopenharmony_ci | SSC_BF(TCMR_STTDLY, 1) 75362306a36Sopenharmony_ci | SSC_BF(TCMR_PERIOD, 16 - 1)); 75462306a36Sopenharmony_ci /* 75562306a36Sopenharmony_ci * Data length is 16 bit (16 - 1). 75662306a36Sopenharmony_ci * Transmit MSB first. 75762306a36Sopenharmony_ci * Transmit 2 words each transfer. 75862306a36Sopenharmony_ci * Frame sync length is 16 bit (16 - 1). 75962306a36Sopenharmony_ci * Frame starts on negative pulse. 76062306a36Sopenharmony_ci */ 76162306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, TFMR, 76262306a36Sopenharmony_ci SSC_BF(TFMR_DATLEN, 16 - 1) 76362306a36Sopenharmony_ci | SSC_BIT(TFMR_MSBF) 76462306a36Sopenharmony_ci | SSC_BF(TFMR_DATNB, 1) 76562306a36Sopenharmony_ci | SSC_BF(TFMR_FSLEN, 16 - 1) 76662306a36Sopenharmony_ci | SSC_BF(TFMR_FSOS, 1)); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci return 0; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic int snd_at73c213_chip_init(struct snd_at73c213 *chip) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci int retval; 77462306a36Sopenharmony_ci unsigned char dac_ctrl = 0; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci retval = snd_at73c213_set_bitrate(chip); 77762306a36Sopenharmony_ci if (retval) 77862306a36Sopenharmony_ci goto out; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci /* Enable DAC master clock. */ 78162306a36Sopenharmony_ci retval = clk_enable(chip->board->dac_clk); 78262306a36Sopenharmony_ci if (retval) 78362306a36Sopenharmony_ci goto out; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* Initialize at73c213 on SPI bus. */ 78662306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RST, 0x04); 78762306a36Sopenharmony_ci if (retval) 78862306a36Sopenharmony_ci goto out_clk; 78962306a36Sopenharmony_ci msleep(1); 79062306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RST, 0x03); 79162306a36Sopenharmony_ci if (retval) 79262306a36Sopenharmony_ci goto out_clk; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* Precharge everything. */ 79562306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_PRECH, 0xff); 79662306a36Sopenharmony_ci if (retval) 79762306a36Sopenharmony_ci goto out_clk; 79862306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, PA_CTRL, (1<<PA_CTRL_APAPRECH)); 79962306a36Sopenharmony_ci if (retval) 80062306a36Sopenharmony_ci goto out_clk; 80162306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_CTRL, 80262306a36Sopenharmony_ci (1<<DAC_CTRL_ONLNOL) | (1<<DAC_CTRL_ONLNOR)); 80362306a36Sopenharmony_ci if (retval) 80462306a36Sopenharmony_ci goto out_clk; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci msleep(50); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* Stop precharging PA. */ 80962306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, PA_CTRL, 81062306a36Sopenharmony_ci (1<<PA_CTRL_APALP) | 0x0f); 81162306a36Sopenharmony_ci if (retval) 81262306a36Sopenharmony_ci goto out_clk; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci msleep(450); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* Stop precharging DAC, turn on master power. */ 81762306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_PRECH, (1<<DAC_PRECH_ONMSTR)); 81862306a36Sopenharmony_ci if (retval) 81962306a36Sopenharmony_ci goto out_clk; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci msleep(1); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci /* Turn on DAC. */ 82462306a36Sopenharmony_ci dac_ctrl = (1<<DAC_CTRL_ONDACL) | (1<<DAC_CTRL_ONDACR) 82562306a36Sopenharmony_ci | (1<<DAC_CTRL_ONLNOL) | (1<<DAC_CTRL_ONLNOR); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_CTRL, dac_ctrl); 82862306a36Sopenharmony_ci if (retval) 82962306a36Sopenharmony_ci goto out_clk; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* Mute sound. */ 83262306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_LMPG, 0x3f); 83362306a36Sopenharmony_ci if (retval) 83462306a36Sopenharmony_ci goto out_clk; 83562306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RMPG, 0x3f); 83662306a36Sopenharmony_ci if (retval) 83762306a36Sopenharmony_ci goto out_clk; 83862306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_LLOG, 0x3f); 83962306a36Sopenharmony_ci if (retval) 84062306a36Sopenharmony_ci goto out_clk; 84162306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RLOG, 0x3f); 84262306a36Sopenharmony_ci if (retval) 84362306a36Sopenharmony_ci goto out_clk; 84462306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_LLIG, 0x11); 84562306a36Sopenharmony_ci if (retval) 84662306a36Sopenharmony_ci goto out_clk; 84762306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RLIG, 0x11); 84862306a36Sopenharmony_ci if (retval) 84962306a36Sopenharmony_ci goto out_clk; 85062306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_AUXG, 0x11); 85162306a36Sopenharmony_ci if (retval) 85262306a36Sopenharmony_ci goto out_clk; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* Enable I2S device, i.e. clock output. */ 85562306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN)); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci goto out; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ciout_clk: 86062306a36Sopenharmony_ci clk_disable(chip->board->dac_clk); 86162306a36Sopenharmony_ciout: 86262306a36Sopenharmony_ci return retval; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic int snd_at73c213_dev_free(struct snd_device *device) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct snd_at73c213 *chip = device->device_data; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); 87062306a36Sopenharmony_ci if (chip->irq >= 0) { 87162306a36Sopenharmony_ci free_irq(chip->irq, chip); 87262306a36Sopenharmony_ci chip->irq = -1; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci return 0; 87662306a36Sopenharmony_ci} 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_cistatic int snd_at73c213_dev_init(struct snd_card *card, 87962306a36Sopenharmony_ci struct spi_device *spi) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci static const struct snd_device_ops ops = { 88262306a36Sopenharmony_ci .dev_free = snd_at73c213_dev_free, 88362306a36Sopenharmony_ci }; 88462306a36Sopenharmony_ci struct snd_at73c213 *chip = get_chip(card); 88562306a36Sopenharmony_ci int irq, retval; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci irq = chip->ssc->irq; 88862306a36Sopenharmony_ci if (irq < 0) 88962306a36Sopenharmony_ci return irq; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci spin_lock_init(&chip->lock); 89262306a36Sopenharmony_ci mutex_init(&chip->mixer_lock); 89362306a36Sopenharmony_ci chip->card = card; 89462306a36Sopenharmony_ci chip->irq = -1; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci retval = clk_enable(chip->ssc->clk); 89762306a36Sopenharmony_ci if (retval) 89862306a36Sopenharmony_ci return retval; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci retval = request_irq(irq, snd_at73c213_interrupt, 0, "at73c213", chip); 90162306a36Sopenharmony_ci if (retval) { 90262306a36Sopenharmony_ci dev_dbg(&chip->spi->dev, "unable to request irq %d\n", irq); 90362306a36Sopenharmony_ci goto out; 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci chip->irq = irq; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci memcpy(&chip->reg_image, &snd_at73c213_original_image, 90862306a36Sopenharmony_ci sizeof(snd_at73c213_original_image)); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci retval = snd_at73c213_ssc_init(chip); 91162306a36Sopenharmony_ci if (retval) 91262306a36Sopenharmony_ci goto out_irq; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci retval = snd_at73c213_chip_init(chip); 91562306a36Sopenharmony_ci if (retval) 91662306a36Sopenharmony_ci goto out_irq; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci retval = snd_at73c213_pcm_new(chip, 0); 91962306a36Sopenharmony_ci if (retval) 92062306a36Sopenharmony_ci goto out_irq; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci retval = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); 92362306a36Sopenharmony_ci if (retval) 92462306a36Sopenharmony_ci goto out_irq; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci retval = snd_at73c213_mixer(chip); 92762306a36Sopenharmony_ci if (retval) 92862306a36Sopenharmony_ci goto out_snd_dev; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci goto out; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ciout_snd_dev: 93362306a36Sopenharmony_ci snd_device_free(card, chip); 93462306a36Sopenharmony_ciout_irq: 93562306a36Sopenharmony_ci free_irq(chip->irq, chip); 93662306a36Sopenharmony_ci chip->irq = -1; 93762306a36Sopenharmony_ciout: 93862306a36Sopenharmony_ci clk_disable(chip->ssc->clk); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci return retval; 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_cistatic int snd_at73c213_probe(struct spi_device *spi) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci struct snd_card *card; 94662306a36Sopenharmony_ci struct snd_at73c213 *chip; 94762306a36Sopenharmony_ci struct at73c213_board_info *board; 94862306a36Sopenharmony_ci int retval; 94962306a36Sopenharmony_ci char id[16]; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci board = spi->dev.platform_data; 95262306a36Sopenharmony_ci if (!board) { 95362306a36Sopenharmony_ci dev_dbg(&spi->dev, "no platform_data\n"); 95462306a36Sopenharmony_ci return -ENXIO; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (!board->dac_clk) { 95862306a36Sopenharmony_ci dev_dbg(&spi->dev, "no DAC clk\n"); 95962306a36Sopenharmony_ci return -ENXIO; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (IS_ERR(board->dac_clk)) { 96362306a36Sopenharmony_ci dev_dbg(&spi->dev, "no DAC clk\n"); 96462306a36Sopenharmony_ci return PTR_ERR(board->dac_clk); 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci /* Allocate "card" using some unused identifiers. */ 96862306a36Sopenharmony_ci snprintf(id, sizeof id, "at73c213_%d", board->ssc_id); 96962306a36Sopenharmony_ci retval = snd_card_new(&spi->dev, -1, id, THIS_MODULE, 97062306a36Sopenharmony_ci sizeof(struct snd_at73c213), &card); 97162306a36Sopenharmony_ci if (retval < 0) 97262306a36Sopenharmony_ci goto out; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci chip = card->private_data; 97562306a36Sopenharmony_ci chip->spi = spi; 97662306a36Sopenharmony_ci chip->board = board; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci chip->ssc = ssc_request(board->ssc_id); 97962306a36Sopenharmony_ci if (IS_ERR(chip->ssc)) { 98062306a36Sopenharmony_ci dev_dbg(&spi->dev, "could not get ssc%d device\n", 98162306a36Sopenharmony_ci board->ssc_id); 98262306a36Sopenharmony_ci retval = PTR_ERR(chip->ssc); 98362306a36Sopenharmony_ci goto out_card; 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci retval = snd_at73c213_dev_init(card, spi); 98762306a36Sopenharmony_ci if (retval) 98862306a36Sopenharmony_ci goto out_ssc; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci strcpy(card->driver, "at73c213"); 99162306a36Sopenharmony_ci strcpy(card->shortname, board->shortname); 99262306a36Sopenharmony_ci sprintf(card->longname, "%s on irq %d", card->shortname, chip->irq); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci retval = snd_card_register(card); 99562306a36Sopenharmony_ci if (retval) 99662306a36Sopenharmony_ci goto out_ssc; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci dev_set_drvdata(&spi->dev, card); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci goto out; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ciout_ssc: 100362306a36Sopenharmony_ci ssc_free(chip->ssc); 100462306a36Sopenharmony_ciout_card: 100562306a36Sopenharmony_ci snd_card_free(card); 100662306a36Sopenharmony_ciout: 100762306a36Sopenharmony_ci return retval; 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_cistatic void snd_at73c213_remove(struct spi_device *spi) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci struct snd_card *card = dev_get_drvdata(&spi->dev); 101362306a36Sopenharmony_ci struct snd_at73c213 *chip = card->private_data; 101462306a36Sopenharmony_ci int retval; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* Stop playback. */ 101762306a36Sopenharmony_ci retval = clk_enable(chip->ssc->clk); 101862306a36Sopenharmony_ci if (retval) 101962306a36Sopenharmony_ci goto out; 102062306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); 102162306a36Sopenharmony_ci clk_disable(chip->ssc->clk); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci /* Mute sound. */ 102462306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_LMPG, 0x3f); 102562306a36Sopenharmony_ci if (retval) 102662306a36Sopenharmony_ci goto out; 102762306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RMPG, 0x3f); 102862306a36Sopenharmony_ci if (retval) 102962306a36Sopenharmony_ci goto out; 103062306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_LLOG, 0x3f); 103162306a36Sopenharmony_ci if (retval) 103262306a36Sopenharmony_ci goto out; 103362306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RLOG, 0x3f); 103462306a36Sopenharmony_ci if (retval) 103562306a36Sopenharmony_ci goto out; 103662306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_LLIG, 0x11); 103762306a36Sopenharmony_ci if (retval) 103862306a36Sopenharmony_ci goto out; 103962306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RLIG, 0x11); 104062306a36Sopenharmony_ci if (retval) 104162306a36Sopenharmony_ci goto out; 104262306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_AUXG, 0x11); 104362306a36Sopenharmony_ci if (retval) 104462306a36Sopenharmony_ci goto out; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci /* Turn off PA. */ 104762306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, PA_CTRL, 104862306a36Sopenharmony_ci chip->reg_image[PA_CTRL] | 0x0f); 104962306a36Sopenharmony_ci if (retval) 105062306a36Sopenharmony_ci goto out; 105162306a36Sopenharmony_ci msleep(10); 105262306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, PA_CTRL, 105362306a36Sopenharmony_ci (1 << PA_CTRL_APALP) | 0x0f); 105462306a36Sopenharmony_ci if (retval) 105562306a36Sopenharmony_ci goto out; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci /* Turn off external DAC. */ 105862306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_CTRL, 0x0c); 105962306a36Sopenharmony_ci if (retval) 106062306a36Sopenharmony_ci goto out; 106162306a36Sopenharmony_ci msleep(2); 106262306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_CTRL, 0x00); 106362306a36Sopenharmony_ci if (retval) 106462306a36Sopenharmony_ci goto out; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci /* Turn off master power. */ 106762306a36Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_PRECH, 0x00); 106862306a36Sopenharmony_ci if (retval) 106962306a36Sopenharmony_ci goto out; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ciout: 107262306a36Sopenharmony_ci /* Stop DAC master clock. */ 107362306a36Sopenharmony_ci clk_disable(chip->board->dac_clk); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci ssc_free(chip->ssc); 107662306a36Sopenharmony_ci snd_card_free(card); 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_cistatic int snd_at73c213_suspend(struct device *dev) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 108462306a36Sopenharmony_ci struct snd_at73c213 *chip = card->private_data; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); 108762306a36Sopenharmony_ci clk_disable(chip->ssc->clk); 108862306a36Sopenharmony_ci clk_disable(chip->board->dac_clk); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci return 0; 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_cistatic int snd_at73c213_resume(struct device *dev) 109462306a36Sopenharmony_ci{ 109562306a36Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 109662306a36Sopenharmony_ci struct snd_at73c213 *chip = card->private_data; 109762306a36Sopenharmony_ci int retval; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci retval = clk_enable(chip->board->dac_clk); 110062306a36Sopenharmony_ci if (retval) 110162306a36Sopenharmony_ci return retval; 110262306a36Sopenharmony_ci retval = clk_enable(chip->ssc->clk); 110362306a36Sopenharmony_ci if (retval) { 110462306a36Sopenharmony_ci clk_disable(chip->board->dac_clk); 110562306a36Sopenharmony_ci return retval; 110662306a36Sopenharmony_ci } 110762306a36Sopenharmony_ci ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN)); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci return 0; 111062306a36Sopenharmony_ci} 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(at73c213_pm_ops, snd_at73c213_suspend, 111362306a36Sopenharmony_ci snd_at73c213_resume); 111462306a36Sopenharmony_ci#define AT73C213_PM_OPS (&at73c213_pm_ops) 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci#else 111762306a36Sopenharmony_ci#define AT73C213_PM_OPS NULL 111862306a36Sopenharmony_ci#endif 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic struct spi_driver at73c213_driver = { 112162306a36Sopenharmony_ci .driver = { 112262306a36Sopenharmony_ci .name = "at73c213", 112362306a36Sopenharmony_ci .pm = AT73C213_PM_OPS, 112462306a36Sopenharmony_ci }, 112562306a36Sopenharmony_ci .probe = snd_at73c213_probe, 112662306a36Sopenharmony_ci .remove = snd_at73c213_remove, 112762306a36Sopenharmony_ci}; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cimodule_spi_driver(at73c213_driver); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ciMODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>"); 113262306a36Sopenharmony_ciMODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC"); 113362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1134