xref: /openbmc/linux/sound/soc/codecs/twl6040.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
12b27bdccSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28ecbabd9SMisael Lopez Cruz /*
38ecbabd9SMisael Lopez Cruz  * ALSA SoC TWL6040 codec driver
48ecbabd9SMisael Lopez Cruz  *
58ecbabd9SMisael Lopez Cruz  * Author:	 Misael Lopez Cruz <x0052729@ti.com>
68ecbabd9SMisael Lopez Cruz  */
78ecbabd9SMisael Lopez Cruz 
88ecbabd9SMisael Lopez Cruz #include <linux/module.h>
98ecbabd9SMisael Lopez Cruz #include <linux/moduleparam.h>
108ecbabd9SMisael Lopez Cruz #include <linux/init.h>
118ecbabd9SMisael Lopez Cruz #include <linux/delay.h>
128ecbabd9SMisael Lopez Cruz #include <linux/pm.h>
138ecbabd9SMisael Lopez Cruz #include <linux/platform_device.h>
1468b40cc4SStephen Rothwell #include <linux/slab.h>
15fb34d3d5SMisael Lopez Cruz #include <linux/mfd/twl6040.h>
168ecbabd9SMisael Lopez Cruz 
178ecbabd9SMisael Lopez Cruz #include <sound/core.h>
188ecbabd9SMisael Lopez Cruz #include <sound/pcm.h>
198ecbabd9SMisael Lopez Cruz #include <sound/pcm_params.h>
208ecbabd9SMisael Lopez Cruz #include <sound/soc.h>
21e48b46baSLiam Girdwood #include <sound/soc-dapm.h>
228ecbabd9SMisael Lopez Cruz #include <sound/initval.h>
238ecbabd9SMisael Lopez Cruz #include <sound/tlv.h>
248ecbabd9SMisael Lopez Cruz 
258ecbabd9SMisael Lopez Cruz #include "twl6040.h"
268ecbabd9SMisael Lopez Cruz 
2768897497SPeter Ujfalusi enum twl6040_dai_id {
2868897497SPeter Ujfalusi 	TWL6040_DAI_LEGACY = 0,
2968897497SPeter Ujfalusi 	TWL6040_DAI_UL,
3068897497SPeter Ujfalusi 	TWL6040_DAI_DL1,
3168897497SPeter Ujfalusi 	TWL6040_DAI_DL2,
3268897497SPeter Ujfalusi 	TWL6040_DAI_VIB,
3368897497SPeter Ujfalusi };
3468897497SPeter Ujfalusi 
3560ea4cecSOlaya, Margarita #define TWL6040_RATES		SNDRV_PCM_RATE_8000_96000
368ecbabd9SMisael Lopez Cruz #define TWL6040_FORMATS	(SNDRV_PCM_FMTBIT_S32_LE)
378ecbabd9SMisael Lopez Cruz 
381bf84759SMargarita Olaya Cabrera #define TWL6040_OUTHS_0dB 0x00
391bf84759SMargarita Olaya Cabrera #define TWL6040_OUTHS_M30dB 0x0F
401bf84759SMargarita Olaya Cabrera #define TWL6040_OUTHF_0dB 0x03
411bf84759SMargarita Olaya Cabrera #define TWL6040_OUTHF_M52dB 0x1D
421bf84759SMargarita Olaya Cabrera 
43290c348eSLars-Peter Clausen #define TWL6040_CACHEREGNUM	(TWL6040_REG_STATUS + 1)
44317596a6SPeter Ujfalusi 
45a2d2362eSJorge Eduardo Candelaria struct twl6040_jack_data {
46a2d2362eSJorge Eduardo Candelaria 	struct snd_soc_jack *jack;
4746dd0b93SPeter Ujfalusi 	struct delayed_work work;
48a2d2362eSJorge Eduardo Candelaria 	int report;
49a2d2362eSJorge Eduardo Candelaria };
50a2d2362eSJorge Eduardo Candelaria 
518ecbabd9SMisael Lopez Cruz /* codec private data */
528ecbabd9SMisael Lopez Cruz struct twl6040_data {
532a433b9dSPeter Ujfalusi 	int plug_irq;
548ecbabd9SMisael Lopez Cruz 	int codec_powered;
558ecbabd9SMisael Lopez Cruz 	int pll;
56af958c72SPeter Ujfalusi 	int pll_power_mode;
576bba63b6SMisael Lopez Cruz 	int hs_power_mode;
586bba63b6SMisael Lopez Cruz 	int hs_power_mode_locked;
5998c5fb1fSPeter Ujfalusi 	bool dl1_unmuted;
6098c5fb1fSPeter Ujfalusi 	bool dl2_unmuted;
6153509108SPeter Ujfalusi 	u8 dl12_cache[TWL6040_REG_HFRCTL - TWL6040_REG_HSLCTL + 1];
62fb34d3d5SMisael Lopez Cruz 	unsigned int clk_in;
638ecbabd9SMisael Lopez Cruz 	unsigned int sysclk;
64a2d2362eSJorge Eduardo Candelaria 	struct twl6040_jack_data hs_jack;
657480389fSKuninori Morimoto 	struct snd_soc_component *component;
66a2d2362eSJorge Eduardo Candelaria 	struct mutex mutex;
678ecbabd9SMisael Lopez Cruz };
688ecbabd9SMisael Lopez Cruz 
69af958c72SPeter Ujfalusi /* set of rates for each pll: low-power and high-performance */
700d76fc6aSLars-Peter Clausen static const unsigned int lp_rates[] = {
71af958c72SPeter Ujfalusi 	8000,
72af958c72SPeter Ujfalusi 	11250,
73af958c72SPeter Ujfalusi 	16000,
74af958c72SPeter Ujfalusi 	22500,
75af958c72SPeter Ujfalusi 	32000,
76af958c72SPeter Ujfalusi 	44100,
77af958c72SPeter Ujfalusi 	48000,
78af958c72SPeter Ujfalusi 	88200,
79af958c72SPeter Ujfalusi 	96000,
80af958c72SPeter Ujfalusi };
81af958c72SPeter Ujfalusi 
820d76fc6aSLars-Peter Clausen static const unsigned int hp_rates[] = {
83af958c72SPeter Ujfalusi 	8000,
84af958c72SPeter Ujfalusi 	16000,
85af958c72SPeter Ujfalusi 	32000,
86af958c72SPeter Ujfalusi 	48000,
87af958c72SPeter Ujfalusi 	96000,
88af958c72SPeter Ujfalusi };
89af958c72SPeter Ujfalusi 
900d76fc6aSLars-Peter Clausen static const struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
91f53c346cSPeter Ujfalusi 	{ .count = ARRAY_SIZE(lp_rates), .list = lp_rates, },
92f53c346cSPeter Ujfalusi 	{ .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },
93af958c72SPeter Ujfalusi };
94af958c72SPeter Ujfalusi 
957480389fSKuninori Morimoto #define to_twl6040(component)	dev_get_drvdata((component)->dev->parent)
963bd33367SKuninori Morimoto 
twl6040_read(struct snd_soc_component * component,unsigned int reg)977480389fSKuninori Morimoto static unsigned int twl6040_read(struct snd_soc_component *component, unsigned int reg)
9853509108SPeter Ujfalusi {
997480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
1007480389fSKuninori Morimoto 	struct twl6040 *twl6040 = to_twl6040(component);
1018ecbabd9SMisael Lopez Cruz 	u8 value;
1028ecbabd9SMisael Lopez Cruz 
1038ecbabd9SMisael Lopez Cruz 	if (reg >= TWL6040_CACHEREGNUM)
1048ecbabd9SMisael Lopez Cruz 		return -EIO;
1058ecbabd9SMisael Lopez Cruz 
106626bcacbSPeter Ujfalusi 	switch (reg) {
107626bcacbSPeter Ujfalusi 	case TWL6040_REG_HSLCTL:
108626bcacbSPeter Ujfalusi 	case TWL6040_REG_HSRCTL:
109626bcacbSPeter Ujfalusi 	case TWL6040_REG_EARCTL:
110626bcacbSPeter Ujfalusi 	case TWL6040_REG_HFLCTL:
111626bcacbSPeter Ujfalusi 	case TWL6040_REG_HFRCTL:
112626bcacbSPeter Ujfalusi 		value = priv->dl12_cache[reg - TWL6040_REG_HSLCTL];
113626bcacbSPeter Ujfalusi 		break;
114626bcacbSPeter Ujfalusi 	default:
115fb34d3d5SMisael Lopez Cruz 		value = twl6040_reg_read(twl6040, reg);
116626bcacbSPeter Ujfalusi 		break;
117626bcacbSPeter Ujfalusi 	}
1188ecbabd9SMisael Lopez Cruz 
1198ecbabd9SMisael Lopez Cruz 	return value;
1208ecbabd9SMisael Lopez Cruz }
1218ecbabd9SMisael Lopez Cruz 
twl6040_can_write_to_chip(struct snd_soc_component * component,unsigned int reg)1227480389fSKuninori Morimoto static bool twl6040_can_write_to_chip(struct snd_soc_component *component,
12398c5fb1fSPeter Ujfalusi 				  unsigned int reg)
12498c5fb1fSPeter Ujfalusi {
1257480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
12698c5fb1fSPeter Ujfalusi 
12798c5fb1fSPeter Ujfalusi 	switch (reg) {
12898c5fb1fSPeter Ujfalusi 	case TWL6040_REG_HSLCTL:
12998c5fb1fSPeter Ujfalusi 	case TWL6040_REG_HSRCTL:
13098c5fb1fSPeter Ujfalusi 	case TWL6040_REG_EARCTL:
13198c5fb1fSPeter Ujfalusi 		/* DL1 path */
13298c5fb1fSPeter Ujfalusi 		return priv->dl1_unmuted;
13398c5fb1fSPeter Ujfalusi 	case TWL6040_REG_HFLCTL:
13498c5fb1fSPeter Ujfalusi 	case TWL6040_REG_HFRCTL:
13598c5fb1fSPeter Ujfalusi 		return priv->dl2_unmuted;
13698c5fb1fSPeter Ujfalusi 	default:
137bc94c888SGustavo A. R. Silva 		return true;
138bf551413SSachin Kamat 	}
13998c5fb1fSPeter Ujfalusi }
14098c5fb1fSPeter Ujfalusi 
twl6040_update_dl12_cache(struct snd_soc_component * component,u8 reg,u8 value)1417480389fSKuninori Morimoto static inline void twl6040_update_dl12_cache(struct snd_soc_component *component,
142626bcacbSPeter Ujfalusi 					     u8 reg, u8 value)
143626bcacbSPeter Ujfalusi {
1447480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
145626bcacbSPeter Ujfalusi 
146626bcacbSPeter Ujfalusi 	switch (reg) {
147626bcacbSPeter Ujfalusi 	case TWL6040_REG_HSLCTL:
148626bcacbSPeter Ujfalusi 	case TWL6040_REG_HSRCTL:
149626bcacbSPeter Ujfalusi 	case TWL6040_REG_EARCTL:
150626bcacbSPeter Ujfalusi 	case TWL6040_REG_HFLCTL:
151626bcacbSPeter Ujfalusi 	case TWL6040_REG_HFRCTL:
152626bcacbSPeter Ujfalusi 		priv->dl12_cache[reg - TWL6040_REG_HSLCTL] = value;
153626bcacbSPeter Ujfalusi 		break;
154626bcacbSPeter Ujfalusi 	default:
155626bcacbSPeter Ujfalusi 		break;
156626bcacbSPeter Ujfalusi 	}
157626bcacbSPeter Ujfalusi }
158626bcacbSPeter Ujfalusi 
twl6040_write(struct snd_soc_component * component,unsigned int reg,unsigned int value)1597480389fSKuninori Morimoto static int twl6040_write(struct snd_soc_component *component,
1608ecbabd9SMisael Lopez Cruz 			unsigned int reg, unsigned int value)
1618ecbabd9SMisael Lopez Cruz {
1627480389fSKuninori Morimoto 	struct twl6040 *twl6040 = to_twl6040(component);
163fb34d3d5SMisael Lopez Cruz 
1648ecbabd9SMisael Lopez Cruz 	if (reg >= TWL6040_CACHEREGNUM)
1658ecbabd9SMisael Lopez Cruz 		return -EIO;
1668ecbabd9SMisael Lopez Cruz 
1677480389fSKuninori Morimoto 	twl6040_update_dl12_cache(component, reg, value);
1687480389fSKuninori Morimoto 	if (twl6040_can_write_to_chip(component, reg))
169fb34d3d5SMisael Lopez Cruz 		return twl6040_reg_write(twl6040, reg, value);
170d17bf318SPeter Ujfalusi 	else
171d17bf318SPeter Ujfalusi 		return 0;
1728ecbabd9SMisael Lopez Cruz }
1738ecbabd9SMisael Lopez Cruz 
twl6040_init_chip(struct snd_soc_component * component)1747480389fSKuninori Morimoto static void twl6040_init_chip(struct snd_soc_component *component)
175a52762eeSPeter Ujfalusi {
1767480389fSKuninori Morimoto 	twl6040_read(component, TWL6040_REG_TRIM1);
1777480389fSKuninori Morimoto 	twl6040_read(component, TWL6040_REG_TRIM2);
1787480389fSKuninori Morimoto 	twl6040_read(component, TWL6040_REG_TRIM3);
1797480389fSKuninori Morimoto 	twl6040_read(component, TWL6040_REG_HSOTRIM);
1807480389fSKuninori Morimoto 	twl6040_read(component, TWL6040_REG_HFOTRIM);
181f97217f1SPeter Ujfalusi 
1822c27ff41SPeter Ujfalusi 	/* Change chip defaults */
1832c27ff41SPeter Ujfalusi 	/* No imput selected for microphone amplifiers */
1847480389fSKuninori Morimoto 	twl6040_write(component, TWL6040_REG_MICLCTL, 0x18);
1857480389fSKuninori Morimoto 	twl6040_write(component, TWL6040_REG_MICRCTL, 0x18);
1863acef685SPeter Ujfalusi 
1873acef685SPeter Ujfalusi 	/*
1883acef685SPeter Ujfalusi 	 * We need to lower the default gain values, so the ramp code
1893acef685SPeter Ujfalusi 	 * can work correctly for the first playback.
1903acef685SPeter Ujfalusi 	 * This reduces the pop noise heard at the first playback.
1913acef685SPeter Ujfalusi 	 */
1927480389fSKuninori Morimoto 	twl6040_write(component, TWL6040_REG_HSGAIN, 0xff);
1937480389fSKuninori Morimoto 	twl6040_write(component, TWL6040_REG_EARCTL, 0x1e);
1947480389fSKuninori Morimoto 	twl6040_write(component, TWL6040_REG_HFLGAIN, 0x1d);
1957480389fSKuninori Morimoto 	twl6040_write(component, TWL6040_REG_HFRGAIN, 0x1d);
1967480389fSKuninori Morimoto 	twl6040_write(component, TWL6040_REG_LINEGAIN, 0);
197a52762eeSPeter Ujfalusi }
198a52762eeSPeter Ujfalusi 
1998ecbabd9SMisael Lopez Cruz /* set headset dac and driver power mode */
headset_power_mode(struct snd_soc_component * component,int high_perf)2007480389fSKuninori Morimoto static int headset_power_mode(struct snd_soc_component *component, int high_perf)
2018ecbabd9SMisael Lopez Cruz {
2028ecbabd9SMisael Lopez Cruz 	int hslctl, hsrctl;
203ab6cf139SPeter Ujfalusi 	int mask = TWL6040_HSDRVMODE | TWL6040_HSDACMODE;
2048ecbabd9SMisael Lopez Cruz 
2057480389fSKuninori Morimoto 	hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
2067480389fSKuninori Morimoto 	hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
2078ecbabd9SMisael Lopez Cruz 
2088ecbabd9SMisael Lopez Cruz 	if (high_perf) {
2098ecbabd9SMisael Lopez Cruz 		hslctl &= ~mask;
2108ecbabd9SMisael Lopez Cruz 		hsrctl &= ~mask;
2118ecbabd9SMisael Lopez Cruz 	} else {
2128ecbabd9SMisael Lopez Cruz 		hslctl |= mask;
2138ecbabd9SMisael Lopez Cruz 		hsrctl |= mask;
2148ecbabd9SMisael Lopez Cruz 	}
2158ecbabd9SMisael Lopez Cruz 
2167480389fSKuninori Morimoto 	twl6040_write(component, TWL6040_REG_HSLCTL, hslctl);
2177480389fSKuninori Morimoto 	twl6040_write(component, TWL6040_REG_HSRCTL, hsrctl);
2188ecbabd9SMisael Lopez Cruz 
2198ecbabd9SMisael Lopez Cruz 	return 0;
2208ecbabd9SMisael Lopez Cruz }
2218ecbabd9SMisael Lopez Cruz 
twl6040_hs_dac_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)2220fad4ed7SJorge Eduardo Candelaria static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
2230fad4ed7SJorge Eduardo Candelaria 			struct snd_kcontrol *kcontrol, int event)
2240fad4ed7SJorge Eduardo Candelaria {
2257480389fSKuninori Morimoto 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
22633b6816cSPeter Ujfalusi 	u8 hslctl, hsrctl;
22733b6816cSPeter Ujfalusi 
22833b6816cSPeter Ujfalusi 	/*
22933b6816cSPeter Ujfalusi 	 * Workaround for Headset DC offset caused pop noise:
23033b6816cSPeter Ujfalusi 	 * Both HS DAC need to be turned on (before the HS driver) and off at
23133b6816cSPeter Ujfalusi 	 * the same time.
23233b6816cSPeter Ujfalusi 	 */
2337480389fSKuninori Morimoto 	hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
2347480389fSKuninori Morimoto 	hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
23533b6816cSPeter Ujfalusi 	if (SND_SOC_DAPM_EVENT_ON(event)) {
23633b6816cSPeter Ujfalusi 		hslctl |= TWL6040_HSDACENA;
23733b6816cSPeter Ujfalusi 		hsrctl |= TWL6040_HSDACENA;
23833b6816cSPeter Ujfalusi 	} else {
23933b6816cSPeter Ujfalusi 		hslctl &= ~TWL6040_HSDACENA;
24033b6816cSPeter Ujfalusi 		hsrctl &= ~TWL6040_HSDACENA;
24133b6816cSPeter Ujfalusi 	}
2427480389fSKuninori Morimoto 	twl6040_write(component, TWL6040_REG_HSLCTL, hslctl);
2437480389fSKuninori Morimoto 	twl6040_write(component, TWL6040_REG_HSRCTL, hsrctl);
24433b6816cSPeter Ujfalusi 
2450fad4ed7SJorge Eduardo Candelaria 	msleep(1);
2460fad4ed7SJorge Eduardo Candelaria 	return 0;
2470fad4ed7SJorge Eduardo Candelaria }
2480fad4ed7SJorge Eduardo Candelaria 
twl6040_ep_drv_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)249694b0001SPeter Ujfalusi static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w,
2508ecbabd9SMisael Lopez Cruz 			struct snd_kcontrol *kcontrol, int event)
2518ecbabd9SMisael Lopez Cruz {
2527480389fSKuninori Morimoto 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
2537480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
2546bba63b6SMisael Lopez Cruz 	int ret = 0;
2558ecbabd9SMisael Lopez Cruz 
2566bba63b6SMisael Lopez Cruz 	if (SND_SOC_DAPM_EVENT_ON(event)) {
2576bba63b6SMisael Lopez Cruz 		/* Earphone doesn't support low power mode */
2586bba63b6SMisael Lopez Cruz 		priv->hs_power_mode_locked = 1;
2597480389fSKuninori Morimoto 		ret = headset_power_mode(component, 1);
2606bba63b6SMisael Lopez Cruz 	} else {
2616bba63b6SMisael Lopez Cruz 		priv->hs_power_mode_locked = 0;
2627480389fSKuninori Morimoto 		ret = headset_power_mode(component, priv->hs_power_mode);
2636bba63b6SMisael Lopez Cruz 	}
2648ecbabd9SMisael Lopez Cruz 
2650fad4ed7SJorge Eduardo Candelaria 	msleep(1);
2660fad4ed7SJorge Eduardo Candelaria 
2676bba63b6SMisael Lopez Cruz 	return ret;
2688ecbabd9SMisael Lopez Cruz }
2698ecbabd9SMisael Lopez Cruz 
twl6040_hs_jack_report(struct snd_soc_component * component,struct snd_soc_jack * jack,int report)2707480389fSKuninori Morimoto static void twl6040_hs_jack_report(struct snd_soc_component *component,
271a2d2362eSJorge Eduardo Candelaria 				   struct snd_soc_jack *jack, int report)
272a2d2362eSJorge Eduardo Candelaria {
2737480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
274a2d2362eSJorge Eduardo Candelaria 	int status;
275a2d2362eSJorge Eduardo Candelaria 
276a2d2362eSJorge Eduardo Candelaria 	mutex_lock(&priv->mutex);
277a2d2362eSJorge Eduardo Candelaria 
278a2d2362eSJorge Eduardo Candelaria 	/* Sync status */
2797480389fSKuninori Morimoto 	status = twl6040_read(component, TWL6040_REG_STATUS);
280a2d2362eSJorge Eduardo Candelaria 	if (status & TWL6040_PLUGCOMP)
281a2d2362eSJorge Eduardo Candelaria 		snd_soc_jack_report(jack, report, report);
282a2d2362eSJorge Eduardo Candelaria 	else
283a2d2362eSJorge Eduardo Candelaria 		snd_soc_jack_report(jack, 0, report);
284a2d2362eSJorge Eduardo Candelaria 
285a2d2362eSJorge Eduardo Candelaria 	mutex_unlock(&priv->mutex);
286a2d2362eSJorge Eduardo Candelaria }
287a2d2362eSJorge Eduardo Candelaria 
twl6040_hs_jack_detect(struct snd_soc_component * component,struct snd_soc_jack * jack,int report)2887480389fSKuninori Morimoto void twl6040_hs_jack_detect(struct snd_soc_component *component,
289a2d2362eSJorge Eduardo Candelaria 				struct snd_soc_jack *jack, int report)
290a2d2362eSJorge Eduardo Candelaria {
2917480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
292a2d2362eSJorge Eduardo Candelaria 	struct twl6040_jack_data *hs_jack = &priv->hs_jack;
293a2d2362eSJorge Eduardo Candelaria 
294a2d2362eSJorge Eduardo Candelaria 	hs_jack->jack = jack;
295a2d2362eSJorge Eduardo Candelaria 	hs_jack->report = report;
296a2d2362eSJorge Eduardo Candelaria 
2977480389fSKuninori Morimoto 	twl6040_hs_jack_report(component, hs_jack->jack, hs_jack->report);
298a2d2362eSJorge Eduardo Candelaria }
299a2d2362eSJorge Eduardo Candelaria EXPORT_SYMBOL_GPL(twl6040_hs_jack_detect);
300a2d2362eSJorge Eduardo Candelaria 
twl6040_accessory_work(struct work_struct * work)301a2d2362eSJorge Eduardo Candelaria static void twl6040_accessory_work(struct work_struct *work)
302a2d2362eSJorge Eduardo Candelaria {
303a2d2362eSJorge Eduardo Candelaria 	struct twl6040_data *priv = container_of(work,
30446dd0b93SPeter Ujfalusi 					struct twl6040_data, hs_jack.work.work);
3057480389fSKuninori Morimoto 	struct snd_soc_component *component = priv->component;
306a2d2362eSJorge Eduardo Candelaria 	struct twl6040_jack_data *hs_jack = &priv->hs_jack;
307a2d2362eSJorge Eduardo Candelaria 
3087480389fSKuninori Morimoto 	twl6040_hs_jack_report(component, hs_jack->jack, hs_jack->report);
309a2d2362eSJorge Eduardo Candelaria }
310a2d2362eSJorge Eduardo Candelaria 
3118ecbabd9SMisael Lopez Cruz /* audio interrupt handler */
twl6040_audio_handler(int irq,void * data)312fb34d3d5SMisael Lopez Cruz static irqreturn_t twl6040_audio_handler(int irq, void *data)
3138ecbabd9SMisael Lopez Cruz {
3147480389fSKuninori Morimoto 	struct snd_soc_component *component = data;
3157480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
3168ecbabd9SMisael Lopez Cruz 
317a06e427dSMark Brown 	queue_delayed_work(system_power_efficient_wq,
318a06e427dSMark Brown 			   &priv->hs_jack.work, msecs_to_jiffies(200));
319cf370a5aSOlaya, Margarita 
3208ecbabd9SMisael Lopez Cruz 	return IRQ_HANDLED;
3218ecbabd9SMisael Lopez Cruz }
3228ecbabd9SMisael Lopez Cruz 
twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)32367c34130SPeter Ujfalusi static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
32467c34130SPeter Ujfalusi 	struct snd_ctl_elem_value *ucontrol)
32567c34130SPeter Ujfalusi {
3267480389fSKuninori Morimoto 	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
32767c34130SPeter Ujfalusi 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
32867c34130SPeter Ujfalusi 	unsigned int val;
32967c34130SPeter Ujfalusi 
33067c34130SPeter Ujfalusi 	/* Do not allow changes while Input/FF efect is running */
3317480389fSKuninori Morimoto 	val = twl6040_read(component, e->reg);
33267c34130SPeter Ujfalusi 	if (val & TWL6040_VIBENA && !(val & TWL6040_VIBSEL))
33367c34130SPeter Ujfalusi 		return -EBUSY;
33467c34130SPeter Ujfalusi 
33567c34130SPeter Ujfalusi 	return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
33667c34130SPeter Ujfalusi }
33767c34130SPeter Ujfalusi 
3388ecbabd9SMisael Lopez Cruz /*
3398ecbabd9SMisael Lopez Cruz  * MICATT volume control:
3408ecbabd9SMisael Lopez Cruz  * from -6 to 0 dB in 6 dB steps
3418ecbabd9SMisael Lopez Cruz  */
3428ecbabd9SMisael Lopez Cruz static DECLARE_TLV_DB_SCALE(mic_preamp_tlv, -600, 600, 0);
3438ecbabd9SMisael Lopez Cruz 
3448ecbabd9SMisael Lopez Cruz /*
3458ecbabd9SMisael Lopez Cruz  * MICGAIN volume control:
3462763f45dSRicardo Neri  * from 6 to 30 dB in 6 dB steps
3478ecbabd9SMisael Lopez Cruz  */
3482763f45dSRicardo Neri static DECLARE_TLV_DB_SCALE(mic_amp_tlv, 600, 600, 0);
3498ecbabd9SMisael Lopez Cruz 
3508ecbabd9SMisael Lopez Cruz /*
351370a0314SJorge Eduardo Candelaria  * AFMGAIN volume control:
3521f71a3baSLiam Girdwood  * from -18 to 24 dB in 6 dB steps
353370a0314SJorge Eduardo Candelaria  */
3541f71a3baSLiam Girdwood static DECLARE_TLV_DB_SCALE(afm_amp_tlv, -1800, 600, 0);
355370a0314SJorge Eduardo Candelaria 
356370a0314SJorge Eduardo Candelaria /*
3578ecbabd9SMisael Lopez Cruz  * HSGAIN volume control:
3588ecbabd9SMisael Lopez Cruz  * from -30 to 0 dB in 2 dB steps
3598ecbabd9SMisael Lopez Cruz  */
3608ecbabd9SMisael Lopez Cruz static DECLARE_TLV_DB_SCALE(hs_tlv, -3000, 200, 0);
3618ecbabd9SMisael Lopez Cruz 
3628ecbabd9SMisael Lopez Cruz /*
3638ecbabd9SMisael Lopez Cruz  * HFGAIN volume control:
3648ecbabd9SMisael Lopez Cruz  * from -52 to 6 dB in 2 dB steps
3658ecbabd9SMisael Lopez Cruz  */
3668ecbabd9SMisael Lopez Cruz static DECLARE_TLV_DB_SCALE(hf_tlv, -5200, 200, 0);
3678ecbabd9SMisael Lopez Cruz 
368871a05a7SJorge Eduardo Candelaria /*
369871a05a7SJorge Eduardo Candelaria  * EPGAIN volume control:
370871a05a7SJorge Eduardo Candelaria  * from -24 to 6 dB in 2 dB steps
371871a05a7SJorge Eduardo Candelaria  */
372871a05a7SJorge Eduardo Candelaria static DECLARE_TLV_DB_SCALE(ep_tlv, -2400, 200, 0);
373871a05a7SJorge Eduardo Candelaria 
3748ecbabd9SMisael Lopez Cruz /* Left analog microphone selection */
3758ecbabd9SMisael Lopez Cruz static const char *twl6040_amicl_texts[] =
3768ecbabd9SMisael Lopez Cruz 	{"Headset Mic", "Main Mic", "Aux/FM Left", "Off"};
3778ecbabd9SMisael Lopez Cruz 
3788ecbabd9SMisael Lopez Cruz /* Right analog microphone selection */
3798ecbabd9SMisael Lopez Cruz static const char *twl6040_amicr_texts[] =
3808ecbabd9SMisael Lopez Cruz 	{"Headset Mic", "Sub Mic", "Aux/FM Right", "Off"};
3818ecbabd9SMisael Lopez Cruz 
3828ecbabd9SMisael Lopez Cruz static const struct soc_enum twl6040_enum[] = {
383a1d0d786STakashi Iwai 	SOC_ENUM_SINGLE(TWL6040_REG_MICLCTL, 3,
384a1d0d786STakashi Iwai 			ARRAY_SIZE(twl6040_amicl_texts), twl6040_amicl_texts),
385a1d0d786STakashi Iwai 	SOC_ENUM_SINGLE(TWL6040_REG_MICRCTL, 3,
386a1d0d786STakashi Iwai 			ARRAY_SIZE(twl6040_amicr_texts), twl6040_amicr_texts),
3878ecbabd9SMisael Lopez Cruz };
3888ecbabd9SMisael Lopez Cruz 
389370a0314SJorge Eduardo Candelaria static const char *twl6040_hs_texts[] = {
390370a0314SJorge Eduardo Candelaria 	"Off", "HS DAC", "Line-In amp"
391370a0314SJorge Eduardo Candelaria };
392370a0314SJorge Eduardo Candelaria 
393370a0314SJorge Eduardo Candelaria static const struct soc_enum twl6040_hs_enum[] = {
394370a0314SJorge Eduardo Candelaria 	SOC_ENUM_SINGLE(TWL6040_REG_HSLCTL, 5, ARRAY_SIZE(twl6040_hs_texts),
395370a0314SJorge Eduardo Candelaria 			twl6040_hs_texts),
396370a0314SJorge Eduardo Candelaria 	SOC_ENUM_SINGLE(TWL6040_REG_HSRCTL, 5, ARRAY_SIZE(twl6040_hs_texts),
397370a0314SJorge Eduardo Candelaria 			twl6040_hs_texts),
398370a0314SJorge Eduardo Candelaria };
399370a0314SJorge Eduardo Candelaria 
400370a0314SJorge Eduardo Candelaria static const char *twl6040_hf_texts[] = {
401370a0314SJorge Eduardo Candelaria 	"Off", "HF DAC", "Line-In amp"
402370a0314SJorge Eduardo Candelaria };
403370a0314SJorge Eduardo Candelaria 
404370a0314SJorge Eduardo Candelaria static const struct soc_enum twl6040_hf_enum[] = {
405370a0314SJorge Eduardo Candelaria 	SOC_ENUM_SINGLE(TWL6040_REG_HFLCTL, 2, ARRAY_SIZE(twl6040_hf_texts),
406370a0314SJorge Eduardo Candelaria 			twl6040_hf_texts),
407370a0314SJorge Eduardo Candelaria 	SOC_ENUM_SINGLE(TWL6040_REG_HFRCTL, 2, ARRAY_SIZE(twl6040_hf_texts),
408370a0314SJorge Eduardo Candelaria 			twl6040_hf_texts),
409370a0314SJorge Eduardo Candelaria };
410370a0314SJorge Eduardo Candelaria 
41167c34130SPeter Ujfalusi static const char *twl6040_vibrapath_texts[] = {
41267c34130SPeter Ujfalusi 	"Input FF", "Audio PDM"
41367c34130SPeter Ujfalusi };
41467c34130SPeter Ujfalusi 
41567c34130SPeter Ujfalusi static const struct soc_enum twl6040_vibra_enum[] = {
41667c34130SPeter Ujfalusi 	SOC_ENUM_SINGLE(TWL6040_REG_VIBCTLL, 1,
41767c34130SPeter Ujfalusi 			ARRAY_SIZE(twl6040_vibrapath_texts),
41867c34130SPeter Ujfalusi 			twl6040_vibrapath_texts),
41967c34130SPeter Ujfalusi 	SOC_ENUM_SINGLE(TWL6040_REG_VIBCTLR, 1,
42067c34130SPeter Ujfalusi 			ARRAY_SIZE(twl6040_vibrapath_texts),
42167c34130SPeter Ujfalusi 			twl6040_vibrapath_texts),
42267c34130SPeter Ujfalusi };
42367c34130SPeter Ujfalusi 
4248ecbabd9SMisael Lopez Cruz static const struct snd_kcontrol_new amicl_control =
4258ecbabd9SMisael Lopez Cruz 	SOC_DAPM_ENUM("Route", twl6040_enum[0]);
4268ecbabd9SMisael Lopez Cruz 
4278ecbabd9SMisael Lopez Cruz static const struct snd_kcontrol_new amicr_control =
4288ecbabd9SMisael Lopez Cruz 	SOC_DAPM_ENUM("Route", twl6040_enum[1]);
4298ecbabd9SMisael Lopez Cruz 
4308ecbabd9SMisael Lopez Cruz /* Headset DAC playback switches */
431370a0314SJorge Eduardo Candelaria static const struct snd_kcontrol_new hsl_mux_controls =
432370a0314SJorge Eduardo Candelaria 	SOC_DAPM_ENUM("Route", twl6040_hs_enum[0]);
4338ecbabd9SMisael Lopez Cruz 
434370a0314SJorge Eduardo Candelaria static const struct snd_kcontrol_new hsr_mux_controls =
435370a0314SJorge Eduardo Candelaria 	SOC_DAPM_ENUM("Route", twl6040_hs_enum[1]);
4368ecbabd9SMisael Lopez Cruz 
4378ecbabd9SMisael Lopez Cruz /* Handsfree DAC playback switches */
438370a0314SJorge Eduardo Candelaria static const struct snd_kcontrol_new hfl_mux_controls =
439370a0314SJorge Eduardo Candelaria 	SOC_DAPM_ENUM("Route", twl6040_hf_enum[0]);
4408ecbabd9SMisael Lopez Cruz 
441370a0314SJorge Eduardo Candelaria static const struct snd_kcontrol_new hfr_mux_controls =
442370a0314SJorge Eduardo Candelaria 	SOC_DAPM_ENUM("Route", twl6040_hf_enum[1]);
4438ecbabd9SMisael Lopez Cruz 
444317596a6SPeter Ujfalusi static const struct snd_kcontrol_new ep_path_enable_control =
445290c348eSLars-Peter Clausen 	SOC_DAPM_SINGLE_VIRT("Switch", 1);
446871a05a7SJorge Eduardo Candelaria 
447fdb625ffSPeter Ujfalusi static const struct snd_kcontrol_new auxl_switch_control =
448fdb625ffSPeter Ujfalusi 	SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 6, 1, 0);
449fdb625ffSPeter Ujfalusi 
450fdb625ffSPeter Ujfalusi static const struct snd_kcontrol_new auxr_switch_control =
451fdb625ffSPeter Ujfalusi 	SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 6, 1, 0);
452fdb625ffSPeter Ujfalusi 
45367c34130SPeter Ujfalusi /* Vibra playback switches */
45467c34130SPeter Ujfalusi static const struct snd_kcontrol_new vibral_mux_controls =
45567c34130SPeter Ujfalusi 	SOC_DAPM_ENUM_EXT("Route", twl6040_vibra_enum[0],
45667c34130SPeter Ujfalusi 		snd_soc_dapm_get_enum_double,
45767c34130SPeter Ujfalusi 		twl6040_soc_dapm_put_vibra_enum);
45867c34130SPeter Ujfalusi 
45967c34130SPeter Ujfalusi static const struct snd_kcontrol_new vibrar_mux_controls =
46067c34130SPeter Ujfalusi 	SOC_DAPM_ENUM_EXT("Route", twl6040_vibra_enum[1],
46167c34130SPeter Ujfalusi 		snd_soc_dapm_get_enum_double,
46267c34130SPeter Ujfalusi 		twl6040_soc_dapm_put_vibra_enum);
46367c34130SPeter Ujfalusi 
4646bba63b6SMisael Lopez Cruz /* Headset power mode */
4657cca6067SPeter Ujfalusi static const char *twl6040_power_mode_texts[] = {
4663e453654SSimon Wilson 	"Low-Power", "High-Performance",
4676bba63b6SMisael Lopez Cruz };
4686bba63b6SMisael Lopez Cruz 
469a1d0d786STakashi Iwai static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum,
4707cca6067SPeter Ujfalusi 				twl6040_power_mode_texts);
4716bba63b6SMisael Lopez Cruz 
twl6040_headset_power_get_enum(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4726bba63b6SMisael Lopez Cruz static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
4736bba63b6SMisael Lopez Cruz 	struct snd_ctl_elem_value *ucontrol)
4746bba63b6SMisael Lopez Cruz {
4757480389fSKuninori Morimoto 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
4767480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
4776bba63b6SMisael Lopez Cruz 
4786bba63b6SMisael Lopez Cruz 	ucontrol->value.enumerated.item[0] = priv->hs_power_mode;
4796bba63b6SMisael Lopez Cruz 
4806bba63b6SMisael Lopez Cruz 	return 0;
4816bba63b6SMisael Lopez Cruz }
4826bba63b6SMisael Lopez Cruz 
twl6040_headset_power_put_enum(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4836bba63b6SMisael Lopez Cruz static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
4846bba63b6SMisael Lopez Cruz 	struct snd_ctl_elem_value *ucontrol)
4856bba63b6SMisael Lopez Cruz {
4867480389fSKuninori Morimoto 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
4877480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
4886bba63b6SMisael Lopez Cruz 	int high_perf = ucontrol->value.enumerated.item[0];
4896bba63b6SMisael Lopez Cruz 	int ret = 0;
4906bba63b6SMisael Lopez Cruz 
4916bba63b6SMisael Lopez Cruz 	if (!priv->hs_power_mode_locked)
4927480389fSKuninori Morimoto 		ret = headset_power_mode(component, high_perf);
4936bba63b6SMisael Lopez Cruz 
4946bba63b6SMisael Lopez Cruz 	if (!ret)
4956bba63b6SMisael Lopez Cruz 		priv->hs_power_mode = high_perf;
4966bba63b6SMisael Lopez Cruz 
4976bba63b6SMisael Lopez Cruz 	return ret;
4986bba63b6SMisael Lopez Cruz }
4996bba63b6SMisael Lopez Cruz 
twl6040_pll_get_enum(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)500af958c72SPeter Ujfalusi static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
501af958c72SPeter Ujfalusi 	struct snd_ctl_elem_value *ucontrol)
502af958c72SPeter Ujfalusi {
5037480389fSKuninori Morimoto 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
5047480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
505af958c72SPeter Ujfalusi 
506af958c72SPeter Ujfalusi 	ucontrol->value.enumerated.item[0] = priv->pll_power_mode;
507af958c72SPeter Ujfalusi 
508af958c72SPeter Ujfalusi 	return 0;
509af958c72SPeter Ujfalusi }
510af958c72SPeter Ujfalusi 
twl6040_pll_put_enum(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)511af958c72SPeter Ujfalusi static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
512af958c72SPeter Ujfalusi 	struct snd_ctl_elem_value *ucontrol)
513af958c72SPeter Ujfalusi {
5147480389fSKuninori Morimoto 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
5157480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
516af958c72SPeter Ujfalusi 
517af958c72SPeter Ujfalusi 	priv->pll_power_mode = ucontrol->value.enumerated.item[0];
518af958c72SPeter Ujfalusi 
519af958c72SPeter Ujfalusi 	return 0;
520af958c72SPeter Ujfalusi }
521af958c72SPeter Ujfalusi 
twl6040_get_dl1_gain(struct snd_soc_component * component)5227480389fSKuninori Morimoto int twl6040_get_dl1_gain(struct snd_soc_component *component)
523e48b46baSLiam Girdwood {
5247480389fSKuninori Morimoto 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
525e48b46baSLiam Girdwood 
526e48b46baSLiam Girdwood 	if (snd_soc_dapm_get_pin_status(dapm, "EP"))
527e48b46baSLiam Girdwood 		return -1; /* -1dB */
528e48b46baSLiam Girdwood 
529e48b46baSLiam Girdwood 	if (snd_soc_dapm_get_pin_status(dapm, "HSOR") ||
530e48b46baSLiam Girdwood 		snd_soc_dapm_get_pin_status(dapm, "HSOL")) {
531e48b46baSLiam Girdwood 
5327480389fSKuninori Morimoto 		u8 val = twl6040_read(component, TWL6040_REG_HSLCTL);
533e48b46baSLiam Girdwood 		if (val & TWL6040_HSDACMODE)
534e48b46baSLiam Girdwood 			/* HSDACL in LP mode */
535e48b46baSLiam Girdwood 			return -8; /* -8dB */
536e48b46baSLiam Girdwood 		else
537e48b46baSLiam Girdwood 			/* HSDACL in HP mode */
538e48b46baSLiam Girdwood 			return -1; /* -1dB */
539e48b46baSLiam Girdwood 	}
540e48b46baSLiam Girdwood 	return 0; /* 0dB */
541e48b46baSLiam Girdwood }
542e48b46baSLiam Girdwood EXPORT_SYMBOL_GPL(twl6040_get_dl1_gain);
543e48b46baSLiam Girdwood 
twl6040_get_clk_id(struct snd_soc_component * component)5447480389fSKuninori Morimoto int twl6040_get_clk_id(struct snd_soc_component *component)
545af958c72SPeter Ujfalusi {
5467480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
547af958c72SPeter Ujfalusi 
548ff593ca1SPeter Ujfalusi 	return priv->pll_power_mode;
549af958c72SPeter Ujfalusi }
550af958c72SPeter Ujfalusi EXPORT_SYMBOL_GPL(twl6040_get_clk_id);
551af958c72SPeter Ujfalusi 
twl6040_get_trim_value(struct snd_soc_component * component,enum twl6040_trim trim)5527480389fSKuninori Morimoto int twl6040_get_trim_value(struct snd_soc_component *component, enum twl6040_trim trim)
553db4aabccSPeter Ujfalusi {
554db4aabccSPeter Ujfalusi 	if (unlikely(trim >= TWL6040_TRIM_INVAL))
555db4aabccSPeter Ujfalusi 		return -EINVAL;
556db4aabccSPeter Ujfalusi 
5577480389fSKuninori Morimoto 	return twl6040_read(component, TWL6040_REG_TRIM1 + trim);
558db4aabccSPeter Ujfalusi }
559db4aabccSPeter Ujfalusi EXPORT_SYMBOL_GPL(twl6040_get_trim_value);
560db4aabccSPeter Ujfalusi 
twl6040_get_hs_step_size(struct snd_soc_component * component)5617480389fSKuninori Morimoto int twl6040_get_hs_step_size(struct snd_soc_component *component)
56208656910SLiam Girdwood {
5637480389fSKuninori Morimoto 	struct twl6040 *twl6040 = to_twl6040(component);
56408656910SLiam Girdwood 
565be4ac00aSPeter Ujfalusi 	if (twl6040_get_revid(twl6040) < TWL6040_REV_ES1_3)
56608656910SLiam Girdwood 		/* For ES under ES_1.3 HS step is 2 mV */
56708656910SLiam Girdwood 		return 2;
56808656910SLiam Girdwood 	else
56908656910SLiam Girdwood 		/* For ES_1.3 HS step is 1 mV */
57008656910SLiam Girdwood 		return 1;
57108656910SLiam Girdwood }
57208656910SLiam Girdwood EXPORT_SYMBOL_GPL(twl6040_get_hs_step_size);
57308656910SLiam Girdwood 
5748ecbabd9SMisael Lopez Cruz static const struct snd_kcontrol_new twl6040_snd_controls[] = {
5758ecbabd9SMisael Lopez Cruz 	/* Capture gains */
5768ecbabd9SMisael Lopez Cruz 	SOC_DOUBLE_TLV("Capture Preamplifier Volume",
5778ecbabd9SMisael Lopez Cruz 		TWL6040_REG_MICGAIN, 6, 7, 1, 1, mic_preamp_tlv),
5788ecbabd9SMisael Lopez Cruz 	SOC_DOUBLE_TLV("Capture Volume",
5798ecbabd9SMisael Lopez Cruz 		TWL6040_REG_MICGAIN, 0, 3, 4, 0, mic_amp_tlv),
5808ecbabd9SMisael Lopez Cruz 
581370a0314SJorge Eduardo Candelaria 	/* AFM gains */
582370a0314SJorge Eduardo Candelaria 	SOC_DOUBLE_TLV("Aux FM Volume",
5831f71a3baSLiam Girdwood 		TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv),
584370a0314SJorge Eduardo Candelaria 
5858ecbabd9SMisael Lopez Cruz 	/* Playback gains */
5863bb8a819SPeter Ujfalusi 	SOC_DOUBLE_TLV("Headset Playback Volume",
5873bb8a819SPeter Ujfalusi 		TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, hs_tlv),
5883bb8a819SPeter Ujfalusi 	SOC_DOUBLE_R_TLV("Handsfree Playback Volume",
5893bb8a819SPeter Ujfalusi 		TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
590871a05a7SJorge Eduardo Candelaria 	SOC_SINGLE_TLV("Earphone Playback Volume",
591871a05a7SJorge Eduardo Candelaria 		TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
5926bba63b6SMisael Lopez Cruz 
5937cca6067SPeter Ujfalusi 	SOC_ENUM_EXT("Headset Power Mode", twl6040_power_mode_enum,
5946bba63b6SMisael Lopez Cruz 		twl6040_headset_power_get_enum,
5956bba63b6SMisael Lopez Cruz 		twl6040_headset_power_put_enum),
596af958c72SPeter Ujfalusi 
5970636e8b3SPeter Ujfalusi 	/* Left HS PDM data routed to Right HSDAC */
5980636e8b3SPeter Ujfalusi 	SOC_SINGLE("Headset Mono to Stereo Playback Switch",
5990636e8b3SPeter Ujfalusi 		TWL6040_REG_HSRCTL, 7, 1, 0),
6000636e8b3SPeter Ujfalusi 
6010636e8b3SPeter Ujfalusi 	/* Left HF PDM data routed to Right HFDAC */
6020636e8b3SPeter Ujfalusi 	SOC_SINGLE("Handsfree Mono to Stereo Playback Switch",
6030636e8b3SPeter Ujfalusi 		TWL6040_REG_HFRCTL, 5, 1, 0),
6040636e8b3SPeter Ujfalusi 
605af958c72SPeter Ujfalusi 	SOC_ENUM_EXT("PLL Selection", twl6040_power_mode_enum,
606af958c72SPeter Ujfalusi 		twl6040_pll_get_enum, twl6040_pll_put_enum),
6078ecbabd9SMisael Lopez Cruz };
6088ecbabd9SMisael Lopez Cruz 
6098ecbabd9SMisael Lopez Cruz static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
6108ecbabd9SMisael Lopez Cruz 	/* Inputs */
6118ecbabd9SMisael Lopez Cruz 	SND_SOC_DAPM_INPUT("MAINMIC"),
6128ecbabd9SMisael Lopez Cruz 	SND_SOC_DAPM_INPUT("HSMIC"),
6138ecbabd9SMisael Lopez Cruz 	SND_SOC_DAPM_INPUT("SUBMIC"),
6148ecbabd9SMisael Lopez Cruz 	SND_SOC_DAPM_INPUT("AFML"),
6158ecbabd9SMisael Lopez Cruz 	SND_SOC_DAPM_INPUT("AFMR"),
6168ecbabd9SMisael Lopez Cruz 
6178ecbabd9SMisael Lopez Cruz 	/* Outputs */
6188ecbabd9SMisael Lopez Cruz 	SND_SOC_DAPM_OUTPUT("HSOL"),
6198ecbabd9SMisael Lopez Cruz 	SND_SOC_DAPM_OUTPUT("HSOR"),
6208ecbabd9SMisael Lopez Cruz 	SND_SOC_DAPM_OUTPUT("HFL"),
6218ecbabd9SMisael Lopez Cruz 	SND_SOC_DAPM_OUTPUT("HFR"),
622871a05a7SJorge Eduardo Candelaria 	SND_SOC_DAPM_OUTPUT("EP"),
623fdb625ffSPeter Ujfalusi 	SND_SOC_DAPM_OUTPUT("AUXL"),
624fdb625ffSPeter Ujfalusi 	SND_SOC_DAPM_OUTPUT("AUXR"),
62567c34130SPeter Ujfalusi 	SND_SOC_DAPM_OUTPUT("VIBRAL"),
62667c34130SPeter Ujfalusi 	SND_SOC_DAPM_OUTPUT("VIBRAR"),
6278ecbabd9SMisael Lopez Cruz 
6288ecbabd9SMisael Lopez Cruz 	/* Analog input muxes for the capture amplifiers */
6298ecbabd9SMisael Lopez Cruz 	SND_SOC_DAPM_MUX("Analog Left Capture Route",
6308ecbabd9SMisael Lopez Cruz 			SND_SOC_NOPM, 0, 0, &amicl_control),
6318ecbabd9SMisael Lopez Cruz 	SND_SOC_DAPM_MUX("Analog Right Capture Route",
6328ecbabd9SMisael Lopez Cruz 			SND_SOC_NOPM, 0, 0, &amicr_control),
6338ecbabd9SMisael Lopez Cruz 
6348ecbabd9SMisael Lopez Cruz 	/* Analog capture PGAs */
6358ecbabd9SMisael Lopez Cruz 	SND_SOC_DAPM_PGA("MicAmpL",
6368ecbabd9SMisael Lopez Cruz 			TWL6040_REG_MICLCTL, 0, 0, NULL, 0),
6378ecbabd9SMisael Lopez Cruz 	SND_SOC_DAPM_PGA("MicAmpR",
6388ecbabd9SMisael Lopez Cruz 			TWL6040_REG_MICRCTL, 0, 0, NULL, 0),
6398ecbabd9SMisael Lopez Cruz 
640370a0314SJorge Eduardo Candelaria 	/* Auxiliary FM PGAs */
641370a0314SJorge Eduardo Candelaria 	SND_SOC_DAPM_PGA("AFMAmpL",
642370a0314SJorge Eduardo Candelaria 			TWL6040_REG_MICLCTL, 1, 0, NULL, 0),
643370a0314SJorge Eduardo Candelaria 	SND_SOC_DAPM_PGA("AFMAmpR",
644370a0314SJorge Eduardo Candelaria 			TWL6040_REG_MICRCTL, 1, 0, NULL, 0),
645370a0314SJorge Eduardo Candelaria 
6468ecbabd9SMisael Lopez Cruz 	/* ADCs */
647805238b1SPeter Ujfalusi 	SND_SOC_DAPM_ADC("ADC Left", NULL, TWL6040_REG_MICLCTL, 2, 0),
648805238b1SPeter Ujfalusi 	SND_SOC_DAPM_ADC("ADC Right", NULL, TWL6040_REG_MICRCTL, 2, 0),
6498ecbabd9SMisael Lopez Cruz 
6508ecbabd9SMisael Lopez Cruz 	/* Microphone bias */
651778cee7aSPeter Ujfalusi 	SND_SOC_DAPM_SUPPLY("Headset Mic Bias",
652778cee7aSPeter Ujfalusi 			    TWL6040_REG_AMICBCTL, 0, 0, NULL, 0),
653778cee7aSPeter Ujfalusi 	SND_SOC_DAPM_SUPPLY("Main Mic Bias",
654778cee7aSPeter Ujfalusi 			    TWL6040_REG_AMICBCTL, 4, 0, NULL, 0),
655778cee7aSPeter Ujfalusi 	SND_SOC_DAPM_SUPPLY("Digital Mic1 Bias",
656778cee7aSPeter Ujfalusi 			    TWL6040_REG_DMICBCTL, 0, 0, NULL, 0),
657778cee7aSPeter Ujfalusi 	SND_SOC_DAPM_SUPPLY("Digital Mic2 Bias",
658778cee7aSPeter Ujfalusi 			    TWL6040_REG_DMICBCTL, 4, 0, NULL, 0),
6598ecbabd9SMisael Lopez Cruz 
6608ecbabd9SMisael Lopez Cruz 	/* DACs */
661805238b1SPeter Ujfalusi 	SND_SOC_DAPM_DAC("HSDAC Left", NULL, SND_SOC_NOPM, 0, 0),
662805238b1SPeter Ujfalusi 	SND_SOC_DAPM_DAC("HSDAC Right", NULL, SND_SOC_NOPM, 0, 0),
663805238b1SPeter Ujfalusi 	SND_SOC_DAPM_DAC("HFDAC Left", NULL, TWL6040_REG_HFLCTL, 0, 0),
664805238b1SPeter Ujfalusi 	SND_SOC_DAPM_DAC("HFDAC Right", NULL, TWL6040_REG_HFRCTL, 0, 0),
66567c34130SPeter Ujfalusi 	/* Virtual DAC for vibra path (DL4 channel) */
666805238b1SPeter Ujfalusi 	SND_SOC_DAPM_DAC("VIBRA DAC", NULL, SND_SOC_NOPM, 0, 0),
6678ecbabd9SMisael Lopez Cruz 
668df11ce29SPeter Ujfalusi 	SND_SOC_DAPM_MUX("Handsfree Left Playback",
669370a0314SJorge Eduardo Candelaria 			SND_SOC_NOPM, 0, 0, &hfl_mux_controls),
670df11ce29SPeter Ujfalusi 	SND_SOC_DAPM_MUX("Handsfree Right Playback",
671370a0314SJorge Eduardo Candelaria 			SND_SOC_NOPM, 0, 0, &hfr_mux_controls),
672370a0314SJorge Eduardo Candelaria 	/* Analog playback Muxes */
67345b0f60dSPeter Ujfalusi 	SND_SOC_DAPM_MUX("Headset Left Playback",
674370a0314SJorge Eduardo Candelaria 			SND_SOC_NOPM, 0, 0, &hsl_mux_controls),
67545b0f60dSPeter Ujfalusi 	SND_SOC_DAPM_MUX("Headset Right Playback",
676370a0314SJorge Eduardo Candelaria 			SND_SOC_NOPM, 0, 0, &hsr_mux_controls),
6778ecbabd9SMisael Lopez Cruz 
67867c34130SPeter Ujfalusi 	SND_SOC_DAPM_MUX("Vibra Left Playback", SND_SOC_NOPM, 0, 0,
67967c34130SPeter Ujfalusi 			&vibral_mux_controls),
68067c34130SPeter Ujfalusi 	SND_SOC_DAPM_MUX("Vibra Right Playback", SND_SOC_NOPM, 0, 0,
68167c34130SPeter Ujfalusi 			&vibrar_mux_controls),
68267c34130SPeter Ujfalusi 
683317596a6SPeter Ujfalusi 	SND_SOC_DAPM_SWITCH("Earphone Playback", SND_SOC_NOPM, 0, 0,
684317596a6SPeter Ujfalusi 			&ep_path_enable_control),
685fdb625ffSPeter Ujfalusi 	SND_SOC_DAPM_SWITCH("AUXL Playback", SND_SOC_NOPM, 0, 0,
686fdb625ffSPeter Ujfalusi 			&auxl_switch_control),
687fdb625ffSPeter Ujfalusi 	SND_SOC_DAPM_SWITCH("AUXR Playback", SND_SOC_NOPM, 0, 0,
688fdb625ffSPeter Ujfalusi 			&auxr_switch_control),
689317596a6SPeter Ujfalusi 
6900fad4ed7SJorge Eduardo Candelaria 	/* Analog playback drivers */
6913bb8a819SPeter Ujfalusi 	SND_SOC_DAPM_OUT_DRV("HF Left Driver",
6923bb8a819SPeter Ujfalusi 			TWL6040_REG_HFLCTL, 4, 0, NULL, 0),
6933bb8a819SPeter Ujfalusi 	SND_SOC_DAPM_OUT_DRV("HF Right Driver",
6943bb8a819SPeter Ujfalusi 			TWL6040_REG_HFRCTL, 4, 0, NULL, 0),
6953bb8a819SPeter Ujfalusi 	SND_SOC_DAPM_OUT_DRV("HS Left Driver",
6963bb8a819SPeter Ujfalusi 			TWL6040_REG_HSLCTL, 2, 0, NULL, 0),
6973bb8a819SPeter Ujfalusi 	SND_SOC_DAPM_OUT_DRV("HS Right Driver",
6983bb8a819SPeter Ujfalusi 			TWL6040_REG_HSRCTL, 2, 0, NULL, 0),
699317596a6SPeter Ujfalusi 	SND_SOC_DAPM_OUT_DRV_E("Earphone Driver",
700317596a6SPeter Ujfalusi 			TWL6040_REG_EARCTL, 0, 0, NULL, 0,
701694b0001SPeter Ujfalusi 			twl6040_ep_drv_event,
702aa1a4108SPeter Ujfalusi 			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
70367c34130SPeter Ujfalusi 	SND_SOC_DAPM_OUT_DRV("Vibra Left Driver",
70467c34130SPeter Ujfalusi 			TWL6040_REG_VIBCTLL, 0, 0, NULL, 0),
70567c34130SPeter Ujfalusi 	SND_SOC_DAPM_OUT_DRV("Vibra Right Driver",
70667c34130SPeter Ujfalusi 			TWL6040_REG_VIBCTLR, 0, 0, NULL, 0),
70767c34130SPeter Ujfalusi 
70867c34130SPeter Ujfalusi 	SND_SOC_DAPM_SUPPLY("Vibra Left Control", TWL6040_REG_VIBCTLL, 2, 0,
70967c34130SPeter Ujfalusi 			    NULL, 0),
71067c34130SPeter Ujfalusi 	SND_SOC_DAPM_SUPPLY("Vibra Right Control", TWL6040_REG_VIBCTLR, 2, 0,
71167c34130SPeter Ujfalusi 			    NULL, 0),
71233b6816cSPeter Ujfalusi 	SND_SOC_DAPM_SUPPLY_S("HSDAC Power", 1, SND_SOC_NOPM, 0, 0,
71333b6816cSPeter Ujfalusi 			      twl6040_hs_dac_event,
71433b6816cSPeter Ujfalusi 			      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
7158ecbabd9SMisael Lopez Cruz 
7168ecbabd9SMisael Lopez Cruz 	/* Analog playback PGAs */
717df11ce29SPeter Ujfalusi 	SND_SOC_DAPM_PGA("HF Left PGA",
7188ecbabd9SMisael Lopez Cruz 			TWL6040_REG_HFLCTL, 1, 0, NULL, 0),
719df11ce29SPeter Ujfalusi 	SND_SOC_DAPM_PGA("HF Right PGA",
7208ecbabd9SMisael Lopez Cruz 			TWL6040_REG_HFRCTL, 1, 0, NULL, 0),
7218ecbabd9SMisael Lopez Cruz 
7228ecbabd9SMisael Lopez Cruz };
7238ecbabd9SMisael Lopez Cruz 
7248ecbabd9SMisael Lopez Cruz static const struct snd_soc_dapm_route intercon[] = {
725805238b1SPeter Ujfalusi 	/* Stream -> DAC mapping */
726805238b1SPeter Ujfalusi 	{"HSDAC Left", NULL, "Legacy Playback"},
727805238b1SPeter Ujfalusi 	{"HSDAC Left", NULL, "Headset Playback"},
728805238b1SPeter Ujfalusi 	{"HSDAC Right", NULL, "Legacy Playback"},
729805238b1SPeter Ujfalusi 	{"HSDAC Right", NULL, "Headset Playback"},
730805238b1SPeter Ujfalusi 
731805238b1SPeter Ujfalusi 	{"HFDAC Left", NULL, "Legacy Playback"},
732805238b1SPeter Ujfalusi 	{"HFDAC Left", NULL, "Handsfree Playback"},
733805238b1SPeter Ujfalusi 	{"HFDAC Right", NULL, "Legacy Playback"},
734805238b1SPeter Ujfalusi 	{"HFDAC Right", NULL, "Handsfree Playback"},
735805238b1SPeter Ujfalusi 
736805238b1SPeter Ujfalusi 	{"VIBRA DAC", NULL, "Legacy Playback"},
737805238b1SPeter Ujfalusi 	{"VIBRA DAC", NULL, "Vibra Playback"},
738805238b1SPeter Ujfalusi 
739805238b1SPeter Ujfalusi 	/* ADC -> Stream mapping */
74007ac2296SPeter Ujfalusi 	{"Legacy Capture" , NULL, "ADC Left"},
74107ac2296SPeter Ujfalusi 	{"Capture", NULL, "ADC Left"},
74207ac2296SPeter Ujfalusi 	{"Legacy Capture", NULL, "ADC Right"},
74307ac2296SPeter Ujfalusi 	{"Capture" , NULL, "ADC Right"},
744805238b1SPeter Ujfalusi 
7458ecbabd9SMisael Lopez Cruz 	/* Capture path */
7468ecbabd9SMisael Lopez Cruz 	{"Analog Left Capture Route", "Headset Mic", "HSMIC"},
7478ecbabd9SMisael Lopez Cruz 	{"Analog Left Capture Route", "Main Mic", "MAINMIC"},
7488ecbabd9SMisael Lopez Cruz 	{"Analog Left Capture Route", "Aux/FM Left", "AFML"},
7498ecbabd9SMisael Lopez Cruz 
7508ecbabd9SMisael Lopez Cruz 	{"Analog Right Capture Route", "Headset Mic", "HSMIC"},
7518ecbabd9SMisael Lopez Cruz 	{"Analog Right Capture Route", "Sub Mic", "SUBMIC"},
7528ecbabd9SMisael Lopez Cruz 	{"Analog Right Capture Route", "Aux/FM Right", "AFMR"},
7538ecbabd9SMisael Lopez Cruz 
7548ecbabd9SMisael Lopez Cruz 	{"MicAmpL", NULL, "Analog Left Capture Route"},
7558ecbabd9SMisael Lopez Cruz 	{"MicAmpR", NULL, "Analog Right Capture Route"},
7568ecbabd9SMisael Lopez Cruz 
7578ecbabd9SMisael Lopez Cruz 	{"ADC Left", NULL, "MicAmpL"},
7588ecbabd9SMisael Lopez Cruz 	{"ADC Right", NULL, "MicAmpR"},
7598ecbabd9SMisael Lopez Cruz 
760370a0314SJorge Eduardo Candelaria 	/* AFM path */
7615bf692d9SPeter Ujfalusi 	{"AFMAmpL", NULL, "AFML"},
7625bf692d9SPeter Ujfalusi 	{"AFMAmpR", NULL, "AFMR"},
7638ecbabd9SMisael Lopez Cruz 
76433b6816cSPeter Ujfalusi 	{"HSDAC Left", NULL, "HSDAC Power"},
76533b6816cSPeter Ujfalusi 	{"HSDAC Right", NULL, "HSDAC Power"},
76633b6816cSPeter Ujfalusi 
76745b0f60dSPeter Ujfalusi 	{"Headset Left Playback", "HS DAC", "HSDAC Left"},
76845b0f60dSPeter Ujfalusi 	{"Headset Left Playback", "Line-In amp", "AFMAmpL"},
769370a0314SJorge Eduardo Candelaria 
77045b0f60dSPeter Ujfalusi 	{"Headset Right Playback", "HS DAC", "HSDAC Right"},
77145b0f60dSPeter Ujfalusi 	{"Headset Right Playback", "Line-In amp", "AFMAmpR"},
772370a0314SJorge Eduardo Candelaria 
77345b0f60dSPeter Ujfalusi 	{"HS Left Driver", NULL, "Headset Left Playback"},
77445b0f60dSPeter Ujfalusi 	{"HS Right Driver", NULL, "Headset Right Playback"},
7758ecbabd9SMisael Lopez Cruz 
77645b0f60dSPeter Ujfalusi 	{"HSOL", NULL, "HS Left Driver"},
77745b0f60dSPeter Ujfalusi 	{"HSOR", NULL, "HS Right Driver"},
7788ecbabd9SMisael Lopez Cruz 
779871a05a7SJorge Eduardo Candelaria 	/* Earphone playback path */
780317596a6SPeter Ujfalusi 	{"Earphone Playback", "Switch", "HSDAC Left"},
781317596a6SPeter Ujfalusi 	{"Earphone Driver", NULL, "Earphone Playback"},
782871a05a7SJorge Eduardo Candelaria 	{"EP", NULL, "Earphone Driver"},
783871a05a7SJorge Eduardo Candelaria 
784df11ce29SPeter Ujfalusi 	{"Handsfree Left Playback", "HF DAC", "HFDAC Left"},
785df11ce29SPeter Ujfalusi 	{"Handsfree Left Playback", "Line-In amp", "AFMAmpL"},
7868ecbabd9SMisael Lopez Cruz 
787df11ce29SPeter Ujfalusi 	{"Handsfree Right Playback", "HF DAC", "HFDAC Right"},
788df11ce29SPeter Ujfalusi 	{"Handsfree Right Playback", "Line-In amp", "AFMAmpR"},
789370a0314SJorge Eduardo Candelaria 
790df11ce29SPeter Ujfalusi 	{"HF Left PGA", NULL, "Handsfree Left Playback"},
791df11ce29SPeter Ujfalusi 	{"HF Right PGA", NULL, "Handsfree Right Playback"},
7928ecbabd9SMisael Lopez Cruz 
793df11ce29SPeter Ujfalusi 	{"HF Left Driver", NULL, "HF Left PGA"},
794df11ce29SPeter Ujfalusi 	{"HF Right Driver", NULL, "HF Right PGA"},
7958ecbabd9SMisael Lopez Cruz 
796df11ce29SPeter Ujfalusi 	{"HFL", NULL, "HF Left Driver"},
797df11ce29SPeter Ujfalusi 	{"HFR", NULL, "HF Right Driver"},
798fdb625ffSPeter Ujfalusi 
799fdb625ffSPeter Ujfalusi 	{"AUXL Playback", "Switch", "HF Left PGA"},
800fdb625ffSPeter Ujfalusi 	{"AUXR Playback", "Switch", "HF Right PGA"},
801fdb625ffSPeter Ujfalusi 
802fdb625ffSPeter Ujfalusi 	{"AUXL", NULL, "AUXL Playback"},
803fdb625ffSPeter Ujfalusi 	{"AUXR", NULL, "AUXR Playback"},
80467c34130SPeter Ujfalusi 
80567c34130SPeter Ujfalusi 	/* Vibrator paths */
80667c34130SPeter Ujfalusi 	{"Vibra Left Playback", "Audio PDM", "VIBRA DAC"},
80767c34130SPeter Ujfalusi 	{"Vibra Right Playback", "Audio PDM", "VIBRA DAC"},
80867c34130SPeter Ujfalusi 
80967c34130SPeter Ujfalusi 	{"Vibra Left Driver", NULL, "Vibra Left Playback"},
81067c34130SPeter Ujfalusi 	{"Vibra Right Driver", NULL, "Vibra Right Playback"},
81167c34130SPeter Ujfalusi 	{"Vibra Left Driver", NULL, "Vibra Left Control"},
81267c34130SPeter Ujfalusi 	{"Vibra Right Driver", NULL, "Vibra Right Control"},
81367c34130SPeter Ujfalusi 
81467c34130SPeter Ujfalusi 	{"VIBRAL", NULL, "Vibra Left Driver"},
81567c34130SPeter Ujfalusi 	{"VIBRAR", NULL, "Vibra Right Driver"},
8168ecbabd9SMisael Lopez Cruz };
8178ecbabd9SMisael Lopez Cruz 
twl6040_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)8187480389fSKuninori Morimoto static int twl6040_set_bias_level(struct snd_soc_component *component,
8198ecbabd9SMisael Lopez Cruz 				enum snd_soc_bias_level level)
8208ecbabd9SMisael Lopez Cruz {
8217480389fSKuninori Morimoto 	struct twl6040 *twl6040 = to_twl6040(component);
8227480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
8231135ef11SPeter Ujfalusi 	int ret = 0;
8248ecbabd9SMisael Lopez Cruz 
8258ecbabd9SMisael Lopez Cruz 	switch (level) {
8268ecbabd9SMisael Lopez Cruz 	case SND_SOC_BIAS_ON:
8278ecbabd9SMisael Lopez Cruz 		break;
8288ecbabd9SMisael Lopez Cruz 	case SND_SOC_BIAS_PREPARE:
8298ecbabd9SMisael Lopez Cruz 		break;
8308ecbabd9SMisael Lopez Cruz 	case SND_SOC_BIAS_STANDBY:
8311135ef11SPeter Ujfalusi 		if (priv->codec_powered) {
8321135ef11SPeter Ujfalusi 			/* Select low power PLL in standby */
8331135ef11SPeter Ujfalusi 			ret = twl6040_set_pll(twl6040, TWL6040_SYSCLK_SEL_LPPLL,
8341135ef11SPeter Ujfalusi 					      32768, 19200000);
8358ecbabd9SMisael Lopez Cruz 			break;
8361135ef11SPeter Ujfalusi 		}
8378ecbabd9SMisael Lopez Cruz 
838fb34d3d5SMisael Lopez Cruz 		ret = twl6040_power(twl6040, 1);
8398ecbabd9SMisael Lopez Cruz 		if (ret)
8401135ef11SPeter Ujfalusi 			break;
8418ecbabd9SMisael Lopez Cruz 
8428ecbabd9SMisael Lopez Cruz 		priv->codec_powered = 1;
8438ecbabd9SMisael Lopez Cruz 
84465b7ceccSOlaya, Margarita 		/* Set external boost GPO */
8457480389fSKuninori Morimoto 		twl6040_write(component, TWL6040_REG_GPOCTL, 0x02);
8468ecbabd9SMisael Lopez Cruz 		break;
8478ecbabd9SMisael Lopez Cruz 	case SND_SOC_BIAS_OFF:
8488ecbabd9SMisael Lopez Cruz 		if (!priv->codec_powered)
8498ecbabd9SMisael Lopez Cruz 			break;
8508ecbabd9SMisael Lopez Cruz 
851fb34d3d5SMisael Lopez Cruz 		twl6040_power(twl6040, 0);
8528ecbabd9SMisael Lopez Cruz 		priv->codec_powered = 0;
8538ecbabd9SMisael Lopez Cruz 		break;
8548ecbabd9SMisael Lopez Cruz 	}
8558ecbabd9SMisael Lopez Cruz 
8561135ef11SPeter Ujfalusi 	return ret;
8578ecbabd9SMisael Lopez Cruz }
8588ecbabd9SMisael Lopez Cruz 
twl6040_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)8598ecbabd9SMisael Lopez Cruz static int twl6040_startup(struct snd_pcm_substream *substream,
8608ecbabd9SMisael Lopez Cruz 			struct snd_soc_dai *dai)
8618ecbabd9SMisael Lopez Cruz {
8627480389fSKuninori Morimoto 	struct snd_soc_component *component = dai->component;
8637480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
8648ecbabd9SMisael Lopez Cruz 
8658ecbabd9SMisael Lopez Cruz 	snd_pcm_hw_constraint_list(substream->runtime, 0,
8668ecbabd9SMisael Lopez Cruz 				SNDRV_PCM_HW_PARAM_RATE,
867f53c346cSPeter Ujfalusi 				&sysclk_constraints[priv->pll_power_mode]);
8688ecbabd9SMisael Lopez Cruz 
8698ecbabd9SMisael Lopez Cruz 	return 0;
8708ecbabd9SMisael Lopez Cruz }
8718ecbabd9SMisael Lopez Cruz 
twl6040_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)8728ecbabd9SMisael Lopez Cruz static int twl6040_hw_params(struct snd_pcm_substream *substream,
8738ecbabd9SMisael Lopez Cruz 			struct snd_pcm_hw_params *params,
8748ecbabd9SMisael Lopez Cruz 			struct snd_soc_dai *dai)
8758ecbabd9SMisael Lopez Cruz {
8767480389fSKuninori Morimoto 	struct snd_soc_component *component = dai->component;
8777480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
8788ecbabd9SMisael Lopez Cruz 	int rate;
8798ecbabd9SMisael Lopez Cruz 
8808ecbabd9SMisael Lopez Cruz 	rate = params_rate(params);
8818ecbabd9SMisael Lopez Cruz 	switch (rate) {
88260ea4cecSOlaya, Margarita 	case 11250:
88360ea4cecSOlaya, Margarita 	case 22500:
88460ea4cecSOlaya, Margarita 	case 44100:
8858ecbabd9SMisael Lopez Cruz 	case 88200:
886753621c2SPeter Ujfalusi 		/* These rates are not supported when HPPLL is in use */
887753621c2SPeter Ujfalusi 		if (unlikely(priv->pll == TWL6040_SYSCLK_SEL_HPPLL)) {
8887480389fSKuninori Morimoto 			dev_err(component->dev, "HPPLL does not support rate %d\n",
889753621c2SPeter Ujfalusi 				rate);
890753621c2SPeter Ujfalusi 			return -EINVAL;
891753621c2SPeter Ujfalusi 		}
8928ecbabd9SMisael Lopez Cruz 		priv->sysclk = 17640000;
8938ecbabd9SMisael Lopez Cruz 		break;
89460ea4cecSOlaya, Margarita 	case 8000:
89560ea4cecSOlaya, Margarita 	case 16000:
89660ea4cecSOlaya, Margarita 	case 32000:
89760ea4cecSOlaya, Margarita 	case 48000:
8988ecbabd9SMisael Lopez Cruz 	case 96000:
8998ecbabd9SMisael Lopez Cruz 		priv->sysclk = 19200000;
9008ecbabd9SMisael Lopez Cruz 		break;
9018ecbabd9SMisael Lopez Cruz 	default:
9027480389fSKuninori Morimoto 		dev_err(component->dev, "unsupported rate %d\n", rate);
9038ecbabd9SMisael Lopez Cruz 		return -EINVAL;
9048ecbabd9SMisael Lopez Cruz 	}
9058ecbabd9SMisael Lopez Cruz 
9068ecbabd9SMisael Lopez Cruz 	return 0;
9078ecbabd9SMisael Lopez Cruz }
9088ecbabd9SMisael Lopez Cruz 
twl6040_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)9094e624d06SOlaya, Margarita static int twl6040_prepare(struct snd_pcm_substream *substream,
9104e624d06SOlaya, Margarita 			struct snd_soc_dai *dai)
9118ecbabd9SMisael Lopez Cruz {
9127480389fSKuninori Morimoto 	struct snd_soc_component *component = dai->component;
9137480389fSKuninori Morimoto 	struct twl6040 *twl6040 = to_twl6040(component);
9147480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
915753621c2SPeter Ujfalusi 	int ret;
9168ecbabd9SMisael Lopez Cruz 
9174e624d06SOlaya, Margarita 	if (!priv->sysclk) {
9187480389fSKuninori Morimoto 		dev_err(component->dev,
9194e624d06SOlaya, Margarita 			"no mclk configured, call set_sysclk() on init\n");
9204e624d06SOlaya, Margarita 		return -EINVAL;
9214e624d06SOlaya, Margarita 	}
9224e624d06SOlaya, Margarita 
923753621c2SPeter Ujfalusi 	ret = twl6040_set_pll(twl6040, priv->pll, priv->clk_in, priv->sysclk);
924753621c2SPeter Ujfalusi 	if (ret) {
9257480389fSKuninori Morimoto 		dev_err(component->dev, "Can not set PLL (%d)\n", ret);
926753621c2SPeter Ujfalusi 		return -EPERM;
927753621c2SPeter Ujfalusi 	}
928753621c2SPeter Ujfalusi 
9298ecbabd9SMisael Lopez Cruz 	return 0;
9308ecbabd9SMisael Lopez Cruz }
9318ecbabd9SMisael Lopez Cruz 
twl6040_set_dai_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)9328ecbabd9SMisael Lopez Cruz static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
9338ecbabd9SMisael Lopez Cruz 		int clk_id, unsigned int freq, int dir)
9348ecbabd9SMisael Lopez Cruz {
9357480389fSKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
9367480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
9378ecbabd9SMisael Lopez Cruz 
9388ecbabd9SMisael Lopez Cruz 	switch (clk_id) {
9398ecbabd9SMisael Lopez Cruz 	case TWL6040_SYSCLK_SEL_LPPLL:
9408ecbabd9SMisael Lopez Cruz 	case TWL6040_SYSCLK_SEL_HPPLL:
941753621c2SPeter Ujfalusi 		priv->pll = clk_id;
942753621c2SPeter Ujfalusi 		priv->clk_in = freq;
9438ecbabd9SMisael Lopez Cruz 		break;
9448ecbabd9SMisael Lopez Cruz 	default:
9457480389fSKuninori Morimoto 		dev_err(component->dev, "unknown clk_id %d\n", clk_id);
9468ecbabd9SMisael Lopez Cruz 		return -EINVAL;
9478ecbabd9SMisael Lopez Cruz 	}
9488ecbabd9SMisael Lopez Cruz 
9498ecbabd9SMisael Lopez Cruz 	return 0;
9508ecbabd9SMisael Lopez Cruz }
9518ecbabd9SMisael Lopez Cruz 
twl6040_mute_path(struct snd_soc_component * component,enum twl6040_dai_id id,int mute)9527480389fSKuninori Morimoto static void twl6040_mute_path(struct snd_soc_component *component, enum twl6040_dai_id id,
95398c5fb1fSPeter Ujfalusi 			     int mute)
95498c5fb1fSPeter Ujfalusi {
9557480389fSKuninori Morimoto 	struct twl6040 *twl6040 = to_twl6040(component);
9567480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
95798c5fb1fSPeter Ujfalusi 	int hslctl, hsrctl, earctl;
95898c5fb1fSPeter Ujfalusi 	int hflctl, hfrctl;
95998c5fb1fSPeter Ujfalusi 
96098c5fb1fSPeter Ujfalusi 	switch (id) {
96198c5fb1fSPeter Ujfalusi 	case TWL6040_DAI_DL1:
9627480389fSKuninori Morimoto 		hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
9637480389fSKuninori Morimoto 		hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
9647480389fSKuninori Morimoto 		earctl = twl6040_read(component, TWL6040_REG_EARCTL);
96598c5fb1fSPeter Ujfalusi 
96698c5fb1fSPeter Ujfalusi 		if (mute) {
96798c5fb1fSPeter Ujfalusi 			/* Power down drivers and DACs */
96898c5fb1fSPeter Ujfalusi 			earctl &= ~0x01;
96998c5fb1fSPeter Ujfalusi 			hslctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA);
97098c5fb1fSPeter Ujfalusi 			hsrctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA);
97198c5fb1fSPeter Ujfalusi 
97298c5fb1fSPeter Ujfalusi 		}
97398c5fb1fSPeter Ujfalusi 
97498c5fb1fSPeter Ujfalusi 		twl6040_reg_write(twl6040, TWL6040_REG_EARCTL, earctl);
97598c5fb1fSPeter Ujfalusi 		twl6040_reg_write(twl6040, TWL6040_REG_HSLCTL, hslctl);
97698c5fb1fSPeter Ujfalusi 		twl6040_reg_write(twl6040, TWL6040_REG_HSRCTL, hsrctl);
97798c5fb1fSPeter Ujfalusi 		priv->dl1_unmuted = !mute;
97898c5fb1fSPeter Ujfalusi 		break;
97998c5fb1fSPeter Ujfalusi 	case TWL6040_DAI_DL2:
9807480389fSKuninori Morimoto 		hflctl = twl6040_read(component, TWL6040_REG_HFLCTL);
9817480389fSKuninori Morimoto 		hfrctl = twl6040_read(component, TWL6040_REG_HFRCTL);
98298c5fb1fSPeter Ujfalusi 
98398c5fb1fSPeter Ujfalusi 		if (mute) {
98498c5fb1fSPeter Ujfalusi 			/* Power down drivers and DACs */
98598c5fb1fSPeter Ujfalusi 			hflctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA |
98645c04704SPeter Ujfalusi 				    TWL6040_HFDRVENA | TWL6040_HFSWENA);
98798c5fb1fSPeter Ujfalusi 			hfrctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA |
98845c04704SPeter Ujfalusi 				    TWL6040_HFDRVENA | TWL6040_HFSWENA);
98998c5fb1fSPeter Ujfalusi 		}
99098c5fb1fSPeter Ujfalusi 
99198c5fb1fSPeter Ujfalusi 		twl6040_reg_write(twl6040, TWL6040_REG_HFLCTL, hflctl);
99298c5fb1fSPeter Ujfalusi 		twl6040_reg_write(twl6040, TWL6040_REG_HFRCTL, hfrctl);
99398c5fb1fSPeter Ujfalusi 		priv->dl2_unmuted = !mute;
99498c5fb1fSPeter Ujfalusi 		break;
99598c5fb1fSPeter Ujfalusi 	default:
99698c5fb1fSPeter Ujfalusi 		break;
997bf551413SSachin Kamat 	}
99898c5fb1fSPeter Ujfalusi }
99998c5fb1fSPeter Ujfalusi 
twl6040_mute_stream(struct snd_soc_dai * dai,int mute,int direction)1000*54b59270SKuninori Morimoto static int twl6040_mute_stream(struct snd_soc_dai *dai, int mute, int direction)
100198c5fb1fSPeter Ujfalusi {
100298c5fb1fSPeter Ujfalusi 	switch (dai->id) {
100398c5fb1fSPeter Ujfalusi 	case TWL6040_DAI_LEGACY:
10047480389fSKuninori Morimoto 		twl6040_mute_path(dai->component, TWL6040_DAI_DL1, mute);
10057480389fSKuninori Morimoto 		twl6040_mute_path(dai->component, TWL6040_DAI_DL2, mute);
100698c5fb1fSPeter Ujfalusi 		break;
100798c5fb1fSPeter Ujfalusi 	case TWL6040_DAI_DL1:
100898c5fb1fSPeter Ujfalusi 	case TWL6040_DAI_DL2:
10097480389fSKuninori Morimoto 		twl6040_mute_path(dai->component, dai->id, mute);
101098c5fb1fSPeter Ujfalusi 		break;
101198c5fb1fSPeter Ujfalusi 	default:
101298c5fb1fSPeter Ujfalusi 		break;
101398c5fb1fSPeter Ujfalusi 	}
101498c5fb1fSPeter Ujfalusi 
101598c5fb1fSPeter Ujfalusi 	return 0;
101698c5fb1fSPeter Ujfalusi }
101798c5fb1fSPeter Ujfalusi 
101885e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops twl6040_dai_ops = {
10198ecbabd9SMisael Lopez Cruz 	.startup	= twl6040_startup,
10208ecbabd9SMisael Lopez Cruz 	.hw_params	= twl6040_hw_params,
10214e624d06SOlaya, Margarita 	.prepare	= twl6040_prepare,
10228ecbabd9SMisael Lopez Cruz 	.set_sysclk	= twl6040_set_dai_sysclk,
1023*54b59270SKuninori Morimoto 	.mute_stream	= twl6040_mute_stream,
1024*54b59270SKuninori Morimoto 	.no_capture_mute = 1,
10258ecbabd9SMisael Lopez Cruz };
10268ecbabd9SMisael Lopez Cruz 
10276510bdc3SLiam Girdwood static struct snd_soc_dai_driver twl6040_dai[] = {
10286510bdc3SLiam Girdwood {
1029d13f1fe0SPeter Ujfalusi 	.name = "twl6040-legacy",
103068897497SPeter Ujfalusi 	.id = TWL6040_DAI_LEGACY,
10318ecbabd9SMisael Lopez Cruz 	.playback = {
1032805238b1SPeter Ujfalusi 		.stream_name = "Legacy Playback",
10338ecbabd9SMisael Lopez Cruz 		.channels_min = 1,
1034cdd5054cSPeter Ujfalusi 		.channels_max = 5,
10358ecbabd9SMisael Lopez Cruz 		.rates = TWL6040_RATES,
10368ecbabd9SMisael Lopez Cruz 		.formats = TWL6040_FORMATS,
10378ecbabd9SMisael Lopez Cruz 	},
10388ecbabd9SMisael Lopez Cruz 	.capture = {
1039805238b1SPeter Ujfalusi 		.stream_name = "Legacy Capture",
10408ecbabd9SMisael Lopez Cruz 		.channels_min = 1,
10418ecbabd9SMisael Lopez Cruz 		.channels_max = 2,
10428ecbabd9SMisael Lopez Cruz 		.rates = TWL6040_RATES,
10438ecbabd9SMisael Lopez Cruz 		.formats = TWL6040_FORMATS,
10448ecbabd9SMisael Lopez Cruz 	},
10458ecbabd9SMisael Lopez Cruz 	.ops = &twl6040_dai_ops,
104621385eebSPeter Ujfalusi },
104721385eebSPeter Ujfalusi {
10486510bdc3SLiam Girdwood 	.name = "twl6040-ul",
104968897497SPeter Ujfalusi 	.id = TWL6040_DAI_UL,
10508ecbabd9SMisael Lopez Cruz 	.capture = {
10518ecbabd9SMisael Lopez Cruz 		.stream_name = "Capture",
10528ecbabd9SMisael Lopez Cruz 		.channels_min = 1,
10538ecbabd9SMisael Lopez Cruz 		.channels_max = 2,
10548ecbabd9SMisael Lopez Cruz 		.rates = TWL6040_RATES,
10558ecbabd9SMisael Lopez Cruz 		.formats = TWL6040_FORMATS,
10568ecbabd9SMisael Lopez Cruz 	},
10578ecbabd9SMisael Lopez Cruz 	.ops = &twl6040_dai_ops,
10586510bdc3SLiam Girdwood },
10596510bdc3SLiam Girdwood {
10606510bdc3SLiam Girdwood 	.name = "twl6040-dl1",
106168897497SPeter Ujfalusi 	.id = TWL6040_DAI_DL1,
10626510bdc3SLiam Girdwood 	.playback = {
10636510bdc3SLiam Girdwood 		.stream_name = "Headset Playback",
10646510bdc3SLiam Girdwood 		.channels_min = 1,
10656510bdc3SLiam Girdwood 		.channels_max = 2,
10666510bdc3SLiam Girdwood 		.rates = TWL6040_RATES,
10676510bdc3SLiam Girdwood 		.formats = TWL6040_FORMATS,
10686510bdc3SLiam Girdwood 	},
10696510bdc3SLiam Girdwood 	.ops = &twl6040_dai_ops,
10706510bdc3SLiam Girdwood },
10716510bdc3SLiam Girdwood {
10726510bdc3SLiam Girdwood 	.name = "twl6040-dl2",
107368897497SPeter Ujfalusi 	.id = TWL6040_DAI_DL2,
10746510bdc3SLiam Girdwood 	.playback = {
10756510bdc3SLiam Girdwood 		.stream_name = "Handsfree Playback",
10766510bdc3SLiam Girdwood 		.channels_min = 1,
10776510bdc3SLiam Girdwood 		.channels_max = 2,
10786510bdc3SLiam Girdwood 		.rates = TWL6040_RATES,
10796510bdc3SLiam Girdwood 		.formats = TWL6040_FORMATS,
10806510bdc3SLiam Girdwood 	},
10816510bdc3SLiam Girdwood 	.ops = &twl6040_dai_ops,
10826510bdc3SLiam Girdwood },
10836510bdc3SLiam Girdwood {
10846510bdc3SLiam Girdwood 	.name = "twl6040-vib",
108568897497SPeter Ujfalusi 	.id = TWL6040_DAI_VIB,
10866510bdc3SLiam Girdwood 	.playback = {
10876510bdc3SLiam Girdwood 		.stream_name = "Vibra Playback",
1088d8dd032dSPeter Ujfalusi 		.channels_min = 1,
1089d8dd032dSPeter Ujfalusi 		.channels_max = 1,
10906510bdc3SLiam Girdwood 		.rates = SNDRV_PCM_RATE_CONTINUOUS,
10916510bdc3SLiam Girdwood 		.formats = TWL6040_FORMATS,
10926510bdc3SLiam Girdwood 	},
10936510bdc3SLiam Girdwood 	.ops = &twl6040_dai_ops,
10946510bdc3SLiam Girdwood },
10958ecbabd9SMisael Lopez Cruz };
10968ecbabd9SMisael Lopez Cruz 
twl6040_probe(struct snd_soc_component * component)10977480389fSKuninori Morimoto static int twl6040_probe(struct snd_soc_component *component)
10988ecbabd9SMisael Lopez Cruz {
10998ecbabd9SMisael Lopez Cruz 	struct twl6040_data *priv;
11007480389fSKuninori Morimoto 	struct platform_device *pdev = to_platform_device(component->dev);
11018ecbabd9SMisael Lopez Cruz 	int ret = 0;
11028ecbabd9SMisael Lopez Cruz 
11037480389fSKuninori Morimoto 	priv = devm_kzalloc(component->dev, sizeof(*priv), GFP_KERNEL);
11048ecbabd9SMisael Lopez Cruz 	if (priv == NULL)
11058ecbabd9SMisael Lopez Cruz 		return -ENOMEM;
11069523fcdcSPeter Ujfalusi 
11077480389fSKuninori Morimoto 	snd_soc_component_set_drvdata(component, priv);
11088ecbabd9SMisael Lopez Cruz 
11097480389fSKuninori Morimoto 	priv->component = component;
1110a2d2362eSJorge Eduardo Candelaria 
11112a433b9dSPeter Ujfalusi 	priv->plug_irq = platform_get_irq(pdev, 0);
1112cf9441adSStephen Boyd 	if (priv->plug_irq < 0)
1113cfe267daSGustavo A. R. Silva 		return priv->plug_irq;
11148ecbabd9SMisael Lopez Cruz 
111546dd0b93SPeter Ujfalusi 	INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work);
1116a2d2362eSJorge Eduardo Candelaria 
1117a2d2362eSJorge Eduardo Candelaria 	mutex_init(&priv->mutex);
11188ecbabd9SMisael Lopez Cruz 
1119f60596d6SPeter Ujfalusi 	ret = request_threaded_irq(priv->plug_irq, NULL,
1120208ba89bSFabio Estevam 					twl6040_audio_handler,
1121208ba89bSFabio Estevam 					IRQF_NO_SUSPEND | IRQF_ONESHOT,
11227480389fSKuninori Morimoto 					"twl6040_irq_plug", component);
1123fb34d3d5SMisael Lopez Cruz 	if (ret) {
11247480389fSKuninori Morimoto 		dev_err(component->dev, "PLUG IRQ request failed: %d\n", ret);
1125da2107d1SPeter Ujfalusi 		return ret;
1126fb34d3d5SMisael Lopez Cruz 	}
1127fb34d3d5SMisael Lopez Cruz 
11287480389fSKuninori Morimoto 	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
11297480389fSKuninori Morimoto 	twl6040_init_chip(component);
1130fb34d3d5SMisael Lopez Cruz 
1131626bcacbSPeter Ujfalusi 	return 0;
11328ecbabd9SMisael Lopez Cruz }
11338ecbabd9SMisael Lopez Cruz 
twl6040_remove(struct snd_soc_component * component)11347480389fSKuninori Morimoto static void twl6040_remove(struct snd_soc_component *component)
11358ecbabd9SMisael Lopez Cruz {
11367480389fSKuninori Morimoto 	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
1137f60596d6SPeter Ujfalusi 
11387480389fSKuninori Morimoto 	free_irq(priv->plug_irq, component);
1139f0fba2adSLiam Girdwood }
11408ecbabd9SMisael Lopez Cruz 
11417480389fSKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_twl6040 = {
1142f0fba2adSLiam Girdwood 	.probe			= twl6040_probe,
1143f0fba2adSLiam Girdwood 	.remove			= twl6040_remove,
11448146acffSTony Lindgren 	.read			= twl6040_read,
1145c9d06665SPeter Ujfalusi 	.write			= twl6040_write,
1146f0fba2adSLiam Girdwood 	.set_bias_level		= twl6040_set_bias_level,
1147a175fce0SPeter Ujfalusi 	.controls		= twl6040_snd_controls,
1148a175fce0SPeter Ujfalusi 	.num_controls		= ARRAY_SIZE(twl6040_snd_controls),
1149a175fce0SPeter Ujfalusi 	.dapm_widgets		= twl6040_dapm_widgets,
1150a175fce0SPeter Ujfalusi 	.num_dapm_widgets	= ARRAY_SIZE(twl6040_dapm_widgets),
1151a175fce0SPeter Ujfalusi 	.dapm_routes		= intercon,
1152a175fce0SPeter Ujfalusi 	.num_dapm_routes	= ARRAY_SIZE(intercon),
11537480389fSKuninori Morimoto 	.suspend_bias_off	= 1,
11547480389fSKuninori Morimoto 	.idle_bias_on		= 1,
11557480389fSKuninori Morimoto 	.endianness		= 1,
1156f0fba2adSLiam Girdwood };
1157f0fba2adSLiam Girdwood 
twl6040_codec_probe(struct platform_device * pdev)11587a79e94eSBill Pemberton static int twl6040_codec_probe(struct platform_device *pdev)
1159f0fba2adSLiam Girdwood {
11607480389fSKuninori Morimoto 	return devm_snd_soc_register_component(&pdev->dev,
11617480389fSKuninori Morimoto 				      &soc_component_dev_twl6040,
11626510bdc3SLiam Girdwood 				      twl6040_dai, ARRAY_SIZE(twl6040_dai));
1163f0fba2adSLiam Girdwood }
1164f0fba2adSLiam Girdwood 
11658ecbabd9SMisael Lopez Cruz static struct platform_driver twl6040_codec_driver = {
11668ecbabd9SMisael Lopez Cruz 	.driver = {
1167f0fba2adSLiam Girdwood 		.name = "twl6040-codec",
11688ecbabd9SMisael Lopez Cruz 	},
11698ecbabd9SMisael Lopez Cruz 	.probe = twl6040_codec_probe,
11708ecbabd9SMisael Lopez Cruz };
11718ecbabd9SMisael Lopez Cruz 
11725bbcc3c0SMark Brown module_platform_driver(twl6040_codec_driver);
11738ecbabd9SMisael Lopez Cruz 
11748ecbabd9SMisael Lopez Cruz MODULE_DESCRIPTION("ASoC TWL6040 codec driver");
11758ecbabd9SMisael Lopez Cruz MODULE_AUTHOR("Misael Lopez Cruz");
11768ecbabd9SMisael Lopez Cruz MODULE_LICENSE("GPL");
1177