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

Commit 759426ec authored by Rohit kumar's avatar Rohit kumar Committed by Tanya Dixit
Browse files

ASoC: Add WCD937X slave and core driver



Add wcd937x swr slave and codec driver.
This adds only basic support for codec registration.

Change-Id: I87519a234f14d34a019c8f66652b7224759e639c
Signed-off-by: default avatarRohit kumar <rohitkr@codeaurora.org>
parent 2e628184
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -30,8 +30,8 @@ include $(MY_LOCAL_PATH)/asoc/codecs/aqt1000/Android.mk
endif

ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE)),true)
$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/bolero/Module.symvers)
include $(MY_LOCAL_PATH)/asoc/codecs/bolero/Android.mk
$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/Module.symvers)
include $(MY_LOCAL_PATH)/asoc/codecs/wcd937x/Android.mk
endif

ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605),true)
+1 −0
Original line number Diff line number Diff line
@@ -186,6 +186,7 @@ ifeq ($(KERNEL_BUILD), 1)
	obj-y	+= sdm660_cdc/
	obj-y	+= msm_sdw/
	obj-y	+= wcd9360/
	obj-y	+= wcd937x/
endif
# Module information used by KBuild framework
obj-$(CONFIG_WCD9XXX_CODEC_CORE) += wcd_core_dlkm.o
+57 −0
Original line number Diff line number Diff line
# Android makefile for audio kernel modules

# Assume no targets will be supported

# Check if this driver needs be built for current target
ifeq ($(call is-board-platform,$(MSMSTEPPE)),true)
AUDIO_SELECT  := CONFIG_SND_SOC_SM6150=m
endif

AUDIO_CHIPSET := audio
# Build/Package only in case of supported target
ifeq ($(call is-board-platform-in-list,msm8953 sdm845 sdm670 qcs605 msmnile $(MSMSTEPPE)),true)

LOCAL_PATH := $(call my-dir)

# This makefile is only for DLKM
ifneq ($(findstring vendor,$(LOCAL_PATH)),)

ifneq ($(findstring opensource,$(LOCAL_PATH)),)
	AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/vendor/qcom/opensource/audio-kernel
endif # opensource

DLKM_DIR := $(TOP)/device/qcom/common/dlkm

# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko
###########################################################
# This is set once per LOCAL_PATH, not per (kernel) module
KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR)

# We are actually building audio.ko here, as per the
# requirement we are specifying <chipset>_audio.ko as LOCAL_MODULE.
# This means we need to rename the module to <chipset>_audio.ko
# after audio.ko is built.
KBUILD_OPTIONS += MODNAME=wcd937x_dlkm
KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM)
KBUILD_OPTIONS += $(AUDIO_SELECT)

###########################################################
include $(CLEAR_VARS)
LOCAL_MODULE              := $(AUDIO_CHIPSET)_wcd937x.ko
LOCAL_MODULE_KBUILD_NAME  := wcd937x_dlkm.ko
LOCAL_MODULE_TAGS         := optional
LOCAL_MODULE_DEBUG_ENABLE := true
LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk
###########################################################
include $(CLEAR_VARS)
LOCAL_MODULE              := $(AUDIO_CHIPSET)_wcd937x_slave.ko
LOCAL_MODULE_KBUILD_NAME  := wcd937x_slave_dlkm.ko
LOCAL_MODULE_TAGS         := optional
LOCAL_MODULE_DEBUG_ENABLE := true
LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk
###########################################################

endif # DLKM check
endif # supported target check
+110 −0
Original line number Diff line number Diff line
# We can build either as part of a standalone Kernel build or as
# an external module.  Determine which mechanism is being used
ifeq ($(MODNAME),)
	KERNEL_BUILD := 1
else
	KERNEL_BUILD := 0
endif



ifeq ($(KERNEL_BUILD), 1)
	# These are configurable via Kconfig for kernel-based builds
	# Need to explicitly configure for Android-based builds
	AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/kernel/msm-4.9
	AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio
