Commit 0c5dacf2 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/cs42l56', 'asoc/topic/cs42xx8' and...

Merge remote-tracking branches 'asoc/topic/cs42l56', 'asoc/topic/cs42xx8' and 'asoc/topic/davinci' into asoc-next
CS42L52 audio CODEC
Required properties:
- compatible : "cirrus,cs42l56"
- reg : the I2C address of the device for I2C
- VA-supply, VCP-supply, VLDO-supply : power supplies for the device,
as covered in Documentation/devicetree/bindings/regulator/regulator.txt.
Optional properties:
- cirrus,gpio-nreset : GPIO controller's phandle and the number
of the GPIO used to reset the codec.
- cirrus,chgfreq-divisor : Values used to set the Charge Pump Frequency.
Allowable values of 0x00 through 0x0F. These are raw values written to the
register, not the actual frequency. The frequency is determined by the following.
Frequency = MCLK / 4 * (N+2)
N = chgfreq_val
MCLK = Where MCLK is the frequency of the mclk signal after the MCLKDIV2 circuit.
- cirrus,ain1a-ref-cfg, ain1b-ref-cfg : boolean, If present, AIN1A or AIN1B are configured
as a pseudo-differential input referenced to AIN1REF/AIN3A.
- cirrus,ain2a-ref-cfg, ain2b-ref-cfg : boolean, If present, AIN2A or AIN2B are configured
as a pseudo-differential input referenced to AIN2REF/AIN3B.
- cirrus,micbias-lvl: Set the output voltage level on the MICBIAS Pin.
0 = 0.5 x VA
1 = 0.6 x VA
2 = 0.7 x VA
3 = 0.8 x VA
4 = 0.83 x VA
5 = 0.91 x VA
- cirrus,adaptive-pwr-cfg : Configures how the power to the Headphone and Lineout
Amplifiers adapt to the output signal levels.
0 = Adapt to Volume Mode. Voltage level determined by the sum of the relevant volume settings.
1 = Fixed - Headphone and Line Amp supply = + or - VCP/2.
2 = Fixed - Headphone and Line Amp supply = + or - VCP.
3 = Adapted to Signal; Voltage level is dynamically determined by the output signal.
- cirrus,hpf-left-freq, hpf-right-freq : Sets the corner frequency (-3dB point) for the internal High-Pass
Filter.
0 = 1.8Hz
1 = 119Hz
2 = 236Hz
3 = 464Hz
Example:
codec: codec@4b {
compatible = "cirrus,cs42l56";
reg = <0x4b>;
gpio-reset = <&gpio 10 0>;
cirrus,chgfreq-divisor = <0x05>;
cirrus.ain1_ref_cfg;
cirrus,micbias-lvl = <5>;
VA-supply = <&reg_audio>;
};
/*
* linux/sound/cs42l56.h -- Platform data for CS42L56
*
* Copyright (c) 2014 Cirrus Logic Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __CS42L56_H
#define __CS42L56_H
struct cs42l56_platform_data {
/* GPIO for Reset */
unsigned int gpio_nreset;
/* MICBIAS Level. Check datasheet Pg48 */
unsigned int micbias_lvl;
/* Analog Input 1A Reference 0=Single 1=Pseudo-Differential */
unsigned int ain1a_ref_cfg;
/* Analog Input 2A Reference 0=Single 1=Pseudo-Differential */
unsigned int ain2a_ref_cfg;
/* Analog Input 1B Reference 0=Single 1=Pseudo-Differential */
unsigned int ain1b_ref_cfg;
/* Analog Input 2B Reference 0=Single 1=Pseudo-Differential */
unsigned int ain2b_ref_cfg;
/* Charge Pump Freq. Check datasheet Pg62 */
unsigned int chgfreq;
/* HighPass Filter Right Channel Corner Frequency */
unsigned int hpfb_freq;
/* HighPass Filter Left Channel Corner Frequency */
unsigned int hpfa_freq;
/* Adaptive Power Control for LO/HP */
unsigned int adaptive_pwr;
};
#endif /* __CS42L56_H */
......@@ -382,6 +382,8 @@ int snd_soc_resume(struct device *dev);
int snd_soc_poweroff(struct device *dev);
int snd_soc_register_platform(struct device *dev,
const struct snd_soc_platform_driver *platform_drv);
int devm_snd_soc_register_platform(struct device *dev,
const struct snd_soc_platform_driver *platform_drv);
void snd_soc_unregister_platform(struct device *dev);
int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
const struct snd_soc_platform_driver *platform_drv);
......
......@@ -39,8 +39,9 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ALC5623 if I2C
select SND_SOC_ALC5632 if I2C
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
select SND_SOC_CS42L51 if I2C
select SND_SOC_CS42L52 if I2C
select SND_SOC_CS42L51_I2C if I2C
select SND_SOC_CS42L52 if I2C && INPUT
select SND_SOC_CS42L56 if I2C && INPUT
select SND_SOC_CS42L73 if I2C
select SND_SOC_CS4270 if I2C
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
......@@ -128,7 +129,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8955 if I2C
select SND_SOC_WM8960 if I2C
select SND_SOC_WM8961 if I2C
select SND_SOC_WM8962 if I2C
select SND_SOC_WM8962 if I2C && INPUT
select SND_SOC_WM8971 if I2C
select SND_SOC_WM8974 if I2C
select SND_SOC_WM8978 if I2C
......@@ -281,9 +282,17 @@ config SND_SOC_CQ0093VC
config SND_SOC_CS42L51
tristate
config SND_SOC_CS42L51_I2C
tristate
select SND_SOC_CS42L51
config SND_SOC_CS42L52
tristate "Cirrus Logic CS42L52 CODEC"
depends on I2C
depends on I2C && INPUT
config SND_SOC_CS42L56
tristate "Cirrus Logic CS42L56 CODEC"
depends on I2C && INPUT
config SND_SOC_CS42L73
tristate "Cirrus Logic CS42L73 CODEC"
......@@ -603,7 +612,7 @@ config SND_SOC_WM8961
config SND_SOC_WM8962
tristate "Wolfson Microelectronics WM8962 CODEC"
depends on I2C
depends on I2C && INPUT
config SND_SOC_WM8971
tristate
......
......@@ -26,7 +26,9 @@ snd-soc-ak5386-objs := ak5386.o
snd-soc-arizona-objs := arizona.o
snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
snd-soc-cs42l52-objs := cs42l52.o
snd-soc-cs42l56-objs := cs42l56.o
snd-soc-cs42l73-objs := cs42l73.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cs4271-objs := cs4271.o
......@@ -178,7 +180,9 @@ obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o
obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o
obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o
obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
......
/*
* cs42l56.c -- CS42L51 ALSA SoC I2C audio driver
*
* Copyright 2014 CirrusLogic, Inc.
*
* Author: Brian Austin <brian.austin@cirrus.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/i2c.h>
#include <linux/module.h>
#include <sound/soc.h>
#include "cs42l51.h"
static struct i2c_device_id cs42l51_i2c_id[] = {
{"cs42l51", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id);
static int cs42l51_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct regmap_config config;
config = cs42l51_regmap;
config.val_bits = 8;
config.reg_bits = 8;
return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config));
}
static int cs42l51_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_codec(&i2c->dev);
return 0;
}
static struct i2c_driver cs42l51_i2c_driver = {
.driver = {
.name = "cs42l51",
.owner = THIS_MODULE,
},
.probe = cs42l51_i2c_probe,
.remove = cs42l51_i2c_remove,
.id_table = cs42l51_i2c_id,
};
module_i2c_driver(cs42l51_i2c_driver);
MODULE_DESCRIPTION("ASoC CS42L51 I2C Driver");
MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
MODULE_LICENSE("GPL");
......@@ -29,7 +29,6 @@
#include <sound/initval.h>
#include <sound/pcm_params.h>
#include <sound/pcm.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include "cs42l51.h"
......@@ -483,7 +482,7 @@ static struct snd_soc_dai_driver cs42l51_dai = {
.ops = &cs42l51_dai_ops,
};
static int cs42l51_probe(struct snd_soc_codec *codec)
static int cs42l51_codec_probe(struct snd_soc_codec *codec)
{
int ret, reg;
......@@ -504,7 +503,7 @@ static int cs42l51_probe(struct snd_soc_codec *codec)
}
static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
.probe = cs42l51_probe,
.probe = cs42l51_codec_probe,
.controls = cs42l51_snd_controls,
.num_controls = ARRAY_SIZE(cs42l51_snd_controls),
......@@ -514,91 +513,56 @@ static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
.num_dapm_routes = ARRAY_SIZE(cs42l51_routes),
};
static const struct regmap_config cs42l51_regmap = {
.reg_bits = 8,
.val_bits = 8,
const struct regmap_config cs42l51_regmap = {
.max_register = CS42L51_CHARGE_FREQ,
.cache_type = REGCACHE_RBTREE,
};
EXPORT_SYMBOL_GPL(cs42l51_regmap);
static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
int cs42l51_probe(struct device *dev, struct regmap *regmap)
{
struct cs42l51_private *cs42l51;
struct regmap *regmap;
unsigned int val;
int ret;
regmap = devm_regmap_init_i2c(i2c_client, &cs42l51_regmap);
if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
dev_err(&i2c_client->dev, "Failed to create regmap: %d\n",
ret);
return ret;
}
if (IS_ERR(regmap))
return PTR_ERR(regmap);
cs42l51 = devm_kzalloc(dev, sizeof(struct cs42l51_private),
GFP_KERNEL);
if (!cs42l51)
return -ENOMEM;
dev_set_drvdata(dev, cs42l51);
/* Verify that we have a CS42L51 */
ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);
if (ret < 0) {
dev_err(&i2c_client->dev, "failed to read I2C\n");
dev_err(dev, "failed to read I2C\n");
goto error;
}
if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
(val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
dev_err(&i2c_client->dev, "Invalid chip id: %x\n", val);
dev_err(dev, "Invalid chip id: %x\n", val);
ret = -ENODEV;
goto error;
}
dev_info(dev, "Cirrus Logic CS42L51, Revision: %02X\n",
val & CS42L51_CHIP_REV_MASK);
dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
val & 7);
cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private),
GFP_KERNEL);
if (!cs42l51)
return -ENOMEM;
i2c_set_clientdata(i2c_client, cs42l51);
ret = snd_soc_register_codec(&i2c_client->dev,
ret = snd_soc_register_codec(dev,
&soc_codec_device_cs42l51, &cs42l51_dai, 1);
error:
return ret;
}
static int cs42l51_i2c_remove(struct i2c_client *client)
{
snd_soc_unregister_codec(&client->dev);
return 0;
}
static const struct i2c_device_id cs42l51_id[] = {
{"cs42l51", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, cs42l51_id);
EXPORT_SYMBOL_GPL(cs42l51_probe);
static const struct of_device_id cs42l51_of_match[] = {
{ .compatible = "cirrus,cs42l51", },
{ }
};
MODULE_DEVICE_TABLE(of, cs42l51_of_match);
static struct i2c_driver cs42l51_i2c_driver = {
.driver = {
.name = "cs42l51-codec",
.owner = THIS_MODULE,
.of_match_table = cs42l51_of_match,
},
.id_table = cs42l51_id,
.probe = cs42l51_i2c_probe,
.remove = cs42l51_i2c_remove,
};
module_i2c_driver(cs42l51_i2c_driver);
MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
MODULE_LICENSE("GPL");
......@@ -18,9 +18,15 @@
#ifndef _CS42L51_H
#define _CS42L51_H
struct device;
extern const struct regmap_config cs42l51_regmap;
int cs42l51_probe(struct device *dev, struct regmap *regmap);
#define CS42L51_CHIP_ID 0x1B
#define CS42L51_CHIP_REV_A 0x00
#define CS42L51_CHIP_REV_B 0x01
#define CS42L51_CHIP_REV_MASK 0x07
#define CS42L51_CHIP_REV_ID 0x01
#define CS42L51_MK_CHIP_REV(a, b) ((a)<<3|(b))
......
......@@ -50,11 +50,9 @@ struct cs42l52_private {
u8 mclksel;
u32 mclk;
u8 flags;
#if IS_ENABLED(CONFIG_INPUT)
struct input_dev *beep;
struct work_struct beep_work;
int beep_rate;
#endif
};
static const struct reg_default cs42l52_reg_defaults[] = {
......@@ -962,7 +960,6 @@ static int cs42l52_resume(struct snd_soc_codec *codec)
return 0;
}
#if IS_ENABLED(CONFIG_INPUT)
static int beep_rates[] = {
261, 522, 585, 667, 706, 774, 889, 1000,
1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
......@@ -1096,15 +1093,6 @@ static void cs42l52_free_beep(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, CS42L52_BEEP_TONE_CTL,
CS42L52_BEEP_EN_MASK, 0);
}
#else
static void cs42l52_init_beep(struct snd_soc_codec *codec)
{
}
static void cs42l52_free_beep(struct snd_soc_codec *codec)
{
}
#endif
static int cs42l52_probe(struct snd_soc_codec *codec)
{
......
/*
* cs42l56.c -- CS42L56 ALSA SoC audio driver
*
* Copyright 2014 CirrusLogic, Inc.
*
* Author: Brian Austin <brian.austin@cirrus.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/cs42l56.h>
#include "cs42l56.h"
#define CS42L56_NUM_SUPPLIES 3
static const char *const cs42l56_supply_names[CS42L56_NUM_SUPPLIES] = {
"VA",
"VCP",
"VLDO",
};
struct cs42l56_private {
struct regmap *regmap;
struct snd_soc_codec *codec;
struct device *dev;
struct cs42l56_platform_data pdata;
struct regulator_bulk_data supplies[CS42L56_NUM_SUPPLIES];
u32 mclk;
u8 mclk_prediv;
u8 mclk_div2;
u8 mclk_ratio;
u8 iface;
u8 iface_fmt;
u8 iface_inv;
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
struct input_dev *beep;
struct work_struct beep_work;
int beep_rate;
#endif
};
static const struct reg_default cs42l56_reg_defaults[] = {
{ 1, 0x56 }, /* r01 - ID 1 */
{ 2, 0x04 }, /* r02 - ID 2 */
{ 3, 0x7f }, /* r03 - Power Ctl 1 */
{ 4, 0xff }, /* r04 - Power Ctl 2 */
{ 5, 0x00 }, /* ro5 - Clocking Ctl 1 */
{ 6, 0x0b }, /* r06 - Clocking Ctl 2 */
{ 7, 0x00 }, /* r07 - Serial Format */
{ 8, 0x05 }, /* r08 - Class H Ctl */
{ 9, 0x0c }, /* r09 - Misc Ctl */
{ 10, 0x80 }, /* r0a - INT Status */
{ 11, 0x00 }, /* r0b - Playback Ctl */
{ 12, 0x0c }, /* r0c - DSP Mute Ctl */
{ 13, 0x00 }, /* r0d - ADCA Mixer Volume */
{ 14, 0x00 }, /* r0e - ADCB Mixer Volume */
{ 15, 0x00 }, /* r0f - PCMA Mixer Volume */
{ 16, 0x00 }, /* r10 - PCMB Mixer Volume */
{ 17, 0x00 }, /* r11 - Analog Input Advisory Volume */
{ 18, 0x00 }, /* r12 - Digital Input Advisory Volume */
{ 19, 0x00 }, /* r13 - Master A Volume */
{ 20, 0x00 }, /* r14 - Master B Volume */
{ 21, 0x00 }, /* r15 - Beep Freq / On Time */
{ 22, 0x00 }, /* r16 - Beep Volume / Off Time */
{ 23, 0x00 }, /* r17 - Beep Tone Ctl */
{ 24, 0x88 }, /* r18 - Tone Ctl */
{ 25, 0x00 }, /* r19 - Channel Mixer & Swap */
{ 26, 0x00 }, /* r1a - AIN Ref Config / ADC Mux */
{ 27, 0xa0 }, /* r1b - High-Pass Filter Ctl */
{ 28, 0x00 }, /* r1c - Misc ADC Ctl */
{ 29, 0x00 }, /* r1d - Gain & Bias Ctl */
{ 30, 0x00 }, /* r1e - PGAA Mux & Volume */
{ 31, 0x00 }, /* r1f - PGAB Mux & Volume */
{ 32, 0x00 }, /* r20 - ADCA Attenuator */
{ 33, 0x00 }, /* r21 - ADCB Attenuator */
{ 34, 0x00 }, /* r22 - ALC Enable & Attack Rate */
{ 35, 0xbf }, /* r23 - ALC Release Rate */
{ 36, 0x00 }, /* r24 - ALC Threshold */
{ 37, 0x00 }, /* r25 - Noise Gate Ctl */
{ 38, 0x00 }, /* r26 - ALC, Limiter, SFT, ZeroCross */
{ 39, 0x00 }, /* r27 - Analog Mute, LO & HP Mux */
{ 40, 0x00 }, /* r28 - HP A Volume */
{ 41, 0x00 }, /* r29 - HP B Volume */
{ 42, 0x00 }, /* r2a - LINEOUT A Volume */
{ 43, 0x00 }, /* r2b - LINEOUT B Volume */
{ 44, 0x00 }, /* r2c - Limit Threshold Ctl */
{ 45, 0x7f }, /* r2d - Limiter Ctl & Release Rate */
{ 46, 0x00 }, /* r2e - Limiter Attack Rate */
};
static bool cs42l56_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case CS42L56_CHIP_ID_1:
case CS42L56_CHIP_ID_2:
case CS42L56_PWRCTL_1:
case CS42L56_PWRCTL_2:
case CS42L56_CLKCTL_1:
case CS42L56_CLKCTL_2:
case CS42L56_SERIAL_FMT:
case CS42L56_CLASSH_CTL:
case CS42L56_MISC_CTL:
case CS42L56_INT_STATUS:
case CS42L56_PLAYBACK_CTL:
case CS42L56_DSP_MUTE_CTL:
case CS42L56_ADCA_MIX_VOLUME:
case CS42L56_ADCB_MIX_VOLUME:
case CS42L56_PCMA_MIX_VOLUME:
case CS42L56_PCMB_MIX_VOLUME:
case CS42L56_ANAINPUT_ADV_VOLUME:
case CS42L56_DIGINPUT_ADV_VOLUME:
case CS42L56_MASTER_A_VOLUME:
case CS42L56_MASTER_B_VOLUME:
case CS42L56_BEEP_FREQ_ONTIME:
case CS42L56_BEEP_FREQ_OFFTIME:
case CS42L56_BEEP_TONE_CFG:
case CS42L56_TONE_CTL:
case CS42L56_CHAN_MIX_SWAP:
case CS42L56_AIN_REFCFG_ADC_MUX:
case CS42L56_HPF_CTL:
case CS42L56_MISC_ADC_CTL:
case CS42L56_GAIN_BIAS_CTL:
case CS42L56_PGAA_MUX_VOLUME:
case CS42L56_PGAB_MUX_VOLUME:
case CS42L56_ADCA_ATTENUATOR:
case CS42L56_ADCB_ATTENUATOR:
case CS42L56_ALC_EN_ATTACK_RATE:
case CS42L56_ALC_RELEASE_RATE:
case CS42L56_ALC_THRESHOLD:
case CS42L56_NOISE_GATE_CTL:
case CS42L56_ALC_LIM_SFT_ZC:
case CS42L56_AMUTE_HPLO_MUX:
case CS42L56_HPA_VOLUME:
case CS42L56_HPB_VOLUME:
case CS42L56_LOA_VOLUME:
case CS42L56_LOB_VOLUME:
case CS42L56_LIM_THRESHOLD_CTL:
case CS42L56_LIM_CTL_RELEASE_RATE:
case CS42L56_LIM_ATTACK_RATE:
return true;
default:
return false;
}
}
static bool cs42l56_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case CS42L56_INT_STATUS:
return 1;
default:
return 0;
}
}
static DECLARE_TLV_DB_SCALE(beep_tlv, -5000, 200, 0);
static DECLARE_TLV_DB_SCALE(hl_tlv, -6000, 50, 0);
static DECLARE_TLV_DB_SCALE(adv_tlv, -10200, 50, 0);
static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, 0);
static DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
static DECLARE_TLV_DB_SCALE(preamp_tlv, 0, 1000, 0);
static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
static const unsigned int ngnb_tlv[] = {
TLV_DB_RANGE_HEAD(2),
0, 1, TLV_DB_SCALE_ITEM(-8200, 600, 0),
2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0),
};
static const unsigned int ngb_tlv[] = {
TLV_DB_RANGE_HEAD(2),
0, 2, TLV_DB_SCALE_ITEM(-6400, 600, 0),
3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0),
};
static const unsigned int alc_tlv[] = {
TLV_DB_RANGE_HEAD(2),
0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0),
};
static const char * const beep_config_text[] = {
"Off", "Single", "Multiple", "Continuous"
};
static const struct soc_enum beep_config_enum =
SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 6,
ARRAY_SIZE(beep_config_text), beep_config_text);
static const char * const beep_pitch_text[] = {
"C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
"C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
};
static const struct soc_enum beep_pitch_enum =
SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 4,
ARRAY_SIZE(beep_pitch_text), beep_pitch_text);
static const char * const beep_ontime_text[] = {
"86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
"1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s",
"3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
};
static const struct soc_enum beep_ontime_enum =
SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 0,
ARRAY_SIZE(beep_ontime_text), beep_ontime_text);
static const char * const beep_offtime_text[] = {
"1.23 s", "2.58 s", "3.90 s", "5.20 s",
"6.60 s", "8.05 s", "9.35 s", "10.80 s"
};
static const struct soc_enum beep_offtime_enum =
SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_OFFTIME, 5,
ARRAY_SIZE(beep_offtime_text), beep_offtime_text);
static const char * const beep_treble_text[] = {
"5kHz", "7kHz", "10kHz", "15kHz"
};
static const struct soc_enum beep_treble_enum =
SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 3,
ARRAY_SIZE(beep_treble_text), beep_treble_text);
static const char * const beep_bass_text[] = {
"50Hz", "100Hz", "200Hz", "250Hz"
};
static const struct soc_enum beep_bass_enum =
SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 1,
ARRAY_SIZE(beep_bass_text), beep_bass_text);
static const char * const adc_swap_text[] = {
"None", "A+B/2", "A-B/2", "Swap"
};
static const struct soc_enum adc_swap_enum =
SOC_ENUM_SINGLE(CS42L56_MISC_ADC_CTL, 3,
ARRAY_SIZE(adc_swap_text), adc_swap_text);
static const char * const pgaa_mux_text[] = {
"AIN1A", "AIN2A", "AIN3A"};
static const struct soc_enum pgaa_mux_enum =
SOC_ENUM_SINGLE(CS42L56_PGAA_MUX_VOLUME, 0,
ARRAY_SIZE(pgaa_mux_text),
pgaa_mux_text);
static const struct snd_kcontrol_new pgaa_mux =
SOC_DAPM_ENUM("Route", pgaa_mux_enum);
static const char * const pgab_mux_text[] = {
"AIN1B", "AIN2B", "AIN3B"};
static const struct soc_enum pgab_mux_enum =
SOC_ENUM_SINGLE(CS42L56_PGAB_MUX_VOLUME, 0,
ARRAY_SIZE(pgab_mux_text),
pgab_mux_text);
static const struct snd_kcontrol_new pgab_mux =
SOC_DAPM_ENUM("Route", pgab_mux_enum);
static const char * const adca_mux_text[] = {
"PGAA", "AIN1A", "AIN2A", "AIN3A"};
static const struct soc_enum adca_mux_enum =
SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 0,
ARRAY_SIZE(adca_mux_text),
adca_mux_text);
static const struct snd_kcontrol_new adca_mux =
SOC_DAPM_ENUM("Route", adca_mux_enum);
static const char * const adcb_mux_text[] = {
"PGAB", "AIN1B", "AIN2B", "AIN3B"};
static const struct soc_enum adcb_mux_enum =
SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 2,
ARRAY_SIZE(adcb_mux_text),
adcb_mux_text);
static const struct snd_kcontrol_new adcb_mux =
SOC_DAPM_ENUM("Route", adcb_mux_enum);
static const char * const left_swap_text[] = {
"Left", "LR 2", "Right"};
static const char * const right_swap_text[] = {
"Right", "LR 2", "Left"};
static const unsigned int swap_values[] = { 0, 1, 3 };
static const struct soc_enum adca_swap_enum =
SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 0, 3,
ARRAY_SIZE(left_swap_text),
left_swap_text,
swap_values);
static const struct soc_enum pcma_swap_enum =
SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3,
ARRAY_SIZE(left_swap_text),
left_swap_text,
swap_values);
static const struct soc_enum adcb_swap_enum =
SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3,
ARRAY_SIZE(right_swap_text),
right_swap_text,
swap_values);
static const struct soc_enum pcmb_swap_enum =
SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3,
ARRAY_SIZE(right_swap_text),
right_swap_text,
swap_values);
static const struct snd_kcontrol_new hpa_switch =
SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1);
static const struct snd_kcontrol_new hpb_switch =
SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 4, 1, 1);
static const struct snd_kcontrol_new loa_switch =
SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 2, 1, 1);
static const struct snd_kcontrol_new lob_switch =
SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 0, 1, 1);
static const char * const hploa_input_text[] = {
"DACA", "PGAA"};
static const struct soc_enum lineouta_input_enum =
SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 2,
ARRAY_SIZE(hploa_input_text),
hploa_input_text);
static const struct snd_kcontrol_new lineouta_input =
SOC_DAPM_ENUM("Route", lineouta_input_enum);
static const struct soc_enum hpa_input_enum =
SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 0,
ARRAY_SIZE(hploa_input_text),
hploa_input_text);
static const struct snd_kcontrol_new hpa_input =
SOC_DAPM_ENUM("Route", hpa_input_enum);
static const char * const hplob_input_text[] = {
"DACB", "PGAB"};
static const struct soc_enum lineoutb_input_enum =
SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 3,
ARRAY_SIZE(hplob_input_text),
hplob_input_text);
static const struct snd_kcontrol_new lineoutb_input =
SOC_DAPM_ENUM("Route", lineoutb_input_enum);
static const struct soc_enum hpb_input_enum =
SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 1,
ARRAY_SIZE(hplob_input_text),
hplob_input_text);
static const struct snd_kcontrol_new hpb_input =
SOC_DAPM_ENUM("Route", hpb_input_enum);
static const char * const dig_mux_text[] = {
"ADC", "DSP"};
static const struct soc_enum dig_mux_enum =
SOC_ENUM_SINGLE(CS42L56_MISC_CTL, 7,
ARRAY_SIZE(dig_mux_text),
dig_mux_text);
static const struct snd_kcontrol_new dig_mux =
SOC_DAPM_ENUM("Route", dig_mux_enum);
static const char * const hpf_freq_text[] = {
"1.8Hz", "119Hz", "236Hz", "464Hz"
};
static const struct soc_enum hpfa_freq_enum =
SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 0,
ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
static const struct soc_enum hpfb_freq_enum =
SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 2,
ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
static const char * const ng_delay_text[] = {
"50ms", "100ms", "150ms", "200ms"
};
static const struct soc_enum ng_delay_enum =
SOC_ENUM_SINGLE(CS42L56_NOISE_GATE_CTL, 0,
ARRAY_SIZE(ng_delay_text), ng_delay_text);
static const struct snd_kcontrol_new cs42l56_snd_controls[] = {
SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L56_MASTER_A_VOLUME,
CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xfd, adv_tlv),
SOC_DOUBLE("Master Mute Switch", CS42L56_DSP_MUTE_CTL, 0, 1, 1, 1),
SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L56_ADCA_MIX_VOLUME,
CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv),
SOC_DOUBLE("ADC Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 6, 7, 1, 1),
SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L56_PCMA_MIX_VOLUME,
CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv),
SOC_DOUBLE("PCM Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 4, 5, 1, 1),
SOC_SINGLE_TLV("Analog Advisory Volume",
CS42L56_ANAINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
SOC_SINGLE_TLV("Digital Advisory Volume",
CS42L56_DIGINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L56_PGAA_MUX_VOLUME,
CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0xfd, pga_tlv),
SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR,
CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv),
SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1),
SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1),
SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME,
CS42L56_HPA_VOLUME, 0, 0x44, 0x55, hl_tlv),
SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME,
CS42L56_LOA_VOLUME, 0, 0x44, 0x55, hl_tlv),
SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL,
0, 0x00, 1, tone_tlv),
SOC_SINGLE_TLV("Treble Shelving Volume", CS42L56_TONE_CTL,
4, 0x00, 1, tone_tlv),
SOC_DOUBLE_TLV("PGA Preamp Volume", CS42L56_GAIN_BIAS_CTL,
4, 6, 0x02, 1, preamp_tlv),
SOC_SINGLE("DSP Switch", CS42L56_PLAYBACK_CTL, 7, 1, 1),
SOC_SINGLE("Gang Playback Switch", CS42L56_PLAYBACK_CTL, 4, 1, 1),
SOC_SINGLE("Gang ADC Switch", CS42L56_MISC_ADC_CTL, 7, 1, 1),
SOC_SINGLE("Gang PGA Switch", CS42L56_MISC_ADC_CTL, 6, 1, 1),
SOC_SINGLE("PCMA Invert", CS42L56_PLAYBACK_CTL, 2, 1, 1),
SOC_SINGLE("PCMB Invert", CS42L56_PLAYBACK_CTL, 3, 1, 1),
SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1),
SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1),
SOC_ENUM("PCMA Swap", pcma_swap_enum),
SOC_ENUM("PCMB Swap", pcmb_swap_enum),
SOC_ENUM("ADCA Swap", adca_swap_enum),
SOC_ENUM("ADCB Swap", adcb_swap_enum),
SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1),
SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1),
SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum),
SOC_ENUM("HPFB Corner Freq", hpfb_freq_enum),
SOC_SINGLE("Analog Soft Ramp", CS42L56_MISC_CTL, 4, 1, 1),
SOC_DOUBLE("Analog Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
7, 5, 1, 1),
SOC_SINGLE("Analog Zero Cross", CS42L56_MISC_CTL, 3, 1, 1),
SOC_DOUBLE("Analog Zero Cross Disable", CS42L56_ALC_LIM_SFT_ZC,
6, 4, 1, 1),
SOC_SINGLE("Digital Soft Ramp", CS42L56_MISC_CTL, 2, 1, 1),
SOC_SINGLE("Digital Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
3, 1, 1),
SOC_SINGLE("HL Deemphasis", CS42L56_PLAYBACK_CTL, 6, 1, 1),
SOC_SINGLE("ALC Switch", CS42L56_ALC_EN_ATTACK_RATE, 6, 1, 1),
SOC_SINGLE("ALC Limit All Switch", CS42L56_ALC_RELEASE_RATE, 7, 1, 1),
SOC_SINGLE_RANGE("ALC Attack", CS42L56_ALC_EN_ATTACK_RATE,
0, 0, 0x3f, 0),
SOC_SINGLE_RANGE("ALC Release", CS42L56_ALC_RELEASE_RATE,
0, 0x3f, 0, 0),
SOC_SINGLE_TLV("ALC MAX", CS42L56_ALC_THRESHOLD,
5, 0x07, 1, alc_tlv),
SOC_SINGLE_TLV("ALC MIN", CS42L56_ALC_THRESHOLD,
2, 0x07, 1, alc_tlv),
SOC_SINGLE("Limiter Switch", CS42L56_LIM_CTL_RELEASE_RATE, 7, 1, 1),
SOC_SINGLE("Limit All Switch", CS42L56_LIM_CTL_RELEASE_RATE, 6, 1, 1),
SOC_SINGLE_RANGE("Limiter Attack", CS42L56_LIM_ATTACK_RATE,
0, 0, 0x3f, 0),
SOC_SINGLE_RANGE("Limiter Release", CS42L56_LIM_CTL_RELEASE_RATE,
0, 0x3f, 0, 0),
SOC_SINGLE_TLV("Limiter MAX", CS42L56_LIM_THRESHOLD_CTL,
5, 0x07, 1, alc_tlv),
SOC_SINGLE_TLV("Limiter Cushion", CS42L56_ALC_THRESHOLD,
2, 0x07, 1, alc_tlv),
SOC_SINGLE("NG Switch", CS42L56_NOISE_GATE_CTL, 6, 1, 1),
SOC_SINGLE("NG All Switch", CS42L56_NOISE_GATE_CTL, 7, 1, 1),
SOC_SINGLE("NG Boost Switch", CS42L56_NOISE_GATE_CTL, 5, 1, 1),
SOC_SINGLE_TLV("NG Unboost Threshold", CS42L56_NOISE_GATE_CTL,
2, 0x07, 1, ngnb_tlv),
SOC_SINGLE_TLV("NG Boost Threshold", CS42L56_NOISE_GATE_CTL,
2, 0x07, 1, ngb_tlv),
SOC_ENUM("NG Delay", ng_delay_enum),
SOC_ENUM("Beep Config", beep_config_enum),
SOC_ENUM("Beep Pitch", beep_pitch_enum),
SOC_ENUM("Beep on Time", beep_ontime_enum),
SOC_ENUM("Beep off Time", beep_offtime_enum),
SOC_SINGLE_SX_TLV("Beep Volume", CS42L56_BEEP_FREQ_OFFTIME,
0, 0x07, 0x23, beep_tlv),
SOC_SINGLE("Beep Tone Ctl Switch", CS42L56_BEEP_TONE_CFG, 0, 1, 1),
SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum),
SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum),
};
static const struct snd_soc_dapm_widget cs42l56_dapm_widgets[] = {
SND_SOC_DAPM_SIGGEN("Beep"),
SND_SOC_DAPM_SUPPLY("VBUF", CS42L56_PWRCTL_1, 5, 1, NULL, 0),
SND_SOC_DAPM_MICBIAS("MIC1 Bias", CS42L56_PWRCTL_1, 4, 1),
SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L56_PWRCTL_1, 3, 1, NULL, 0),
SND_SOC_DAPM_INPUT("AIN1A"),
SND_SOC_DAPM_INPUT("AIN2A"),
SND_SOC_DAPM_INPUT("AIN1B"),
SND_SOC_DAPM_INPUT("AIN2B"),
SND_SOC_DAPM_INPUT("AIN3A"),
SND_SOC_DAPM_INPUT("AIN3B"),
SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_MUX("Digital Output Mux", SND_SOC_NOPM,
0, 0, &dig_mux),
SND_SOC_DAPM_PGA("PGAA", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("PGAB", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MUX("PGAA Input Mux",
SND_SOC_NOPM, 0, 0, &pgaa_mux),
SND_SOC_DAPM_MUX("PGAB Input Mux",
SND_SOC_NOPM, 0, 0, &pgab_mux),
SND_SOC_DAPM_MUX("ADCA Mux", SND_SOC_NOPM,
0, 0, &adca_mux),
SND_SOC_DAPM_MUX("ADCB Mux", SND_SOC_NOPM,
0, 0, &adcb_mux),
SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1),
SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1),
SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_OUTPUT("HPA"),
SND_SOC_DAPM_OUTPUT("LOA"),
SND_SOC_DAPM_OUTPUT("HPB"),
SND_SOC_DAPM_OUTPUT("LOB"),
SND_SOC_DAPM_SWITCH("Headphone Right",
CS42L56_PWRCTL_2, 4, 1, &hpb_switch),
SND_SOC_DAPM_SWITCH("Headphone Left",
CS42L56_PWRCTL_2, 6, 1, &hpa_switch),
SND_SOC_DAPM_SWITCH("Lineout Right",
CS42L56_PWRCTL_2, 0, 1, &lob_switch),
SND_SOC_DAPM_SWITCH("Lineout Left",
CS42L56_PWRCTL_2, 2, 1, &loa_switch),
SND_SOC_DAPM_MUX("LINEOUTA Input Mux", SND_SOC_NOPM,
0, 0, &lineouta_input),
SND_SOC_DAPM_MUX("LINEOUTB Input Mux", SND_SOC_NOPM,
0, 0, &lineoutb_input),
SND_SOC_DAPM_MUX("HPA Input Mux", SND_SOC_NOPM,
0, 0, &hpa_input),
SND_SOC_DAPM_MUX("HPB Input Mux", SND_SOC_NOPM,
0, 0, &hpb_input),
};
static const struct snd_soc_dapm_route cs42l56_audio_map[] = {
{"HiFi Capture", "DSP", "Digital Output Mux"},
{"HiFi Capture", "ADC", "Digital Output Mux"},
{"Digital Output Mux", NULL, "ADCA"},
{"Digital Output Mux", NULL, "ADCB"},
{"ADCB", NULL, "ADCB Mux"},
{"ADCA", NULL, "ADCA Mux"},
{"ADCA Mux", NULL, "AIN3A"},
{"ADCA Mux", NULL, "AIN2A"},
{"ADCA Mux", NULL, "AIN1A"},
{"ADCA Mux", NULL, "PGAA"},
{"ADCB Mux", NULL, "AIN3B"},
{"ADCB Mux", NULL, "AIN2B"},
{"ADCB Mux", NULL, "AIN1B"},
{"ADCB Mux", NULL, "PGAB"},
{"PGAA", "AIN1A", "PGAA Input Mux"},
{"PGAA", "AIN2A", "PGAA Input Mux"},
{"PGAA", "AIN3A", "PGAA Input Mux"},
{"PGAB", "AIN1B", "PGAB Input Mux"},
{"PGAB", "AIN2B", "PGAB Input Mux"},
{"PGAB", "AIN3B", "PGAB Input Mux"},
{"PGAA Input Mux", NULL, "AIN1A"},
{"PGAA Input Mux", NULL, "AIN2A"},
{"PGAA Input Mux", NULL, "AIN3A"},
{"PGAB Input Mux", NULL, "AIN1B"},
{"PGAB Input Mux", NULL, "AIN2B"},
{"PGAB Input Mux", NULL, "AIN3B"},
{"LOB", NULL, "Lineout Right"},
{"LOA", NULL, "Lineout Left"},
{"Lineout Right", "Switch", "LINEOUTB Input Mux"},
{"Lineout Left", "Switch", "LINEOUTA Input Mux"},
{"LINEOUTA Input Mux", "PGAA", "PGAA"},
{"LINEOUTB Input Mux", "PGAB", "PGAB"},
{"LINEOUTA Input Mux", "DACA", "DACA"},
{"LINEOUTB Input Mux", "DACB", "DACB"},
{"HPA", NULL, "Headphone Left"},
{"HPB", NULL, "Headphone Right"},
{"Headphone Right", "Switch", "HPB Input Mux"},
{"Headphone Left", "Switch", "HPA Input Mux"},
{"HPA Input Mux", "PGAA", "PGAA"},
{"HPB Input Mux", "PGAB", "PGAB"},
{"HPA Input Mux", "DACA", "DACA"},
{"HPB Input Mux", "DACB", "DACB"},
{"DACB", NULL, "HiFi Playback"},
{"DACA", NULL, "HiFi Playback"},
};
struct cs42l56_clk_para {
u32 mclk;
u32 srate;
u8 ratio;
};
static const struct cs42l56_clk_para clk_ratio_table[] = {
/* 8k */
{ 6000000, 8000, CS42L56_MCLK_LRCLK_768 },
{ 6144000, 8000, CS42L56_MCLK_LRCLK_750 },
{ 12000000, 8000, CS42L56_MCLK_LRCLK_768 },
{ 12288000, 8000, CS42L56_MCLK_LRCLK_750 },
{ 24000000, 8000, CS42L56_MCLK_LRCLK_768 },
{ 24576000, 8000, CS42L56_MCLK_LRCLK_750 },
/* 11.025k */
{ 5644800, 11025, CS42L56_MCLK_LRCLK_512},
{ 11289600, 11025, CS42L56_MCLK_LRCLK_512},
{ 22579200, 11025, CS42L56_MCLK_LRCLK_512 },
/* 11.0294k */
{ 6000000, 110294, CS42L56_MCLK_LRCLK_544 },
{ 12000000, 110294, CS42L56_MCLK_LRCLK_544 },
{ 24000000, 110294, CS42L56_MCLK_LRCLK_544 },
/* 12k */
{ 6000000, 12000, CS42L56_MCLK_LRCLK_500 },
{ 6144000, 12000, CS42L56_MCLK_LRCLK_512 },
{ 12000000, 12000, CS42L56_MCLK_LRCLK_500 },
{ 12288000, 12000, CS42L56_MCLK_LRCLK_512 },
{ 24000000, 12000, CS42L56_MCLK_LRCLK_500 },
{ 24576000, 12000, CS42L56_MCLK_LRCLK_512 },
/* 16k */
{ 6000000, 16000, CS42L56_MCLK_LRCLK_375 },
{ 6144000, 16000, CS42L56_MCLK_LRCLK_384 },
{ 12000000, 16000, CS42L56_MCLK_LRCLK_375 },
{ 12288000, 16000, CS42L56_MCLK_LRCLK_384 },
{ 24000000, 16000, CS42L56_MCLK_LRCLK_375 },
{ 24576000, 16000, CS42L56_MCLK_LRCLK_384 },
/* 22.050k */
{ 5644800, 22050, CS42L56_MCLK_LRCLK_256 },
{ 11289600, 22050, CS42L56_MCLK_LRCLK_256 },
{ 22579200, 22050, CS42L56_MCLK_LRCLK_256 },
/* 22.0588k */
{ 6000000, 220588, CS42L56_MCLK_LRCLK_272 },
{ 12000000, 220588, CS42L56_MCLK_LRCLK_272 },
{ 24000000, 220588, CS42L56_MCLK_LRCLK_272 },
/* 24k */
{ 6000000, 24000, CS42L56_MCLK_LRCLK_250 },
{ 6144000, 24000, CS42L56_MCLK_LRCLK_256 },
{ 12000000, 24000, CS42L56_MCLK_LRCLK_250 },
{ 12288000, 24000, CS42L56_MCLK_LRCLK_256 },
{ 24000000, 24000, CS42L56_MCLK_LRCLK_250 },
{ 24576000, 24000, CS42L56_MCLK_LRCLK_256 },
/* 32k */
{ 6000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
{ 6144000, 32000, CS42L56_MCLK_LRCLK_192 },
{ 12000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
{ 12288000, 32000, CS42L56_MCLK_LRCLK_192 },
{ 24000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
{ 24576000, 32000, CS42L56_MCLK_LRCLK_192 },
/* 44.118k */
{ 6000000, 44118, CS42L56_MCLK_LRCLK_136 },
{ 12000000, 44118, CS42L56_MCLK_LRCLK_136 },
{ 24000000, 44118, CS42L56_MCLK_LRCLK_136 },
/* 44.1k */
{ 5644800, 44100, CS42L56_MCLK_LRCLK_128 },
{ 11289600, 44100, CS42L56_MCLK_LRCLK_128 },
{ 22579200, 44100, CS42L56_MCLK_LRCLK_128 },
/* 48k */
{ 6000000, 48000, CS42L56_MCLK_LRCLK_125 },
{ 6144000, 48000, CS42L56_MCLK_LRCLK_128 },
{ 12000000, 48000, CS42L56_MCLK_LRCLK_125 },
{ 12288000, 48000, CS42L56_MCLK_LRCLK_128 },
{ 24000000, 48000, CS42L56_MCLK_LRCLK_125 },
{ 24576000, 48000, CS42L56_MCLK_LRCLK_128 },
};
static int cs42l56_get_mclk_ratio(int mclk, int rate)
{
int i;
for (i = 0; i < ARRAY_SIZE(clk_ratio_table); i++) {
if (clk_ratio_table[i].mclk == mclk &&
clk_ratio_table[i].srate == rate)
return clk_ratio_table[i].ratio;
}
return -EINVAL;
}
static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
switch (freq) {
case CS42L56_MCLK_5P6448MHZ:
case CS42L56_MCLK_6MHZ:
case CS42L56_MCLK_6P144MHZ:
cs42l56->mclk_div2 = 0;
cs42l56->mclk_prediv = 0;
break;
case CS42L56_MCLK_11P2896MHZ:
case CS42L56_MCLK_12MHZ:
case CS42L56_MCLK_12P288MHZ:
cs42l56->mclk_div2 = 1;
cs42l56->mclk_prediv = 0;
break;
case CS42L56_MCLK_22P5792MHZ:
case CS42L56_MCLK_24MHZ:
case CS42L56_MCLK_24P576MHZ:
cs42l56->mclk_div2 = 1;
cs42l56->mclk_prediv = 1;
break;
default:
return -EINVAL;
}
cs42l56->mclk = freq;
snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
CS42L56_MCLK_PREDIV_MASK,
cs42l56->mclk_prediv);
snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
CS42L56_MCLK_DIV2_MASK,
cs42l56->mclk_div2);
return 0;
}
static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
cs42l56->iface = CS42L56_MASTER_MODE;
break;
case SND_SOC_DAIFMT_CBS_CFS:
cs42l56->iface = CS42L56_SLAVE_MODE;
break;
default:
return -EINVAL;
}
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
cs42l56->iface_fmt = CS42L56_DIG_FMT_I2S;
break;
case SND_SOC_DAIFMT_LEFT_J:
cs42l56->iface_fmt = CS42L56_DIG_FMT_LEFT_J;
break;
default:
return -EINVAL;
}
/* sclk inversion */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
cs42l56->iface_inv = 0;
break;
case SND_SOC_DAIFMT_IB_NF:
cs42l56->iface_inv = CS42L56_SCLK_INV;
break;
default:
return -EINVAL;
}
snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
CS42L56_MS_MODE_MASK, cs42l56->iface);
snd_soc_update_bits(codec, CS42L56_SERIAL_FMT,
CS42L56_DIG_FMT_MASK, cs42l56->iface_fmt);
snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
CS42L56_SCLK_INV_MASK, cs42l56->iface_inv);
return 0;
}
static int cs42l56_digital_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
if (mute) {
/* Hit the DSP Mixer first */
snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL,
CS42L56_ADCAMIX_MUTE_MASK |
CS42L56_ADCBMIX_MUTE_MASK |
CS42L56_PCMAMIX_MUTE_MASK |
CS42L56_PCMBMIX_MUTE_MASK |
CS42L56_MSTB_MUTE_MASK |
CS42L56_MSTA_MUTE_MASK,
CS42L56_MUTE);
/* Mute ADC's */
snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL,
CS42L56_ADCA_MUTE_MASK |
CS42L56_ADCB_MUTE_MASK,
CS42L56_MUTE);
/* HP And LO */
snd_soc_update_bits(codec, CS42L56_HPA_VOLUME,
CS42L56_HP_MUTE_MASK,
CS42L56_MUTE);
snd_soc_update_bits(codec, CS42L56_HPB_VOLUME,
CS42L56_HP_MUTE_MASK,
CS42L56_MUTE);
snd_soc_update_bits(codec, CS42L56_LOA_VOLUME,
CS42L56_LO_MUTE_MASK,
CS42L56_MUTE);
snd_soc_update_bits(codec, CS42L56_LOB_VOLUME,
CS42L56_LO_MUTE_MASK,
CS42L56_MUTE);
} else {
snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL,
CS42L56_ADCAMIX_MUTE_MASK |
CS42L56_ADCBMIX_MUTE_MASK |
CS42L56_PCMAMIX_MUTE_MASK |
CS42L56_PCMBMIX_MUTE_MASK |
CS42L56_MSTB_MUTE_MASK |
CS42L56_MSTA_MUTE_MASK,
CS42L56_UNMUTE);
snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL,
CS42L56_ADCA_MUTE_MASK |
CS42L56_ADCB_MUTE_MASK,
CS42L56_UNMUTE);
snd_soc_update_bits(codec, CS42L56_HPA_VOLUME,
CS42L56_HP_MUTE_MASK,
CS42L56_UNMUTE);
snd_soc_update_bits(codec, CS42L56_HPB_VOLUME,
CS42L56_HP_MUTE_MASK,
CS42L56_UNMUTE);
snd_soc_update_bits(codec, CS42L56_LOA_VOLUME,
CS42L56_LO_MUTE_MASK,
CS42L56_UNMUTE);
snd_soc_update_bits(codec, CS42L56_LOB_VOLUME,
CS42L56_LO_MUTE_MASK,
CS42L56_UNMUTE);
}
return 0;
}
static int cs42l56_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
int ratio;
ratio = cs42l56_get_mclk_ratio(cs42l56->mclk, params_rate(params));
if (ratio >= 0) {
snd_soc_update_bits(codec, CS42L56_CLKCTL_2,
CS42L56_CLK_RATIO_MASK, ratio);
} else {
dev_err(codec->dev, "unsupported mclk/sclk/lrclk ratio\n");
return -EINVAL;
}
return 0;
}
static int cs42l56_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
int ret;
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
CS42L56_MCLK_DIS_MASK, 0);
snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
CS42L56_PDN_ALL_MASK, 0);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
regcache_cache_only(cs42l56->regmap, false);
regcache_sync(cs42l56->regmap);
ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
cs42l56->supplies);
if (ret != 0) {
dev_err(cs42l56->dev,
"Failed to enable regulators: %d\n",
ret);
return ret;
}
}
snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
CS42L56_PDN_ALL_MASK, 1);
break;
case SND_SOC_BIAS_OFF:
snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
CS42L56_PDN_ALL_MASK, 1);
snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
CS42L56_MCLK_DIS_MASK, 1);
regcache_cache_only(cs42l56->regmap, true);
regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
cs42l56->supplies);
break;
}
codec->dapm.bias_level = level;
return 0;
}
#define CS42L56_RATES (SNDRV_PCM_RATE_8000_48000)
#define CS42L56_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_ops cs42l56_ops = {
.hw_params = cs42l56_pcm_hw_params,
.digital_mute = cs42l56_digital_mute,
.set_fmt = cs42l56_set_dai_fmt,
.set_sysclk = cs42l56_set_sysclk,
};
static struct snd_soc_dai_driver cs42l56_dai = {
.name = "cs42l56",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
.channels_max = 2,
.rates = CS42L56_RATES,
.formats = CS42L56_FORMATS,
},
.capture = {
.stream_name = "HiFi Capture",
.channels_min = 1,
.channels_max = 2,
.rates = CS42L56_RATES,
.formats = CS42L56_FORMATS,
},
.ops = &cs42l56_ops,
};
static int cs42l56_suspend(struct snd_soc_codec *codec)
{
cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int cs42l56_resume(struct snd_soc_codec *codec)
{
cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
static int beep_freq[] = {
261, 522, 585, 667, 706, 774, 889, 1000,
1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
};
static void cs42l56_beep_work(struct work_struct *work)
{
struct cs42l56_private *cs42l56 =
container_of(work, struct cs42l56_private, beep_work);
struct snd_soc_codec *codec = cs42l56->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int i;
int val = 0;
int best = 0;
if (cs42l56->beep_rate) {
for (i = 0; i < ARRAY_SIZE(beep_freq); i++) {
if (abs(cs42l56->beep_rate - beep_freq[i]) <
abs(cs42l56->beep_rate - beep_freq[best]))
best = i;
}
dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
beep_freq[best], cs42l56->beep_rate);
val = (best << CS42L56_BEEP_RATE_SHIFT);
snd_soc_dapm_enable_pin(dapm, "Beep");
} else {
dev_dbg(codec->dev, "Disabling beep\n");
snd_soc_dapm_disable_pin(dapm, "Beep");
}
snd_soc_update_bits(codec, CS42L56_BEEP_FREQ_ONTIME,
CS42L56_BEEP_FREQ_MASK, val);
snd_soc_dapm_sync(dapm);
}
/* For usability define a way of injecting beep events for the device -
* many systems will not have a keyboard.
*/
static int cs42l56_beep_event(struct input_dev *dev, unsigned int type,
unsigned int code, int hz)
{
struct snd_soc_codec *codec = input_get_drvdata(dev);
struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
switch (code) {
case SND_BELL:
if (hz)
hz = 261;
case SND_TONE:
break;
default:
return -1;
}
/* Kick the beep from a workqueue */
cs42l56->beep_rate = hz;
schedule_work(&cs42l56->beep_work);
return 0;
}
static ssize_t cs42l56_beep_set(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct cs42l56_private *cs42l56 = dev_get_drvdata(dev);
long int time;
int ret;
ret = kstrtol(buf, 10, &time);
if (ret != 0)
return ret;
input_event(cs42l56->beep, EV_SND, SND_TONE, time);
return count;
}
static DEVICE_ATTR(beep, 0200, NULL, cs42l56_beep_set);
static void cs42l56_init_beep(struct snd_soc_codec *codec)
{
struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
int ret;
cs42l56->beep = devm_input_allocate_device(codec->dev);
if (!cs42l56->beep) {
dev_err(codec->dev, "Failed to allocate beep device\n");
return;
}
INIT_WORK(&cs42l56->beep_work, cs42l56_beep_work);
cs42l56->beep_rate = 0;
cs42l56->beep->name = "CS42L56 Beep Generator";
cs42l56->beep->phys = dev_name(codec->dev);
cs42l56->beep->id.bustype = BUS_I2C;
cs42l56->beep->evbit[0] = BIT_MASK(EV_SND);
cs42l56->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
cs42l56->beep->event = cs42l56_beep_event;
cs42l56->beep->dev.parent = codec->dev;
input_set_drvdata(cs42l56->beep, codec);
ret = input_register_device(cs42l56->beep);
if (ret != 0) {
cs42l56->beep = NULL;
dev_err(codec->dev, "Failed to register beep device\n");
}
ret = device_create_file(codec->dev, &dev_attr_beep);
if (ret != 0) {
dev_err(codec->dev, "Failed to create keyclick file: %d\n",
ret);
}
}
static void cs42l56_free_beep(struct snd_soc_codec *codec)
{
struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
device_remove_file(codec->dev, &dev_attr_beep);
cancel_work_sync(&cs42l56->beep_work);
cs42l56->beep = NULL;
snd_soc_update_bits(codec, CS42L56_BEEP_TONE_CFG,
CS42L56_BEEP_EN_MASK, 0);
}
static int cs42l56_probe(struct snd_soc_codec *codec)
{
cs42l56_init_beep(codec);
cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
static int cs42l56_remove(struct snd_soc_codec *codec)
{
struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
cs42l56_free_beep(codec);
cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_free(ARRAY_SIZE(cs42l56->supplies), cs42l56->supplies);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
.probe = cs42l56_probe,
.remove = cs42l56_remove,
.suspend = cs42l56_suspend,
.resume = cs42l56_resume,
.set_bias_level = cs42l56_set_bias_level,
.dapm_widgets = cs42l56_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets),
.dapm_routes = cs42l56_audio_map,
.num_dapm_routes = ARRAY_SIZE(cs42l56_audio_map),
.controls = cs42l56_snd_controls,
.num_controls = ARRAY_SIZE(cs42l56_snd_controls),
};
static struct regmap_config cs42l56_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = CS42L56_MAX_REGISTER,
.reg_defaults = cs42l56_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults),
.readable_reg = cs42l56_readable_register,
.volatile_reg = cs42l56_volatile_register,
.cache_type = REGCACHE_RBTREE,
};
static int cs42l56_handle_of_data(struct i2c_client *i2c_client,
struct cs42l56_platform_data *pdata)
{
struct device_node *np = i2c_client->dev.of_node;
u32 val32;
if (of_property_read_bool(np, "cirrus,ain1a-reference-cfg"))
pdata->ain1a_ref_cfg = true;
if (of_property_read_bool(np, "cirrus,ain2a-reference-cfg"))
pdata->ain2a_ref_cfg = true;
if (of_property_read_bool(np, "cirrus,ain1b-reference-cfg"))
pdata->ain1b_ref_cfg = true;
if (of_property_read_bool(np, "cirrus,ain2b-reference-cfg"))
pdata->ain2b_ref_cfg = true;
if (of_property_read_u32(np, "cirrus,micbias-lvl", &val32) >= 0)
pdata->micbias_lvl = val32;
if (of_property_read_u32(np, "cirrus,chgfreq-divisor", &val32) >= 0)
pdata->chgfreq = val32;
if (of_property_read_u32(np, "cirrus,adaptive-pwr-cfg", &val32) >= 0)
pdata->adaptive_pwr = val32;
if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
pdata->hpfa_freq = val32;
if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
pdata->hpfb_freq = val32;
pdata->gpio_nreset = of_get_named_gpio(np, "cirrus,gpio-nreset", 0);
return 0;
}
static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct cs42l56_private *cs42l56;
struct cs42l56_platform_data *pdata =
dev_get_platdata(&i2c_client->dev);
int ret, i;
unsigned int devid = 0;
unsigned int alpha_rev, metal_rev;
unsigned int reg;
cs42l56 = devm_kzalloc(&i2c_client->dev,
sizeof(struct cs42l56_private),
GFP_KERNEL);
if (cs42l56 == NULL)
return -ENOMEM;
cs42l56->dev = &i2c_client->dev;
cs42l56->regmap = devm_regmap_init_i2c(i2c_client, &cs42l56_regmap);
if (IS_ERR(cs42l56->regmap)) {
ret = PTR_ERR(cs42l56->regmap);
dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
return ret;
}
if (pdata) {
cs42l56->pdata = *pdata;
} else {
pdata = devm_kzalloc(&i2c_client->dev,
sizeof(struct cs42l56_platform_data),
GFP_KERNEL);
if (!pdata) {
dev_err(&i2c_client->dev,
"could not allocate pdata\n");
return -ENOMEM;
}
if (i2c_client->dev.of_node) {
ret = cs42l56_handle_of_data(i2c_client,
&cs42l56->pdata);
if (ret != 0)
return ret;
}
cs42l56->pdata = *pdata;
}
if (cs42l56->pdata.gpio_nreset) {
ret = gpio_request_one(cs42l56->pdata.gpio_nreset,
GPIOF_OUT_INIT_HIGH, "CS42L56 /RST");
if (ret < 0) {
dev_err(&i2c_client->dev,
"Failed to request /RST %d: %d\n",
cs42l56->pdata.gpio_nreset, ret);
return ret;
}
gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 0);
gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 1);
}
i2c_set_clientdata(i2c_client, cs42l56);
for (i = 0; i < ARRAY_SIZE(cs42l56->supplies); i++)
cs42l56->supplies[i].supply = cs42l56_supply_names[i];
ret = devm_regulator_bulk_get(&i2c_client->dev,
ARRAY_SIZE(cs42l56->supplies),
cs42l56->supplies);
if (ret != 0) {
dev_err(&i2c_client->dev,
"Failed to request supplies: %d\n", ret);
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
cs42l56->supplies);
if (ret != 0) {
dev_err(&i2c_client->dev,
"Failed to enable supplies: %d\n", ret);
return ret;
}
regcache_cache_bypass(cs42l56->regmap, true);
ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, &reg);
devid = reg & CS42L56_CHIP_ID_MASK;
if (devid != CS42L56_DEVID) {
dev_err(&i2c_client->dev,
"CS42L56 Device ID (%X). Expected %X\n",
devid, CS42L56_DEVID);
goto err_enable;
}
alpha_rev = reg & CS42L56_AREV_MASK;
metal_rev = reg & CS42L56_MTLREV_MASK;
dev_info(&i2c_client->dev, "Cirrus Logic CS42L56 ");
dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n",
alpha_rev, metal_rev);
regcache_cache_bypass(cs42l56->regmap, false);
if (cs42l56->pdata.ain1a_ref_cfg)
regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
CS42L56_AIN1A_REF_MASK, 1);
if (cs42l56->pdata.ain1b_ref_cfg)
regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
CS42L56_AIN1B_REF_MASK, 1);
if (cs42l56->pdata.ain2a_ref_cfg)
regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
CS42L56_AIN2A_REF_MASK, 1);
if (cs42l56->pdata.ain2b_ref_cfg)
regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
CS42L56_AIN2B_REF_MASK, 1);
if (cs42l56->pdata.micbias_lvl)
regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL,
CS42L56_MIC_BIAS_MASK,
cs42l56->pdata.micbias_lvl);
if (cs42l56->pdata.chgfreq)
regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
CS42L56_CHRG_FREQ_MASK,
cs42l56->pdata.chgfreq);
if (cs42l56->pdata.hpfb_freq)
regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
CS42L56_HPFB_FREQ_MASK,
cs42l56->pdata.hpfb_freq);
if (cs42l56->pdata.hpfa_freq)
regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
CS42L56_HPFA_FREQ_MASK,
cs42l56->pdata.hpfa_freq);
if (cs42l56->pdata.adaptive_pwr)
regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
CS42L56_ADAPT_PWR_MASK,
cs42l56->pdata.adaptive_pwr);
ret = snd_soc_register_codec(&i2c_client->dev,
&soc_codec_dev_cs42l56, &cs42l56_dai, 1);
if (ret < 0)
return ret;
return 0;
err_enable:
regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
cs42l56->supplies);
return ret;
}
static int cs42l56_i2c_remove(struct i2c_client *client)
{
struct cs42l56_private *cs42l56 = i2c_get_clientdata(client);
snd_soc_unregister_codec(&client->dev);
regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
cs42l56->supplies);
return 0;
}
static const struct of_device_id cs42l56_of_match[] = {
{ .compatible = "cirrus,cs42l56", },
{ }
};
MODULE_DEVICE_TABLE(of, cs42l56_of_match);
static const struct i2c_device_id cs42l56_id[] = {
{ "cs42l56", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, cs42l56_id);
static struct i2c_driver cs42l56_i2c_driver = {
.driver = {
.name = "cs42l56",
.owner = THIS_MODULE,
.of_match_table = cs42l56_of_match,
},
.id_table = cs42l56_id,
.probe = cs42l56_i2c_probe,
.remove = cs42l56_i2c_remove,
};
module_i2c_driver(cs42l56_i2c_driver);
MODULE_DESCRIPTION("ASoC CS42L56 driver");
MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
MODULE_LICENSE("GPL");
/*
* cs42l52.h -- CS42L56 ALSA SoC audio driver
*
* Copyright 2014 CirrusLogic, Inc.
*
* Author: Brian Austin <brian.austin@cirrus.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __CS42L56_H__
#define __CS42L56_H__
#define CS42L56_CHIP_ID_1 0x01
#define CS42L56_CHIP_ID_2 0x02
#define CS42L56_PWRCTL_1 0x03
#define CS42L56_PWRCTL_2 0x04
#define CS42L56_CLKCTL_1 0x05
#define CS42L56_CLKCTL_2 0x06
#define CS42L56_SERIAL_FMT 0x07
#define CS42L56_CLASSH_CTL 0x08
#define CS42L56_MISC_CTL 0x09
#define CS42L56_INT_STATUS 0x0a
#define CS42L56_PLAYBACK_CTL 0x0b
#define CS42L56_DSP_MUTE_CTL 0x0c
#define CS42L56_ADCA_MIX_VOLUME 0x0d
#define CS42L56_ADCB_MIX_VOLUME 0x0e
#define CS42L56_PCMA_MIX_VOLUME 0x0f
#define CS42L56_PCMB_MIX_VOLUME 0x10
#define CS42L56_ANAINPUT_ADV_VOLUME 0x11
#define CS42L56_DIGINPUT_ADV_VOLUME 0x12
#define CS42L56_MASTER_A_VOLUME 0x13
#define CS42L56_MASTER_B_VOLUME 0x14
#define CS42L56_BEEP_FREQ_ONTIME 0x15
#define CS42L56_BEEP_FREQ_OFFTIME 0x16
#define CS42L56_BEEP_TONE_CFG 0x17
#define CS42L56_TONE_CTL 0x18
#define CS42L56_CHAN_MIX_SWAP 0x19
#define CS42L56_AIN_REFCFG_ADC_MUX 0x1a
#define CS42L56_HPF_CTL 0x1b
#define CS42L56_MISC_ADC_CTL 0x1c
#define CS42L56_GAIN_BIAS_CTL 0x1d
#define CS42L56_PGAA_MUX_VOLUME 0x1e
#define CS42L56_PGAB_MUX_VOLUME 0x1f
#define CS42L56_ADCA_ATTENUATOR 0x20
#define CS42L56_ADCB_ATTENUATOR 0x21
#define CS42L56_ALC_EN_ATTACK_RATE 0x22
#define CS42L56_ALC_RELEASE_RATE 0x23
#define CS42L56_ALC_THRESHOLD 0x24
#define CS42L56_NOISE_GATE_CTL 0x25
#define CS42L56_ALC_LIM_SFT_ZC 0x26
#define CS42L56_AMUTE_HPLO_MUX 0x27
#define CS42L56_HPA_VOLUME 0x28
#define CS42L56_HPB_VOLUME 0x29
#define CS42L56_LOA_VOLUME 0x2a
#define CS42L56_LOB_VOLUME 0x2b
#define CS42L56_LIM_THRESHOLD_CTL 0x2c
#define CS42L56_LIM_CTL_RELEASE_RATE 0x2d
#define CS42L56_LIM_ATTACK_RATE 0x2e
/* Device ID and Rev ID Masks */
#define CS42L56_DEVID 0x56
#define CS42L56_CHIP_ID_MASK 0xff
#define CS42L56_AREV_MASK 0x1c
#define CS42L56_MTLREV_MASK 0x03
/* Power bit masks */
#define CS42L56_PDN_ALL_MASK 0x01
#define CS42L56_PDN_ADCA_MASK 0x02
#define CS42L56_PDN_ADCB_MASK 0x04
#define CS42L56_PDN_CHRG_MASK 0x08
#define CS42L56_PDN_BIAS_MASK 0x10
#define CS42L56_PDN_VBUF_MASK 0x20
#define CS42L56_PDN_LOA_MASK 0x03
#define CS42L56_PDN_LOB_MASK 0x0c
#define CS42L56_PDN_HPA_MASK 0x30
#define CS42L56_PDN_HPB_MASK 0xc0
/* serial port and clk masks */
#define CS42L56_MASTER_MODE 1
#define CS42L56_SLAVE_MODE 0
#define CS42L56_MS_MODE_MASK 0x40
#define CS42L56_SCLK_INV 1
#define CS42L56_SCLK_INV_MASK 0x20
#define CS42L56_SCLK_MCLK_MASK 0x18
#define CS42L56_MCLK_PREDIV_MASK 0x04
#define CS42L56_MCLK_DIV2_MASK 0x02
#define CS42L56_MCLK_DIS_MASK 0x01
#define CS42L56_CLK_AUTO_MASK 0x20
#define CS42L56_CLK_RATIO_MASK 0x1f
#define CS42L56_DIG_FMT_I2S 0
#define CS42L56_DIG_FMT_LEFT_J 1
#define CS42L56_DIG_FMT_MASK 0x08
/* Class H and misc ctl masks */
#define CS42L56_ADAPT_PWR_MASK 0xc0
#define CS42L56_CHRG_FREQ_MASK 0x0f
#define CS42L56_DIG_MUX_MASK 0x80
#define CS42L56_ANLGSFT_MASK 0x10
#define CS42L56_ANLGZC_MASK 0x08
#define CS42L56_DIGSFT_MASK 0x04
#define CS42L56_FREEZE_MASK 0x01
#define CS42L56_MIC_BIAS_MASK 0x03
#define CS42L56_HPFA_FREQ_MASK 0x03
#define CS42L56_HPFB_FREQ_MASK 0xc0
#define CS42L56_AIN1A_REF_MASK 0x10
#define CS42L56_AIN2A_REF_MASK 0x40
#define CS42L56_AIN1B_REF_MASK 0x20
#define CS42L56_AIN2B_REF_MASK 0x80
/* Playback Capture ctl masks */
#define CS42L56_PDN_DSP_MASK 0x80
#define CS42L56_DEEMPH_MASK 0x40
#define CS42L56_PLYBCK_GANG_MASK 0x10
#define CS42L56_PCM_INV_MASK 0x0c
#define CS42L56_MUTE 1
#define CS42L56_UNMUTE 0
#define CS42L56_ADCAMIX_MUTE_MASK 0x40
#define CS42L56_ADCBMIX_MUTE_MASK 0x80
#define CS42L56_PCMAMIX_MUTE_MASK 0x10
#define CS42L56_PCMBMIX_MUTE_MASK 0x20
#define CS42L56_MSTB_MUTE_MASK 0x02
#define CS42L56_MSTA_MUTE_MASK 0x01
#define CS42L56_ADCA_MUTE_MASK 0x01
#define CS42L56_ADCB_MUTE_MASK 0x02
#define CS42L56_HP_MUTE_MASK 0x80
#define CS42L56_LO_MUTE_MASK 0x80
/* Beep masks */
#define CS42L56_BEEP_FREQ_MASK 0xf0
#define CS42L56_BEEP_ONTIME_MASK 0x0f
#define CS42L56_BEEP_OFFTIME_MASK 0xe0
#define CS42L56_BEEP_CFG_MASK 0xc0
#define CS42L56_BEEP_TREBCF_MASK 0x18
#define CS42L56_BEEP_BASSCF_MASK 0x06
#define CS42L56_BEEP_TCEN_MASK 0x01
#define CS42L56_BEEP_RATE_SHIFT 4
#define CS42L56_BEEP_EN_MASK 0x3f
/* Supported MCLKS */
#define CS42L56_MCLK_5P6448MHZ 5644800
#define CS42L56_MCLK_6MHZ 6000000
#define CS42L56_MCLK_6P144MHZ 6144000
#define CS42L56_MCLK_11P2896MHZ 11289600
#define CS42L56_MCLK_12MHZ 12000000
#define CS42L56_MCLK_12P288MHZ 12288000
#define CS42L56_MCLK_22P5792MHZ 22579200
#define CS42L56_MCLK_24MHZ 24000000
#define CS42L56_MCLK_24P576MHZ 24576000
/* Clock ratios */
#define CS42L56_MCLK_LRCLK_128 0x08
#define CS42L56_MCLK_LRCLK_125 0x09
#define CS42L56_MCLK_LRCLK_136 0x0b
#define CS42L56_MCLK_LRCLK_192 0x0c
#define CS42L56_MCLK_LRCLK_187P5 0x0d
#define CS42L56_MCLK_LRCLK_256 0x10
#define CS42L56_MCLK_LRCLK_250 0x11
#define CS42L56_MCLK_LRCLK_272 0x13
#define CS42L56_MCLK_LRCLK_384 0x14
#define CS42L56_MCLK_LRCLK_375 0x15
#define CS42L56_MCLK_LRCLK_512 0x18
#define CS42L56_MCLK_LRCLK_500 0x19
#define CS42L56_MCLK_LRCLK_544 0x1b
#define CS42L56_MCLK_LRCLK_750 0x1c
#define CS42L56_MCLK_LRCLK_768 0x1d
#define CS42L56_MAX_REGISTER 0x34
#endif
......@@ -248,8 +248,7 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_codec *codec = dai->codec;
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
u32 ratio = cs42xx8->sysclk / params_rate(params);
......
......@@ -74,11 +74,9 @@ struct wm8962_priv {
struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES];
struct notifier_block disable_nb[WM8962_NUM_SUPPLIES];
#if IS_ENABLED(CONFIG_INPUT)
struct input_dev *beep;
struct work_struct beep_work;
int beep_rate;
#endif
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio_chip;
......@@ -3154,7 +3152,6 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
}
EXPORT_SYMBOL_GPL(wm8962_mic_detect);
#if IS_ENABLED(CONFIG_INPUT)
static int beep_rates[] = {
500, 1000, 2000, 4000,
};
......@@ -3286,15 +3283,6 @@ static void wm8962_free_beep(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);
}
#else
static void wm8962_init_beep(struct snd_soc_codec *codec)
{
}
static void wm8962_free_beep(struct snd_soc_codec *codec)
{
}
#endif
static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio)
{
......
......@@ -18,7 +18,7 @@ config SND_DAVINCI_SOC_GENERIC_EVM
config SND_AM33XX_SOC_EVM
tristate "SoC Audio for the AM33XX chip based boards"
depends on SND_DAVINCI_SOC && SOC_AM33XX
depends on SND_DAVINCI_SOC && SOC_AM33XX && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y or M if you want to add support for SoC audio on AM33XX
......@@ -28,7 +28,7 @@ config SND_AM33XX_SOC_EVM
config SND_DAVINCI_SOC_EVM
tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
depends on SND_DAVINCI_SOC
depends on SND_DAVINCI_SOC && I2C
depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
select SND_DAVINCI_SOC_GENERIC_EVM
help
......@@ -56,7 +56,7 @@ endchoice
config SND_DM6467_SOC_EVM
tristate "SoC Audio support for DaVinci DM6467 EVM"
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
select SND_SOC_SPDIF
......@@ -65,7 +65,7 @@ config SND_DM6467_SOC_EVM
config SND_DA830_SOC_EVM
tristate "SoC Audio support for DA830/OMAP-L137 EVM"
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
help
......@@ -74,7 +74,7 @@ config SND_DA830_SOC_EVM
config SND_DA850_SOC_EVM
tristate "SoC Audio support for DA850/OMAP-L138 EVM"
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y if you want to add support for SoC audio on TI
......
......@@ -757,7 +757,6 @@ static int davinci_i2s_remove(struct platform_device *pdev)
struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
davinci_soc_platform_unregister(&pdev->dev);
clk_disable(dev->clk);
clk_put(dev->clk);
......
......@@ -36,6 +36,9 @@
#include "davinci-pcm.h"
#include "davinci-mcasp.h"
#include "../omap/omap-pcm.h"
#define MCASP_MAX_AFIFO_DEPTH 64
struct davinci_mcasp_context {
u32 txfmtctl;
......@@ -269,25 +272,51 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
int ret = 0;
u32 data_delay;
bool fs_pol_rising;
bool inv_fs = false;
pm_runtime_get_sync(mcasp->dev);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
/* 1st data bit occur one ACLK cycle after the frame sync */
data_delay = 1;
break;
case SND_SOC_DAIFMT_DSP_B:
case SND_SOC_DAIFMT_AC97:
mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
/* No delay after FS */
data_delay = 0;
break;
default:
case SND_SOC_DAIFMT_I2S:
/* configure a full-word SYNC pulse (LRCLK) */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
/* make 1st data bit occur one ACLK cycle after the frame sync */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(1));
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(1));
/* 1st data bit occur one ACLK cycle after the frame sync */
data_delay = 1;
/* FS need to be inverted */
inv_fs = true;
break;
case SND_SOC_DAIFMT_LEFT_J:
/* configure a full-word SYNC pulse (LRCLK) */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
/* No delay after FS */
data_delay = 0;
break;
default:
ret = -EINVAL;
goto out;
}
mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay),
FSXDLY(3));
mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay),
FSRDLY(3));
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
/* codec is clock and frame slave */
......@@ -325,7 +354,6 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
mcasp->bclk_master = 0;
break;
default:
ret = -EINVAL;
goto out;
......@@ -334,39 +362,38 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_NF:
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
fs_pol_rising = true;
break;
case SND_SOC_DAIFMT_NB_IF:
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
fs_pol_rising = false;
break;
case SND_SOC_DAIFMT_IB_IF:
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
fs_pol_rising = false;
break;
case SND_SOC_DAIFMT_NB_NF:
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
fs_pol_rising = true;
break;
default:
ret = -EINVAL;
break;
goto out;
}
if (inv_fs)
fs_pol_rising = !fs_pol_rising;
if (fs_pol_rising) {
mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
} else {
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
}
out:
pm_runtime_put_sync(mcasp->dev);
......@@ -464,17 +491,19 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
}
static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
int channels)
int period_words, int channels)
{
struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[stream];
struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream];
int i;
u8 tx_ser = 0;
u8 rx_ser = 0;
u8 ser;
u8 slots = mcasp->tdm_slots;
u8 max_active_serializers = (channels + slots - 1) / slots;
int active_serializers, numevt, n;
u32 reg;
/* Default configuration */
if (mcasp->version != MCASP_VERSION_4)
if (mcasp->version < MCASP_VERSION_3)
mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
/* All PINS as McASP */
......@@ -505,37 +534,71 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
}
}
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
ser = tx_ser;
else
ser = rx_ser;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
active_serializers = tx_ser;
numevt = mcasp->txnumevt;
reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
} else {
active_serializers = rx_ser;
numevt = mcasp->rxnumevt;
reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
}
if (ser < max_active_serializers) {
if (active_serializers < max_active_serializers) {
dev_warn(mcasp->dev, "stream has more channels (%d) than are "
"enabled in mcasp (%d)\n", channels, ser * slots);
"enabled in mcasp (%d)\n", channels,
active_serializers * slots);
return -EINVAL;
}
if (mcasp->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (mcasp->txnumevt * tx_ser > 64)
mcasp->txnumevt = 1;
reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
mcasp_mod_bits(mcasp, reg, tx_ser, NUMDMA_MASK);
mcasp_mod_bits(mcasp, reg, ((mcasp->txnumevt * tx_ser) << 8),
NUMEVT_MASK);
/* AFIFO is not in use */
if (!numevt) {
/* Configure the burst size for platform drivers */
if (active_serializers > 1) {
/*
* If more than one serializers are in use we have one
* DMA request to provide data for all serializers.
* For example if three serializers are enabled the DMA
* need to transfer three words per DMA request.
*/
dma_params->fifo_level = active_serializers;
dma_data->maxburst = active_serializers;
} else {
dma_params->fifo_level = 0;
dma_data->maxburst = 0;
}
return 0;
}
if (mcasp->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) {
if (mcasp->rxnumevt * rx_ser > 64)
mcasp->rxnumevt = 1;
reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
mcasp_mod_bits(mcasp, reg, rx_ser, NUMDMA_MASK);
mcasp_mod_bits(mcasp, reg, ((mcasp->rxnumevt * rx_ser) << 8),
NUMEVT_MASK);
if (period_words % active_serializers) {
dev_err(mcasp->dev, "Invalid combination of period words and "
"active serializers: %d, %d\n", period_words,
active_serializers);
return -EINVAL;
}
/*
* Calculate the optimal AFIFO depth for platform side:
* The number of words for numevt need to be in steps of active
* serializers.
*/
n = numevt % active_serializers;
if (n)
numevt += (active_serializers - n);
while (period_words % numevt && numevt > 0)
numevt -= active_serializers;
if (numevt <= 0)
numevt = active_serializers;
mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK);
mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK);
/* Configure the burst size for platform drivers */
if (numevt == 1)
numevt = 0;
dma_params->fifo_level = numevt;
dma_data->maxburst = numevt;
return 0;
}
......@@ -607,27 +670,24 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
struct davinci_pcm_dma_params *dma_params =
&mcasp->dma_params[substream->stream];
struct snd_dmaengine_dai_dma_data *dma_data =
&mcasp->dma_data[substream->stream];
int word_length;
u8 fifo_level;
u8 slots = mcasp->tdm_slots;
u8 active_serializers;
int channels = params_channels(params);
int period_size = params_period_size(params);
int ret;
/* If mcasp is BCLK master we need to set BCLK divider */
if (mcasp->bclk_master) {
unsigned int bclk_freq = snd_soc_params_to_bclk(params);
if (mcasp->sysclk_freq % bclk_freq != 0) {
dev_err(mcasp->dev, "Can't produce requred BCLK\n");
dev_err(mcasp->dev, "Can't produce required BCLK\n");
return -EINVAL;
}
davinci_mcasp_set_clkdiv(
cpu_dai, 1, mcasp->sysclk_freq / bclk_freq);
}
ret = mcasp_common_hw_param(mcasp, substream->stream, channels);
ret = mcasp_common_hw_param(mcasp, substream->stream,
period_size * channels, channels);
if (ret)
return ret;
......@@ -671,21 +731,11 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
/* Calculate FIFO level */
active_serializers = (channels + slots - 1) / slots;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
fifo_level = mcasp->txnumevt * active_serializers;
else
fifo_level = mcasp->rxnumevt * active_serializers;
if (mcasp->version == MCASP_VERSION_2 && !fifo_level)
if (mcasp->version == MCASP_VERSION_2 && !dma_params->fifo_level)
dma_params->acnt = 4;
else
dma_params->acnt = dma_params->data_type;
dma_params->fifo_level = fifo_level;
dma_data->maxburst = fifo_level;
davinci_config_channel_size(mcasp, word_length);
return 0;
......@@ -716,22 +766,7 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
return ret;
}
static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
if (mcasp->version == MCASP_VERSION_4)
snd_soc_dai_set_dma_data(dai, substream,
&mcasp->dma_data[substream->stream]);
else
snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params);
return 0;
}
static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
.startup = davinci_mcasp_startup,
.trigger = davinci_mcasp_trigger,
.hw_params = davinci_mcasp_hw_params,
.set_fmt = davinci_mcasp_set_dai_fmt,
......@@ -739,6 +774,25 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
.set_sysclk = davinci_mcasp_set_sysclk,
};
static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
if (mcasp->version == MCASP_VERSION_4) {
/* Using dmaengine PCM */
dai->playback_dma_data =
&mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
dai->capture_dma_data =
&mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
} else {
/* Using davinci-pcm */
dai->playback_dma_data = mcasp->dma_params;
dai->capture_dma_data = mcasp->dma_params;
}
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
{
......@@ -792,6 +846,7 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai)
static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
{
.name = "davinci-mcasp.0",
.probe = davinci_mcasp_dai_probe,
.suspend = davinci_mcasp_suspend,
.resume = davinci_mcasp_resume,
.playback = {
......@@ -811,6 +866,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
},
{
.name = "davinci-mcasp.1",
.probe = davinci_mcasp_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 384,
......@@ -1078,7 +1134,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (!mcasp->base) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
goto err_release_clk;
goto err;
}
mcasp->op_mode = pdata->op_mode;
......@@ -1159,25 +1215,37 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp_reparent_fck(pdev);
ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
&davinci_mcasp_dai[pdata->op_mode], 1);
ret = devm_snd_soc_register_component(&pdev->dev,
&davinci_mcasp_component,
&davinci_mcasp_dai[pdata->op_mode], 1);
if (ret != 0)
goto err_release_clk;
goto err;
if (mcasp->version != MCASP_VERSION_4) {
switch (mcasp->version) {
case MCASP_VERSION_1:
case MCASP_VERSION_2:
case MCASP_VERSION_3:
ret = davinci_soc_platform_register(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
goto err_unregister_component;
}
break;
case MCASP_VERSION_4:
ret = omap_pcm_platform_register(&pdev->dev);
break;
default:
dev_err(&pdev->dev, "Invalid McASP version: %d\n",
mcasp->version);
ret = -EINVAL;
break;
}
if (ret) {
dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
goto err;
}
return 0;
err_unregister_component:
snd_soc_unregister_component(&pdev->dev);
err_release_clk:
err:
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return ret;
......@@ -1185,12 +1253,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
static int davinci_mcasp_remove(struct platform_device *pdev)
{
struct davinci_mcasp *mcasp = dev_get_drvdata(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
if (mcasp->version != MCASP_VERSION_4)
davinci_soc_platform_unregister(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
......
......@@ -283,6 +283,7 @@
*/
#define FIFO_ENABLE BIT(16)
#define NUMEVT_MASK (0xFF << 8)
#define NUMEVT(x) (((x) & 0xFF) << 8)
#define NUMDMA_MASK (0xFF)
#endif /* DAVINCI_MCASP_H */
......@@ -852,16 +852,10 @@ static struct snd_soc_platform_driver davinci_soc_platform = {
int davinci_soc_platform_register(struct device *dev)
{
return snd_soc_register_platform(dev, &davinci_soc_platform);
return devm_snd_soc_register_platform(dev, &davinci_soc_platform);
}
EXPORT_SYMBOL_GPL(davinci_soc_platform_register);
void davinci_soc_platform_unregister(struct device *dev)
{
snd_soc_unregister_platform(dev);
}
EXPORT_SYMBOL_GPL(davinci_soc_platform_unregister);
MODULE_AUTHOR("Vladimir Barinov");
MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
MODULE_LICENSE("GPL");
......@@ -29,7 +29,13 @@ struct davinci_pcm_dma_params {
unsigned int fifo_level;
};
#if IS_ENABLED(CONFIG_SND_DAVINCI_SOC)
int davinci_soc_platform_register(struct device *dev);
void davinci_soc_platform_unregister(struct device *dev);
#else
static inline int davinci_soc_platform_register(struct device *dev)
{
return 0;
}
#endif /* CONFIG_SND_DAVINCI_SOC */
#endif
......@@ -258,7 +258,6 @@ static int davinci_vcif_probe(struct platform_device *pdev)
static int davinci_vcif_remove(struct platform_device *pdev)
{
snd_soc_unregister_component(&pdev->dev);
davinci_soc_platform_unregister(&pdev->dev);
return 0;
}
......
......@@ -187,7 +187,7 @@ config SND_SOC_EUKREA_TLV320
config SND_SOC_IMX_WM8962
tristate "SoC Audio support for i.MX boards with wm8962"
depends on OF && I2C
depends on OF && I2C && INPUT
select SND_SOC_WM8962
select SND_SOC_IMX_PCM_DMA
select SND_SOC_IMX_AUDMUX
......
......@@ -38,7 +38,6 @@
#include "omap-mcbsp.h"
#include "../codecs/cx20442.h"
/* Board specific DAPM widgets */
static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = {
/* Handset */
......@@ -90,17 +89,23 @@ static const unsigned short ams_delta_audio_mode_pins[] = {
static unsigned short ams_delta_audio_agc;
/*
* Used for passing a codec structure pointer
* from the board initialization code to the tty line discipline.
*/
static struct snd_soc_codec *cx20442_codec;
static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = &card->dapm;
struct soc_enum *control = (struct soc_enum *)kcontrol->private_value;
unsigned short pins;
int pin, changed = 0;
/* Refuse any mode changes if we are not able to control the codec. */
if (!codec->hw_write)
if (!cx20442_codec->hw_write)
return -EUNATCH;
if (ucontrol->value.enumerated.item[0] >= control->items)
......@@ -166,8 +171,8 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = &card->dapm;
unsigned short pins, mode;
pins = ((snd_soc_dapm_get_pin_status(dapm, "Mouthpiece") <<
......@@ -270,12 +275,6 @@ static void cx81801_timeout(unsigned long data)
ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, 0);
}
/*
* Used for passing a codec structure pointer
* from the board initialization code to the tty line discipline.
*/
static struct snd_soc_codec *cx20442_codec;
/* Line discipline .open() */
static int cx81801_open(struct tty_struct *tty)
{
......@@ -302,7 +301,7 @@ static int cx81801_open(struct tty_struct *tty)
static void cx81801_close(struct tty_struct *tty)
{
struct snd_soc_codec *codec = tty->disc_data;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dapm_context *dapm = &codec->card->dapm;
del_timer_sync(&cx81801_timer);
......@@ -475,15 +474,14 @@ static void ams_delta_shutdown(struct snd_pcm_substream *substream)
static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_card *card = rtd->card;
struct snd_soc_dapm_context *dapm = &card->dapm;
int ret;
/* Codec is ready, now add/activate board specific controls */
/* Store a pointer to the codec structure for tty ldisc use */
cx20442_codec = codec;
cx20442_codec = rtd->codec;
/* Set up digital mute if not provided by the codec */
if (!codec_dai->driver->ops) {
......@@ -520,39 +518,12 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
/* Add board specific DAPM widgets and routes */
ret = snd_soc_dapm_new_controls(dapm, ams_delta_dapm_widgets,
ARRAY_SIZE(ams_delta_dapm_widgets));
if (ret) {
dev_warn(card->dev,
"Failed to register DAPM controls, "
"will continue without any.\n");
return 0;
}
ret = snd_soc_dapm_add_routes(dapm, ams_delta_audio_map,
ARRAY_SIZE(ams_delta_audio_map));
if (ret) {
dev_warn(card->dev,
"Failed to set up DAPM routes, "
"will continue with codec default map.\n");
return 0;
}
/* Set up initial pin constellation */
snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
snd_soc_dapm_disable_pin(dapm, "Speaker");
snd_soc_dapm_disable_pin(dapm, "AGCIN");
snd_soc_dapm_disable_pin(dapm, "AGCOUT");
/* Add virtual switch */
ret = snd_soc_add_codec_controls(codec, ams_delta_audio_controls,
ARRAY_SIZE(ams_delta_audio_controls));
if (ret)
dev_warn(card->dev,
"Failed to register audio mode control, "
"will continue without it.\n");
return 0;
}
......@@ -574,6 +545,13 @@ static struct snd_soc_card ams_delta_audio_card = {
.owner = THIS_MODULE,
.dai_link = &ams_delta_dai_link,
.num_links = 1,
.controls = ams_delta_audio_controls,
.num_controls = ARRAY_SIZE(ams_delta_audio_controls),
.dapm_widgets = ams_delta_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ams_delta_dapm_widgets),
.dapm_routes = ams_delta_audio_map,
.num_dapm_routes = ARRAY_SIZE(ams_delta_audio_map),
};
/* Module init/exit */
......
......@@ -232,6 +232,12 @@ static struct snd_soc_platform_driver omap_soc_platform = {
.pcm_free = omap_pcm_free_dma_buffers,
};
int omap_pcm_platform_register(struct device *dev)
{
return devm_snd_soc_register_platform(dev, &omap_soc_platform);
}
EXPORT_SYMBOL_GPL(omap_pcm_platform_register);
static int omap_pcm_probe(struct platform_device *pdev)
{
return snd_soc_register_platform(&pdev->dev,
......
/*
* omap-pcm.h - OMAP PCM driver
*
* Copyright (C) 2014 Texas Instruments, Inc.
*
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef __OMAP_PCM_H__
#define __OMAP_PCM_H__
#if IS_ENABLED(CONFIG_SND_OMAP_SOC)
int omap_pcm_platform_register(struct device *dev);
#else
static inline int omap_pcm_platform_register(struct device *dev)
{
return 0;
}
#endif /* CONFIG_SND_OMAP_SOC */
#endif /* __OMAP_PCM_H__ */
......@@ -121,7 +121,7 @@ static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
* |A| <~~clk~~+
* |P| <--- TWL4030 <--------- Line In and MICs
*/
static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
static const struct snd_soc_dapm_widget omap3pandora_dapm_widgets[] = {
SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM,
0, 0, omap3pandora_dac_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
......@@ -130,22 +130,18 @@ static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_LINE("Line Out", NULL),
};
static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Mic (internal)", NULL),
SND_SOC_DAPM_MIC("Mic (external)", NULL),
SND_SOC_DAPM_LINE("Line In", NULL),
};
static const struct snd_soc_dapm_route omap3pandora_out_map[] = {
static const struct snd_soc_dapm_route omap3pandora_map[] = {
{"PCM DAC", NULL, "APLL Enable"},
{"Headphone Amplifier", NULL, "PCM DAC"},
{"Line Out", NULL, "PCM DAC"},
{"Headphone Jack", NULL, "Headphone Amplifier"},
};
static const struct snd_soc_dapm_route omap3pandora_in_map[] = {
{"AUXL", NULL, "Line In"},
{"AUXR", NULL, "Line In"},
......@@ -160,7 +156,6 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
/* All TWL4030 output pins are floating */
snd_soc_dapm_nc_pin(dapm, "EARPIECE");
......@@ -174,20 +169,13 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "HFR");
snd_soc_dapm_nc_pin(dapm, "VIBRA");
ret = snd_soc_dapm_new_controls(dapm, omap3pandora_out_dapm_widgets,
ARRAY_SIZE(omap3pandora_out_dapm_widgets));
if (ret < 0)
return ret;
return snd_soc_dapm_add_routes(dapm, omap3pandora_out_map,
ARRAY_SIZE(omap3pandora_out_map));
return 0;
}
static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
/* Not comnnected */
snd_soc_dapm_nc_pin(dapm, "HSMIC");
......@@ -195,13 +183,7 @@ static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
ret = snd_soc_dapm_new_controls(dapm, omap3pandora_in_dapm_widgets,
ARRAY_SIZE(omap3pandora_in_dapm_widgets));
if (ret < 0)
return ret;
return snd_soc_dapm_add_routes(dapm, omap3pandora_in_map,
ARRAY_SIZE(omap3pandora_in_map));
return 0;
}
static struct snd_soc_ops omap3pandora_ops = {
......@@ -241,6 +223,11 @@ static struct snd_soc_card snd_soc_card_omap3pandora = {
.owner = THIS_MODULE,
.dai_link = omap3pandora_dai,
.num_links = ARRAY_SIZE(omap3pandora_dai),
.dapm_widgets = omap3pandora_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(omap3pandora_dapm_widgets),
.dapm_routes = omap3pandora_map,
.num_dapm_routes = ARRAY_SIZE(omap3pandora_map),
};
static struct platform_device *omap3pandora_snd_device;
......
......@@ -237,9 +237,6 @@ static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event),
SND_SOC_DAPM_MIC("HS Mic", NULL),
SND_SOC_DAPM_LINE("FM Transmitter", NULL),
};
static const struct snd_soc_dapm_widget aic34_dapm_widgetsb[] = {
SND_SOC_DAPM_SPK("Earphone", NULL),
};
......@@ -253,9 +250,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"DMic Rate 64", NULL, "Mic Bias"},
{"Mic Bias", NULL, "DMic"},
};
static const struct snd_soc_dapm_route audio_mapb[] = {
{"b LINE2R", NULL, "MONO_LOUT"},
{"Earphone", NULL, "b HPLOUT"},
......@@ -281,9 +276,6 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = {
SOC_ENUM_EXT("Jack Function", rx51_enum[2],
rx51_get_jack, rx51_set_jack),
SOC_DAPM_PIN_SWITCH("FM Transmitter"),
};
static const struct snd_kcontrol_new aic34_rx51_controlsb[] = {
SOC_DAPM_PIN_SWITCH("Earphone"),
};
......@@ -298,19 +290,6 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "MIC3R");
snd_soc_dapm_nc_pin(dapm, "LINE1R");
/* Add RX-51 specific controls */
err = snd_soc_add_card_controls(rtd->card, aic34_rx51_controls,
ARRAY_SIZE(aic34_rx51_controls));
if (err < 0)
return err;
/* Add RX-51 specific widgets */
snd_soc_dapm_new_controls(dapm, aic34_dapm_widgets,
ARRAY_SIZE(aic34_dapm_widgets));
/* Set up RX-51 specific audio path audio_map */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
err = tpa6130a2_add_controls(codec);
if (err < 0)
return err;
......@@ -333,24 +312,6 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
return err;
}
static int rx51_aic34b_init(struct snd_soc_dapm_context *dapm)
{
int err;
err = snd_soc_add_card_controls(dapm->card, aic34_rx51_controlsb,
ARRAY_SIZE(aic34_rx51_controlsb));
if (err < 0)
return err;
err = snd_soc_dapm_new_controls(dapm, aic34_dapm_widgetsb,
ARRAY_SIZE(aic34_dapm_widgetsb));
if (err < 0)
return 0;
return snd_soc_dapm_add_routes(dapm, audio_mapb,
ARRAY_SIZE(audio_mapb));
}
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link rx51_dai[] = {
{
......@@ -371,7 +332,6 @@ static struct snd_soc_aux_dev rx51_aux_dev[] = {
{
.name = "TLV320AIC34b",
.codec_name = "tlv320aic3x-codec.2-0019",
.init = rx51_aic34b_init,
},
};
......@@ -392,6 +352,13 @@ static struct snd_soc_card rx51_sound_card = {
.num_aux_devs = ARRAY_SIZE(rx51_aux_dev),
.codec_conf = rx51_codec_conf,
.num_configs = ARRAY_SIZE(rx51_codec_conf),
.controls = aic34_rx51_controls,
.num_controls = ARRAY_SIZE(aic34_rx51_controls),
.dapm_widgets = aic34_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(aic34_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *rx51_snd_device;
......
......@@ -204,7 +204,7 @@ config SND_SOC_SPEYSIDE
config SND_SOC_TOBERMORY
tristate "Audio support for Wolfson Tobermory"
depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && INPUT
select SND_SAMSUNG_I2S
select SND_SOC_WM8962
......
......@@ -52,6 +52,40 @@ int devm_snd_soc_register_component(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_snd_soc_register_component);
static void devm_platform_release(struct device *dev, void *res)
{
snd_soc_unregister_platform(*(struct device **)res);
}
/**
* devm_snd_soc_register_platform - resource managed platform registration
* @dev: Device used to manage platform
* @platform: platform to register
*
* Register a platform driver with automatic unregistration when the device is
* unregistered.
*/
int devm_snd_soc_register_platform(struct device *dev,
const struct snd_soc_platform_driver *platform_drv)
{
struct device **ptr;
int ret;
ptr = devres_alloc(devm_platform_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return -ENOMEM;
ret = snd_soc_register_platform(dev, platform_drv);
if (ret == 0) {
*ptr = dev;
devres_add(dev, ptr);
} else {
devres_free(ptr);
}
return ret;
}
static void devm_card_release(struct device *dev, void *res)
{
snd_soc_unregister_card(*(struct snd_soc_card **)res);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment