14bb3f43cSMark Brown /* 24bb3f43cSMark Brown * Driver for the 1250-EV1 audio I/O module 34bb3f43cSMark Brown * 44bb3f43cSMark Brown * Copyright 2011 Wolfson Microelectronics plc 54bb3f43cSMark Brown * 64bb3f43cSMark Brown * This program is free software; you can redistribute it and/or modify it 74bb3f43cSMark Brown * under the terms of the GNU General Public License as published by the 84bb3f43cSMark Brown * Free Software Foundation; either version 2 of the License, or (at your 94bb3f43cSMark Brown * option) any later version. 104bb3f43cSMark Brown * 114bb3f43cSMark Brown */ 124bb3f43cSMark Brown 134bb3f43cSMark Brown #include <linux/init.h> 144bb3f43cSMark Brown #include <linux/module.h> 154bb3f43cSMark Brown #include <linux/i2c.h> 164bb3f43cSMark Brown 174bb3f43cSMark Brown #include <sound/soc.h> 184bb3f43cSMark Brown #include <sound/soc-dapm.h> 194bb3f43cSMark Brown 204bb3f43cSMark Brown static const struct snd_soc_dapm_widget wm1250_ev1_dapm_widgets[] = { 214bb3f43cSMark Brown SND_SOC_DAPM_ADC("ADC", "wm1250-ev1 Capture", SND_SOC_NOPM, 0, 0), 224bb3f43cSMark Brown SND_SOC_DAPM_DAC("DAC", "wm1250-ev1 Playback", SND_SOC_NOPM, 0, 0), 234bb3f43cSMark Brown 244bb3f43cSMark Brown SND_SOC_DAPM_INPUT("WM1250 Input"), 25979f4869SAxel Lin SND_SOC_DAPM_OUTPUT("WM1250 Output"), 264bb3f43cSMark Brown }; 274bb3f43cSMark Brown 284bb3f43cSMark Brown static const struct snd_soc_dapm_route wm1250_ev1_dapm_routes[] = { 294bb3f43cSMark Brown { "ADC", NULL, "WM1250 Input" }, 304bb3f43cSMark Brown { "WM1250 Output", NULL, "DAC" }, 314bb3f43cSMark Brown }; 324bb3f43cSMark Brown 334bb3f43cSMark Brown static struct snd_soc_dai_driver wm1250_ev1_dai = { 344bb3f43cSMark Brown .name = "wm1250-ev1", 354bb3f43cSMark Brown .playback = { 364bb3f43cSMark Brown .stream_name = "Playback", 374bb3f43cSMark Brown .channels_min = 1, 384bb3f43cSMark Brown .channels_max = 1, 394bb3f43cSMark Brown .rates = SNDRV_PCM_RATE_8000, 404bb3f43cSMark Brown .formats = SNDRV_PCM_FMTBIT_S16_LE, 414bb3f43cSMark Brown }, 424bb3f43cSMark Brown .capture = { 434bb3f43cSMark Brown .stream_name = "Capture", 444bb3f43cSMark Brown .channels_min = 1, 454bb3f43cSMark Brown .channels_max = 1, 464bb3f43cSMark Brown .rates = SNDRV_PCM_RATE_8000, 474bb3f43cSMark Brown .formats = SNDRV_PCM_FMTBIT_S16_LE, 484bb3f43cSMark Brown }, 494bb3f43cSMark Brown }; 504bb3f43cSMark Brown 514bb3f43cSMark Brown static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = { 524bb3f43cSMark Brown .dapm_widgets = wm1250_ev1_dapm_widgets, 534bb3f43cSMark Brown .num_dapm_widgets = ARRAY_SIZE(wm1250_ev1_dapm_widgets), 544bb3f43cSMark Brown .dapm_routes = wm1250_ev1_dapm_routes, 554bb3f43cSMark Brown .num_dapm_routes = ARRAY_SIZE(wm1250_ev1_dapm_routes), 564bb3f43cSMark Brown }; 574bb3f43cSMark Brown 584bb3f43cSMark Brown static int __devinit wm1250_ev1_probe(struct i2c_client *i2c, 59*eaefb38fSMark Brown const struct i2c_device_id *i2c_id) 604bb3f43cSMark Brown { 61*eaefb38fSMark Brown int ret, id, board, rev; 62*eaefb38fSMark Brown 63*eaefb38fSMark Brown board = i2c_smbus_read_byte_data(i2c, 0); 64*eaefb38fSMark Brown if (board < 0) { 65*eaefb38fSMark Brown dev_err(&i2c->dev, "Failed to read ID: %d\n", ret); 66*eaefb38fSMark Brown return ret; 67*eaefb38fSMark Brown } 68*eaefb38fSMark Brown 69*eaefb38fSMark Brown id = (board & 0xfe) >> 2; 70*eaefb38fSMark Brown rev = board & 0x3; 71*eaefb38fSMark Brown 72*eaefb38fSMark Brown if (id != 1) { 73*eaefb38fSMark Brown dev_err(&i2c->dev, "Unknown board ID %d\n", id); 74*eaefb38fSMark Brown return -ENODEV; 75*eaefb38fSMark Brown } 76*eaefb38fSMark Brown 77*eaefb38fSMark Brown dev_info(&i2c->dev, "revision %d\n", rev); 78*eaefb38fSMark Brown 794bb3f43cSMark Brown return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1, 804bb3f43cSMark Brown &wm1250_ev1_dai, 1); 814bb3f43cSMark Brown } 824bb3f43cSMark Brown 834bb3f43cSMark Brown static int __devexit wm1250_ev1_remove(struct i2c_client *i2c) 844bb3f43cSMark Brown { 854bb3f43cSMark Brown snd_soc_unregister_codec(&i2c->dev); 864bb3f43cSMark Brown 874bb3f43cSMark Brown return 0; 884bb3f43cSMark Brown } 894bb3f43cSMark Brown 904bb3f43cSMark Brown static const struct i2c_device_id wm1250_ev1_i2c_id[] = { 914bb3f43cSMark Brown { "wm1250-ev1", 0 }, 924bb3f43cSMark Brown { } 934bb3f43cSMark Brown }; 94420dd718SMark Brown MODULE_DEVICE_TABLE(i2c, wm1250_ev1_i2c_id); 954bb3f43cSMark Brown 964bb3f43cSMark Brown static struct i2c_driver wm1250_ev1_i2c_driver = { 974bb3f43cSMark Brown .driver = { 984bb3f43cSMark Brown .name = "wm1250-ev1", 994bb3f43cSMark Brown .owner = THIS_MODULE, 1004bb3f43cSMark Brown }, 1014bb3f43cSMark Brown .probe = wm1250_ev1_probe, 1024bb3f43cSMark Brown .remove = __devexit_p(wm1250_ev1_remove), 1034bb3f43cSMark Brown .id_table = wm1250_ev1_i2c_id, 1044bb3f43cSMark Brown }; 1054bb3f43cSMark Brown 1064bb3f43cSMark Brown static int __init wm1250_ev1_modinit(void) 1074bb3f43cSMark Brown { 1084bb3f43cSMark Brown int ret = 0; 1094bb3f43cSMark Brown 1104bb3f43cSMark Brown ret = i2c_add_driver(&wm1250_ev1_i2c_driver); 1114bb3f43cSMark Brown if (ret != 0) 1124bb3f43cSMark Brown pr_err("Failed to register WM1250-EV1 I2C driver: %d\n", ret); 1134bb3f43cSMark Brown 1144bb3f43cSMark Brown return ret; 1154bb3f43cSMark Brown } 1164bb3f43cSMark Brown module_init(wm1250_ev1_modinit); 1174bb3f43cSMark Brown 1184bb3f43cSMark Brown static void __exit wm1250_ev1_exit(void) 1194bb3f43cSMark Brown { 1204bb3f43cSMark Brown i2c_del_driver(&wm1250_ev1_i2c_driver); 1214bb3f43cSMark Brown } 1224bb3f43cSMark Brown module_exit(wm1250_ev1_exit); 1234bb3f43cSMark Brown 1244bb3f43cSMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 1254bb3f43cSMark Brown MODULE_DESCRIPTION("WM1250-EV1 audio I/O module driver"); 1264bb3f43cSMark Brown MODULE_LICENSE("GPL"); 127