endif

ifeq ($(KERNEL_BUILD), 0)
	ifeq ($(CONFIG_ARCH_SM6150), y)
		include $(AUDIO_ROOT)/config/sm6150auto.conf
		export
		INCS    +=  -include $(AUDIO_ROOT)/config/sm6150autoconf.h
	endif
endif

# As per target team, build is done as follows:
# Defconfig : build with default flags
# Slub      : defconfig  + CONFIG_SLUB_DEBUG := y +
#	      CONFIG_SLUB_DEBUG_ON := y + CONFIG_PAGE_POISONING := y
# Perf      : Using appropriate msmXXXX-perf_defconfig
#
# Shipment builds (user variants) should not have any debug feature
# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds
# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since
# there is no other way to identify defconfig builds, QTI internal
# representation of perf builds (identified using the string 'perf'),
# is used to identify if the build is a slub or defconfig one. This
# way no critical debug feature will be enabled for perf and shipment
# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT
# config.

############ UAPI ############
UAPI_DIR :=	uapi
UAPI_INC :=	-I$(AUDIO_ROOT)/include/$(UAPI_DIR)

############ COMMON ############
COMMON_DIR :=	include
COMMON_INC :=	-I$(AUDIO_ROOT)/$(COMMON_DIR)

############ WCD937X ############

# for WCD937X Codec
ifdef CONFIG_SND_SOC_WCD937X
	WCD937X_OBJS += wcd937x.o
endif

ifdef CONFIG_SND_SOC_WCD937X_SLAVE
	WCD937X_SLAVE_OBJS += wcd937x_slave.o
endif

LINUX_INC +=	-Iinclude/linux

INCS +=		$(COMMON_INC) \
		$(UAPI_INC)

EXTRA_CFLAGS += $(INCS)


CDEFINES +=	-DANI_LITTLE_BYTE_ENDIAN \
		-DANI_LITTLE_BIT_ENDIAN \
		-DDOT11F_LITTLE_ENDIAN_HOST \
		-DANI_COMPILER_TYPE_GCC \
		-DANI_OS_TYPE_ANDROID=6 \
		-DPTT_SOCK_SVC_ENABLE \
		-Wall\
		-Werror\
		-D__linux__

KBUILD_CPPFLAGS += $(CDEFINES)

# Currently, for versions of gcc which support it, the kernel Makefile
# is disabling the maybe-uninitialized warning.  Re-enable it for the
# AUDIO driver.  Note that we must use EXTRA_CFLAGS here so that it
# will override the kernel settings.
ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y)
EXTRA_CFLAGS += -Wmaybe-uninitialized
endif
#EXTRA_CFLAGS += -Wmissing-prototypes

ifeq ($(call cc-option-yn, -Wheader-guard),y)
EXTRA_CFLAGS += -Wheader-guard
endif

ifeq ($(KERNEL_BUILD), 0)
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers
endif

# Module information used by KBuild framework
obj-$(CONFIG_SND_SOC_WCD937X) += wcd937x_dlkm.o
wcd937x_dlkm-y := $(WCD937X_OBJS)

obj-$(CONFIG_SND_SOC_WCD937X_SLAVE) += wcd937x_slave_dlkm.o
wcd937x_slave_dlkm-y := $(WCD937X_SLAVE_OBJS)

# inject some build related information
DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\"
+310 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2018, 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.
 */

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/component.h>
#include <sound/soc.h>
#include <soc/soundwire.h>
#include "../msm-cdc-pinctrl.h"

struct wcd937x_priv {
	struct device *dev;
	struct snd_soc_codec *codec;
	struct device_node *rst_np;
	struct swr_device *rx_swr_dev;
	struct swr_device *tx_swr_dev;
};

struct wcd937x_pdata {
	struct device_node *rst_np;
	struct device_node *rx_slave;
	struct device_node *tx_slave;
};

