162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * uda1380.c - Philips UDA1380 ALSA SoC audio driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2007-2009 Philipp Zabel <philipp.zabel@gmail.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Modified by Richard Purdie <richard@openedhand.com> to fit into SoC 862306a36Sopenharmony_ci * codec model. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org> 1162306a36Sopenharmony_ci * Copyright 2005 Openedhand Ltd. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/types.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/errno.h> 1962306a36Sopenharmony_ci#include <linux/gpio.h> 2062306a36Sopenharmony_ci#include <linux/delay.h> 2162306a36Sopenharmony_ci#include <linux/i2c.h> 2262306a36Sopenharmony_ci#include <linux/workqueue.h> 2362306a36Sopenharmony_ci#include <sound/core.h> 2462306a36Sopenharmony_ci#include <sound/control.h> 2562306a36Sopenharmony_ci#include <sound/initval.h> 2662306a36Sopenharmony_ci#include <sound/soc.h> 2762306a36Sopenharmony_ci#include <sound/tlv.h> 2862306a36Sopenharmony_ci#include <sound/uda1380.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "uda1380.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* codec private data */ 3362306a36Sopenharmony_cistruct uda1380_priv { 3462306a36Sopenharmony_ci struct snd_soc_component *component; 3562306a36Sopenharmony_ci unsigned int dac_clk; 3662306a36Sopenharmony_ci struct work_struct work; 3762306a36Sopenharmony_ci struct i2c_client *i2c; 3862306a36Sopenharmony_ci u16 *reg_cache; 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * uda1380 register cache 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_cistatic const u16 uda1380_reg[UDA1380_CACHEREGNUM] = { 4562306a36Sopenharmony_ci 0x0502, 0x0000, 0x0000, 0x3f3f, 4662306a36Sopenharmony_ci 0x0202, 0x0000, 0x0000, 0x0000, 4762306a36Sopenharmony_ci 0x0000, 0x0000, 0x0000, 0x0000, 4862306a36Sopenharmony_ci 0x0000, 0x0000, 0x0000, 0x0000, 4962306a36Sopenharmony_ci 0x0000, 0xff00, 0x0000, 0x4800, 5062306a36Sopenharmony_ci 0x0000, 0x0000, 0x0000, 0x0000, 5162306a36Sopenharmony_ci 0x0000, 0x0000, 0x0000, 0x0000, 5262306a36Sopenharmony_ci 0x0000, 0x0000, 0x0000, 0x0000, 5362306a36Sopenharmony_ci 0x0000, 0x8000, 0x0002, 0x0000, 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic unsigned long uda1380_cache_dirty; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* 5962306a36Sopenharmony_ci * read uda1380 register cache 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_cistatic inline unsigned int uda1380_read_reg_cache(struct snd_soc_component *component, 6262306a36Sopenharmony_ci unsigned int reg) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component); 6562306a36Sopenharmony_ci u16 *cache = uda1380->reg_cache; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (reg == UDA1380_RESET) 6862306a36Sopenharmony_ci return 0; 6962306a36Sopenharmony_ci if (reg >= UDA1380_CACHEREGNUM) 7062306a36Sopenharmony_ci return -1; 7162306a36Sopenharmony_ci return cache[reg]; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * write uda1380 register cache 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_cistatic inline void uda1380_write_reg_cache(struct snd_soc_component *component, 7862306a36Sopenharmony_ci u16 reg, unsigned int value) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component); 8162306a36Sopenharmony_ci u16 *cache = uda1380->reg_cache; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (reg >= UDA1380_CACHEREGNUM) 8462306a36Sopenharmony_ci return; 8562306a36Sopenharmony_ci if ((reg >= 0x10) && (cache[reg] != value)) 8662306a36Sopenharmony_ci set_bit(reg - 0x10, &uda1380_cache_dirty); 8762306a36Sopenharmony_ci cache[reg] = value; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* 9162306a36Sopenharmony_ci * write to the UDA1380 register space 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistatic int uda1380_write(struct snd_soc_component *component, unsigned int reg, 9462306a36Sopenharmony_ci unsigned int value) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component); 9762306a36Sopenharmony_ci u8 data[3]; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* data is 10062306a36Sopenharmony_ci * data[0] is register offset 10162306a36Sopenharmony_ci * data[1] is MS byte 10262306a36Sopenharmony_ci * data[2] is LS byte 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci data[0] = reg; 10562306a36Sopenharmony_ci data[1] = (value & 0xff00) >> 8; 10662306a36Sopenharmony_ci data[2] = value & 0x00ff; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci uda1380_write_reg_cache(component, reg, value); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* the interpolator & decimator regs must only be written when the 11162306a36Sopenharmony_ci * codec DAI is active. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci if (!snd_soc_component_active(component) && (reg >= UDA1380_MVOL)) 11462306a36Sopenharmony_ci return 0; 11562306a36Sopenharmony_ci pr_debug("uda1380: hw write %x val %x\n", reg, value); 11662306a36Sopenharmony_ci if (i2c_master_send(uda1380->i2c, data, 3) == 3) { 11762306a36Sopenharmony_ci unsigned int val; 11862306a36Sopenharmony_ci i2c_master_send(uda1380->i2c, data, 1); 11962306a36Sopenharmony_ci i2c_master_recv(uda1380->i2c, data, 2); 12062306a36Sopenharmony_ci val = (data[0]<<8) | data[1]; 12162306a36Sopenharmony_ci if (val != value) { 12262306a36Sopenharmony_ci pr_debug("uda1380: READ BACK VAL %x\n", 12362306a36Sopenharmony_ci (data[0]<<8) | data[1]); 12462306a36Sopenharmony_ci return -EIO; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci if (reg >= 0x10) 12762306a36Sopenharmony_ci clear_bit(reg - 0x10, &uda1380_cache_dirty); 12862306a36Sopenharmony_ci return 0; 12962306a36Sopenharmony_ci } else 13062306a36Sopenharmony_ci return -EIO; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic void uda1380_sync_cache(struct snd_soc_component *component) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component); 13662306a36Sopenharmony_ci int reg; 13762306a36Sopenharmony_ci u8 data[3]; 13862306a36Sopenharmony_ci u16 *cache = uda1380->reg_cache; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* Sync reg_cache with the hardware */ 14162306a36Sopenharmony_ci for (reg = 0; reg < UDA1380_MVOL; reg++) { 14262306a36Sopenharmony_ci data[0] = reg; 14362306a36Sopenharmony_ci data[1] = (cache[reg] & 0xff00) >> 8; 14462306a36Sopenharmony_ci data[2] = cache[reg] & 0x00ff; 14562306a36Sopenharmony_ci if (i2c_master_send(uda1380->i2c, data, 3) != 3) 14662306a36Sopenharmony_ci dev_err(component->dev, "%s: write to reg 0x%x failed\n", 14762306a36Sopenharmony_ci __func__, reg); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic int uda1380_reset(struct snd_soc_component *component) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct uda1380_platform_data *pdata = component->dev->platform_data; 15462306a36Sopenharmony_ci struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (gpio_is_valid(pdata->gpio_reset)) { 15762306a36Sopenharmony_ci gpio_set_value(pdata->gpio_reset, 1); 15862306a36Sopenharmony_ci mdelay(1); 15962306a36Sopenharmony_ci gpio_set_value(pdata->gpio_reset, 0); 16062306a36Sopenharmony_ci } else { 16162306a36Sopenharmony_ci u8 data[3]; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci data[0] = UDA1380_RESET; 16462306a36Sopenharmony_ci data[1] = 0; 16562306a36Sopenharmony_ci data[2] = 0; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (i2c_master_send(uda1380->i2c, data, 3) != 3) { 16862306a36Sopenharmony_ci dev_err(component->dev, "%s: failed\n", __func__); 16962306a36Sopenharmony_ci return -EIO; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic void uda1380_flush_work(struct work_struct *work) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct uda1380_priv *uda1380 = container_of(work, struct uda1380_priv, work); 17962306a36Sopenharmony_ci struct snd_soc_component *uda1380_component = uda1380->component; 18062306a36Sopenharmony_ci int bit, reg; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci for_each_set_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) { 18362306a36Sopenharmony_ci reg = 0x10 + bit; 18462306a36Sopenharmony_ci pr_debug("uda1380: flush reg %x val %x:\n", reg, 18562306a36Sopenharmony_ci uda1380_read_reg_cache(uda1380_component, reg)); 18662306a36Sopenharmony_ci uda1380_write(uda1380_component, reg, 18762306a36Sopenharmony_ci uda1380_read_reg_cache(uda1380_component, reg)); 18862306a36Sopenharmony_ci clear_bit(bit, &uda1380_cache_dirty); 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* declarations of ALSA reg_elem_REAL controls */ 19462306a36Sopenharmony_cistatic const char *uda1380_deemp[] = { 19562306a36Sopenharmony_ci "None", 19662306a36Sopenharmony_ci "32kHz", 19762306a36Sopenharmony_ci "44.1kHz", 19862306a36Sopenharmony_ci "48kHz", 19962306a36Sopenharmony_ci "96kHz", 20062306a36Sopenharmony_ci}; 20162306a36Sopenharmony_cistatic const char *uda1380_input_sel[] = { 20262306a36Sopenharmony_ci "Line", 20362306a36Sopenharmony_ci "Mic + Line R", 20462306a36Sopenharmony_ci "Line L", 20562306a36Sopenharmony_ci "Mic", 20662306a36Sopenharmony_ci}; 20762306a36Sopenharmony_cistatic const char *uda1380_output_sel[] = { 20862306a36Sopenharmony_ci "DAC", 20962306a36Sopenharmony_ci "Analog Mixer", 21062306a36Sopenharmony_ci}; 21162306a36Sopenharmony_cistatic const char *uda1380_spf_mode[] = { 21262306a36Sopenharmony_ci "Flat", 21362306a36Sopenharmony_ci "Minimum1", 21462306a36Sopenharmony_ci "Minimum2", 21562306a36Sopenharmony_ci "Maximum" 21662306a36Sopenharmony_ci}; 21762306a36Sopenharmony_cistatic const char *uda1380_capture_sel[] = { 21862306a36Sopenharmony_ci "ADC", 21962306a36Sopenharmony_ci "Digital Mixer" 22062306a36Sopenharmony_ci}; 22162306a36Sopenharmony_cistatic const char *uda1380_sel_ns[] = { 22262306a36Sopenharmony_ci "3rd-order", 22362306a36Sopenharmony_ci "5th-order" 22462306a36Sopenharmony_ci}; 22562306a36Sopenharmony_cistatic const char *uda1380_mix_control[] = { 22662306a36Sopenharmony_ci "off", 22762306a36Sopenharmony_ci "PCM only", 22862306a36Sopenharmony_ci "before sound processing", 22962306a36Sopenharmony_ci "after sound processing" 23062306a36Sopenharmony_ci}; 23162306a36Sopenharmony_cistatic const char *uda1380_sdet_setting[] = { 23262306a36Sopenharmony_ci "3200", 23362306a36Sopenharmony_ci "4800", 23462306a36Sopenharmony_ci "9600", 23562306a36Sopenharmony_ci "19200" 23662306a36Sopenharmony_ci}; 23762306a36Sopenharmony_cistatic const char *uda1380_os_setting[] = { 23862306a36Sopenharmony_ci "single-speed", 23962306a36Sopenharmony_ci "double-speed (no mixing)", 24062306a36Sopenharmony_ci "quad-speed (no mixing)" 24162306a36Sopenharmony_ci}; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic const struct soc_enum uda1380_deemp_enum[] = { 24462306a36Sopenharmony_ci SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, ARRAY_SIZE(uda1380_deemp), 24562306a36Sopenharmony_ci uda1380_deemp), 24662306a36Sopenharmony_ci SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, ARRAY_SIZE(uda1380_deemp), 24762306a36Sopenharmony_ci uda1380_deemp), 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(uda1380_input_sel_enum, 25062306a36Sopenharmony_ci UDA1380_ADC, 2, uda1380_input_sel); /* SEL_MIC, SEL_LNA */ 25162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(uda1380_output_sel_enum, 25262306a36Sopenharmony_ci UDA1380_PM, 7, uda1380_output_sel); /* R02_EN_AVC */ 25362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(uda1380_spf_enum, 25462306a36Sopenharmony_ci UDA1380_MODE, 14, uda1380_spf_mode); /* M */ 25562306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(uda1380_capture_sel_enum, 25662306a36Sopenharmony_ci UDA1380_IFACE, 6, uda1380_capture_sel); /* SEL_SOURCE */ 25762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(uda1380_sel_ns_enum, 25862306a36Sopenharmony_ci UDA1380_MIXER, 14, uda1380_sel_ns); /* SEL_NS */ 25962306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(uda1380_mix_enum, 26062306a36Sopenharmony_ci UDA1380_MIXER, 12, uda1380_mix_control); /* MIX, MIX_POS */ 26162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(uda1380_sdet_enum, 26262306a36Sopenharmony_ci UDA1380_MIXER, 4, uda1380_sdet_setting); /* SD_VALUE */ 26362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(uda1380_os_enum, 26462306a36Sopenharmony_ci UDA1380_MIXER, 0, uda1380_os_setting); /* OS */ 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/* 26762306a36Sopenharmony_ci * from -48 dB in 1.5 dB steps (mute instead of -49.5 dB) 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(amix_tlv, -4950, 150, 1); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/* 27262306a36Sopenharmony_ci * from -78 dB in 1 dB steps (3 dB steps, really. LSB are ignored), 27362306a36Sopenharmony_ci * from -66 dB in 0.5 dB steps (2 dB steps, really) and 27462306a36Sopenharmony_ci * from -52 dB in 0.25 dB steps 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(mvol_tlv, 27762306a36Sopenharmony_ci 0, 15, TLV_DB_SCALE_ITEM(-8200, 100, 1), 27862306a36Sopenharmony_ci 16, 43, TLV_DB_SCALE_ITEM(-6600, 50, 0), 27962306a36Sopenharmony_ci 44, 252, TLV_DB_SCALE_ITEM(-5200, 25, 0) 28062306a36Sopenharmony_ci); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/* 28362306a36Sopenharmony_ci * from -72 dB in 1.5 dB steps (6 dB steps really), 28462306a36Sopenharmony_ci * from -66 dB in 0.75 dB steps (3 dB steps really), 28562306a36Sopenharmony_ci * from -60 dB in 0.5 dB steps (2 dB steps really) and 28662306a36Sopenharmony_ci * from -46 dB in 0.25 dB steps 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(vc_tlv, 28962306a36Sopenharmony_ci 0, 7, TLV_DB_SCALE_ITEM(-7800, 150, 1), 29062306a36Sopenharmony_ci 8, 15, TLV_DB_SCALE_ITEM(-6600, 75, 0), 29162306a36Sopenharmony_ci 16, 43, TLV_DB_SCALE_ITEM(-6000, 50, 0), 29262306a36Sopenharmony_ci 44, 228, TLV_DB_SCALE_ITEM(-4600, 25, 0) 29362306a36Sopenharmony_ci); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/* from 0 to 6 dB in 2 dB steps if SPF mode != flat */ 29662306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(tr_tlv, 0, 200, 0); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/* from 0 to 24 dB in 2 dB steps, if SPF mode == maximum, otherwise cuts 29962306a36Sopenharmony_ci * off at 18 dB max) */ 30062306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(bb_tlv, 0, 200, 0); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci/* from -63 to 24 dB in 0.5 dB steps (-128...48) */ 30362306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(dec_tlv, -6400, 50, 1); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/* from 0 to 24 dB in 3 dB steps */ 30662306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/* from 0 to 30 dB in 2 dB steps */ 30962306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(vga_tlv, 0, 200, 0); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic const struct snd_kcontrol_new uda1380_snd_controls[] = { 31262306a36Sopenharmony_ci SOC_DOUBLE_TLV("Analog Mixer Volume", UDA1380_AMIX, 0, 8, 44, 1, amix_tlv), /* AVCR, AVCL */ 31362306a36Sopenharmony_ci SOC_DOUBLE_TLV("Master Playback Volume", UDA1380_MVOL, 0, 8, 252, 1, mvol_tlv), /* MVCL, MVCR */ 31462306a36Sopenharmony_ci SOC_SINGLE_TLV("ADC Playback Volume", UDA1380_MIXVOL, 8, 228, 1, vc_tlv), /* VC2 */ 31562306a36Sopenharmony_ci SOC_SINGLE_TLV("PCM Playback Volume", UDA1380_MIXVOL, 0, 228, 1, vc_tlv), /* VC1 */ 31662306a36Sopenharmony_ci SOC_ENUM("Sound Processing Filter", uda1380_spf_enum), /* M */ 31762306a36Sopenharmony_ci SOC_DOUBLE_TLV("Tone Control - Treble", UDA1380_MODE, 4, 12, 3, 0, tr_tlv), /* TRL, TRR */ 31862306a36Sopenharmony_ci SOC_DOUBLE_TLV("Tone Control - Bass", UDA1380_MODE, 0, 8, 15, 0, bb_tlv), /* BBL, BBR */ 31962306a36Sopenharmony_ci/**/ SOC_SINGLE("Master Playback Switch", UDA1380_DEEMP, 14, 1, 1), /* MTM */ 32062306a36Sopenharmony_ci SOC_SINGLE("ADC Playback Switch", UDA1380_DEEMP, 11, 1, 1), /* MT2 from decimation filter */ 32162306a36Sopenharmony_ci SOC_ENUM("ADC Playback De-emphasis", uda1380_deemp_enum[0]), /* DE2 */ 32262306a36Sopenharmony_ci SOC_SINGLE("PCM Playback Switch", UDA1380_DEEMP, 3, 1, 1), /* MT1, from digital data input */ 32362306a36Sopenharmony_ci SOC_ENUM("PCM Playback De-emphasis", uda1380_deemp_enum[1]), /* DE1 */ 32462306a36Sopenharmony_ci SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0), /* DA_POL_INV */ 32562306a36Sopenharmony_ci SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum), /* SEL_NS */ 32662306a36Sopenharmony_ci SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum), /* MIX_POS, MIX */ 32762306a36Sopenharmony_ci SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0), /* SDET_ON */ 32862306a36Sopenharmony_ci SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum), /* SD_VALUE */ 32962306a36Sopenharmony_ci SOC_ENUM("Oversampling Input", uda1380_os_enum), /* OS */ 33062306a36Sopenharmony_ci SOC_DOUBLE_S8_TLV("ADC Capture Volume", UDA1380_DEC, -128, 48, dec_tlv), /* ML_DEC, MR_DEC */ 33162306a36Sopenharmony_ci/**/ SOC_SINGLE("ADC Capture Switch", UDA1380_PGA, 15, 1, 1), /* MT_ADC */ 33262306a36Sopenharmony_ci SOC_DOUBLE_TLV("Line Capture Volume", UDA1380_PGA, 0, 8, 8, 0, pga_tlv), /* PGA_GAINCTRLL, PGA_GAINCTRLR */ 33362306a36Sopenharmony_ci SOC_SINGLE("ADC Polarity inverting Switch", UDA1380_ADC, 12, 1, 0), /* ADCPOL_INV */ 33462306a36Sopenharmony_ci SOC_SINGLE_TLV("Mic Capture Volume", UDA1380_ADC, 8, 15, 0, vga_tlv), /* VGA_CTRL */ 33562306a36Sopenharmony_ci SOC_SINGLE("DC Filter Bypass Switch", UDA1380_ADC, 1, 1, 0), /* SKIP_DCFIL (before decimator) */ 33662306a36Sopenharmony_ci SOC_SINGLE("DC Filter Enable Switch", UDA1380_ADC, 0, 1, 0), /* EN_DCFIL (at output of decimator) */ 33762306a36Sopenharmony_ci SOC_SINGLE("AGC Timing", UDA1380_AGC, 8, 7, 0), /* TODO: enum, see table 62 */ 33862306a36Sopenharmony_ci SOC_SINGLE("AGC Target level", UDA1380_AGC, 2, 3, 1), /* AGC_LEVEL */ 33962306a36Sopenharmony_ci /* -5.5, -8, -11.5, -14 dBFS */ 34062306a36Sopenharmony_ci SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0), 34162306a36Sopenharmony_ci}; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci/* Input mux */ 34462306a36Sopenharmony_cistatic const struct snd_kcontrol_new uda1380_input_mux_control = 34562306a36Sopenharmony_ci SOC_DAPM_ENUM("Route", uda1380_input_sel_enum); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci/* Output mux */ 34862306a36Sopenharmony_cistatic const struct snd_kcontrol_new uda1380_output_mux_control = 34962306a36Sopenharmony_ci SOC_DAPM_ENUM("Route", uda1380_output_sel_enum); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci/* Capture mux */ 35262306a36Sopenharmony_cistatic const struct snd_kcontrol_new uda1380_capture_mux_control = 35362306a36Sopenharmony_ci SOC_DAPM_ENUM("Route", uda1380_capture_sel_enum); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = { 35762306a36Sopenharmony_ci SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, 35862306a36Sopenharmony_ci &uda1380_input_mux_control), 35962306a36Sopenharmony_ci SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM, 0, 0, 36062306a36Sopenharmony_ci &uda1380_output_mux_control), 36162306a36Sopenharmony_ci SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, 36262306a36Sopenharmony_ci &uda1380_capture_mux_control), 36362306a36Sopenharmony_ci SND_SOC_DAPM_PGA("Left PGA", UDA1380_PM, 3, 0, NULL, 0), 36462306a36Sopenharmony_ci SND_SOC_DAPM_PGA("Right PGA", UDA1380_PM, 1, 0, NULL, 0), 36562306a36Sopenharmony_ci SND_SOC_DAPM_PGA("Mic LNA", UDA1380_PM, 4, 0, NULL, 0), 36662306a36Sopenharmony_ci SND_SOC_DAPM_ADC("Left ADC", "Left Capture", UDA1380_PM, 2, 0), 36762306a36Sopenharmony_ci SND_SOC_DAPM_ADC("Right ADC", "Right Capture", UDA1380_PM, 0, 0), 36862306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("VINM"), 36962306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("VINL"), 37062306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("VINR"), 37162306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("Analog Mixer", UDA1380_PM, 6, 0, NULL, 0), 37262306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("VOUTLHP"), 37362306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("VOUTRHP"), 37462306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("VOUTL"), 37562306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("VOUTR"), 37662306a36Sopenharmony_ci SND_SOC_DAPM_DAC("DAC", "Playback", UDA1380_PM, 10, 0), 37762306a36Sopenharmony_ci SND_SOC_DAPM_PGA("HeadPhone Driver", UDA1380_PM, 13, 0, NULL, 0), 37862306a36Sopenharmony_ci}; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic const struct snd_soc_dapm_route uda1380_dapm_routes[] = { 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* output mux */ 38362306a36Sopenharmony_ci {"HeadPhone Driver", NULL, "Output Mux"}, 38462306a36Sopenharmony_ci {"VOUTR", NULL, "Output Mux"}, 38562306a36Sopenharmony_ci {"VOUTL", NULL, "Output Mux"}, 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci {"Analog Mixer", NULL, "VINR"}, 38862306a36Sopenharmony_ci {"Analog Mixer", NULL, "VINL"}, 38962306a36Sopenharmony_ci {"Analog Mixer", NULL, "DAC"}, 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci {"Output Mux", "DAC", "DAC"}, 39262306a36Sopenharmony_ci {"Output Mux", "Analog Mixer", "Analog Mixer"}, 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* {"DAC", "Digital Mixer", "I2S" } */ 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* headphone driver */ 39762306a36Sopenharmony_ci {"VOUTLHP", NULL, "HeadPhone Driver"}, 39862306a36Sopenharmony_ci {"VOUTRHP", NULL, "HeadPhone Driver"}, 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* input mux */ 40162306a36Sopenharmony_ci {"Left ADC", NULL, "Input Mux"}, 40262306a36Sopenharmony_ci {"Input Mux", "Mic", "Mic LNA"}, 40362306a36Sopenharmony_ci {"Input Mux", "Mic + Line R", "Mic LNA"}, 40462306a36Sopenharmony_ci {"Input Mux", "Line L", "Left PGA"}, 40562306a36Sopenharmony_ci {"Input Mux", "Line", "Left PGA"}, 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* right input */ 40862306a36Sopenharmony_ci {"Right ADC", "Mic + Line R", "Right PGA"}, 40962306a36Sopenharmony_ci {"Right ADC", "Line", "Right PGA"}, 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* inputs */ 41262306a36Sopenharmony_ci {"Mic LNA", NULL, "VINM"}, 41362306a36Sopenharmony_ci {"Left PGA", NULL, "VINL"}, 41462306a36Sopenharmony_ci {"Right PGA", NULL, "VINR"}, 41562306a36Sopenharmony_ci}; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai, 41862306a36Sopenharmony_ci unsigned int fmt) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 42162306a36Sopenharmony_ci int iface; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* set up DAI based upon fmt */ 42462306a36Sopenharmony_ci iface = uda1380_read_reg_cache(component, UDA1380_IFACE); 42562306a36Sopenharmony_ci iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 42862306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 42962306a36Sopenharmony_ci iface |= R01_SFORI_I2S | R01_SFORO_I2S; 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci case SND_SOC_DAIFMT_LSB: 43262306a36Sopenharmony_ci iface |= R01_SFORI_LSB16 | R01_SFORO_LSB16; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case SND_SOC_DAIFMT_MSB: 43562306a36Sopenharmony_ci iface |= R01_SFORI_MSB | R01_SFORO_MSB; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* DATAI is consumer only */ 43962306a36Sopenharmony_ci if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) 44062306a36Sopenharmony_ci return -EINVAL; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci uda1380_write_reg_cache(component, UDA1380_IFACE, iface); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return 0; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai, 44862306a36Sopenharmony_ci unsigned int fmt) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 45162306a36Sopenharmony_ci int iface; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* set up DAI based upon fmt */ 45462306a36Sopenharmony_ci iface = uda1380_read_reg_cache(component, UDA1380_IFACE); 45562306a36Sopenharmony_ci iface &= ~R01_SFORI_MASK; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 45862306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 45962306a36Sopenharmony_ci iface |= R01_SFORI_I2S; 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci case SND_SOC_DAIFMT_LSB: 46262306a36Sopenharmony_ci iface |= R01_SFORI_LSB16; 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci case SND_SOC_DAIFMT_MSB: 46562306a36Sopenharmony_ci iface |= R01_SFORI_MSB; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* DATAI is consumer only */ 46962306a36Sopenharmony_ci if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) 47062306a36Sopenharmony_ci return -EINVAL; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci uda1380_write(component, UDA1380_IFACE, iface); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai, 47862306a36Sopenharmony_ci unsigned int fmt) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 48162306a36Sopenharmony_ci int iface; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* set up DAI based upon fmt */ 48462306a36Sopenharmony_ci iface = uda1380_read_reg_cache(component, UDA1380_IFACE); 48562306a36Sopenharmony_ci iface &= ~(R01_SIM | R01_SFORO_MASK); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 48862306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 48962306a36Sopenharmony_ci iface |= R01_SFORO_I2S; 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci case SND_SOC_DAIFMT_LSB: 49262306a36Sopenharmony_ci iface |= R01_SFORO_LSB16; 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci case SND_SOC_DAIFMT_MSB: 49562306a36Sopenharmony_ci iface |= R01_SFORO_MSB; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_CBP_CFP) 49962306a36Sopenharmony_ci iface |= R01_SIM; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci uda1380_write(component, UDA1380_IFACE, iface); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci return 0; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic int uda1380_trigger(struct snd_pcm_substream *substream, int cmd, 50762306a36Sopenharmony_ci struct snd_soc_dai *dai) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 51062306a36Sopenharmony_ci struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component); 51162306a36Sopenharmony_ci int mixer = uda1380_read_reg_cache(component, UDA1380_MIXER); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci switch (cmd) { 51462306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 51562306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 51662306a36Sopenharmony_ci uda1380_write_reg_cache(component, UDA1380_MIXER, 51762306a36Sopenharmony_ci mixer & ~R14_SILENCE); 51862306a36Sopenharmony_ci schedule_work(&uda1380->work); 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 52162306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 52262306a36Sopenharmony_ci uda1380_write_reg_cache(component, UDA1380_MIXER, 52362306a36Sopenharmony_ci mixer | R14_SILENCE); 52462306a36Sopenharmony_ci schedule_work(&uda1380->work); 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci return 0; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, 53162306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 53262306a36Sopenharmony_ci struct snd_soc_dai *dai) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 53562306a36Sopenharmony_ci u16 clk = uda1380_read_reg_cache(component, UDA1380_CLK); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* set WSPLL power and divider if running from this clock */ 53862306a36Sopenharmony_ci if (clk & R00_DAC_CLK) { 53962306a36Sopenharmony_ci int rate = params_rate(params); 54062306a36Sopenharmony_ci u16 pm = uda1380_read_reg_cache(component, UDA1380_PM); 54162306a36Sopenharmony_ci clk &= ~0x3; /* clear SEL_LOOP_DIV */ 54262306a36Sopenharmony_ci switch (rate) { 54362306a36Sopenharmony_ci case 6250 ... 12500: 54462306a36Sopenharmony_ci clk |= 0x0; 54562306a36Sopenharmony_ci break; 54662306a36Sopenharmony_ci case 12501 ... 25000: 54762306a36Sopenharmony_ci clk |= 0x1; 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci case 25001 ... 50000: 55062306a36Sopenharmony_ci clk |= 0x2; 55162306a36Sopenharmony_ci break; 55262306a36Sopenharmony_ci case 50001 ... 100000: 55362306a36Sopenharmony_ci clk |= 0x3; 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci uda1380_write(component, UDA1380_PM, R02_PON_PLL | pm); 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 56062306a36Sopenharmony_ci clk |= R00_EN_DAC | R00_EN_INT; 56162306a36Sopenharmony_ci else 56262306a36Sopenharmony_ci clk |= R00_EN_ADC | R00_EN_DEC; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci uda1380_write(component, UDA1380_CLK, clk); 56562306a36Sopenharmony_ci return 0; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic void uda1380_pcm_shutdown(struct snd_pcm_substream *substream, 56962306a36Sopenharmony_ci struct snd_soc_dai *dai) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 57262306a36Sopenharmony_ci u16 clk = uda1380_read_reg_cache(component, UDA1380_CLK); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* shut down WSPLL power if running from this clock */ 57562306a36Sopenharmony_ci if (clk & R00_DAC_CLK) { 57662306a36Sopenharmony_ci u16 pm = uda1380_read_reg_cache(component, UDA1380_PM); 57762306a36Sopenharmony_ci uda1380_write(component, UDA1380_PM, ~R02_PON_PLL & pm); 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 58162306a36Sopenharmony_ci clk &= ~(R00_EN_DAC | R00_EN_INT); 58262306a36Sopenharmony_ci else 58362306a36Sopenharmony_ci clk &= ~(R00_EN_ADC | R00_EN_DEC); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci uda1380_write(component, UDA1380_CLK, clk); 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic int uda1380_set_bias_level(struct snd_soc_component *component, 58962306a36Sopenharmony_ci enum snd_soc_bias_level level) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci int pm = uda1380_read_reg_cache(component, UDA1380_PM); 59262306a36Sopenharmony_ci int reg; 59362306a36Sopenharmony_ci struct uda1380_platform_data *pdata = component->dev->platform_data; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci switch (level) { 59662306a36Sopenharmony_ci case SND_SOC_BIAS_ON: 59762306a36Sopenharmony_ci case SND_SOC_BIAS_PREPARE: 59862306a36Sopenharmony_ci /* ADC, DAC on */ 59962306a36Sopenharmony_ci uda1380_write(component, UDA1380_PM, R02_PON_BIAS | pm); 60062306a36Sopenharmony_ci break; 60162306a36Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 60262306a36Sopenharmony_ci if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { 60362306a36Sopenharmony_ci if (gpio_is_valid(pdata->gpio_power)) { 60462306a36Sopenharmony_ci gpio_set_value(pdata->gpio_power, 1); 60562306a36Sopenharmony_ci mdelay(1); 60662306a36Sopenharmony_ci uda1380_reset(component); 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci uda1380_sync_cache(component); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci uda1380_write(component, UDA1380_PM, 0x0); 61262306a36Sopenharmony_ci break; 61362306a36Sopenharmony_ci case SND_SOC_BIAS_OFF: 61462306a36Sopenharmony_ci if (!gpio_is_valid(pdata->gpio_power)) 61562306a36Sopenharmony_ci break; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci gpio_set_value(pdata->gpio_power, 0); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* Mark mixer regs cache dirty to sync them with 62062306a36Sopenharmony_ci * codec regs on power on. 62162306a36Sopenharmony_ci */ 62262306a36Sopenharmony_ci for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++) 62362306a36Sopenharmony_ci set_bit(reg - 0x10, &uda1380_cache_dirty); 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci return 0; 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci#define UDA1380_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ 62962306a36Sopenharmony_ci SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ 63062306a36Sopenharmony_ci SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic const struct snd_soc_dai_ops uda1380_dai_ops = { 63362306a36Sopenharmony_ci .hw_params = uda1380_pcm_hw_params, 63462306a36Sopenharmony_ci .shutdown = uda1380_pcm_shutdown, 63562306a36Sopenharmony_ci .trigger = uda1380_trigger, 63662306a36Sopenharmony_ci .set_fmt = uda1380_set_dai_fmt_both, 63762306a36Sopenharmony_ci}; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_cistatic const struct snd_soc_dai_ops uda1380_dai_ops_playback = { 64062306a36Sopenharmony_ci .hw_params = uda1380_pcm_hw_params, 64162306a36Sopenharmony_ci .shutdown = uda1380_pcm_shutdown, 64262306a36Sopenharmony_ci .trigger = uda1380_trigger, 64362306a36Sopenharmony_ci .set_fmt = uda1380_set_dai_fmt_playback, 64462306a36Sopenharmony_ci}; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic const struct snd_soc_dai_ops uda1380_dai_ops_capture = { 64762306a36Sopenharmony_ci .hw_params = uda1380_pcm_hw_params, 64862306a36Sopenharmony_ci .shutdown = uda1380_pcm_shutdown, 64962306a36Sopenharmony_ci .trigger = uda1380_trigger, 65062306a36Sopenharmony_ci .set_fmt = uda1380_set_dai_fmt_capture, 65162306a36Sopenharmony_ci}; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic struct snd_soc_dai_driver uda1380_dai[] = { 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci .name = "uda1380-hifi", 65662306a36Sopenharmony_ci .playback = { 65762306a36Sopenharmony_ci .stream_name = "Playback", 65862306a36Sopenharmony_ci .channels_min = 1, 65962306a36Sopenharmony_ci .channels_max = 2, 66062306a36Sopenharmony_ci .rates = UDA1380_RATES, 66162306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 66262306a36Sopenharmony_ci .capture = { 66362306a36Sopenharmony_ci .stream_name = "Capture", 66462306a36Sopenharmony_ci .channels_min = 1, 66562306a36Sopenharmony_ci .channels_max = 2, 66662306a36Sopenharmony_ci .rates = UDA1380_RATES, 66762306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 66862306a36Sopenharmony_ci .ops = &uda1380_dai_ops, 66962306a36Sopenharmony_ci}, 67062306a36Sopenharmony_ci{ /* playback only - dual interface */ 67162306a36Sopenharmony_ci .name = "uda1380-hifi-playback", 67262306a36Sopenharmony_ci .playback = { 67362306a36Sopenharmony_ci .stream_name = "Playback", 67462306a36Sopenharmony_ci .channels_min = 1, 67562306a36Sopenharmony_ci .channels_max = 2, 67662306a36Sopenharmony_ci .rates = UDA1380_RATES, 67762306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 67862306a36Sopenharmony_ci }, 67962306a36Sopenharmony_ci .ops = &uda1380_dai_ops_playback, 68062306a36Sopenharmony_ci}, 68162306a36Sopenharmony_ci{ /* capture only - dual interface*/ 68262306a36Sopenharmony_ci .name = "uda1380-hifi-capture", 68362306a36Sopenharmony_ci .capture = { 68462306a36Sopenharmony_ci .stream_name = "Capture", 68562306a36Sopenharmony_ci .channels_min = 1, 68662306a36Sopenharmony_ci .channels_max = 2, 68762306a36Sopenharmony_ci .rates = UDA1380_RATES, 68862306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 68962306a36Sopenharmony_ci }, 69062306a36Sopenharmony_ci .ops = &uda1380_dai_ops_capture, 69162306a36Sopenharmony_ci}, 69262306a36Sopenharmony_ci}; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int uda1380_probe(struct snd_soc_component *component) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci struct uda1380_platform_data *pdata =component->dev->platform_data; 69762306a36Sopenharmony_ci struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component); 69862306a36Sopenharmony_ci int ret; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci uda1380->component = component; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (!gpio_is_valid(pdata->gpio_power)) { 70362306a36Sopenharmony_ci ret = uda1380_reset(component); 70462306a36Sopenharmony_ci if (ret) 70562306a36Sopenharmony_ci return ret; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci INIT_WORK(&uda1380->work, uda1380_flush_work); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* set clock input */ 71162306a36Sopenharmony_ci switch (pdata->dac_clk) { 71262306a36Sopenharmony_ci case UDA1380_DAC_CLK_SYSCLK: 71362306a36Sopenharmony_ci uda1380_write_reg_cache(component, UDA1380_CLK, 0); 71462306a36Sopenharmony_ci break; 71562306a36Sopenharmony_ci case UDA1380_DAC_CLK_WSPLL: 71662306a36Sopenharmony_ci uda1380_write_reg_cache(component, UDA1380_CLK, 71762306a36Sopenharmony_ci R00_DAC_CLK); 71862306a36Sopenharmony_ci break; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return 0; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_uda1380 = { 72562306a36Sopenharmony_ci .probe = uda1380_probe, 72662306a36Sopenharmony_ci .read = uda1380_read_reg_cache, 72762306a36Sopenharmony_ci .write = uda1380_write, 72862306a36Sopenharmony_ci .set_bias_level = uda1380_set_bias_level, 72962306a36Sopenharmony_ci .controls = uda1380_snd_controls, 73062306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(uda1380_snd_controls), 73162306a36Sopenharmony_ci .dapm_widgets = uda1380_dapm_widgets, 73262306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets), 73362306a36Sopenharmony_ci .dapm_routes = uda1380_dapm_routes, 73462306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes), 73562306a36Sopenharmony_ci .suspend_bias_off = 1, 73662306a36Sopenharmony_ci .idle_bias_on = 1, 73762306a36Sopenharmony_ci .use_pmdown_time = 1, 73862306a36Sopenharmony_ci .endianness = 1, 73962306a36Sopenharmony_ci}; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic int uda1380_i2c_probe(struct i2c_client *i2c) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci struct uda1380_platform_data *pdata = i2c->dev.platform_data; 74462306a36Sopenharmony_ci struct uda1380_priv *uda1380; 74562306a36Sopenharmony_ci int ret; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (!pdata) 74862306a36Sopenharmony_ci return -EINVAL; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci uda1380 = devm_kzalloc(&i2c->dev, sizeof(struct uda1380_priv), 75162306a36Sopenharmony_ci GFP_KERNEL); 75262306a36Sopenharmony_ci if (uda1380 == NULL) 75362306a36Sopenharmony_ci return -ENOMEM; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (gpio_is_valid(pdata->gpio_reset)) { 75662306a36Sopenharmony_ci ret = devm_gpio_request_one(&i2c->dev, pdata->gpio_reset, 75762306a36Sopenharmony_ci GPIOF_OUT_INIT_LOW, "uda1380 reset"); 75862306a36Sopenharmony_ci if (ret) 75962306a36Sopenharmony_ci return ret; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (gpio_is_valid(pdata->gpio_power)) { 76362306a36Sopenharmony_ci ret = devm_gpio_request_one(&i2c->dev, pdata->gpio_power, 76462306a36Sopenharmony_ci GPIOF_OUT_INIT_LOW, "uda1380 power"); 76562306a36Sopenharmony_ci if (ret) 76662306a36Sopenharmony_ci return ret; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci uda1380->reg_cache = devm_kmemdup(&i2c->dev, 77062306a36Sopenharmony_ci uda1380_reg, 77162306a36Sopenharmony_ci ARRAY_SIZE(uda1380_reg) * sizeof(u16), 77262306a36Sopenharmony_ci GFP_KERNEL); 77362306a36Sopenharmony_ci if (!uda1380->reg_cache) 77462306a36Sopenharmony_ci return -ENOMEM; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci i2c_set_clientdata(i2c, uda1380); 77762306a36Sopenharmony_ci uda1380->i2c = i2c; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&i2c->dev, 78062306a36Sopenharmony_ci &soc_component_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai)); 78162306a36Sopenharmony_ci return ret; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic const struct i2c_device_id uda1380_i2c_id[] = { 78562306a36Sopenharmony_ci { "uda1380", 0 }, 78662306a36Sopenharmony_ci { } 78762306a36Sopenharmony_ci}; 78862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, uda1380_i2c_id); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic const struct of_device_id uda1380_of_match[] = { 79162306a36Sopenharmony_ci { .compatible = "nxp,uda1380", }, 79262306a36Sopenharmony_ci { } 79362306a36Sopenharmony_ci}; 79462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, uda1380_of_match); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic struct i2c_driver uda1380_i2c_driver = { 79762306a36Sopenharmony_ci .driver = { 79862306a36Sopenharmony_ci .name = "uda1380-codec", 79962306a36Sopenharmony_ci .of_match_table = uda1380_of_match, 80062306a36Sopenharmony_ci }, 80162306a36Sopenharmony_ci .probe = uda1380_i2c_probe, 80262306a36Sopenharmony_ci .id_table = uda1380_i2c_id, 80362306a36Sopenharmony_ci}; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cimodule_i2c_driver(uda1380_i2c_driver); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ciMODULE_AUTHOR("Giorgio Padrin"); 80862306a36Sopenharmony_ciMODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); 80962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 810