12dcf9fb9SGraeme Gregory /* 22dcf9fb9SGraeme Gregory * ads117x.c -- Driver for ads1174/8 ADC chips 32dcf9fb9SGraeme Gregory * 42dcf9fb9SGraeme Gregory * Copyright 2009 ShotSpotter Inc. 52dcf9fb9SGraeme Gregory * Author: Graeme Gregory <gg@slimlogic.co.uk> 62dcf9fb9SGraeme Gregory * 72dcf9fb9SGraeme Gregory * This program is free software; you can redistribute it and/or modify it 82dcf9fb9SGraeme Gregory * under the terms of the GNU General Public License as published by the 92dcf9fb9SGraeme Gregory * Free Software Foundation; either version 2 of the License, or (at your 102dcf9fb9SGraeme Gregory * option) any later version. 112dcf9fb9SGraeme Gregory */ 122dcf9fb9SGraeme Gregory 132dcf9fb9SGraeme Gregory #include <linux/kernel.h> 14*5a0e3ad6STejun Heo #include <linux/slab.h> 152dcf9fb9SGraeme Gregory #include <linux/init.h> 162dcf9fb9SGraeme Gregory #include <linux/device.h> 172dcf9fb9SGraeme Gregory #include <sound/core.h> 182dcf9fb9SGraeme Gregory #include <sound/pcm.h> 192dcf9fb9SGraeme Gregory #include <sound/initval.h> 202dcf9fb9SGraeme Gregory #include <sound/soc.h> 212dcf9fb9SGraeme Gregory 222dcf9fb9SGraeme Gregory #include "ads117x.h" 232dcf9fb9SGraeme Gregory 242dcf9fb9SGraeme Gregory #define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000) 252dcf9fb9SGraeme Gregory 262dcf9fb9SGraeme Gregory #define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) 272dcf9fb9SGraeme Gregory 282dcf9fb9SGraeme Gregory struct snd_soc_dai ads117x_dai = { 292dcf9fb9SGraeme Gregory /* ADC */ 302dcf9fb9SGraeme Gregory .name = "ADS117X ADC", 312dcf9fb9SGraeme Gregory .id = 1, 322dcf9fb9SGraeme Gregory .capture = { 332dcf9fb9SGraeme Gregory .stream_name = "Capture", 342dcf9fb9SGraeme Gregory .channels_min = 1, 352dcf9fb9SGraeme Gregory .channels_max = 32, 362dcf9fb9SGraeme Gregory .rates = ADS117X_RATES, 372dcf9fb9SGraeme Gregory .formats = ADS117X_FORMATS,}, 382dcf9fb9SGraeme Gregory }; 392dcf9fb9SGraeme Gregory EXPORT_SYMBOL_GPL(ads117x_dai); 402dcf9fb9SGraeme Gregory 412dcf9fb9SGraeme Gregory static int ads117x_probe(struct platform_device *pdev) 422dcf9fb9SGraeme Gregory { 432dcf9fb9SGraeme Gregory struct snd_soc_device *socdev = platform_get_drvdata(pdev); 442dcf9fb9SGraeme Gregory struct snd_soc_codec *codec; 452dcf9fb9SGraeme Gregory int ret; 462dcf9fb9SGraeme Gregory 472dcf9fb9SGraeme Gregory codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); 482dcf9fb9SGraeme Gregory if (codec == NULL) 492dcf9fb9SGraeme Gregory return -ENOMEM; 502dcf9fb9SGraeme Gregory 512dcf9fb9SGraeme Gregory socdev->card->codec = codec; 522dcf9fb9SGraeme Gregory mutex_init(&codec->mutex); 532dcf9fb9SGraeme Gregory INIT_LIST_HEAD(&codec->dapm_widgets); 542dcf9fb9SGraeme Gregory INIT_LIST_HEAD(&codec->dapm_paths); 55f3d0e82fSMark Brown codec->name = "ADS117X"; 56f3d0e82fSMark Brown codec->owner = THIS_MODULE; 57f3d0e82fSMark Brown codec->dai = &ads117x_dai; 58f3d0e82fSMark Brown codec->num_dai = 1; 592dcf9fb9SGraeme Gregory 60f3d0e82fSMark Brown /* register pcms */ 61f3d0e82fSMark Brown ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 62f3d0e82fSMark Brown if (ret < 0) { 63f3d0e82fSMark Brown printk(KERN_ERR "ads117x: failed to create pcms\n"); 642dcf9fb9SGraeme Gregory kfree(codec); 652dcf9fb9SGraeme Gregory return ret; 662dcf9fb9SGraeme Gregory } 672dcf9fb9SGraeme Gregory 68f3d0e82fSMark Brown return 0; 69f3d0e82fSMark Brown } 70f3d0e82fSMark Brown 712dcf9fb9SGraeme Gregory static int ads117x_remove(struct platform_device *pdev) 722dcf9fb9SGraeme Gregory { 732dcf9fb9SGraeme Gregory struct snd_soc_device *socdev = platform_get_drvdata(pdev); 742dcf9fb9SGraeme Gregory struct snd_soc_codec *codec = socdev->card->codec; 752dcf9fb9SGraeme Gregory 762dcf9fb9SGraeme Gregory snd_soc_free_pcms(socdev); 772dcf9fb9SGraeme Gregory kfree(codec); 782dcf9fb9SGraeme Gregory 792dcf9fb9SGraeme Gregory return 0; 802dcf9fb9SGraeme Gregory } 812dcf9fb9SGraeme Gregory 822dcf9fb9SGraeme Gregory struct snd_soc_codec_device soc_codec_dev_ads117x = { 832dcf9fb9SGraeme Gregory .probe = ads117x_probe, 842dcf9fb9SGraeme Gregory .remove = ads117x_remove, 852dcf9fb9SGraeme Gregory }; 862dcf9fb9SGraeme Gregory EXPORT_SYMBOL_GPL(soc_codec_dev_ads117x); 872dcf9fb9SGraeme Gregory 88f3d0e82fSMark Brown static __devinit int ads117x_platform_probe(struct platform_device *pdev) 892dcf9fb9SGraeme Gregory { 90f3d0e82fSMark Brown ads117x_dai.dev = &pdev->dev; 912dcf9fb9SGraeme Gregory return snd_soc_register_dai(&ads117x_dai); 922dcf9fb9SGraeme Gregory } 93f3d0e82fSMark Brown 94f3d0e82fSMark Brown static int __devexit ads117x_platform_remove(struct platform_device *pdev) 95f3d0e82fSMark Brown { 96f3d0e82fSMark Brown snd_soc_unregister_dai(&ads117x_dai); 97f3d0e82fSMark Brown return 0; 98f3d0e82fSMark Brown } 99f3d0e82fSMark Brown 100f3d0e82fSMark Brown static struct platform_driver ads117x_codec_driver = { 101f3d0e82fSMark Brown .driver = { 102f3d0e82fSMark Brown .name = "ads117x", 103f3d0e82fSMark Brown .owner = THIS_MODULE, 104f3d0e82fSMark Brown }, 105f3d0e82fSMark Brown 106f3d0e82fSMark Brown .probe = ads117x_platform_probe, 107f3d0e82fSMark Brown .remove = __devexit_p(ads117x_platform_remove), 108f3d0e82fSMark Brown }; 109f3d0e82fSMark Brown 110f3d0e82fSMark Brown static int __init ads117x_init(void) 111f3d0e82fSMark Brown { 112f3d0e82fSMark Brown return platform_driver_register(&ads117x_codec_driver); 113f3d0e82fSMark Brown } 114f3d0e82fSMark Brown module_init(ads117x_init); 1152dcf9fb9SGraeme Gregory 1162dcf9fb9SGraeme Gregory static void __exit ads117x_exit(void) 1172dcf9fb9SGraeme Gregory { 118f3d0e82fSMark Brown platform_driver_unregister(&ads117x_codec_driver); 1192dcf9fb9SGraeme Gregory } 1202dcf9fb9SGraeme Gregory module_exit(ads117x_exit); 1212dcf9fb9SGraeme Gregory 1222dcf9fb9SGraeme Gregory MODULE_DESCRIPTION("ASoC ads117x driver"); 1232dcf9fb9SGraeme Gregory MODULE_AUTHOR("Graeme Gregory"); 1242dcf9fb9SGraeme Gregory MODULE_LICENSE("GPL"); 125