Commit c26f642e2683fb1a367686bc0bac9f5947885cb6

Authored by Dmitry Artamonow
Committed by Mark Brown
1 parent 00d2701070

ASoC: add iPAQ hx4700 machine driver

AK4641 connected via I2S and I2C, jack detection via GPIO.

Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
Signed-off-by: Dmitry Artamonow <mad_soft@inbox.ru>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>

Showing 3 changed files with 266 additions and 0 deletions Side-by-side Diff

sound/soc/pxa/Kconfig
... ... @@ -155,6 +155,15 @@
155 155 help
156 156 Say Y if you want to add support for SoC audio on Raumfeld devices
157 157  
  158 +config SND_PXA2XX_SOC_HX4700
  159 + tristate "SoC Audio support for HP iPAQ hx4700"
  160 + depends on SND_PXA2XX_SOC && MACH_H4700
  161 + select SND_PXA2XX_SOC_I2S
  162 + select SND_SOC_AK4641
  163 + help
  164 + Say Y if you want to add support for SoC audio on the
  165 + HP iPAQ hx4700.
  166 +
158 167 config SND_PXA2XX_SOC_MAGICIAN
159 168 tristate "SoC Audio support for HTC Magician"
160 169 depends on SND_PXA2XX_SOC && MACH_MAGICIAN
sound/soc/pxa/Makefile
... ... @@ -22,6 +22,7 @@
22 22 snd-soc-saarb-objs := saarb.o
23 23 snd-soc-tavorevb3-objs := tavorevb3.o
24 24 snd-soc-zylonite-objs := zylonite.o
  25 +snd-soc-hx4700-objs := hx4700.o
25 26 snd-soc-magician-objs := magician.o
26 27 snd-soc-mioa701-objs := mioa701_wm9713.o
27 28 snd-soc-z2-objs := z2.o
... ... @@ -37,6 +38,7 @@
37 38 obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
38 39 obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
39 40 obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
  41 +obj-$(CONFIG_SND_PXA2XX_SOC_HX4700) += snd-soc-hx4700.o