static int wcd937x_soc_codec_probe(struct snd_soc_codec *codec)
{
	struct wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);

	if (!wcd937x)
		return -EINVAL;

	return 0;
}

static int wcd937x_soc_codec_remove(struct snd_soc_codec *codec)
{
	struct wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);

	if (!wcd937x)
		return -EINVAL;

	return 0;
}

static struct regmap *wcd937x_get_regmap(struct device *dev)
{
	struct wcd937x_priv *wcd937x = dev_get_drvdata(dev);

	return wcd937x->regmap;
}

static const struct snd_kcontrol_new wcd937x_snd_controls[] = {
};

static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = {
};

static const struct snd_soc_dapm_route wcd937x_audio_map[] = {
};

static struct snd_soc_codec_driver soc_codec_dev_wcd937x = {
	.probe = wcd937x_soc_codec_probe,
	.remove = wcd937x_soc_codec_remove,
	.get_regmap = wcd937x_get_regmap,
	.component_driver = {
		.controls = wcd937x_snd_controls,
		.num_controls = ARRAY_SIZE(wcd937x_snd_controls),
		.dapm_widgets = wcd937x_dapm_widgets,
		.num_dapm_widgets = ARRAY_SIZE(wcd937x_dapm_widgets),
		.dapm_routes = wcd937x_audio_map,
		.num_dapm_routes = ARRAY_SIZE(wcd937x_audio_map),
	},
};

int wcd937x_reset(struct device *dev)
{
	struct wcd937x_priv *wcd937x = NULL;
	int rc = 0;
	int value = 0;

	if (!dev)
		return -ENODEV;

	wcd937x = dev_get_drvdata(dev);
	if (!wcd937x)
		return -EINVAL;

	if (!wcd937x->rst_np) {
		dev_err(dev, "%s: reset gpio device node not specified\n",
				__func__);
		return -EINVAL;
	}

	value = msm_cdc_pinctrl_get_state(wcd937x->rst_np);
	if (value > 0)
		return 0;

	rc = msm_cdc_pinctrl_select_sleep_state(wcd937x->rst_np);
	if (rc) {
		dev_err(dev, "%s: wcd sleep state request fail!\n",
				__func__);
		return rc;
	}

	/* 20ms sleep required after pulling the reset gpio to LOW */
	msleep(20);

	rc = msm_cdc_pinctrl_select_active_state(wcd937x->rst_np);
	if (rc) {
		dev_err(dev, "%s: wcd active state request fail!\n",
				__func__);
		return rc;
	}
	msleep(20);

	return rc;
}

struct wcd937x_pdata *wcd937x_populate_dt_data(struct device *dev)
{
	struct wcd937x_pdata *pdata = NULL;

	pdata = devm_kzalloc(dev, sizeof(struct wcd937x_pdata),
				GFP_KERNEL);
	if (!pdata)
		return NULL;

	pdata->rst_np = of_parse_phandle(dev->of_node,
			"qcom,wcd937x-reset-node", 0);
	if (!pdata->rst_np) {
		dev_err(dev, "%s: Looking up %s property in node %s failed\n",
				__func__, "qcom,wcd937x-reset-node",
				dev->of_node->full_name);
		return NULL;
	}

	pdata->rx_slave = of_parse_phandle(dev->of_node, "qcom,rx-slave", 0);
	pdata->tx_slave = of_parse_phandle(dev->of_node, "qcom,tx-slave", 0);

	return pdata;
}

