cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wm9090.c (20049B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ALSA SoC WM9090 driver
      4 *
      5 * Copyright 2009-12 Wolfson Microelectronics
      6 *
      7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/errno.h>
     12#include <linux/device.h>
     13#include <linux/i2c.h>
     14#include <linux/delay.h>
     15#include <linux/regmap.h>
     16#include <linux/slab.h>
     17#include <sound/initval.h>
     18#include <sound/soc.h>
     19#include <sound/tlv.h>
     20#include <sound/wm9090.h>
     21
     22#include "wm9090.h"
     23
     24static const struct reg_default wm9090_reg_defaults[] = {
     25	{ 1,  0x0006 },     /* R1   - Power Management (1) */
     26	{ 2,  0x6000 },     /* R2   - Power Management (2) */
     27	{ 3,  0x0000 },     /* R3   - Power Management (3) */
     28	{ 6,  0x01C0 },     /* R6   - Clocking 1 */
     29	{ 22, 0x0003 },     /* R22  - IN1 Line Control */
     30	{ 23, 0x0003 },     /* R23  - IN2 Line Control */
     31	{ 24, 0x0083 },     /* R24  - IN1 Line Input A Volume */
     32	{ 25, 0x0083 },     /* R25  - IN1  Line Input B Volume */
     33	{ 26, 0x0083 },     /* R26  - IN2 Line Input A Volume */
     34	{ 27, 0x0083 },     /* R27  - IN2 Line Input B Volume */
     35	{ 28, 0x002D },     /* R28  - Left Output Volume */
     36	{ 29, 0x002D },     /* R29  - Right Output Volume */
     37	{ 34, 0x0100 },     /* R34  - SPKMIXL Attenuation */
     38	{ 35, 0x0010 },     /* R36  - SPKOUT Mixers */
     39	{ 37, 0x0140 },     /* R37  - ClassD3 */
     40	{ 38, 0x0039 },     /* R38  - Speaker Volume Left */
     41	{ 45, 0x0000 },     /* R45  - Output Mixer1 */
     42	{ 46, 0x0000 },     /* R46  - Output Mixer2 */
     43	{ 47, 0x0100 },     /* R47  - Output Mixer3 */
     44	{ 48, 0x0100 },     /* R48  - Output Mixer4 */
     45	{ 54, 0x0000 },     /* R54  - Speaker Mixer */
     46	{ 57, 0x000D },     /* R57  - AntiPOP2 */
     47	{ 70, 0x0000 },     /* R70  - Write Sequencer 0 */
     48	{ 71, 0x0000 },     /* R71  - Write Sequencer 1 */
     49	{ 72, 0x0000 },     /* R72  - Write Sequencer 2 */
     50	{ 73, 0x0000 },     /* R73  - Write Sequencer 3 */
     51	{ 74, 0x0000 },     /* R74  - Write Sequencer 4 */
     52	{ 75, 0x0000 },     /* R75  - Write Sequencer 5 */
     53	{ 76, 0x1F25 },     /* R76  - Charge Pump 1 */
     54	{ 85, 0x054A },     /* R85  - DC Servo 1 */
     55	{ 87, 0x0000 },     /* R87  - DC Servo 3 */
     56	{ 96, 0x0100 },     /* R96  - Analogue HP 0 */
     57	{ 98, 0x8640 },     /* R98  - AGC Control 0 */
     58	{ 99, 0xC000 },     /* R99  - AGC Control 1 */
     59	{ 100, 0x0200 },     /* R100 - AGC Control 2 */
     60};
     61
     62/* This struct is used to save the context */
     63struct wm9090_priv {
     64	struct wm9090_platform_data pdata;
     65	struct regmap *regmap;
     66};
     67
     68static bool wm9090_volatile(struct device *dev, unsigned int reg)
     69{
     70	switch (reg) {
     71	case WM9090_SOFTWARE_RESET:
     72	case WM9090_DC_SERVO_0:
     73	case WM9090_DC_SERVO_READBACK_0:
     74	case WM9090_DC_SERVO_READBACK_1:
     75	case WM9090_DC_SERVO_READBACK_2:
     76		return true;
     77
     78	default:
     79		return false;
     80	}
     81}
     82
     83static bool wm9090_readable(struct device *dev, unsigned int reg)
     84{
     85	switch (reg) {
     86	case WM9090_SOFTWARE_RESET:
     87	case WM9090_POWER_MANAGEMENT_1:
     88	case WM9090_POWER_MANAGEMENT_2:
     89	case WM9090_POWER_MANAGEMENT_3:
     90	case WM9090_CLOCKING_1:
     91	case WM9090_IN1_LINE_CONTROL:
     92	case WM9090_IN2_LINE_CONTROL:
     93	case WM9090_IN1_LINE_INPUT_A_VOLUME:
     94	case WM9090_IN1_LINE_INPUT_B_VOLUME:
     95	case WM9090_IN2_LINE_INPUT_A_VOLUME:
     96	case WM9090_IN2_LINE_INPUT_B_VOLUME:
     97	case WM9090_LEFT_OUTPUT_VOLUME:
     98	case WM9090_RIGHT_OUTPUT_VOLUME:
     99	case WM9090_SPKMIXL_ATTENUATION:
    100	case WM9090_SPKOUT_MIXERS:
    101	case WM9090_CLASSD3:
    102	case WM9090_SPEAKER_VOLUME_LEFT:
    103	case WM9090_OUTPUT_MIXER1:
    104	case WM9090_OUTPUT_MIXER2:
    105	case WM9090_OUTPUT_MIXER3:
    106	case WM9090_OUTPUT_MIXER4:
    107	case WM9090_SPEAKER_MIXER:
    108	case WM9090_ANTIPOP2:
    109	case WM9090_WRITE_SEQUENCER_0:
    110	case WM9090_WRITE_SEQUENCER_1:
    111	case WM9090_WRITE_SEQUENCER_2:
    112	case WM9090_WRITE_SEQUENCER_3:
    113	case WM9090_WRITE_SEQUENCER_4:
    114	case WM9090_WRITE_SEQUENCER_5:
    115	case WM9090_CHARGE_PUMP_1:
    116	case WM9090_DC_SERVO_0:
    117	case WM9090_DC_SERVO_1:
    118	case WM9090_DC_SERVO_3:
    119	case WM9090_DC_SERVO_READBACK_0:
    120	case WM9090_DC_SERVO_READBACK_1:
    121	case WM9090_DC_SERVO_READBACK_2:
    122	case WM9090_ANALOGUE_HP_0:
    123	case WM9090_AGC_CONTROL_0:
    124	case WM9090_AGC_CONTROL_1:
    125	case WM9090_AGC_CONTROL_2:
    126		return true;
    127
    128	default:
    129		return false;
    130	}
    131}
    132
    133static void wait_for_dc_servo(struct snd_soc_component *component)
    134{
    135	unsigned int reg;
    136	int count = 0;
    137
    138	dev_dbg(component->dev, "Waiting for DC servo...\n");
    139	do {
    140		count++;
    141		msleep(1);
    142		reg = snd_soc_component_read(component, WM9090_DC_SERVO_READBACK_0);
    143		dev_dbg(component->dev, "DC servo status: %x\n", reg);
    144	} while ((reg & WM9090_DCS_CAL_COMPLETE_MASK)
    145		 != WM9090_DCS_CAL_COMPLETE_MASK && count < 1000);
    146
    147	if ((reg & WM9090_DCS_CAL_COMPLETE_MASK)
    148	    != WM9090_DCS_CAL_COMPLETE_MASK)
    149		dev_err(component->dev, "Timed out waiting for DC Servo\n");
    150}
    151
    152static const DECLARE_TLV_DB_RANGE(in_tlv,
    153	0, 0, TLV_DB_SCALE_ITEM(-600, 0, 0),
    154	1, 3, TLV_DB_SCALE_ITEM(-350, 350, 0),
    155	4, 6, TLV_DB_SCALE_ITEM(600, 600, 0)
    156);
    157static const DECLARE_TLV_DB_RANGE(mix_tlv,
    158	0, 2, TLV_DB_SCALE_ITEM(-1200, 300, 0),
    159	3, 3, TLV_DB_SCALE_ITEM(0, 0, 0)
    160);
    161static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
    162static const DECLARE_TLV_DB_RANGE(spkboost_tlv,
    163	0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
    164	7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0)
    165);
    166
    167static const struct snd_kcontrol_new wm9090_controls[] = {
    168SOC_SINGLE_TLV("IN1A Volume", WM9090_IN1_LINE_INPUT_A_VOLUME, 0, 6, 0,
    169	       in_tlv),
    170SOC_SINGLE("IN1A Switch", WM9090_IN1_LINE_INPUT_A_VOLUME, 7, 1, 1),
    171SOC_SINGLE("IN1A ZC Switch", WM9090_IN1_LINE_INPUT_A_VOLUME, 6, 1, 0),
    172
    173SOC_SINGLE_TLV("IN2A Volume", WM9090_IN2_LINE_INPUT_A_VOLUME, 0, 6, 0,
    174	       in_tlv),
    175SOC_SINGLE("IN2A Switch", WM9090_IN2_LINE_INPUT_A_VOLUME, 7, 1, 1),
    176SOC_SINGLE("IN2A ZC Switch", WM9090_IN2_LINE_INPUT_A_VOLUME, 6, 1, 0),
    177
    178SOC_SINGLE("MIXOUTL Switch", WM9090_OUTPUT_MIXER3, 8, 1, 1),
    179SOC_SINGLE_TLV("MIXOUTL IN1A Volume", WM9090_OUTPUT_MIXER3, 6, 3, 1,
    180	       mix_tlv),
    181SOC_SINGLE_TLV("MIXOUTL IN2A Volume", WM9090_OUTPUT_MIXER3, 2, 3, 1,
    182	       mix_tlv),
    183
    184SOC_SINGLE("MIXOUTR Switch", WM9090_OUTPUT_MIXER4, 8, 1, 1),
    185SOC_SINGLE_TLV("MIXOUTR IN1A Volume", WM9090_OUTPUT_MIXER4, 6, 3, 1,
    186	       mix_tlv),
    187SOC_SINGLE_TLV("MIXOUTR IN2A Volume", WM9090_OUTPUT_MIXER4, 2, 3, 1,
    188	       mix_tlv),
    189
    190SOC_SINGLE("SPKMIX Switch", WM9090_SPKMIXL_ATTENUATION, 8, 1, 1),
    191SOC_SINGLE_TLV("SPKMIX IN1A Volume", WM9090_SPKMIXL_ATTENUATION, 6, 3, 1,
    192	       mix_tlv),
    193SOC_SINGLE_TLV("SPKMIX IN2A Volume", WM9090_SPKMIXL_ATTENUATION, 2, 3, 1,
    194	       mix_tlv),
    195
    196SOC_DOUBLE_R_TLV("Headphone Volume", WM9090_LEFT_OUTPUT_VOLUME,
    197		 WM9090_RIGHT_OUTPUT_VOLUME, 0, 63, 0, out_tlv),
    198SOC_DOUBLE_R("Headphone Switch", WM9090_LEFT_OUTPUT_VOLUME,
    199	     WM9090_RIGHT_OUTPUT_VOLUME, 6, 1, 1),
    200SOC_DOUBLE_R("Headphone ZC Switch", WM9090_LEFT_OUTPUT_VOLUME,
    201	     WM9090_RIGHT_OUTPUT_VOLUME, 7, 1, 0),
    202
    203SOC_SINGLE_TLV("Speaker Volume", WM9090_SPEAKER_VOLUME_LEFT, 0, 63, 0,
    204	       out_tlv),
    205SOC_SINGLE("Speaker Switch", WM9090_SPEAKER_VOLUME_LEFT, 6, 1, 1),
    206SOC_SINGLE("Speaker ZC Switch", WM9090_SPEAKER_VOLUME_LEFT, 7, 1, 0),
    207SOC_SINGLE_TLV("Speaker Boost Volume", WM9090_CLASSD3, 3, 7, 0, spkboost_tlv),
    208};
    209
    210static const struct snd_kcontrol_new wm9090_in1_se_controls[] = {
    211SOC_SINGLE_TLV("IN1B Volume", WM9090_IN1_LINE_INPUT_B_VOLUME, 0, 6, 0,
    212	       in_tlv),
    213SOC_SINGLE("IN1B Switch", WM9090_IN1_LINE_INPUT_B_VOLUME, 7, 1, 1),
    214SOC_SINGLE("IN1B ZC Switch", WM9090_IN1_LINE_INPUT_B_VOLUME, 6, 1, 0),
    215
    216SOC_SINGLE_TLV("SPKMIX IN1B Volume", WM9090_SPKMIXL_ATTENUATION, 4, 3, 1,
    217	       mix_tlv),
    218SOC_SINGLE_TLV("MIXOUTL IN1B Volume", WM9090_OUTPUT_MIXER3, 4, 3, 1,
    219	       mix_tlv),
    220SOC_SINGLE_TLV("MIXOUTR IN1B Volume", WM9090_OUTPUT_MIXER4, 4, 3, 1,
    221	       mix_tlv),
    222};
    223
    224static const struct snd_kcontrol_new wm9090_in2_se_controls[] = {
    225SOC_SINGLE_TLV("IN2B Volume", WM9090_IN2_LINE_INPUT_B_VOLUME, 0, 6, 0,
    226	       in_tlv),
    227SOC_SINGLE("IN2B Switch", WM9090_IN2_LINE_INPUT_B_VOLUME, 7, 1, 1),
    228SOC_SINGLE("IN2B ZC Switch", WM9090_IN2_LINE_INPUT_B_VOLUME, 6, 1, 0),
    229
    230SOC_SINGLE_TLV("SPKMIX IN2B Volume", WM9090_SPKMIXL_ATTENUATION, 0, 3, 1,
    231	       mix_tlv),
    232SOC_SINGLE_TLV("MIXOUTL IN2B Volume", WM9090_OUTPUT_MIXER3, 0, 3, 1,
    233	       mix_tlv),
    234SOC_SINGLE_TLV("MIXOUTR IN2B Volume", WM9090_OUTPUT_MIXER4, 0, 3, 1,
    235	       mix_tlv),
    236};
    237
    238static int hp_ev(struct snd_soc_dapm_widget *w,
    239		 struct snd_kcontrol *kcontrol, int event)
    240{
    241	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    242	unsigned int reg = snd_soc_component_read(component, WM9090_ANALOGUE_HP_0);
    243
    244	switch (event) {
    245	case SND_SOC_DAPM_POST_PMU:
    246		snd_soc_component_update_bits(component, WM9090_CHARGE_PUMP_1,
    247				    WM9090_CP_ENA, WM9090_CP_ENA);
    248
    249		msleep(5);
    250
    251		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_1,
    252				    WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA,
    253				    WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA);
    254
    255		reg |= WM9090_HPOUT1L_DLY | WM9090_HPOUT1R_DLY;
    256		snd_soc_component_write(component, WM9090_ANALOGUE_HP_0, reg);
    257
    258		/* Start the DC servo.  We don't currently use the
    259		 * ability to save the state since we don't have full
    260		 * control of the analogue paths and they can change
    261		 * DC offsets; see the WM8904 driver for an example of
    262		 * doing so.
    263		 */
    264		snd_soc_component_write(component, WM9090_DC_SERVO_0,
    265			      WM9090_DCS_ENA_CHAN_0 |
    266			      WM9090_DCS_ENA_CHAN_1 |
    267			      WM9090_DCS_TRIG_STARTUP_1 |
    268			      WM9090_DCS_TRIG_STARTUP_0);
    269		wait_for_dc_servo(component);
    270
    271		reg |= WM9090_HPOUT1R_OUTP | WM9090_HPOUT1R_RMV_SHORT |
    272			WM9090_HPOUT1L_OUTP | WM9090_HPOUT1L_RMV_SHORT;
    273		snd_soc_component_write(component, WM9090_ANALOGUE_HP_0, reg);
    274		break;
    275
    276	case SND_SOC_DAPM_PRE_PMD:
    277		reg &= ~(WM9090_HPOUT1L_RMV_SHORT |
    278			 WM9090_HPOUT1L_DLY |
    279			 WM9090_HPOUT1L_OUTP |
    280			 WM9090_HPOUT1R_RMV_SHORT |
    281			 WM9090_HPOUT1R_DLY |
    282			 WM9090_HPOUT1R_OUTP);
    283
    284		snd_soc_component_write(component, WM9090_ANALOGUE_HP_0, reg);
    285
    286		snd_soc_component_write(component, WM9090_DC_SERVO_0, 0);
    287
    288		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_1,
    289				    WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA,
    290				    0);
    291
    292		snd_soc_component_update_bits(component, WM9090_CHARGE_PUMP_1,
    293				    WM9090_CP_ENA, 0);
    294		break;
    295	}
    296
    297	return 0;
    298}
    299
    300static const struct snd_kcontrol_new spkmix[] = {
    301SOC_DAPM_SINGLE("IN1A Switch", WM9090_SPEAKER_MIXER, 6, 1, 0),
    302SOC_DAPM_SINGLE("IN1B Switch", WM9090_SPEAKER_MIXER, 4, 1, 0),
    303SOC_DAPM_SINGLE("IN2A Switch", WM9090_SPEAKER_MIXER, 2, 1, 0),
    304SOC_DAPM_SINGLE("IN2B Switch", WM9090_SPEAKER_MIXER, 0, 1, 0),
    305};
    306
    307static const struct snd_kcontrol_new spkout[] = {
    308SOC_DAPM_SINGLE("Mixer Switch", WM9090_SPKOUT_MIXERS, 4, 1, 0),
    309};
    310
    311static const struct snd_kcontrol_new mixoutl[] = {
    312SOC_DAPM_SINGLE("IN1A Switch", WM9090_OUTPUT_MIXER1, 6, 1, 0),
    313SOC_DAPM_SINGLE("IN1B Switch", WM9090_OUTPUT_MIXER1, 4, 1, 0),
    314SOC_DAPM_SINGLE("IN2A Switch", WM9090_OUTPUT_MIXER1, 2, 1, 0),
    315SOC_DAPM_SINGLE("IN2B Switch", WM9090_OUTPUT_MIXER1, 0, 1, 0),
    316};
    317
    318static const struct snd_kcontrol_new mixoutr[] = {
    319SOC_DAPM_SINGLE("IN1A Switch", WM9090_OUTPUT_MIXER2, 6, 1, 0),
    320SOC_DAPM_SINGLE("IN1B Switch", WM9090_OUTPUT_MIXER2, 4, 1, 0),
    321SOC_DAPM_SINGLE("IN2A Switch", WM9090_OUTPUT_MIXER2, 2, 1, 0),
    322SOC_DAPM_SINGLE("IN2B Switch", WM9090_OUTPUT_MIXER2, 0, 1, 0),
    323};
    324
    325static const struct snd_soc_dapm_widget wm9090_dapm_widgets[] = {
    326SND_SOC_DAPM_INPUT("IN1+"),
    327SND_SOC_DAPM_INPUT("IN1-"),
    328SND_SOC_DAPM_INPUT("IN2+"),
    329SND_SOC_DAPM_INPUT("IN2-"),
    330
    331SND_SOC_DAPM_SUPPLY("OSC", WM9090_POWER_MANAGEMENT_1, 3, 0, NULL, 0),
    332
    333SND_SOC_DAPM_PGA("IN1A PGA", WM9090_POWER_MANAGEMENT_2, 7, 0, NULL, 0),
    334SND_SOC_DAPM_PGA("IN1B PGA", WM9090_POWER_MANAGEMENT_2, 6, 0, NULL, 0),
    335SND_SOC_DAPM_PGA("IN2A PGA", WM9090_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
    336SND_SOC_DAPM_PGA("IN2B PGA", WM9090_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
    337
    338SND_SOC_DAPM_MIXER("SPKMIX", WM9090_POWER_MANAGEMENT_3, 3, 0,
    339		   spkmix, ARRAY_SIZE(spkmix)),
    340SND_SOC_DAPM_MIXER("MIXOUTL", WM9090_POWER_MANAGEMENT_3, 5, 0,
    341		   mixoutl, ARRAY_SIZE(mixoutl)),
    342SND_SOC_DAPM_MIXER("MIXOUTR", WM9090_POWER_MANAGEMENT_3, 4, 0,
    343		   mixoutr, ARRAY_SIZE(mixoutr)),
    344
    345SND_SOC_DAPM_PGA_E("HP PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
    346		   hp_ev, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
    347
    348SND_SOC_DAPM_PGA("SPKPGA", WM9090_POWER_MANAGEMENT_3, 8, 0, NULL, 0),
    349SND_SOC_DAPM_MIXER("SPKOUT", WM9090_POWER_MANAGEMENT_1, 12, 0,
    350		   spkout, ARRAY_SIZE(spkout)),
    351
    352SND_SOC_DAPM_OUTPUT("HPR"),
    353SND_SOC_DAPM_OUTPUT("HPL"),
    354SND_SOC_DAPM_OUTPUT("Speaker"),
    355};
    356
    357static const struct snd_soc_dapm_route audio_map[] = {
    358	{ "IN1A PGA", NULL, "IN1+" },
    359	{ "IN2A PGA", NULL, "IN2+" },
    360
    361	{ "SPKMIX", "IN1A Switch", "IN1A PGA" },
    362	{ "SPKMIX", "IN2A Switch", "IN2A PGA" },
    363
    364	{ "MIXOUTL", "IN1A Switch", "IN1A PGA" },
    365	{ "MIXOUTL", "IN2A Switch", "IN2A PGA" },
    366
    367	{ "MIXOUTR", "IN1A Switch", "IN1A PGA" },
    368	{ "MIXOUTR", "IN2A Switch", "IN2A PGA" },
    369
    370	{ "HP PGA", NULL, "OSC" },
    371	{ "HP PGA", NULL, "MIXOUTL" },
    372	{ "HP PGA", NULL, "MIXOUTR" },
    373
    374	{ "HPL", NULL, "HP PGA" },
    375	{ "HPR", NULL, "HP PGA" },
    376
    377	{ "SPKPGA", NULL, "OSC" },
    378	{ "SPKPGA", NULL, "SPKMIX" },
    379
    380	{ "SPKOUT", "Mixer Switch", "SPKPGA" },
    381
    382	{ "Speaker", NULL, "SPKOUT" },
    383};
    384
    385static const struct snd_soc_dapm_route audio_map_in1_se[] = {
    386	{ "IN1B PGA", NULL, "IN1-" },	
    387
    388	{ "SPKMIX", "IN1B Switch", "IN1B PGA" },
    389	{ "MIXOUTL", "IN1B Switch", "IN1B PGA" },
    390	{ "MIXOUTR", "IN1B Switch", "IN1B PGA" },
    391};
    392
    393static const struct snd_soc_dapm_route audio_map_in1_diff[] = {
    394	{ "IN1A PGA", NULL, "IN1-" },	
    395};
    396
    397static const struct snd_soc_dapm_route audio_map_in2_se[] = {
    398	{ "IN2B PGA", NULL, "IN2-" },	
    399
    400	{ "SPKMIX", "IN2B Switch", "IN2B PGA" },
    401	{ "MIXOUTL", "IN2B Switch", "IN2B PGA" },
    402	{ "MIXOUTR", "IN2B Switch", "IN2B PGA" },
    403};
    404
    405static const struct snd_soc_dapm_route audio_map_in2_diff[] = {
    406	{ "IN2A PGA", NULL, "IN2-" },	
    407};
    408
    409static int wm9090_add_controls(struct snd_soc_component *component)
    410{
    411	struct wm9090_priv *wm9090 = snd_soc_component_get_drvdata(component);
    412	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
    413	int i;
    414
    415	snd_soc_dapm_new_controls(dapm, wm9090_dapm_widgets,
    416				  ARRAY_SIZE(wm9090_dapm_widgets));
    417
    418	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
    419
    420	snd_soc_add_component_controls(component, wm9090_controls,
    421			     ARRAY_SIZE(wm9090_controls));
    422
    423	if (wm9090->pdata.lin1_diff) {
    424		snd_soc_dapm_add_routes(dapm, audio_map_in1_diff,
    425					ARRAY_SIZE(audio_map_in1_diff));
    426	} else {
    427		snd_soc_dapm_add_routes(dapm, audio_map_in1_se,
    428					ARRAY_SIZE(audio_map_in1_se));
    429		snd_soc_add_component_controls(component, wm9090_in1_se_controls,
    430				     ARRAY_SIZE(wm9090_in1_se_controls));
    431	}
    432
    433	if (wm9090->pdata.lin2_diff) {
    434		snd_soc_dapm_add_routes(dapm, audio_map_in2_diff,
    435					ARRAY_SIZE(audio_map_in2_diff));
    436	} else {
    437		snd_soc_dapm_add_routes(dapm, audio_map_in2_se,
    438					ARRAY_SIZE(audio_map_in2_se));
    439		snd_soc_add_component_controls(component, wm9090_in2_se_controls,
    440				     ARRAY_SIZE(wm9090_in2_se_controls));
    441	}
    442
    443	if (wm9090->pdata.agc_ena) {
    444		for (i = 0; i < ARRAY_SIZE(wm9090->pdata.agc); i++)
    445			snd_soc_component_write(component, WM9090_AGC_CONTROL_0 + i,
    446				      wm9090->pdata.agc[i]);
    447		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_3,
    448				    WM9090_AGC_ENA, WM9090_AGC_ENA);
    449	} else {
    450		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_3,
    451				    WM9090_AGC_ENA, 0);
    452	}
    453
    454	return 0;
    455
    456}
    457
    458/*
    459 * The machine driver should call this from their set_bias_level; if there
    460 * isn't one then this can just be set as the set_bias_level function.
    461 */
    462static int wm9090_set_bias_level(struct snd_soc_component *component,
    463				 enum snd_soc_bias_level level)
    464{
    465	struct wm9090_priv *wm9090 = snd_soc_component_get_drvdata(component);
    466
    467	switch (level) {
    468	case SND_SOC_BIAS_ON:
    469		break;
    470
    471	case SND_SOC_BIAS_PREPARE:
    472		snd_soc_component_update_bits(component, WM9090_ANTIPOP2, WM9090_VMID_ENA,
    473				    WM9090_VMID_ENA);
    474		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_1,
    475				    WM9090_BIAS_ENA |
    476				    WM9090_VMID_RES_MASK,
    477				    WM9090_BIAS_ENA |
    478				    1 << WM9090_VMID_RES_SHIFT);
    479		msleep(1);  /* Probably an overestimate */
    480		break;
    481
    482	case SND_SOC_BIAS_STANDBY:
    483		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
    484			/* Restore the register cache */
    485			regcache_sync(wm9090->regmap);
    486		}
    487
    488		/* We keep VMID off during standby since the combination of
    489		 * ground referenced outputs and class D speaker mean that
    490		 * latency is not an issue.
    491		 */
    492		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_1,
    493				    WM9090_BIAS_ENA | WM9090_VMID_RES_MASK, 0);
    494		snd_soc_component_update_bits(component, WM9090_ANTIPOP2,
    495				    WM9090_VMID_ENA, 0);
    496		break;
    497
    498	case SND_SOC_BIAS_OFF:
    499		break;
    500	}
    501
    502	return 0;
    503}
    504
    505static int wm9090_probe(struct snd_soc_component *component)
    506{
    507	/* Configure some defaults; they will be written out when we
    508	 * bring the bias up.
    509	 */
    510	snd_soc_component_update_bits(component, WM9090_IN1_LINE_INPUT_A_VOLUME,
    511			    WM9090_IN1_VU | WM9090_IN1A_ZC,
    512			    WM9090_IN1_VU | WM9090_IN1A_ZC);
    513	snd_soc_component_update_bits(component, WM9090_IN1_LINE_INPUT_B_VOLUME,
    514			    WM9090_IN1_VU | WM9090_IN1B_ZC,
    515			    WM9090_IN1_VU | WM9090_IN1B_ZC);
    516	snd_soc_component_update_bits(component, WM9090_IN2_LINE_INPUT_A_VOLUME,
    517			    WM9090_IN2_VU | WM9090_IN2A_ZC,
    518			    WM9090_IN2_VU | WM9090_IN2A_ZC);
    519	snd_soc_component_update_bits(component, WM9090_IN2_LINE_INPUT_B_VOLUME,
    520			    WM9090_IN2_VU | WM9090_IN2B_ZC,
    521			    WM9090_IN2_VU | WM9090_IN2B_ZC);
    522	snd_soc_component_update_bits(component, WM9090_SPEAKER_VOLUME_LEFT,
    523			    WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC,
    524			    WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC);
    525	snd_soc_component_update_bits(component, WM9090_LEFT_OUTPUT_VOLUME,
    526			    WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC,
    527			    WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC);
    528	snd_soc_component_update_bits(component, WM9090_RIGHT_OUTPUT_VOLUME,
    529			    WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC,
    530			    WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC);
    531
    532	snd_soc_component_update_bits(component, WM9090_CLOCKING_1,
    533			    WM9090_TOCLK_ENA, WM9090_TOCLK_ENA);
    534
    535	wm9090_add_controls(component);
    536
    537	return 0;
    538}
    539
    540static const struct snd_soc_component_driver soc_component_dev_wm9090 = {
    541	.probe			= wm9090_probe,
    542	.set_bias_level		= wm9090_set_bias_level,
    543	.suspend_bias_off	= 1,
    544	.idle_bias_on		= 1,
    545	.use_pmdown_time	= 1,
    546	.non_legacy_dai_naming	= 1,
    547};
    548
    549static const struct regmap_config wm9090_regmap = {
    550	.reg_bits = 8,
    551	.val_bits = 16,
    552
    553	.max_register = WM9090_MAX_REGISTER,
    554	.volatile_reg = wm9090_volatile,
    555	.readable_reg = wm9090_readable,
    556
    557	.cache_type = REGCACHE_RBTREE,
    558	.reg_defaults = wm9090_reg_defaults,
    559	.num_reg_defaults = ARRAY_SIZE(wm9090_reg_defaults),
    560};
    561
    562
    563static int wm9090_i2c_probe(struct i2c_client *i2c)
    564{
    565	struct wm9090_priv *wm9090;
    566	unsigned int reg;
    567	int ret;
    568
    569	wm9090 = devm_kzalloc(&i2c->dev, sizeof(*wm9090), GFP_KERNEL);
    570	if (!wm9090)
    571		return -ENOMEM;
    572
    573	wm9090->regmap = devm_regmap_init_i2c(i2c, &wm9090_regmap);
    574	if (IS_ERR(wm9090->regmap)) {
    575		ret = PTR_ERR(wm9090->regmap);
    576		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
    577		return ret;
    578	}
    579
    580	ret = regmap_read(wm9090->regmap, WM9090_SOFTWARE_RESET, &reg);
    581	if (ret < 0)
    582		return ret;
    583
    584	if (reg != 0x9093) {
    585		dev_err(&i2c->dev, "Device is not a WM9090, ID=%x\n", reg);
    586		return -ENODEV;
    587	}
    588
    589	ret = regmap_write(wm9090->regmap, WM9090_SOFTWARE_RESET, 0);
    590	if (ret < 0)
    591		return ret;
    592
    593	if (i2c->dev.platform_data)
    594		memcpy(&wm9090->pdata, i2c->dev.platform_data,
    595		       sizeof(wm9090->pdata));
    596
    597	i2c_set_clientdata(i2c, wm9090);
    598
    599	ret =  devm_snd_soc_register_component(&i2c->dev,
    600			&soc_component_dev_wm9090,  NULL, 0);
    601	if (ret != 0) {
    602		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
    603		return ret;
    604	}
    605
    606	return 0;
    607}
    608
    609static const struct i2c_device_id wm9090_id[] = {
    610	{ "wm9090", 0 },
    611	{ "wm9093", 0 },
    612	{ }
    613};
    614MODULE_DEVICE_TABLE(i2c, wm9090_id);
    615
    616static struct i2c_driver wm9090_i2c_driver = {
    617	.driver = {
    618		.name = "wm9090",
    619	},
    620	.probe_new = wm9090_i2c_probe,
    621	.id_table = wm9090_id,
    622};
    623
    624module_i2c_driver(wm9090_i2c_driver);
    625
    626MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
    627MODULE_DESCRIPTION("WM9090 ASoC driver");
    628MODULE_LICENSE("GPL");