18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for AT73C213 16-bit stereo DAC connected to Atmel SSC 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2007 Atmel Norway 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/*#define DEBUG*/ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/clk.h> 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/device.h> 148c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/mutex.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/io.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <sound/initval.h> 238c2ecf20Sopenharmony_ci#include <sound/control.h> 248c2ecf20Sopenharmony_ci#include <sound/core.h> 258c2ecf20Sopenharmony_ci#include <sound/pcm.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/atmel-ssc.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 308c2ecf20Sopenharmony_ci#include <linux/spi/at73c213.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "at73c213.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define BITRATE_MIN 8000 /* Hardware limit? */ 358c2ecf20Sopenharmony_ci#define BITRATE_TARGET CONFIG_SND_AT73C213_TARGET_BITRATE 368c2ecf20Sopenharmony_ci#define BITRATE_MAX 50000 /* Hardware limit. */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* Initial (hardware reset) AT73C213 register values. */ 398c2ecf20Sopenharmony_cistatic const u8 snd_at73c213_original_image[18] = 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci 0x00, /* 00 - CTRL */ 428c2ecf20Sopenharmony_ci 0x05, /* 01 - LLIG */ 438c2ecf20Sopenharmony_ci 0x05, /* 02 - RLIG */ 448c2ecf20Sopenharmony_ci 0x08, /* 03 - LPMG */ 458c2ecf20Sopenharmony_ci 0x08, /* 04 - RPMG */ 468c2ecf20Sopenharmony_ci 0x00, /* 05 - LLOG */ 478c2ecf20Sopenharmony_ci 0x00, /* 06 - RLOG */ 488c2ecf20Sopenharmony_ci 0x22, /* 07 - OLC */ 498c2ecf20Sopenharmony_ci 0x09, /* 08 - MC */ 508c2ecf20Sopenharmony_ci 0x00, /* 09 - CSFC */ 518c2ecf20Sopenharmony_ci 0x00, /* 0A - MISC */ 528c2ecf20Sopenharmony_ci 0x00, /* 0B - */ 538c2ecf20Sopenharmony_ci 0x00, /* 0C - PRECH */ 548c2ecf20Sopenharmony_ci 0x05, /* 0D - AUXG */ 558c2ecf20Sopenharmony_ci 0x00, /* 0E - */ 568c2ecf20Sopenharmony_ci 0x00, /* 0F - */ 578c2ecf20Sopenharmony_ci 0x00, /* 10 - RST */ 588c2ecf20Sopenharmony_ci 0x00, /* 11 - PA_CTRL */ 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistruct snd_at73c213 { 628c2ecf20Sopenharmony_ci struct snd_card *card; 638c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 648c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream; 658c2ecf20Sopenharmony_ci struct at73c213_board_info *board; 668c2ecf20Sopenharmony_ci int irq; 678c2ecf20Sopenharmony_ci int period; 688c2ecf20Sopenharmony_ci unsigned long bitrate; 698c2ecf20Sopenharmony_ci struct ssc_device *ssc; 708c2ecf20Sopenharmony_ci struct spi_device *spi; 718c2ecf20Sopenharmony_ci u8 spi_wbuffer[2]; 728c2ecf20Sopenharmony_ci u8 spi_rbuffer[2]; 738c2ecf20Sopenharmony_ci /* Image of the SPI registers in AT73C213. */ 748c2ecf20Sopenharmony_ci u8 reg_image[18]; 758c2ecf20Sopenharmony_ci /* Protect SSC registers against concurrent access. */ 768c2ecf20Sopenharmony_ci spinlock_t lock; 778c2ecf20Sopenharmony_ci /* Protect mixer registers against concurrent access. */ 788c2ecf20Sopenharmony_ci struct mutex mixer_lock; 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define get_chip(card) ((struct snd_at73c213 *)card->private_data) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int 848c2ecf20Sopenharmony_cisnd_at73c213_write_reg(struct snd_at73c213 *chip, u8 reg, u8 val) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct spi_message msg; 878c2ecf20Sopenharmony_ci struct spi_transfer msg_xfer = { 888c2ecf20Sopenharmony_ci .len = 2, 898c2ecf20Sopenharmony_ci .cs_change = 0, 908c2ecf20Sopenharmony_ci }; 918c2ecf20Sopenharmony_ci int retval; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci spi_message_init(&msg); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci chip->spi_wbuffer[0] = reg; 968c2ecf20Sopenharmony_ci chip->spi_wbuffer[1] = val; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci msg_xfer.tx_buf = chip->spi_wbuffer; 998c2ecf20Sopenharmony_ci msg_xfer.rx_buf = chip->spi_rbuffer; 1008c2ecf20Sopenharmony_ci spi_message_add_tail(&msg_xfer, &msg); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci retval = spi_sync(chip->spi, &msg); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (!retval) 1058c2ecf20Sopenharmony_ci chip->reg_image[reg] = val; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return retval; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic struct snd_pcm_hardware snd_at73c213_playback_hw = { 1118c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | 1128c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER, 1138c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_BE, 1148c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS, 1158c2ecf20Sopenharmony_ci .rate_min = 8000, /* Replaced by chip->bitrate later. */ 1168c2ecf20Sopenharmony_ci .rate_max = 50000, /* Replaced by chip->bitrate later. */ 1178c2ecf20Sopenharmony_ci .channels_min = 1, 1188c2ecf20Sopenharmony_ci .channels_max = 2, 1198c2ecf20Sopenharmony_ci .buffer_bytes_max = 64 * 1024 - 1, 1208c2ecf20Sopenharmony_ci .period_bytes_min = 512, 1218c2ecf20Sopenharmony_ci .period_bytes_max = 64 * 1024 - 1, 1228c2ecf20Sopenharmony_ci .periods_min = 4, 1238c2ecf20Sopenharmony_ci .periods_max = 1024, 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/* 1278c2ecf20Sopenharmony_ci * Calculate and set bitrate and divisions. 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_cistatic int snd_at73c213_set_bitrate(struct snd_at73c213 *chip) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci unsigned long ssc_rate = clk_get_rate(chip->ssc->clk); 1328c2ecf20Sopenharmony_ci unsigned long dac_rate_new, ssc_div; 1338c2ecf20Sopenharmony_ci int status; 1348c2ecf20Sopenharmony_ci unsigned long ssc_div_max, ssc_div_min; 1358c2ecf20Sopenharmony_ci int max_tries; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * We connect two clocks here, picking divisors so the I2S clocks 1398c2ecf20Sopenharmony_ci * out data at the same rate the DAC clocks it in ... and as close 1408c2ecf20Sopenharmony_ci * as practical to the desired target rate. 1418c2ecf20Sopenharmony_ci * 1428c2ecf20Sopenharmony_ci * The DAC master clock (MCLK) is programmable, and is either 256 1438c2ecf20Sopenharmony_ci * or (not here) 384 times the I2S output clock (BCLK). 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* SSC clock / (bitrate * stereo * 16-bit). */ 1478c2ecf20Sopenharmony_ci ssc_div = ssc_rate / (BITRATE_TARGET * 2 * 16); 1488c2ecf20Sopenharmony_ci ssc_div_min = ssc_rate / (BITRATE_MAX * 2 * 16); 1498c2ecf20Sopenharmony_ci ssc_div_max = ssc_rate / (BITRATE_MIN * 2 * 16); 1508c2ecf20Sopenharmony_ci max_tries = (ssc_div_max - ssc_div_min) / 2; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (max_tries < 1) 1538c2ecf20Sopenharmony_ci max_tries = 1; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* ssc_div must be even. */ 1568c2ecf20Sopenharmony_ci ssc_div = (ssc_div + 1) & ~1UL; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) { 1598c2ecf20Sopenharmony_ci ssc_div -= 2; 1608c2ecf20Sopenharmony_ci if ((ssc_rate / (ssc_div * 2 * 16)) > BITRATE_MAX) 1618c2ecf20Sopenharmony_ci return -ENXIO; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* Search for a possible bitrate. */ 1658c2ecf20Sopenharmony_ci do { 1668c2ecf20Sopenharmony_ci /* SSC clock / (ssc divider * 16-bit * stereo). */ 1678c2ecf20Sopenharmony_ci if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) 1688c2ecf20Sopenharmony_ci return -ENXIO; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* 256 / (2 * 16) = 8 */ 1718c2ecf20Sopenharmony_ci dac_rate_new = 8 * (ssc_rate / ssc_div); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci status = clk_round_rate(chip->board->dac_clk, dac_rate_new); 1748c2ecf20Sopenharmony_ci if (status <= 0) 1758c2ecf20Sopenharmony_ci return status; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* Ignore difference smaller than 256 Hz. */ 1788c2ecf20Sopenharmony_ci if ((status/256) == (dac_rate_new/256)) 1798c2ecf20Sopenharmony_ci goto set_rate; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci ssc_div += 2; 1828c2ecf20Sopenharmony_ci } while (--max_tries); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* Not able to find a valid bitrate. */ 1858c2ecf20Sopenharmony_ci return -ENXIO; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ciset_rate: 1888c2ecf20Sopenharmony_ci status = clk_set_rate(chip->board->dac_clk, status); 1898c2ecf20Sopenharmony_ci if (status < 0) 1908c2ecf20Sopenharmony_ci return status; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* Set divider in SSC device. */ 1938c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, CMR, ssc_div/2); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* SSC clock / (ssc divider * 16-bit * stereo). */ 1968c2ecf20Sopenharmony_ci chip->bitrate = ssc_rate / (ssc_div * 16 * 2); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci dev_info(&chip->spi->dev, 1998c2ecf20Sopenharmony_ci "at73c213: supported bitrate is %lu (%lu divider)\n", 2008c2ecf20Sopenharmony_ci chip->bitrate, ssc_div); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return 0; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic int snd_at73c213_pcm_open(struct snd_pcm_substream *substream) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); 2088c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 2098c2ecf20Sopenharmony_ci int err; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* ensure buffer_size is a multiple of period_size */ 2128c2ecf20Sopenharmony_ci err = snd_pcm_hw_constraint_integer(runtime, 2138c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS); 2148c2ecf20Sopenharmony_ci if (err < 0) 2158c2ecf20Sopenharmony_ci return err; 2168c2ecf20Sopenharmony_ci snd_at73c213_playback_hw.rate_min = chip->bitrate; 2178c2ecf20Sopenharmony_ci snd_at73c213_playback_hw.rate_max = chip->bitrate; 2188c2ecf20Sopenharmony_ci runtime->hw = snd_at73c213_playback_hw; 2198c2ecf20Sopenharmony_ci chip->substream = substream; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci err = clk_enable(chip->ssc->clk); 2228c2ecf20Sopenharmony_ci if (err) 2238c2ecf20Sopenharmony_ci return err; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return 0; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic int snd_at73c213_pcm_close(struct snd_pcm_substream *substream) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); 2318c2ecf20Sopenharmony_ci chip->substream = NULL; 2328c2ecf20Sopenharmony_ci clk_disable(chip->ssc->clk); 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int snd_at73c213_pcm_hw_params(struct snd_pcm_substream *substream, 2378c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); 2408c2ecf20Sopenharmony_ci int channels = params_channels(hw_params); 2418c2ecf20Sopenharmony_ci int val; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci val = ssc_readl(chip->ssc->regs, TFMR); 2448c2ecf20Sopenharmony_ci val = SSC_BFINS(TFMR_DATNB, channels - 1, val); 2458c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, TFMR, val); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int snd_at73c213_pcm_prepare(struct snd_pcm_substream *substream) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); 2538c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 2548c2ecf20Sopenharmony_ci int block_size; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci block_size = frames_to_bytes(runtime, runtime->period_size); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci chip->period = 0; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_TPR, 2618c2ecf20Sopenharmony_ci (long)runtime->dma_addr); 2628c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_TCR, 2638c2ecf20Sopenharmony_ci runtime->period_size * runtime->channels); 2648c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_TNPR, 2658c2ecf20Sopenharmony_ci (long)runtime->dma_addr + block_size); 2668c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_TNCR, 2678c2ecf20Sopenharmony_ci runtime->period_size * runtime->channels); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic int snd_at73c213_pcm_trigger(struct snd_pcm_substream *substream, 2738c2ecf20Sopenharmony_ci int cmd) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); 2768c2ecf20Sopenharmony_ci int retval = 0; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci spin_lock(&chip->lock); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci switch (cmd) { 2818c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 2828c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, IER, SSC_BIT(IER_ENDTX)); 2838c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTEN)); 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 2868c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTDIS)); 2878c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, IDR, SSC_BIT(IDR_ENDTX)); 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci default: 2908c2ecf20Sopenharmony_ci dev_dbg(&chip->spi->dev, "spurious command %x\n", cmd); 2918c2ecf20Sopenharmony_ci retval = -EINVAL; 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci spin_unlock(&chip->lock); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return retval; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t 3018c2ecf20Sopenharmony_cisnd_at73c213_pcm_pointer(struct snd_pcm_substream *substream) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); 3048c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 3058c2ecf20Sopenharmony_ci snd_pcm_uframes_t pos; 3068c2ecf20Sopenharmony_ci unsigned long bytes; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci bytes = ssc_readl(chip->ssc->regs, PDC_TPR) 3098c2ecf20Sopenharmony_ci - (unsigned long)runtime->dma_addr; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci pos = bytes_to_frames(runtime, bytes); 3128c2ecf20Sopenharmony_ci if (pos >= runtime->buffer_size) 3138c2ecf20Sopenharmony_ci pos -= runtime->buffer_size; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return pos; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops at73c213_playback_ops = { 3198c2ecf20Sopenharmony_ci .open = snd_at73c213_pcm_open, 3208c2ecf20Sopenharmony_ci .close = snd_at73c213_pcm_close, 3218c2ecf20Sopenharmony_ci .hw_params = snd_at73c213_pcm_hw_params, 3228c2ecf20Sopenharmony_ci .prepare = snd_at73c213_pcm_prepare, 3238c2ecf20Sopenharmony_ci .trigger = snd_at73c213_pcm_trigger, 3248c2ecf20Sopenharmony_ci .pointer = snd_at73c213_pcm_pointer, 3258c2ecf20Sopenharmony_ci}; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic int snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 3308c2ecf20Sopenharmony_ci int retval; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci retval = snd_pcm_new(chip->card, chip->card->shortname, 3338c2ecf20Sopenharmony_ci device, 1, 0, &pcm); 3348c2ecf20Sopenharmony_ci if (retval < 0) 3358c2ecf20Sopenharmony_ci goto out; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci pcm->private_data = chip; 3388c2ecf20Sopenharmony_ci pcm->info_flags = SNDRV_PCM_INFO_BLOCK_TRANSFER; 3398c2ecf20Sopenharmony_ci strcpy(pcm->name, "at73c213"); 3408c2ecf20Sopenharmony_ci chip->pcm = pcm; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &at73c213_playback_ops); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(chip->pcm, 3458c2ecf20Sopenharmony_ci SNDRV_DMA_TYPE_DEV, &chip->ssc->pdev->dev, 3468c2ecf20Sopenharmony_ci 64 * 1024, 64 * 1024); 3478c2ecf20Sopenharmony_ciout: 3488c2ecf20Sopenharmony_ci return retval; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic irqreturn_t snd_at73c213_interrupt(int irq, void *dev_id) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = dev_id; 3548c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = chip->substream->runtime; 3558c2ecf20Sopenharmony_ci u32 status; 3568c2ecf20Sopenharmony_ci int offset; 3578c2ecf20Sopenharmony_ci int block_size; 3588c2ecf20Sopenharmony_ci int next_period; 3598c2ecf20Sopenharmony_ci int retval = IRQ_NONE; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci spin_lock(&chip->lock); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci block_size = frames_to_bytes(runtime, runtime->period_size); 3648c2ecf20Sopenharmony_ci status = ssc_readl(chip->ssc->regs, IMR); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (status & SSC_BIT(IMR_ENDTX)) { 3678c2ecf20Sopenharmony_ci chip->period++; 3688c2ecf20Sopenharmony_ci if (chip->period == runtime->periods) 3698c2ecf20Sopenharmony_ci chip->period = 0; 3708c2ecf20Sopenharmony_ci next_period = chip->period + 1; 3718c2ecf20Sopenharmony_ci if (next_period == runtime->periods) 3728c2ecf20Sopenharmony_ci next_period = 0; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci offset = block_size * next_period; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_TNPR, 3778c2ecf20Sopenharmony_ci (long)runtime->dma_addr + offset); 3788c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, PDC_TNCR, 3798c2ecf20Sopenharmony_ci runtime->period_size * runtime->channels); 3808c2ecf20Sopenharmony_ci retval = IRQ_HANDLED; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci ssc_readl(chip->ssc->regs, IMR); 3848c2ecf20Sopenharmony_ci spin_unlock(&chip->lock); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (status & SSC_BIT(IMR_ENDTX)) 3878c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(chip->substream); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci return retval; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci/* 3938c2ecf20Sopenharmony_ci * Mixer functions. 3948c2ecf20Sopenharmony_ci */ 3958c2ecf20Sopenharmony_cistatic int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol, 3968c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); 3998c2ecf20Sopenharmony_ci int reg = kcontrol->private_value & 0xff; 4008c2ecf20Sopenharmony_ci int shift = (kcontrol->private_value >> 8) & 0xff; 4018c2ecf20Sopenharmony_ci int mask = (kcontrol->private_value >> 16) & 0xff; 4028c2ecf20Sopenharmony_ci int invert = (kcontrol->private_value >> 24) & 0xff; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_lock); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 4078c2ecf20Sopenharmony_ci (chip->reg_image[reg] >> shift) & mask; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (invert) 4108c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 4118c2ecf20Sopenharmony_ci mask - ucontrol->value.integer.value[0]; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci return 0; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic int snd_at73c213_mono_put(struct snd_kcontrol *kcontrol, 4198c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); 4228c2ecf20Sopenharmony_ci int reg = kcontrol->private_value & 0xff; 4238c2ecf20Sopenharmony_ci int shift = (kcontrol->private_value >> 8) & 0xff; 4248c2ecf20Sopenharmony_ci int mask = (kcontrol->private_value >> 16) & 0xff; 4258c2ecf20Sopenharmony_ci int invert = (kcontrol->private_value >> 24) & 0xff; 4268c2ecf20Sopenharmony_ci int change, retval; 4278c2ecf20Sopenharmony_ci unsigned short val; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci val = (ucontrol->value.integer.value[0] & mask); 4308c2ecf20Sopenharmony_ci if (invert) 4318c2ecf20Sopenharmony_ci val = mask - val; 4328c2ecf20Sopenharmony_ci val <<= shift; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_lock); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci val = (chip->reg_image[reg] & ~(mask << shift)) | val; 4378c2ecf20Sopenharmony_ci change = val != chip->reg_image[reg]; 4388c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, reg, val); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (retval) 4438c2ecf20Sopenharmony_ci return retval; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return change; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic int snd_at73c213_stereo_info(struct snd_kcontrol *kcontrol, 4498c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci int mask = (kcontrol->private_value >> 24) & 0xff; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (mask == 1) 4548c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 4558c2ecf20Sopenharmony_ci else 4568c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci uinfo->count = 2; 4598c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 4608c2ecf20Sopenharmony_ci uinfo->value.integer.max = mask; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return 0; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol, 4668c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); 4698c2ecf20Sopenharmony_ci int left_reg = kcontrol->private_value & 0xff; 4708c2ecf20Sopenharmony_ci int right_reg = (kcontrol->private_value >> 8) & 0xff; 4718c2ecf20Sopenharmony_ci int shift_left = (kcontrol->private_value >> 16) & 0x07; 4728c2ecf20Sopenharmony_ci int shift_right = (kcontrol->private_value >> 19) & 0x07; 4738c2ecf20Sopenharmony_ci int mask = (kcontrol->private_value >> 24) & 0xff; 4748c2ecf20Sopenharmony_ci int invert = (kcontrol->private_value >> 22) & 1; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_lock); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 4798c2ecf20Sopenharmony_ci (chip->reg_image[left_reg] >> shift_left) & mask; 4808c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = 4818c2ecf20Sopenharmony_ci (chip->reg_image[right_reg] >> shift_right) & mask; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (invert) { 4848c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 4858c2ecf20Sopenharmony_ci mask - ucontrol->value.integer.value[0]; 4868c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = 4878c2ecf20Sopenharmony_ci mask - ucontrol->value.integer.value[1]; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci return 0; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol, 4968c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); 4998c2ecf20Sopenharmony_ci int left_reg = kcontrol->private_value & 0xff; 5008c2ecf20Sopenharmony_ci int right_reg = (kcontrol->private_value >> 8) & 0xff; 5018c2ecf20Sopenharmony_ci int shift_left = (kcontrol->private_value >> 16) & 0x07; 5028c2ecf20Sopenharmony_ci int shift_right = (kcontrol->private_value >> 19) & 0x07; 5038c2ecf20Sopenharmony_ci int mask = (kcontrol->private_value >> 24) & 0xff; 5048c2ecf20Sopenharmony_ci int invert = (kcontrol->private_value >> 22) & 1; 5058c2ecf20Sopenharmony_ci int change, retval; 5068c2ecf20Sopenharmony_ci unsigned short val1, val2; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci val1 = ucontrol->value.integer.value[0] & mask; 5098c2ecf20Sopenharmony_ci val2 = ucontrol->value.integer.value[1] & mask; 5108c2ecf20Sopenharmony_ci if (invert) { 5118c2ecf20Sopenharmony_ci val1 = mask - val1; 5128c2ecf20Sopenharmony_ci val2 = mask - val2; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci val1 <<= shift_left; 5158c2ecf20Sopenharmony_ci val2 <<= shift_right; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_lock); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci val1 = (chip->reg_image[left_reg] & ~(mask << shift_left)) | val1; 5208c2ecf20Sopenharmony_ci val2 = (chip->reg_image[right_reg] & ~(mask << shift_right)) | val2; 5218c2ecf20Sopenharmony_ci change = val1 != chip->reg_image[left_reg] 5228c2ecf20Sopenharmony_ci || val2 != chip->reg_image[right_reg]; 5238c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, left_reg, val1); 5248c2ecf20Sopenharmony_ci if (retval) { 5258c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 5268c2ecf20Sopenharmony_ci goto out; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, right_reg, val2); 5298c2ecf20Sopenharmony_ci if (retval) { 5308c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 5318c2ecf20Sopenharmony_ci goto out; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return change; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ciout: 5398c2ecf20Sopenharmony_ci return retval; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci#define snd_at73c213_mono_switch_info snd_ctl_boolean_mono_info 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, 5458c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); 5488c2ecf20Sopenharmony_ci int reg = kcontrol->private_value & 0xff; 5498c2ecf20Sopenharmony_ci int shift = (kcontrol->private_value >> 8) & 0xff; 5508c2ecf20Sopenharmony_ci int invert = (kcontrol->private_value >> 24) & 0xff; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_lock); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 5558c2ecf20Sopenharmony_ci (chip->reg_image[reg] >> shift) & 0x01; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (invert) 5588c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 5598c2ecf20Sopenharmony_ci 0x01 - ucontrol->value.integer.value[0]; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol, 5678c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); 5708c2ecf20Sopenharmony_ci int reg = kcontrol->private_value & 0xff; 5718c2ecf20Sopenharmony_ci int shift = (kcontrol->private_value >> 8) & 0xff; 5728c2ecf20Sopenharmony_ci int mask = (kcontrol->private_value >> 16) & 0xff; 5738c2ecf20Sopenharmony_ci int invert = (kcontrol->private_value >> 24) & 0xff; 5748c2ecf20Sopenharmony_ci int change, retval; 5758c2ecf20Sopenharmony_ci unsigned short val; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (ucontrol->value.integer.value[0]) 5788c2ecf20Sopenharmony_ci val = mask; 5798c2ecf20Sopenharmony_ci else 5808c2ecf20Sopenharmony_ci val = 0; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (invert) 5838c2ecf20Sopenharmony_ci val = mask - val; 5848c2ecf20Sopenharmony_ci val <<= shift; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci mutex_lock(&chip->mixer_lock); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci val |= (chip->reg_image[reg] & ~(mask << shift)); 5898c2ecf20Sopenharmony_ci change = val != chip->reg_image[reg]; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, reg, val); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci mutex_unlock(&chip->mixer_lock); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (retval) 5968c2ecf20Sopenharmony_ci return retval; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci return change; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic int snd_at73c213_pa_volume_info(struct snd_kcontrol *kcontrol, 6028c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 6058c2ecf20Sopenharmony_ci uinfo->count = 1; 6068c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 6078c2ecf20Sopenharmony_ci uinfo->value.integer.max = ((kcontrol->private_value >> 16) & 0xff) - 1; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci return 0; 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic int snd_at73c213_line_capture_volume_info( 6138c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, 6148c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 6178c2ecf20Sopenharmony_ci uinfo->count = 2; 6188c2ecf20Sopenharmony_ci /* When inverted will give values 0x10001 => 0. */ 6198c2ecf20Sopenharmony_ci uinfo->value.integer.min = 14; 6208c2ecf20Sopenharmony_ci uinfo->value.integer.max = 31; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci return 0; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int snd_at73c213_aux_capture_volume_info( 6268c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, 6278c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 6308c2ecf20Sopenharmony_ci uinfo->count = 1; 6318c2ecf20Sopenharmony_ci /* When inverted will give values 0x10001 => 0. */ 6328c2ecf20Sopenharmony_ci uinfo->value.integer.min = 14; 6338c2ecf20Sopenharmony_ci uinfo->value.integer.max = 31; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return 0; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci#define AT73C213_MONO_SWITCH(xname, xindex, reg, shift, mask, invert) \ 6398c2ecf20Sopenharmony_ci{ \ 6408c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 6418c2ecf20Sopenharmony_ci .name = xname, \ 6428c2ecf20Sopenharmony_ci .index = xindex, \ 6438c2ecf20Sopenharmony_ci .info = snd_at73c213_mono_switch_info, \ 6448c2ecf20Sopenharmony_ci .get = snd_at73c213_mono_switch_get, \ 6458c2ecf20Sopenharmony_ci .put = snd_at73c213_mono_switch_put, \ 6468c2ecf20Sopenharmony_ci .private_value = (reg | (shift << 8) | (mask << 16) | (invert << 24)) \ 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci#define AT73C213_STEREO(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ 6508c2ecf20Sopenharmony_ci{ \ 6518c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 6528c2ecf20Sopenharmony_ci .name = xname, \ 6538c2ecf20Sopenharmony_ci .index = xindex, \ 6548c2ecf20Sopenharmony_ci .info = snd_at73c213_stereo_info, \ 6558c2ecf20Sopenharmony_ci .get = snd_at73c213_stereo_get, \ 6568c2ecf20Sopenharmony_ci .put = snd_at73c213_stereo_put, \ 6578c2ecf20Sopenharmony_ci .private_value = (left_reg | (right_reg << 8) \ 6588c2ecf20Sopenharmony_ci | (shift_left << 16) | (shift_right << 19) \ 6598c2ecf20Sopenharmony_ci | (mask << 24) | (invert << 22)) \ 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_at73c213_controls[] = { 6638c2ecf20Sopenharmony_ciAT73C213_STEREO("Master Playback Volume", 0, DAC_LMPG, DAC_RMPG, 0, 0, 0x1f, 1), 6648c2ecf20Sopenharmony_ciAT73C213_STEREO("Master Playback Switch", 0, DAC_LMPG, DAC_RMPG, 5, 5, 1, 1), 6658c2ecf20Sopenharmony_ciAT73C213_STEREO("PCM Playback Volume", 0, DAC_LLOG, DAC_RLOG, 0, 0, 0x1f, 1), 6668c2ecf20Sopenharmony_ciAT73C213_STEREO("PCM Playback Switch", 0, DAC_LLOG, DAC_RLOG, 5, 5, 1, 1), 6678c2ecf20Sopenharmony_ciAT73C213_MONO_SWITCH("Mono PA Playback Switch", 0, DAC_CTRL, DAC_CTRL_ONPADRV, 6688c2ecf20Sopenharmony_ci 0x01, 0), 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 6718c2ecf20Sopenharmony_ci .name = "PA Playback Volume", 6728c2ecf20Sopenharmony_ci .index = 0, 6738c2ecf20Sopenharmony_ci .info = snd_at73c213_pa_volume_info, 6748c2ecf20Sopenharmony_ci .get = snd_at73c213_mono_get, 6758c2ecf20Sopenharmony_ci .put = snd_at73c213_mono_put, 6768c2ecf20Sopenharmony_ci .private_value = PA_CTRL | (PA_CTRL_APAGAIN << 8) | \ 6778c2ecf20Sopenharmony_ci (0x0f << 16) | (1 << 24), 6788c2ecf20Sopenharmony_ci}, 6798c2ecf20Sopenharmony_ciAT73C213_MONO_SWITCH("PA High Gain Playback Switch", 0, PA_CTRL, PA_CTRL_APALP, 6808c2ecf20Sopenharmony_ci 0x01, 1), 6818c2ecf20Sopenharmony_ciAT73C213_MONO_SWITCH("PA Playback Switch", 0, PA_CTRL, PA_CTRL_APAON, 0x01, 0), 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 6848c2ecf20Sopenharmony_ci .name = "Aux Capture Volume", 6858c2ecf20Sopenharmony_ci .index = 0, 6868c2ecf20Sopenharmony_ci .info = snd_at73c213_aux_capture_volume_info, 6878c2ecf20Sopenharmony_ci .get = snd_at73c213_mono_get, 6888c2ecf20Sopenharmony_ci .put = snd_at73c213_mono_put, 6898c2ecf20Sopenharmony_ci .private_value = DAC_AUXG | (0 << 8) | (0x1f << 16) | (1 << 24), 6908c2ecf20Sopenharmony_ci}, 6918c2ecf20Sopenharmony_ciAT73C213_MONO_SWITCH("Aux Capture Switch", 0, DAC_CTRL, DAC_CTRL_ONAUXIN, 6928c2ecf20Sopenharmony_ci 0x01, 0), 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 6958c2ecf20Sopenharmony_ci .name = "Line Capture Volume", 6968c2ecf20Sopenharmony_ci .index = 0, 6978c2ecf20Sopenharmony_ci .info = snd_at73c213_line_capture_volume_info, 6988c2ecf20Sopenharmony_ci .get = snd_at73c213_stereo_get, 6998c2ecf20Sopenharmony_ci .put = snd_at73c213_stereo_put, 7008c2ecf20Sopenharmony_ci .private_value = DAC_LLIG | (DAC_RLIG << 8) | (0 << 16) | (0 << 19) 7018c2ecf20Sopenharmony_ci | (0x1f << 24) | (1 << 22), 7028c2ecf20Sopenharmony_ci}, 7038c2ecf20Sopenharmony_ciAT73C213_MONO_SWITCH("Line Capture Switch", 0, DAC_CTRL, 0, 0x03, 0), 7048c2ecf20Sopenharmony_ci}; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic int snd_at73c213_mixer(struct snd_at73c213 *chip) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci struct snd_card *card; 7098c2ecf20Sopenharmony_ci int errval, idx; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (chip == NULL || chip->pcm == NULL) 7128c2ecf20Sopenharmony_ci return -EINVAL; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci card = chip->card; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci strcpy(card->mixername, chip->pcm->name); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(snd_at73c213_controls); idx++) { 7198c2ecf20Sopenharmony_ci errval = snd_ctl_add(card, 7208c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_at73c213_controls[idx], 7218c2ecf20Sopenharmony_ci chip)); 7228c2ecf20Sopenharmony_ci if (errval < 0) 7238c2ecf20Sopenharmony_ci goto cleanup; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return 0; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cicleanup: 7298c2ecf20Sopenharmony_ci for (idx = 1; idx < ARRAY_SIZE(snd_at73c213_controls) + 1; idx++) { 7308c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl; 7318c2ecf20Sopenharmony_ci kctl = snd_ctl_find_numid(card, idx); 7328c2ecf20Sopenharmony_ci if (kctl) 7338c2ecf20Sopenharmony_ci snd_ctl_remove(card, kctl); 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci return errval; 7368c2ecf20Sopenharmony_ci} 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci/* 7398c2ecf20Sopenharmony_ci * Device functions 7408c2ecf20Sopenharmony_ci */ 7418c2ecf20Sopenharmony_cistatic int snd_at73c213_ssc_init(struct snd_at73c213 *chip) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci /* 7448c2ecf20Sopenharmony_ci * Continuous clock output. 7458c2ecf20Sopenharmony_ci * Starts on falling TF. 7468c2ecf20Sopenharmony_ci * Delay 1 cycle (1 bit). 7478c2ecf20Sopenharmony_ci * Periode is 16 bit (16 - 1). 7488c2ecf20Sopenharmony_ci */ 7498c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, TCMR, 7508c2ecf20Sopenharmony_ci SSC_BF(TCMR_CKO, 1) 7518c2ecf20Sopenharmony_ci | SSC_BF(TCMR_START, 4) 7528c2ecf20Sopenharmony_ci | SSC_BF(TCMR_STTDLY, 1) 7538c2ecf20Sopenharmony_ci | SSC_BF(TCMR_PERIOD, 16 - 1)); 7548c2ecf20Sopenharmony_ci /* 7558c2ecf20Sopenharmony_ci * Data length is 16 bit (16 - 1). 7568c2ecf20Sopenharmony_ci * Transmit MSB first. 7578c2ecf20Sopenharmony_ci * Transmit 2 words each transfer. 7588c2ecf20Sopenharmony_ci * Frame sync length is 16 bit (16 - 1). 7598c2ecf20Sopenharmony_ci * Frame starts on negative pulse. 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, TFMR, 7628c2ecf20Sopenharmony_ci SSC_BF(TFMR_DATLEN, 16 - 1) 7638c2ecf20Sopenharmony_ci | SSC_BIT(TFMR_MSBF) 7648c2ecf20Sopenharmony_ci | SSC_BF(TFMR_DATNB, 1) 7658c2ecf20Sopenharmony_ci | SSC_BF(TFMR_FSLEN, 16 - 1) 7668c2ecf20Sopenharmony_ci | SSC_BF(TFMR_FSOS, 1)); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci return 0; 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_cistatic int snd_at73c213_chip_init(struct snd_at73c213 *chip) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci int retval; 7748c2ecf20Sopenharmony_ci unsigned char dac_ctrl = 0; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci retval = snd_at73c213_set_bitrate(chip); 7778c2ecf20Sopenharmony_ci if (retval) 7788c2ecf20Sopenharmony_ci goto out; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci /* Enable DAC master clock. */ 7818c2ecf20Sopenharmony_ci retval = clk_enable(chip->board->dac_clk); 7828c2ecf20Sopenharmony_ci if (retval) 7838c2ecf20Sopenharmony_ci goto out; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci /* Initialize at73c213 on SPI bus. */ 7868c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RST, 0x04); 7878c2ecf20Sopenharmony_ci if (retval) 7888c2ecf20Sopenharmony_ci goto out_clk; 7898c2ecf20Sopenharmony_ci msleep(1); 7908c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RST, 0x03); 7918c2ecf20Sopenharmony_ci if (retval) 7928c2ecf20Sopenharmony_ci goto out_clk; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci /* Precharge everything. */ 7958c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_PRECH, 0xff); 7968c2ecf20Sopenharmony_ci if (retval) 7978c2ecf20Sopenharmony_ci goto out_clk; 7988c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, PA_CTRL, (1<<PA_CTRL_APAPRECH)); 7998c2ecf20Sopenharmony_ci if (retval) 8008c2ecf20Sopenharmony_ci goto out_clk; 8018c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_CTRL, 8028c2ecf20Sopenharmony_ci (1<<DAC_CTRL_ONLNOL) | (1<<DAC_CTRL_ONLNOR)); 8038c2ecf20Sopenharmony_ci if (retval) 8048c2ecf20Sopenharmony_ci goto out_clk; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci msleep(50); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* Stop precharging PA. */ 8098c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, PA_CTRL, 8108c2ecf20Sopenharmony_ci (1<<PA_CTRL_APALP) | 0x0f); 8118c2ecf20Sopenharmony_ci if (retval) 8128c2ecf20Sopenharmony_ci goto out_clk; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci msleep(450); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci /* Stop precharging DAC, turn on master power. */ 8178c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_PRECH, (1<<DAC_PRECH_ONMSTR)); 8188c2ecf20Sopenharmony_ci if (retval) 8198c2ecf20Sopenharmony_ci goto out_clk; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci msleep(1); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* Turn on DAC. */ 8248c2ecf20Sopenharmony_ci dac_ctrl = (1<<DAC_CTRL_ONDACL) | (1<<DAC_CTRL_ONDACR) 8258c2ecf20Sopenharmony_ci | (1<<DAC_CTRL_ONLNOL) | (1<<DAC_CTRL_ONLNOR); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_CTRL, dac_ctrl); 8288c2ecf20Sopenharmony_ci if (retval) 8298c2ecf20Sopenharmony_ci goto out_clk; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci /* Mute sound. */ 8328c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_LMPG, 0x3f); 8338c2ecf20Sopenharmony_ci if (retval) 8348c2ecf20Sopenharmony_ci goto out_clk; 8358c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RMPG, 0x3f); 8368c2ecf20Sopenharmony_ci if (retval) 8378c2ecf20Sopenharmony_ci goto out_clk; 8388c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_LLOG, 0x3f); 8398c2ecf20Sopenharmony_ci if (retval) 8408c2ecf20Sopenharmony_ci goto out_clk; 8418c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RLOG, 0x3f); 8428c2ecf20Sopenharmony_ci if (retval) 8438c2ecf20Sopenharmony_ci goto out_clk; 8448c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_LLIG, 0x11); 8458c2ecf20Sopenharmony_ci if (retval) 8468c2ecf20Sopenharmony_ci goto out_clk; 8478c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RLIG, 0x11); 8488c2ecf20Sopenharmony_ci if (retval) 8498c2ecf20Sopenharmony_ci goto out_clk; 8508c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_AUXG, 0x11); 8518c2ecf20Sopenharmony_ci if (retval) 8528c2ecf20Sopenharmony_ci goto out_clk; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* Enable I2S device, i.e. clock output. */ 8558c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN)); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci goto out; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ciout_clk: 8608c2ecf20Sopenharmony_ci clk_disable(chip->board->dac_clk); 8618c2ecf20Sopenharmony_ciout: 8628c2ecf20Sopenharmony_ci return retval; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic int snd_at73c213_dev_free(struct snd_device *device) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = device->device_data; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); 8708c2ecf20Sopenharmony_ci if (chip->irq >= 0) { 8718c2ecf20Sopenharmony_ci free_irq(chip->irq, chip); 8728c2ecf20Sopenharmony_ci chip->irq = -1; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci return 0; 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic int snd_at73c213_dev_init(struct snd_card *card, 8798c2ecf20Sopenharmony_ci struct spi_device *spi) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci static const struct snd_device_ops ops = { 8828c2ecf20Sopenharmony_ci .dev_free = snd_at73c213_dev_free, 8838c2ecf20Sopenharmony_ci }; 8848c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = get_chip(card); 8858c2ecf20Sopenharmony_ci int irq, retval; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci irq = chip->ssc->irq; 8888c2ecf20Sopenharmony_ci if (irq < 0) 8898c2ecf20Sopenharmony_ci return irq; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci spin_lock_init(&chip->lock); 8928c2ecf20Sopenharmony_ci mutex_init(&chip->mixer_lock); 8938c2ecf20Sopenharmony_ci chip->card = card; 8948c2ecf20Sopenharmony_ci chip->irq = -1; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci retval = clk_enable(chip->ssc->clk); 8978c2ecf20Sopenharmony_ci if (retval) 8988c2ecf20Sopenharmony_ci return retval; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci retval = request_irq(irq, snd_at73c213_interrupt, 0, "at73c213", chip); 9018c2ecf20Sopenharmony_ci if (retval) { 9028c2ecf20Sopenharmony_ci dev_dbg(&chip->spi->dev, "unable to request irq %d\n", irq); 9038c2ecf20Sopenharmony_ci goto out; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci chip->irq = irq; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci memcpy(&chip->reg_image, &snd_at73c213_original_image, 9088c2ecf20Sopenharmony_ci sizeof(snd_at73c213_original_image)); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci retval = snd_at73c213_ssc_init(chip); 9118c2ecf20Sopenharmony_ci if (retval) 9128c2ecf20Sopenharmony_ci goto out_irq; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci retval = snd_at73c213_chip_init(chip); 9158c2ecf20Sopenharmony_ci if (retval) 9168c2ecf20Sopenharmony_ci goto out_irq; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci retval = snd_at73c213_pcm_new(chip, 0); 9198c2ecf20Sopenharmony_ci if (retval) 9208c2ecf20Sopenharmony_ci goto out_irq; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci retval = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); 9238c2ecf20Sopenharmony_ci if (retval) 9248c2ecf20Sopenharmony_ci goto out_irq; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci retval = snd_at73c213_mixer(chip); 9278c2ecf20Sopenharmony_ci if (retval) 9288c2ecf20Sopenharmony_ci goto out_snd_dev; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci goto out; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ciout_snd_dev: 9338c2ecf20Sopenharmony_ci snd_device_free(card, chip); 9348c2ecf20Sopenharmony_ciout_irq: 9358c2ecf20Sopenharmony_ci free_irq(chip->irq, chip); 9368c2ecf20Sopenharmony_ci chip->irq = -1; 9378c2ecf20Sopenharmony_ciout: 9388c2ecf20Sopenharmony_ci clk_disable(chip->ssc->clk); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci return retval; 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_cistatic int snd_at73c213_probe(struct spi_device *spi) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci struct snd_card *card; 9468c2ecf20Sopenharmony_ci struct snd_at73c213 *chip; 9478c2ecf20Sopenharmony_ci struct at73c213_board_info *board; 9488c2ecf20Sopenharmony_ci int retval; 9498c2ecf20Sopenharmony_ci char id[16]; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci board = spi->dev.platform_data; 9528c2ecf20Sopenharmony_ci if (!board) { 9538c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "no platform_data\n"); 9548c2ecf20Sopenharmony_ci return -ENXIO; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (!board->dac_clk) { 9588c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "no DAC clk\n"); 9598c2ecf20Sopenharmony_ci return -ENXIO; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (IS_ERR(board->dac_clk)) { 9638c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "no DAC clk\n"); 9648c2ecf20Sopenharmony_ci return PTR_ERR(board->dac_clk); 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* Allocate "card" using some unused identifiers. */ 9688c2ecf20Sopenharmony_ci snprintf(id, sizeof id, "at73c213_%d", board->ssc_id); 9698c2ecf20Sopenharmony_ci retval = snd_card_new(&spi->dev, -1, id, THIS_MODULE, 9708c2ecf20Sopenharmony_ci sizeof(struct snd_at73c213), &card); 9718c2ecf20Sopenharmony_ci if (retval < 0) 9728c2ecf20Sopenharmony_ci goto out; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci chip = card->private_data; 9758c2ecf20Sopenharmony_ci chip->spi = spi; 9768c2ecf20Sopenharmony_ci chip->board = board; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci chip->ssc = ssc_request(board->ssc_id); 9798c2ecf20Sopenharmony_ci if (IS_ERR(chip->ssc)) { 9808c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "could not get ssc%d device\n", 9818c2ecf20Sopenharmony_ci board->ssc_id); 9828c2ecf20Sopenharmony_ci retval = PTR_ERR(chip->ssc); 9838c2ecf20Sopenharmony_ci goto out_card; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci retval = snd_at73c213_dev_init(card, spi); 9878c2ecf20Sopenharmony_ci if (retval) 9888c2ecf20Sopenharmony_ci goto out_ssc; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci strcpy(card->driver, "at73c213"); 9918c2ecf20Sopenharmony_ci strcpy(card->shortname, board->shortname); 9928c2ecf20Sopenharmony_ci sprintf(card->longname, "%s on irq %d", card->shortname, chip->irq); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci retval = snd_card_register(card); 9958c2ecf20Sopenharmony_ci if (retval) 9968c2ecf20Sopenharmony_ci goto out_ssc; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci dev_set_drvdata(&spi->dev, card); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci goto out; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ciout_ssc: 10038c2ecf20Sopenharmony_ci ssc_free(chip->ssc); 10048c2ecf20Sopenharmony_ciout_card: 10058c2ecf20Sopenharmony_ci snd_card_free(card); 10068c2ecf20Sopenharmony_ciout: 10078c2ecf20Sopenharmony_ci return retval; 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_cistatic int snd_at73c213_remove(struct spi_device *spi) 10118c2ecf20Sopenharmony_ci{ 10128c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(&spi->dev); 10138c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = card->private_data; 10148c2ecf20Sopenharmony_ci int retval; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci /* Stop playback. */ 10178c2ecf20Sopenharmony_ci retval = clk_enable(chip->ssc->clk); 10188c2ecf20Sopenharmony_ci if (retval) 10198c2ecf20Sopenharmony_ci goto out; 10208c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); 10218c2ecf20Sopenharmony_ci clk_disable(chip->ssc->clk); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci /* Mute sound. */ 10248c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_LMPG, 0x3f); 10258c2ecf20Sopenharmony_ci if (retval) 10268c2ecf20Sopenharmony_ci goto out; 10278c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RMPG, 0x3f); 10288c2ecf20Sopenharmony_ci if (retval) 10298c2ecf20Sopenharmony_ci goto out; 10308c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_LLOG, 0x3f); 10318c2ecf20Sopenharmony_ci if (retval) 10328c2ecf20Sopenharmony_ci goto out; 10338c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RLOG, 0x3f); 10348c2ecf20Sopenharmony_ci if (retval) 10358c2ecf20Sopenharmony_ci goto out; 10368c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_LLIG, 0x11); 10378c2ecf20Sopenharmony_ci if (retval) 10388c2ecf20Sopenharmony_ci goto out; 10398c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_RLIG, 0x11); 10408c2ecf20Sopenharmony_ci if (retval) 10418c2ecf20Sopenharmony_ci goto out; 10428c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_AUXG, 0x11); 10438c2ecf20Sopenharmony_ci if (retval) 10448c2ecf20Sopenharmony_ci goto out; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* Turn off PA. */ 10478c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, PA_CTRL, 10488c2ecf20Sopenharmony_ci chip->reg_image[PA_CTRL] | 0x0f); 10498c2ecf20Sopenharmony_ci if (retval) 10508c2ecf20Sopenharmony_ci goto out; 10518c2ecf20Sopenharmony_ci msleep(10); 10528c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, PA_CTRL, 10538c2ecf20Sopenharmony_ci (1 << PA_CTRL_APALP) | 0x0f); 10548c2ecf20Sopenharmony_ci if (retval) 10558c2ecf20Sopenharmony_ci goto out; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci /* Turn off external DAC. */ 10588c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_CTRL, 0x0c); 10598c2ecf20Sopenharmony_ci if (retval) 10608c2ecf20Sopenharmony_ci goto out; 10618c2ecf20Sopenharmony_ci msleep(2); 10628c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_CTRL, 0x00); 10638c2ecf20Sopenharmony_ci if (retval) 10648c2ecf20Sopenharmony_ci goto out; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci /* Turn off master power. */ 10678c2ecf20Sopenharmony_ci retval = snd_at73c213_write_reg(chip, DAC_PRECH, 0x00); 10688c2ecf20Sopenharmony_ci if (retval) 10698c2ecf20Sopenharmony_ci goto out; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ciout: 10728c2ecf20Sopenharmony_ci /* Stop DAC master clock. */ 10738c2ecf20Sopenharmony_ci clk_disable(chip->board->dac_clk); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci ssc_free(chip->ssc); 10768c2ecf20Sopenharmony_ci snd_card_free(card); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci return 0; 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic int snd_at73c213_suspend(struct device *dev) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 10868c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = card->private_data; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); 10898c2ecf20Sopenharmony_ci clk_disable(chip->ssc->clk); 10908c2ecf20Sopenharmony_ci clk_disable(chip->board->dac_clk); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci return 0; 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_cistatic int snd_at73c213_resume(struct device *dev) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 10988c2ecf20Sopenharmony_ci struct snd_at73c213 *chip = card->private_data; 10998c2ecf20Sopenharmony_ci int retval; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci retval = clk_enable(chip->board->dac_clk); 11028c2ecf20Sopenharmony_ci if (retval) 11038c2ecf20Sopenharmony_ci return retval; 11048c2ecf20Sopenharmony_ci retval = clk_enable(chip->ssc->clk); 11058c2ecf20Sopenharmony_ci if (retval) { 11068c2ecf20Sopenharmony_ci clk_disable(chip->board->dac_clk); 11078c2ecf20Sopenharmony_ci return retval; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN)); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci return 0; 11128c2ecf20Sopenharmony_ci} 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(at73c213_pm_ops, snd_at73c213_suspend, 11158c2ecf20Sopenharmony_ci snd_at73c213_resume); 11168c2ecf20Sopenharmony_ci#define AT73C213_PM_OPS (&at73c213_pm_ops) 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci#else 11198c2ecf20Sopenharmony_ci#define AT73C213_PM_OPS NULL 11208c2ecf20Sopenharmony_ci#endif 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_cistatic struct spi_driver at73c213_driver = { 11238c2ecf20Sopenharmony_ci .driver = { 11248c2ecf20Sopenharmony_ci .name = "at73c213", 11258c2ecf20Sopenharmony_ci .pm = AT73C213_PM_OPS, 11268c2ecf20Sopenharmony_ci }, 11278c2ecf20Sopenharmony_ci .probe = snd_at73c213_probe, 11288c2ecf20Sopenharmony_ci .remove = snd_at73c213_remove, 11298c2ecf20Sopenharmony_ci}; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cimodule_spi_driver(at73c213_driver); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ciMODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>"); 11348c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC"); 11358c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1136