40 42 obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
41 43 obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
42 44 obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
sound/soc/pxa/hx4700.c
  1 +/*
  2 + * SoC audio for HP iPAQ hx4700
  3 + *
  4 + * Copyright (c) 2009 Philipp Zabel
  5 + *
  6 + * This program is free software; you can redistribute it and/or modify it
  7 + * under the terms of the GNU General Public License as published by the
  8 + * Free Software Foundation; either version 2 of the License, or (at your
  9 + * option) any later version.
  10 + *
  11 + */
  12 +
  13 +#include <linux/module.h>
  14 +#include <linux/timer.h>
  15 +#include <linux/interrupt.h>
  16 +#include <linux/platform_device.h>
  17 +#include <linux/delay.h>
  18 +#include <linux/gpio.h>
  19 +
  20 +#include <sound/core.h>
  21 +#include <sound/jack.h>
  22 +#include <sound/pcm.h>
  23 +#include <sound/pcm_params.h>
  24 +#include <sound/soc.h>
  25 +
  26 +#include <mach/hx4700.h>
  27 +#include <asm/mach-types.h>
  28 +#include "pxa2xx-i2s.h"
  29 +
  30 +#include "../codecs/ak4641.h"
  31 +
  32 +static struct snd_soc_jack hs_jack;
  33 +
  34 +/* Headphones jack detection DAPM pin */
  35 +static struct snd_soc_jack_pin hs_jack_pin[] = {
  36 + {
  37 + .pin = "Headphone Jack",
  38 + .mask = SND_JACK_HEADPHONE,
  39 + },
  40 + {
  41 + .pin = "Speaker",
  42 + /* disable speaker when hp jack is inserted */
  43 + .mask = SND_JACK_HEADPHONE,
  44 + .invert = 1,
  45 + },
  46 +};
  47 +
  48 +/* Headphones jack detection GPIO */
  49 +static struct snd_soc_jack_gpio hs_jack_gpio = {
  50 + .gpio = GPIO75_HX4700_EARPHONE_nDET,
  51 + .invert = true,
  52 + .name = "hp-gpio",
  53 + .report = SND_JACK_HEADPHONE,
  54 + .debounce_time = 200,
  55 +};
  56 +
  57 +/*
  58 + * iPAQ hx4700 uses I2S for capture and playback.
  59 + */
  60 +static int hx4700_hw_params(struct snd_pcm_substream *substream,
  61 + struct snd_pcm_hw_params *params)
  62 +{
  63 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
  64 + struct snd_soc_dai *codec_dai = rtd->codec_dai;
  65 + struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  66 + int ret = 0;
  67 +
  68 + /* set codec DAI configuration */
  69 + ret = snd_soc_dai_set_fmt(codec_dai,
  70 + SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
  71 + SND_SOC_DAIFMT_CBS_CFS);
  72 + if (ret < 0)
  73 + return ret;
  74 +
  75 + /* set cpu DAI configuration */
  76 + ret = snd_soc_dai_set_fmt(cpu_dai,
  77 + SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
  78 + SND_SOC_DAIFMT_CBS_CFS);
  79 + if (ret < 0)
  80 + return ret;
  81 +
  82 + /* set the I2S system clock as output */
  83 + ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
  84 + SND_SOC_CLOCK_OUT);
  85 + if (ret < 0)
  86 + return ret;
  87 +
  88 + /* inform codec driver about clock freq *
  89 + * (PXA I2S always uses divider 256) */
  90 + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 256 * params_rate(params),
  91 + SND_SOC_CLOCK_IN);
  92 + if (ret < 0)
  93 + return ret;
  94 +
  95 + return 0;
  96 +}
  97 +
  98 +static struct snd_soc_ops hx4700_ops = {
  99 + .hw_params = hx4700_hw_params,
  100 +};
  101 +
  102 +static int hx4700_spk_power(struct snd_soc_dapm_widget *w,
  103 + struct snd_kcontrol *k, int event)
  104 +{
  105 + gpio_set_value(GPIO107_HX4700_SPK_nSD, !!SND_SOC_DAPM_EVENT_ON(event));
  106 + return 0;
  107 +}
  108 +
  109 +static int hx4700_hp_power(struct snd_soc_dapm_widget *w,
  110 + struct snd_kcontrol *k, int event)
  111 +{
  112 + gpio_set_value(GPIO92_HX4700_HP_DRIVER, !!SND_SOC_DAPM_EVENT_ON(event));
  113 + return 0;
  114 +}
  115 +
  116 +/* hx4700 machine dapm widgets */
  117 +static const struct snd_soc_dapm_widget hx4700_dapm_widgets[] = {
  118 + SND_SOC_DAPM_HP("Headphone Jack", hx4700_hp_power),
  119 + SND_SOC_DAPM_SPK("Speaker", hx4700_spk_power),
  120 + SND_SOC_DAPM_MIC("Built-in Microphone", NULL),
  121 +};
  122 +
  123 +/* hx4700 machine audio_map */
  124 +static const struct snd_soc_dapm_route hx4700_audio_map[] = {
  125 +
  126 + /* Headphone connected to LOUT, ROUT */
  127 + {"Headphone Jack", NULL, "LOUT"},
  128 + {"Headphone Jack", NULL, "ROUT"},
  129 +
  130 + /* Speaker connected to MOUT2 */
  131 + {"Speaker", NULL, "MOUT2"},
  132 +
  133 + /* Microphone connected to MICIN */
  134 + {"MICIN", NULL, "Built-in Microphone"},
  135 + {"AIN", NULL, "MICOUT"},
  136 +};
  137 +
  138 +/*
  139 + * Logic for a ak4641 as connected on a HP iPAQ hx4700
  140 + */
  141 +static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
  142 +{
  143 + struct snd_soc_codec *codec = rtd->codec;
  144 + struct snd_soc_dapm_context *dapm = &codec->dapm;
  145 + int err;
  146 +
  147 + /* NC codec pins */
  148 + /* FIXME: is anything connected here? */
  149 + snd_soc_dapm_nc_pin(dapm, "MOUT1");
  150 + snd_soc_dapm_nc_pin(dapm, "MICEXT");
  151 + snd_soc_dapm_nc_pin(dapm, "AUX");
  152 +
  153 + /* Jack detection API stuff */
  154 + err = snd_soc_jack_new(codec, "Headphone Jack",
  155 + SND_JACK_HEADPHONE, &hs_jack);
  156 + if (err)
  157 + return err;
  158 +
  159 + err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pin),
  160 + hs_jack_pin);
  161 + if (err)
  162 + return err;
  163 +
  164 + err = snd_soc_jack_add_gpios(&hs_jack, 1, &hs_jack_gpio);
  165 +
  166 + return err;
  167 +}
  168 +
  169 +/* hx4700 digital audio interface glue - connects codec <--> CPU */
  170 +static struct snd_soc_dai_link hx4700_dai = {
  171 + .name = "ak4641",
  172 + .stream_name = "AK4641",
  173 + .cpu_dai_name = "pxa2xx-i2s",
  174 + .codec_dai_name = "ak4641-hifi",
  175 + .platform_name = "pxa-pcm-audio",
  176 + .codec_name = "ak4641.0-0012",
  177 + .init = hx4700_ak4641_init,
  178 + .ops = &hx4700_ops,
  179 +};
  180 +
  181 +/* hx4700 audio machine driver */
  182 +static struct snd_soc_card snd_soc_card_hx4700 = {
  183 + .name = "iPAQ hx4700",
  184 + .dai_link = &hx4700_dai,
  185 + .num_links = 1,
  186 + .dapm_widgets = hx4700_dapm_widgets,
  187 + .num_dapm_widgets = ARRAY_SIZE(hx4700_dapm_widgets),
  188 + .dapm_routes = hx4700_audio_map,
  189 + .num_dapm_routes = ARRAY_SIZE(hx4700_audio_map),
  190 +};
  191 +
  192 +static struct gpio hx4700_audio_gpios[] = {
  193 + { GPIO107_HX4700_SPK_nSD, GPIOF_OUT_INIT_HIGH, "SPK_POWER" },
  194 + { GPIO92_HX4700_HP_DRIVER, GPIOF_OUT_INIT_LOW, "EP_POWER" },
  195 +};
  196 +
  197 +static int __devinit hx4700_audio_probe(struct platform_device *pdev)
  198 +{
  199 + int ret;
  200 +
  201 + if (!machine_is_h4700())
  202 + return -ENODEV;
  203 +
  204 + ret = gpio_request_array(hx4700_audio_gpios,
  205 + ARRAY_SIZE(hx4700_audio_gpios));
  206 + if (ret)
  207 + return ret;
  208 +
  209 + snd_soc_card_hx4700.dev = &pdev->dev;
  210 + ret = snd_soc_register_card(&snd_soc_card_hx4700);
  211 + if (ret)
  212 + return ret;
  213 +
  214 + return 0;
  215 +}
  216 +
  217 +static int __devexit hx4700_audio_remove(struct platform_device *pdev)
  218 +{
  219 + snd_soc_jack_free_gpios(&hs_jack, 1, &hs_jack_gpio);
  220 + snd_soc_unregister_card(&snd_soc_card_hx4700);
  221 +
  222 + gpio_set_value(GPIO92_HX4700_HP_DRIVER, 0);
  223 + gpio_set_value(GPIO107_HX4700_SPK_nSD, 0);
  224 +
  225 + gpio_free_array(hx4700_audio_gpios, ARRAY_SIZE(hx4700_audio_gpios));
  226 + return 0;
  227 +}
  228 +
  229 +static struct platform_driver hx4700_audio_driver = {
  230 + .driver = {
  231 + .name = "hx4700-audio",
  232 + .owner = THIS_MODULE,
  233 + .pm = &snd_soc_pm_ops,
  234 + },
  235 + .probe = hx4700_audio_probe,
  236 + .remove = __devexit_p(hx4700_audio_remove),
  237 +};
  238 +
  239 +static int __init hx4700_modinit(void)
  240 +{
  241 + return platform_driver_register(&hx4700_audio_driver);
  242 +}
  243 +module_init(hx4700_modinit);
  244 +
  245 +static void __exit hx4700_modexit(void)
  246 +{
  247 + platform_driver_unregister(&hx4700_audio_driver);
  248 +}
  249 +
  250 +module_exit(hx4700_modexit);
  251 +
  252 +MODULE_AUTHOR("Philipp Zabel");
  253 +MODULE_DESCRIPTION("ALSA SoC iPAQ hx4700");
  254 +MODULE_LICENSE("GPL");
  255 +MODULE_ALIAS("platform:hx4700-audio");