^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * osk5912.c -- SoC audio for OSK 5912
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2008 Mistral Solutions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Contact: Arun KS <arunks@mistralsolutions.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/mach-types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/platform_data/asoc-ti-mcbsp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "omap-mcbsp.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "../codecs/tlv320aic23.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define CODEC_CLOCK 12000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static struct clk *tlv320aic23_mclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static int osk_startup(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) return clk_enable(tlv320aic23_mclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static void osk_shutdown(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) clk_disable(tlv320aic23_mclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static int osk_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct snd_pcm_hw_params *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* Set the codec system clock for DAC and ADC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) err =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) printk(KERN_ERR "can't set codec system clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static const struct snd_soc_ops osk_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) .startup = osk_startup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) .hw_params = osk_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) .shutdown = osk_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) SND_SOC_DAPM_HP("Headphone Jack", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) SND_SOC_DAPM_LINE("Line In", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) SND_SOC_DAPM_MIC("Mic Jack", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static const struct snd_soc_dapm_route audio_map[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {"Headphone Jack", NULL, "LHPOUT"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {"Headphone Jack", NULL, "RHPOUT"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {"LLINEIN", NULL, "Line In"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {"RLINEIN", NULL, "Line In"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {"MICIN", NULL, "Mic Jack"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* Digital audio interface glue - connects codec <--> CPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) SND_SOC_DAILINK_DEFS(aic23,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) DAILINK_COMP_ARRAY(COMP_CPU("omap-mcbsp.1")),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic23-codec",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) "tlv320aic23-hifi")),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) DAILINK_COMP_ARRAY(COMP_PLATFORM("omap-mcbsp.1")));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static struct snd_soc_dai_link osk_dai = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) .name = "TLV320AIC23",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) .stream_name = "AIC23",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) SND_SOC_DAIFMT_CBM_CFM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) .ops = &osk_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) SND_SOC_DAILINK_REG(aic23),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /* Audio machine driver */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static struct snd_soc_card snd_soc_card_osk = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .name = "OSK5912",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .dai_link = &osk_dai,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .num_links = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .dapm_widgets = tlv320aic23_dapm_widgets,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .dapm_routes = audio_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .num_dapm_routes = ARRAY_SIZE(audio_map),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static struct platform_device *osk_snd_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static int __init osk_soc_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) u32 curRate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (!(machine_is_omap_osk()))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) osk_snd_device = platform_device_alloc("soc-audio", -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (!osk_snd_device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) platform_set_drvdata(osk_snd_device, &snd_soc_card_osk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) err = platform_device_add(osk_snd_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) goto err1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) dev = &osk_snd_device->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) tlv320aic23_mclk = clk_get(dev, "mclk");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (IS_ERR(tlv320aic23_mclk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) printk(KERN_ERR "Could not get mclk clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) err = PTR_ERR(tlv320aic23_mclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) goto err2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * Configure 12 MHz output on MCLK.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) curRate = (uint) clk_get_rate(tlv320aic23_mclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (curRate != CODEC_CLOCK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) err = -ECANCELED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) goto err3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) printk(KERN_INFO "MCLK = %d [%d]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) err3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) clk_put(tlv320aic23_mclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) err2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) platform_device_del(osk_snd_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) err1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) platform_device_put(osk_snd_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static void __exit osk_soc_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) clk_put(tlv320aic23_mclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) platform_device_unregister(osk_snd_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) module_init(osk_soc_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) module_exit(osk_soc_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) MODULE_DESCRIPTION("ALSA SoC OSK 5912");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) MODULE_LICENSE("GPL");