Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac1480d7 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "sound: soc: Add docking station jack support"

parents a2784d8b 0dfb375b
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * 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.
 */

#ifndef __DEVICE_EVENT_H
#define __DEVICE_EVENT_H

#define QC_AUDIO_EXTERNAL_SPK_1_EVENT "qc_ext_spk_1"
#define QC_AUDIO_EXTERNAL_SPK_2_EVENT "qc_ext_spk_2"
#define QC_AUDIO_EXTERNAL_MIC_EVENT "qc_ext_mic"

#endif /* __DEVICE_EVENT_H */
+130 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <linux/regulator/consumer.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/switch.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -27,6 +28,7 @@
#include <sound/jack.h>
#include <sound/q6afe-v2.h>
#include <sound/pcm_params.h>
#include <device_event.h>
#include "qdsp6v2/msm-pcm-routing-v2.h"
#include "qdsp6v2/q6core.h"
#include "../codecs/wcd9xxx-common.h"
@@ -113,6 +115,16 @@ static int clk_users;
static atomic_t prim_auxpcm_rsc_ref;
static atomic_t sec_auxpcm_rsc_ref;

struct msm8994_liquid_dock_dev {
	int dock_plug_gpio;
	int dock_plug_irq;
	int dock_plug_det;
	struct work_struct irq_work;
	struct switch_dev audio_sdev;
};

static struct msm8994_liquid_dock_dev *msm8994_liquid_dock_dev;

static const char *const pin_states[] = {"Disable", "active"};
static const char *const spk_function[] = {"Off", "On"};
static const char *const slim0_rx_ch_text[] = {"One", "Two"};
@@ -199,6 +211,103 @@ static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
	}
}

static void msm8994_liquid_docking_irq_work(struct work_struct *work)
{
	struct msm8994_liquid_dock_dev *dock_dev =
		container_of(work, struct msm8994_liquid_dock_dev, irq_work);

	dock_dev->dock_plug_det =
		gpio_get_value(dock_dev->dock_plug_gpio);

	switch_set_state(&dock_dev->audio_sdev, dock_dev->dock_plug_det);
	/*notify to audio deamon*/
	sysfs_notify(&dock_dev->audio_sdev.dev->kobj, NULL, "state");
}

static irqreturn_t msm8994_liquid_docking_irq_handler(int irq, void *dev)
{
	struct msm8994_liquid_dock_dev *dock_dev = dev;

	/* switch speakers should not run in interrupt context */
	schedule_work(&dock_dev->irq_work);
	return IRQ_HANDLED;
}

static int msm8994_liquid_init_docking(void)
{
	int ret = 0;
	int dock_plug_gpio = 0;

	/* plug in docking speaker+plug in device OR unplug one of them */
	u32 dock_plug_irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
					IRQF_SHARED;

	dock_plug_gpio = of_get_named_gpio(spdev->dev.of_node,
					   "qcom,dock-plug-det-irq", 0);

	if (dock_plug_gpio >= 0) {
		msm8994_liquid_dock_dev =
		 kzalloc(sizeof(*msm8994_liquid_dock_dev), GFP_KERNEL);
		if (!msm8994_liquid_dock_dev) {
			pr_err("msm8994_liquid_dock_dev alloc fail.\n");
			ret = -ENOMEM;
			goto exit;
		}

		msm8994_liquid_dock_dev->dock_plug_gpio = dock_plug_gpio;

		ret = gpio_request(msm8994_liquid_dock_dev->dock_plug_gpio,
					   "dock-plug-det-irq");
		if (ret) {
			pr_err("%s:failed request msm8994_liquid_dock_plug_gpio err = %d\n",
				__func__, ret);
			ret = -EINVAL;
			goto fail_dock_gpio;
		}

		msm8994_liquid_dock_dev->dock_plug_det =
			gpio_get_value(msm8994_liquid_dock_dev->dock_plug_gpio);
		msm8994_liquid_dock_dev->dock_plug_irq =
			gpio_to_irq(msm8994_liquid_dock_dev->dock_plug_gpio);

		ret = request_irq(msm8994_liquid_dock_dev->dock_plug_irq,
				  msm8994_liquid_docking_irq_handler,
				  dock_plug_irq_flags,
				  "liquid_dock_plug_irq",
				  msm8994_liquid_dock_dev);
		if (ret < 0) {
			pr_err("%s: Request Irq Failed err = %d\n",
				__func__, ret);
			goto fail_dock_gpio;
		}

		msm8994_liquid_dock_dev->audio_sdev.name =
						QC_AUDIO_EXTERNAL_SPK_1_EVENT;

		if (switch_dev_register(
			 &msm8994_liquid_dock_dev->audio_sdev) < 0) {
			pr_err("%s: dock device register in switch diretory failed\n",
				__func__);
			goto fail_switch_dev;
		}

		INIT_WORK(
			&msm8994_liquid_dock_dev->irq_work,
			msm8994_liquid_docking_irq_work);
	}
	return 0;

fail_switch_dev:
	free_irq(msm8994_liquid_dock_dev->dock_plug_irq,
				msm8994_liquid_dock_dev);
fail_dock_gpio:
	gpio_free(msm8994_liquid_dock_dev->dock_plug_gpio);
exit:
	kfree(msm8994_liquid_dock_dev);
	msm8994_liquid_dock_dev = NULL;
	return ret;
}

static void msm8994_ext_control(struct snd_soc_codec *codec)
{
	struct snd_soc_dapm_context *dapm = &codec->dapm;
@@ -1469,6 +1578,13 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
		return err;
	}

	err = msm8994_liquid_init_docking();
	if (err) {
		pr_err("%s: 8994 init Docking stat IRQ failed (%d)\n",
			   __func__, err);
		return err;
	}

	err = msm8994_ext_us_amp_init();
	if (err) {
		pr_err("%s: MTP 8994 US Emitter GPIO init failed (%d)\n",
@@ -2961,6 +3077,20 @@ static int msm8994_asoc_machine_remove(struct platform_device *pdev)

	gpio_free(pdata->mclk_gpio);
	gpio_free(pdata->us_euro_gpio);

	if (msm8994_liquid_dock_dev != NULL) {
		switch_dev_unregister(&msm8994_liquid_dock_dev->audio_sdev);

		if (msm8994_liquid_dock_dev->dock_plug_irq)
			free_irq(msm8994_liquid_dock_dev->dock_plug_irq,
				 msm8994_liquid_dock_dev);

		if (msm8994_liquid_dock_dev->dock_plug_gpio)
			gpio_free(msm8994_liquid_dock_dev->dock_plug_gpio);

		kfree(msm8994_liquid_dock_dev);
		msm8994_liquid_dock_dev = NULL;
	}
	msm_auxpcm_release_pinctrl(pdev, SEC_MI2S_PCM);
	msm_mi2s_release_pinctrl(pdev, PRI_MI2S_PCM);
	snd_soc_unregister_card(card);