Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.16-rc2 580 lines 19 kB view raw
1/* 2 * SiRF audio codec driver 3 * 4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. 5 * 6 * Licensed under GPLv2 or later. 7 */ 8 9#include <linux/module.h> 10#include <linux/platform_device.h> 11#include <linux/pm_runtime.h> 12#include <linux/of.h> 13#include <linux/of_device.h> 14#include <linux/clk.h> 15#include <linux/delay.h> 16#include <linux/io.h> 17#include <linux/regmap.h> 18#include <sound/core.h> 19#include <sound/pcm.h> 20#include <sound/pcm_params.h> 21#include <sound/initval.h> 22#include <sound/tlv.h> 23#include <sound/soc.h> 24#include <sound/dmaengine_pcm.h> 25 26#include "sirf-audio-codec.h" 27 28struct sirf_audio_codec { 29 struct clk *clk; 30 struct regmap *regmap; 31 u32 reg_ctrl0, reg_ctrl1; 32}; 33 34static const char * const input_mode_mux[] = {"Single-ended", 35 "Differential"}; 36 37static const struct soc_enum input_mode_mux_enum = 38 SOC_ENUM_SINGLE(AUDIO_IC_CODEC_CTRL1, 4, 2, input_mode_mux); 39 40static const struct snd_kcontrol_new sirf_audio_codec_input_mode_control = 41 SOC_DAPM_ENUM("Route", input_mode_mux_enum); 42 43static const DECLARE_TLV_DB_SCALE(playback_vol_tlv, -12400, 100, 0); 44static const DECLARE_TLV_DB_SCALE(capture_vol_tlv_prima2, 500, 100, 0); 45static const DECLARE_TLV_DB_RANGE(capture_vol_tlv_atlas6, 46 0, 7, TLV_DB_SCALE_ITEM(-100, 100, 0), 47 0x22, 0x3F, TLV_DB_SCALE_ITEM(700, 100, 0), 48); 49 50static struct snd_kcontrol_new volume_controls_atlas6[] = { 51 SOC_DOUBLE_TLV("Playback Volume", AUDIO_IC_CODEC_CTRL0, 21, 14, 52 0x7F, 0, playback_vol_tlv), 53 SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 16, 10, 54 0x3F, 0, capture_vol_tlv_atlas6), 55}; 56 57static struct snd_kcontrol_new volume_controls_prima2[] = { 58 SOC_DOUBLE_TLV("Speaker Volume", AUDIO_IC_CODEC_CTRL0, 21, 14, 59 0x7F, 0, playback_vol_tlv), 60 SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 15, 10, 61 0x1F, 0, capture_vol_tlv_prima2), 62}; 63 64static struct snd_kcontrol_new left_input_path_controls[] = { 65 SOC_DAPM_SINGLE("Line Left Switch", AUDIO_IC_CODEC_CTRL1, 6, 1, 0), 66 SOC_DAPM_SINGLE("Mic Left Switch", AUDIO_IC_CODEC_CTRL1, 3, 1, 0), 67}; 68 69static struct snd_kcontrol_new right_input_path_controls[] = { 70 SOC_DAPM_SINGLE("Line Right Switch", AUDIO_IC_CODEC_CTRL1, 5, 1, 0), 71 SOC_DAPM_SINGLE("Mic Right Switch", AUDIO_IC_CODEC_CTRL1, 2, 1, 0), 72}; 73 74static struct snd_kcontrol_new left_dac_to_hp_left_amp_switch_control = 75 SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 9, 1, 0); 76 77static struct snd_kcontrol_new left_dac_to_hp_right_amp_switch_control = 78 SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 8, 1, 0); 79 80static struct snd_kcontrol_new right_dac_to_hp_left_amp_switch_control = 81 SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 7, 1, 0); 82 83static struct snd_kcontrol_new right_dac_to_hp_right_amp_switch_control = 84 SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 6, 1, 0); 85 86static struct snd_kcontrol_new left_dac_to_speaker_lineout_switch_control = 87 SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 11, 1, 0); 88 89static struct snd_kcontrol_new right_dac_to_speaker_lineout_switch_control = 90 SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 10, 1, 0); 91 92/* After enable adc, Delay 200ms to avoid pop noise */ 93static int adc_enable_delay_event(struct snd_soc_dapm_widget *w, 94 struct snd_kcontrol *kcontrol, int event) 95{ 96 switch (event) { 97 case SND_SOC_DAPM_POST_PMU: 98 msleep(200); 99 break; 100 default: 101 break; 102 } 103 104 return 0; 105} 106 107static void enable_and_reset_codec(struct regmap *regmap, 108 u32 codec_enable_bits, u32 codec_reset_bits) 109{ 110 regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1, 111 codec_enable_bits | codec_reset_bits, 112 codec_enable_bits); 113 msleep(20); 114 regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1, 115 codec_reset_bits, codec_reset_bits); 116} 117 118static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w, 119 struct snd_kcontrol *kcontrol, int event) 120{ 121#define ATLAS6_CODEC_ENABLE_BITS (1 << 29) 122#define ATLAS6_CODEC_RESET_BITS (1 << 28) 123 struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev); 124 switch (event) { 125 case SND_SOC_DAPM_PRE_PMU: 126 enable_and_reset_codec(sirf_audio_codec->regmap, 127 ATLAS6_CODEC_ENABLE_BITS, ATLAS6_CODEC_RESET_BITS); 128 break; 129 case SND_SOC_DAPM_POST_PMD: 130 regmap_update_bits(sirf_audio_codec->regmap, 131 AUDIO_IC_CODEC_CTRL1, ATLAS6_CODEC_ENABLE_BITS, 0); 132 break; 133 default: 134 break; 135 } 136 137 return 0; 138} 139 140static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w, 141 struct snd_kcontrol *kcontrol, int event) 142{ 143#define PRIMA2_CODEC_ENABLE_BITS (1 << 27) 144#define PRIMA2_CODEC_RESET_BITS (1 << 26) 145 struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev); 146 switch (event) { 147 case SND_SOC_DAPM_POST_PMU: 148 enable_and_reset_codec(sirf_audio_codec->regmap, 149 PRIMA2_CODEC_ENABLE_BITS, PRIMA2_CODEC_RESET_BITS); 150 break; 151 case SND_SOC_DAPM_POST_PMD: 152 regmap_update_bits(sirf_audio_codec->regmap, 153 AUDIO_IC_CODEC_CTRL1, PRIMA2_CODEC_ENABLE_BITS, 0); 154 break; 155 default: 156 break; 157 } 158 159 return 0; 160} 161 162static const struct snd_soc_dapm_widget atlas6_output_driver_dapm_widgets[] = { 163 SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1, 164 25, 0, NULL, 0), 165 SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1, 166 26, 0, NULL, 0), 167 SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1, 168 27, 0, NULL, 0), 169}; 170 171static const struct snd_soc_dapm_widget prima2_output_driver_dapm_widgets[] = { 172 SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1, 173 23, 0, NULL, 0), 174 SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1, 175 24, 0, NULL, 0), 176 SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1, 177 25, 0, NULL, 0), 178}; 179 180static const struct snd_soc_dapm_widget atlas6_codec_clock_dapm_widget = 181 SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0, 182 atlas6_codec_enable_and_reset_event, 183 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); 184 185static const struct snd_soc_dapm_widget prima2_codec_clock_dapm_widget = 186 SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0, 187 prima2_codec_enable_and_reset_event, 188 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); 189 190static const struct snd_soc_dapm_widget sirf_audio_codec_dapm_widgets[] = { 191 SND_SOC_DAPM_DAC("DAC left", NULL, AUDIO_IC_CODEC_CTRL0, 1, 0), 192 SND_SOC_DAPM_DAC("DAC right", NULL, AUDIO_IC_CODEC_CTRL0, 0, 0), 193 SND_SOC_DAPM_SWITCH("Left dac to hp left amp", SND_SOC_NOPM, 0, 0, 194 &left_dac_to_hp_left_amp_switch_control), 195 SND_SOC_DAPM_SWITCH("Left dac to hp right amp", SND_SOC_NOPM, 0, 0, 196 &left_dac_to_hp_right_amp_switch_control), 197 SND_SOC_DAPM_SWITCH("Right dac to hp left amp", SND_SOC_NOPM, 0, 0, 198 &right_dac_to_hp_left_amp_switch_control), 199 SND_SOC_DAPM_SWITCH("Right dac to hp right amp", SND_SOC_NOPM, 0, 0, 200 &right_dac_to_hp_right_amp_switch_control), 201 SND_SOC_DAPM_OUT_DRV("HP amp left driver", AUDIO_IC_CODEC_CTRL0, 3, 0, 202 NULL, 0), 203 SND_SOC_DAPM_OUT_DRV("HP amp right driver", AUDIO_IC_CODEC_CTRL0, 3, 0, 204 NULL, 0), 205 206 SND_SOC_DAPM_SWITCH("Left dac to speaker lineout", SND_SOC_NOPM, 0, 0, 207 &left_dac_to_speaker_lineout_switch_control), 208 SND_SOC_DAPM_SWITCH("Right dac to speaker lineout", SND_SOC_NOPM, 0, 0, 209 &right_dac_to_speaker_lineout_switch_control), 210 SND_SOC_DAPM_OUT_DRV("Speaker amp driver", AUDIO_IC_CODEC_CTRL0, 4, 0, 211 NULL, 0), 212 213 SND_SOC_DAPM_OUTPUT("HPOUTL"), 214 SND_SOC_DAPM_OUTPUT("HPOUTR"), 215 SND_SOC_DAPM_OUTPUT("SPKOUT"), 216 217 SND_SOC_DAPM_ADC_E("ADC left", NULL, AUDIO_IC_CODEC_CTRL1, 8, 0, 218 adc_enable_delay_event, SND_SOC_DAPM_POST_PMU), 219 SND_SOC_DAPM_ADC_E("ADC right", NULL, AUDIO_IC_CODEC_CTRL1, 7, 0, 220 adc_enable_delay_event, SND_SOC_DAPM_POST_PMU), 221 SND_SOC_DAPM_MIXER("Left PGA mixer", AUDIO_IC_CODEC_CTRL1, 1, 0, 222 &left_input_path_controls[0], 223 ARRAY_SIZE(left_input_path_controls)), 224 SND_SOC_DAPM_MIXER("Right PGA mixer", AUDIO_IC_CODEC_CTRL1, 0, 0, 225 &right_input_path_controls[0], 226 ARRAY_SIZE(right_input_path_controls)), 227 228 SND_SOC_DAPM_MUX("Mic input mode mux", SND_SOC_NOPM, 0, 0, 229 &sirf_audio_codec_input_mode_control), 230 SND_SOC_DAPM_MICBIAS("Mic Bias", AUDIO_IC_CODEC_PWR, 3, 0), 231 SND_SOC_DAPM_INPUT("MICIN1"), 232 SND_SOC_DAPM_INPUT("MICIN2"), 233 SND_SOC_DAPM_INPUT("LINEIN1"), 234 SND_SOC_DAPM_INPUT("LINEIN2"), 235 236 SND_SOC_DAPM_SUPPLY("HSL Phase Opposite", AUDIO_IC_CODEC_CTRL0, 237 30, 0, NULL, 0), 238}; 239 240static const struct snd_soc_dapm_route sirf_audio_codec_map[] = { 241 {"SPKOUT", NULL, "Speaker Driver"}, 242 {"Speaker Driver", NULL, "Speaker amp driver"}, 243 {"Speaker amp driver", NULL, "Left dac to speaker lineout"}, 244 {"Speaker amp driver", NULL, "Right dac to speaker lineout"}, 245 {"Left dac to speaker lineout", "Switch", "DAC left"}, 246 {"Right dac to speaker lineout", "Switch", "DAC right"}, 247 {"HPOUTL", NULL, "HP Left Driver"}, 248 {"HPOUTR", NULL, "HP Right Driver"}, 249 {"HP Left Driver", NULL, "HP amp left driver"}, 250 {"HP Right Driver", NULL, "HP amp right driver"}, 251 {"HP amp left driver", NULL, "Right dac to hp left amp"}, 252 {"HP amp right driver", NULL , "Right dac to hp right amp"}, 253 {"HP amp left driver", NULL, "Left dac to hp left amp"}, 254 {"HP amp right driver", NULL , "Right dac to hp right amp"}, 255 {"Right dac to hp left amp", "Switch", "DAC left"}, 256 {"Right dac to hp right amp", "Switch", "DAC right"}, 257 {"Left dac to hp left amp", "Switch", "DAC left"}, 258 {"Left dac to hp right amp", "Switch", "DAC right"}, 259 {"DAC left", NULL, "codecclk"}, 260 {"DAC right", NULL, "codecclk"}, 261 {"DAC left", NULL, "Playback"}, 262 {"DAC right", NULL, "Playback"}, 263 {"DAC left", NULL, "HSL Phase Opposite"}, 264 {"DAC right", NULL, "HSL Phase Opposite"}, 265 266 {"Capture", NULL, "ADC left"}, 267 {"Capture", NULL, "ADC right"}, 268 {"ADC left", NULL, "codecclk"}, 269 {"ADC right", NULL, "codecclk"}, 270 {"ADC left", NULL, "Left PGA mixer"}, 271 {"ADC right", NULL, "Right PGA mixer"}, 272 {"Left PGA mixer", "Line Left Switch", "LINEIN2"}, 273 {"Right PGA mixer", "Line Right Switch", "LINEIN1"}, 274 {"Left PGA mixer", "Mic Left Switch", "MICIN2"}, 275 {"Right PGA mixer", "Mic Right Switch", "Mic input mode mux"}, 276 {"Mic input mode mux", "Single-ended", "MICIN1"}, 277 {"Mic input mode mux", "Differential", "MICIN1"}, 278}; 279 280static void sirf_audio_codec_tx_enable(struct sirf_audio_codec *sirf_audio_codec) 281{ 282 regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 283 AUDIO_FIFO_RESET, AUDIO_FIFO_RESET); 284 regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 285 AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET); 286 regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0); 287 regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0); 288 regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 289 AUDIO_FIFO_START, AUDIO_FIFO_START); 290 regmap_update_bits(sirf_audio_codec->regmap, 291 AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, IC_TX_ENABLE); 292} 293 294static void sirf_audio_codec_tx_disable(struct sirf_audio_codec *sirf_audio_codec) 295{ 296 regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0); 297 regmap_update_bits(sirf_audio_codec->regmap, 298 AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, ~IC_TX_ENABLE); 299} 300 301static void sirf_audio_codec_rx_enable(struct sirf_audio_codec *sirf_audio_codec, 302 int channels) 303{ 304 regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, 305 AUDIO_FIFO_RESET, AUDIO_FIFO_RESET); 306 regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, 307 AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET); 308 regmap_write(sirf_audio_codec->regmap, 309 AUDIO_PORT_IC_RXFIFO_INT_MSK, 0); 310 regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0); 311 regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, 312 AUDIO_FIFO_START, AUDIO_FIFO_START); 313 if (channels == 1) 314 regmap_update_bits(sirf_audio_codec->regmap, 315 AUDIO_PORT_IC_CODEC_RX_CTRL, 316 IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO); 317 else 318 regmap_update_bits(sirf_audio_codec->regmap, 319 AUDIO_PORT_IC_CODEC_RX_CTRL, 320 IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO); 321} 322 323static void sirf_audio_codec_rx_disable(struct sirf_audio_codec *sirf_audio_codec) 324{ 325 regmap_update_bits(sirf_audio_codec->regmap, 326 AUDIO_PORT_IC_CODEC_RX_CTRL, 327 IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO); 328} 329 330static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream, 331 int cmd, 332 struct snd_soc_dai *dai) 333{ 334 struct snd_soc_codec *codec = dai->codec; 335 struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec); 336 int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 337 338 /* 339 * This is a workaround, When stop playback, 340 * need disable HP amp, avoid the current noise. 341 */ 342 switch (cmd) { 343 case SNDRV_PCM_TRIGGER_STOP: 344 case SNDRV_PCM_TRIGGER_SUSPEND: 345 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 346 if (playback) { 347 snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0, 348 IC_HSLEN | IC_HSREN, 0); 349 sirf_audio_codec_tx_disable(sirf_audio_codec); 350 } else 351 sirf_audio_codec_rx_disable(sirf_audio_codec); 352 break; 353 case SNDRV_PCM_TRIGGER_START: 354 case SNDRV_PCM_TRIGGER_RESUME: 355 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 356 if (playback) { 357 sirf_audio_codec_tx_enable(sirf_audio_codec); 358 snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0, 359 IC_HSLEN | IC_HSREN, IC_HSLEN | IC_HSREN); 360 } else 361 sirf_audio_codec_rx_enable(sirf_audio_codec, 362 substream->runtime->channels); 363 break; 364 default: 365 return -EINVAL; 366 } 367 368 return 0; 369} 370 371struct snd_soc_dai_ops sirf_audio_codec_dai_ops = { 372 .trigger = sirf_audio_codec_trigger, 373}; 374 375struct snd_soc_dai_driver sirf_audio_codec_dai = { 376 .name = "sirf-audio-codec", 377 .playback = { 378 .stream_name = "Playback", 379 .channels_min = 2, 380 .channels_max = 2, 381 .rates = SNDRV_PCM_RATE_48000, 382 .formats = SNDRV_PCM_FMTBIT_S16_LE, 383 }, 384 .capture = { 385 .stream_name = "Capture", 386 .channels_min = 1, 387 .channels_max = 2, 388 .rates = SNDRV_PCM_RATE_48000, 389 .formats = SNDRV_PCM_FMTBIT_S16_LE, 390 }, 391 .ops = &sirf_audio_codec_dai_ops, 392}; 393 394static int sirf_audio_codec_probe(struct snd_soc_codec *codec) 395{ 396 struct snd_soc_dapm_context *dapm = &codec->dapm; 397 398 pm_runtime_enable(codec->dev); 399 400 if (of_device_is_compatible(codec->dev->of_node, "sirf,prima2-audio-codec")) { 401 snd_soc_dapm_new_controls(dapm, 402 prima2_output_driver_dapm_widgets, 403 ARRAY_SIZE(prima2_output_driver_dapm_widgets)); 404 snd_soc_dapm_new_controls(dapm, 405 &prima2_codec_clock_dapm_widget, 1); 406 return snd_soc_add_codec_controls(codec, 407 volume_controls_prima2, 408 ARRAY_SIZE(volume_controls_prima2)); 409 } 410 if (of_device_is_compatible(codec->dev->of_node, "sirf,atlas6-audio-codec")) { 411 snd_soc_dapm_new_controls(dapm, 412 atlas6_output_driver_dapm_widgets, 413 ARRAY_SIZE(atlas6_output_driver_dapm_widgets)); 414 snd_soc_dapm_new_controls(dapm, 415 &atlas6_codec_clock_dapm_widget, 1); 416 return snd_soc_add_codec_controls(codec, 417 volume_controls_atlas6, 418 ARRAY_SIZE(volume_controls_atlas6)); 419 } 420 421 return -EINVAL; 422} 423 424static int sirf_audio_codec_remove(struct snd_soc_codec *codec) 425{ 426 pm_runtime_disable(codec->dev); 427 return 0; 428} 429 430static struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = { 431 .probe = sirf_audio_codec_probe, 432 .remove = sirf_audio_codec_remove, 433 .dapm_widgets = sirf_audio_codec_dapm_widgets, 434 .num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets), 435 .dapm_routes = sirf_audio_codec_map, 436 .num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map), 437 .idle_bias_off = true, 438}; 439 440static const struct of_device_id sirf_audio_codec_of_match[] = { 441 { .compatible = "sirf,prima2-audio-codec" }, 442 { .compatible = "sirf,atlas6-audio-codec" }, 443 {} 444}; 445MODULE_DEVICE_TABLE(of, sirf_audio_codec_of_match); 446 447static const struct regmap_config sirf_audio_codec_regmap_config = { 448 .reg_bits = 32, 449 .reg_stride = 4, 450 .val_bits = 32, 451 .max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK, 452 .cache_type = REGCACHE_NONE, 453}; 454 455static int sirf_audio_codec_driver_probe(struct platform_device *pdev) 456{ 457 int ret; 458 struct sirf_audio_codec *sirf_audio_codec; 459 void __iomem *base; 460 struct resource *mem_res; 461 const struct of_device_id *match; 462 463 match = of_match_node(sirf_audio_codec_of_match, pdev->dev.of_node); 464 465 sirf_audio_codec = devm_kzalloc(&pdev->dev, 466 sizeof(struct sirf_audio_codec), GFP_KERNEL); 467 if (!sirf_audio_codec) 468 return -ENOMEM; 469 470 platform_set_drvdata(pdev, sirf_audio_codec); 471 472 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 473 base = devm_ioremap_resource(&pdev->dev, mem_res); 474 if (base == NULL) 475 return -ENOMEM; 476 477 sirf_audio_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base, 478 &sirf_audio_codec_regmap_config); 479 if (IS_ERR(sirf_audio_codec->regmap)) 480 return PTR_ERR(sirf_audio_codec->regmap); 481 482 sirf_audio_codec->clk = devm_clk_get(&pdev->dev, NULL); 483 if (IS_ERR(sirf_audio_codec->clk)) { 484 dev_err(&pdev->dev, "Get clock failed.\n"); 485 return PTR_ERR(sirf_audio_codec->clk); 486 } 487 488 ret = clk_prepare_enable(sirf_audio_codec->clk); 489 if (ret) { 490 dev_err(&pdev->dev, "Enable clock failed.\n"); 491 return ret; 492 } 493 494 ret = snd_soc_register_codec(&(pdev->dev), 495 &soc_codec_device_sirf_audio_codec, 496 &sirf_audio_codec_dai, 1); 497 if (ret) { 498 dev_err(&pdev->dev, "Register Audio Codec dai failed.\n"); 499 goto err_clk_put; 500 } 501 502 /* 503 * Always open charge pump, if not, when the charge pump closed the 504 * adc will not stable 505 */ 506 regmap_update_bits(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0, 507 IC_CPFREQ, IC_CPFREQ); 508 509 if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas6-audio-codec")) 510 regmap_update_bits(sirf_audio_codec->regmap, 511 AUDIO_IC_CODEC_CTRL0, IC_CPEN, IC_CPEN); 512 return 0; 513 514err_clk_put: 515 clk_disable_unprepare(sirf_audio_codec->clk); 516 return ret; 517} 518 519static int sirf_audio_codec_driver_remove(struct platform_device *pdev) 520{ 521 struct sirf_audio_codec *sirf_audio_codec = platform_get_drvdata(pdev); 522 523 clk_disable_unprepare(sirf_audio_codec->clk); 524 snd_soc_unregister_codec(&(pdev->dev)); 525 526 return 0; 527} 528 529#ifdef CONFIG_PM_SLEEP 530static int sirf_audio_codec_suspend(struct device *dev) 531{ 532 struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev); 533 534 regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0, 535 &sirf_audio_codec->reg_ctrl0); 536 regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1, 537 &sirf_audio_codec->reg_ctrl1); 538 clk_disable_unprepare(sirf_audio_codec->clk); 539 540 return 0; 541} 542 543static int sirf_audio_codec_resume(struct device *dev) 544{ 545 struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev); 546 int ret; 547 548 ret = clk_prepare_enable(sirf_audio_codec->clk); 549 if (ret) 550 return ret; 551 552 regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0, 553 sirf_audio_codec->reg_ctrl0); 554 regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1, 555 sirf_audio_codec->reg_ctrl1); 556 557 return 0; 558} 559#endif 560 561static const struct dev_pm_ops sirf_audio_codec_pm_ops = { 562 SET_SYSTEM_SLEEP_PM_OPS(sirf_audio_codec_suspend, sirf_audio_codec_resume) 563}; 564 565static struct platform_driver sirf_audio_codec_driver = { 566 .driver = { 567 .name = "sirf-audio-codec", 568 .owner = THIS_MODULE, 569 .of_match_table = sirf_audio_codec_of_match, 570 .pm = &sirf_audio_codec_pm_ops, 571 }, 572 .probe = sirf_audio_codec_driver_probe, 573 .remove = sirf_audio_codec_driver_remove, 574}; 575 576module_platform_driver(sirf_audio_codec_driver); 577 578MODULE_DESCRIPTION("SiRF audio codec driver"); 579MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>"); 580MODULE_LICENSE("GPL v2");