static int wcd937x_bind(struct device *dev)
{
	int ret = 0;
	struct wcd937x_priv *wcd937x = NULL;
	struct wcd937x_pdata *pdata = NULL;

	wcd937x = devm_kzalloc(dev, sizeof(struct wcd937x_priv), GFP_KERNEL);
	if (!wcd937x)
		return -ENOMEM;

	dev_set_drvdata(dev, wcd937x);

	pdata = wcd937x_populate_dt_data(dev);
	if (!pdata) {
		dev_err(dev, "%s: Fail to obtain platform data\n", __func__);
		return -EINVAL;
	}

	wcd937x->rst_np = pdata->rst_np;
	wcd937x_reset(dev);
	/*
	 * Add 5msec delay to provide sufficient time for
	 * soundwire auto enumeration of slave devices as
	 * as per HW requirement.
	 */
	usleep_range(5000, 5010);
	ret = component_bind_all(dev, wcd937x);
	if (ret) {
		dev_err(dev, "%s: Slave bind failed, ret = %d\n",
			__func__, ret);
		return ret;
	}

	wcd937x->rx_swr_dev = get_matching_swr_slave_device(pdata->rx_slave);
	if (!wcd937x->rx_swr_dev) {
		dev_err(dev, "%s: Could not find RX swr slave device\n",
			 __func__);
		ret = -ENODEV;
		goto err;
	}

	wcd937x->tx_swr_dev = get_matching_swr_slave_device(pdata->tx_slave);
	if (!wcd937x->tx_swr_dev) {
		dev_err(dev, "%s: Could not find TX swr slave device\n",
			__func__);
		ret = -ENODEV;
		goto err;
	}

	ret = snd_soc_register_codec(dev, &soc_codec_dev_wcd937x,
			NULL, 0);
	if (ret) {
		dev_err(dev, "%s: Codec registration failed\n",
				__func__);
		goto err;
	}

	return ret;
err:
	component_unbind_all(dev, wcd937x);
	return ret;
}

static void wcd937x_unbind(struct device *dev)
{
	struct wcd937x_priv *wcd937x = dev_get_drvdata(dev);

	snd_soc_unregister_codec(dev);
	component_unbind_all(dev, wcd937x);
}

static const struct of_device_id wcd937x_dt_match[] = {
	{ .compatible = "qcom,wcd937x-codec" },
	{}
};

static const struct component_master_ops wcd937x_comp_ops = {
	.bind   = wcd937x_bind,
	.unbind = wcd937x_unbind,
};

static int wcd937x_compare_of(struct device *dev, void *data)
{
	return dev->of_node == data;
}

static void wcd937x_release_of(struct device *dev, void *data)
{
	of_node_put(data);
}

static int wcd937x_add_slave_components(struct device *dev,
				struct component_match **matchptr)
{
	struct device_node *np, *rx_node, *tx_node;

	np = dev->of_node;

	rx_node = of_parse_phandle(np, "qcom,rx-slave", 0);
	if (!rx_node) {
		dev_err(dev, "%s: Rx-slave node not defined\n", __func__);
		return -ENODEV;
	}
	of_node_get(rx_node);
	component_match_add_release(dev, matchptr,
			wcd937x_release_of,
			wcd937x_compare_of,
			rx_node);

	tx_node = of_parse_phandle(np, "qcom,tx-slave", 0);
	if (!tx_node) {
		dev_err(dev, "%s: Tx-slave node not defined\n", __func__);
			return -ENODEV;
	}
	of_node_get(tx_node);
	component_match_add_release(dev, matchptr,
			wcd937x_release_of,
			wcd937x_compare_of,
			tx_node);
	return 0;
}

static int wcd937x_probe(struct platform_device *pdev)
{
	struct component_match *match = NULL;
	int ret;

	ret = wcd937x_add_slave_components(&pdev->dev, &match);
	if (ret)
		return ret;

	return component_master_add_with_match(&pdev->dev,
					&wcd937x_comp_ops, match);
}

static int wcd937x_remove(struct platform_device *pdev)
{
	component_master_del(&pdev->dev, &wcd937x_comp_ops);
	return 0;
}

static struct platform_driver wcd937x_codec_driver = {
	.probe = wcd937x_probe,
	.remove = wcd937x_remove,
	.driver = {
		.name = "wcd937x_codec",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(wcd937x_dt_match),
	},
};

module_platform_driver(wcd937x_codec_driver);
MODULE_DESCRIPTION("WCD937X Codec driver");
MODULE_LICENSE("GPL v2");
Loading