diff options
Diffstat (limited to 'sound/soc/tegra/tegra_wired_jack.c')
-rw-r--r-- | sound/soc/tegra/tegra_wired_jack.c | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/sound/soc/tegra/tegra_wired_jack.c b/sound/soc/tegra/tegra_wired_jack.c new file mode 100644 index 000000000000..23eeecbb3422 --- /dev/null +++ b/sound/soc/tegra/tegra_wired_jack.c @@ -0,0 +1,198 @@ +/* + * sound/soc/tegra/tegra_wired_jack.c + * + * Copyright (c) 2011, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/types.h> +#include <linux/switch.h> +#include <linux/notifier.h> +#include <sound/jack.h> +#include <sound/soc.h> +#include <mach/audio.h> + +#include "tegra_soc.h" + +#define HEAD_DET_GPIO 0 + +/* jack */ +static struct snd_soc_jack *tegra_wired_jack; + +static struct snd_soc_jack_pin hs_jack_pins[] = { + { + .pin = "Headset Jack", + .mask = SND_JACK_HEADSET, + }, + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static struct snd_soc_jack_gpio hs_jack_gpios[] = { + { + /* gpio pin depends on board traits */ + .name = "headphone-detect-gpio", + .report = SND_JACK_HEADPHONE, + .invert = 1, + .debounce_time = 200, + }, +}; + +static struct switch_dev wired_switch_dev = { + .name = "h2w", +}; + +static int wired_swith_notify(struct notifier_block *self, + unsigned long action, void* dev) +{ + int state = 0; + + switch (action) { + case SND_JACK_HEADSET: + state = 1; + break; + case SND_JACK_HEADPHONE: + state = 2; + break; + default: + state = 0; + } + + switch_set_state(&wired_switch_dev, state); + + return NOTIFY_OK; +} + +static struct notifier_block wired_switch_nb = { + .notifier_call = wired_swith_notify, +}; + +/* platform driver */ +static int tegra_wired_jack_probe(struct platform_device *pdev) +{ + int ret; + int hp_det_n; + struct tegra_wired_jack_conf *pdata; + + pdata = (struct tegra_wired_jack_conf *)pdev->dev.platform_data; + if (!pdata || !pdata->hp_det_n) { + pr_err("Please set up gpio pins for jack.\n"); + return -EBUSY; + } + + hp_det_n = pdata->hp_det_n; + hs_jack_gpios[HEAD_DET_GPIO].gpio = hp_det_n; + + ret = snd_soc_jack_add_gpios(tegra_wired_jack, + ARRAY_SIZE(hs_jack_gpios), + hs_jack_gpios); + if (ret) { + pr_err("Could NOT set up gpio pins for jack.\n"); + snd_soc_jack_free_gpios(tegra_wired_jack, + ARRAY_SIZE(hs_jack_gpios), + hs_jack_gpios); + return ret; + } + + return 0; +} + +static int tegra_wired_jack_remove(struct platform_device *pdev) +{ + snd_soc_jack_free_gpios(tegra_wired_jack, + ARRAY_SIZE(hs_jack_gpios), + hs_jack_gpios); + + return 0; +} + +static struct platform_driver tegra_wired_jack_driver = { + .probe = tegra_wired_jack_probe, + .remove = __devexit_p(tegra_wired_jack_remove), + .driver = { + .name = "tegra_wired_jack", + .owner = THIS_MODULE, + }, +}; + + +int tegra_jack_init(struct snd_soc_codec *codec) +{ + int ret; + + if (!codec) + return -1; + + tegra_wired_jack = kzalloc(sizeof(*tegra_wired_jack), GFP_KERNEL); + if (!tegra_wired_jack) { + pr_err("failed to allocate tegra_wired_jack \n"); + return -ENOMEM; + } + + /* Add jack detection */ + ret = snd_soc_jack_new(codec->socdev->card, "Headset Jack", + SND_JACK_HEADSET, tegra_wired_jack); + if (ret < 0) + goto failed; + + ret = snd_soc_jack_add_pins(tegra_wired_jack, + ARRAY_SIZE(hs_jack_pins), + hs_jack_pins); + if (ret < 0) + goto failed; + + /* Addd h2w swith class support */ + ret = switch_dev_register(&wired_switch_dev); + if (ret < 0) + goto switch_dev_failed; + + snd_soc_jack_notifier_register(tegra_wired_jack, + &wired_switch_nb); + + ret = platform_driver_register(&tegra_wired_jack_driver); + if (ret < 0) + goto platform_dev_failed; + + return 0; + +switch_dev_failed: + switch_dev_unregister(&wired_switch_dev); +platform_dev_failed: + platform_driver_unregister(&tegra_wired_jack_driver); +failed: + if (tegra_wired_jack) { + kfree(tegra_wired_jack); + tegra_wired_jack = 0; + } + return ret; +} + +void tegra_jack_exit(void) +{ + switch_dev_unregister(&wired_switch_dev); + platform_driver_unregister(&tegra_wired_jack_driver); + + if (tegra_wired_jack) { + kfree(tegra_wired_jack); + tegra_wired_jack = 0; + } +} |