From patchwork Tue Oct 8 18:15:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Murphy X-Patchwork-Id: 175551 Delivered-To: patch@linaro.org Received: by 2002:a92:7e96:0:0:0:0:0 with SMTP id q22csp6047667ill; Tue, 8 Oct 2019 11:16:26 -0700 (PDT) X-Google-Smtp-Source: APXvYqy/+tZROtj5i0CYDlpsKZPyfnXMXA43q208BGopGP58MK+64qNAdd5zA/ESfLapXn/IC1Sd X-Received: by 2002:a17:906:4b47:: with SMTP id j7mr29743815ejv.63.1570558585908; Tue, 08 Oct 2019 11:16:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1570558585; cv=none; d=google.com; s=arc-20160816; b=tgTn7xCpP+u9EJrb3yivvpfjI3nCS4uK/1zBzmXo2O3n+9f3tI9ER/uRN0L7OZAsMu y9TjfAyllOBVTP3RE8UGtTnWBTAFLtn/+7x3cmZSrJIYYK8k0RVTF+VyyjdlaMSzZi39 m2x2vWV4uvpOOs2+kIHih/kA0FBuLs3iYqJxGkDRCbR0+mAbl+y2K+r2zyIp0wAe9cqi x1BIevzTxbvASAO31e2xWUN2I276/Cj8kUytX8IKcVEHSJhtXmwU7wzjNbr/ppRTvxc8 jSrO8QYd8szDvAUkpygBWQYTT1rQN3rZDuHlXQ/jFAR3m/Vp5TaTYoAmXyzwM0p9M5vE hNUA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=MHbt/egTxGNc/lCwyNbm8rdYzujVZ7DY1baO8ocVABU=; b=vSryUXzzBdX0nvDZz+4zOxId+icuKcFJ9w6GIhwYpuTAO0Q5e3UH3cHsHlQJBi/W7s fbs2npKTToADVIbJM8EiYc+WxQAmC+NezmrKOvPQ0dUk7royI6Y+MJ3YCzCugCxo5T5E BkW88V/uB3WFWMuo5VJCBH9o/f7qIsKdzGup3dfZnVpokQ23/B2NHoo6soLwQJEwCh0q CbXI1iBaIvDxitQXgyrxTqN5QNo2PcDHPk9yrdFxaKO8gBaEKnPTT1BG6QV4DjhPmwCw 0RGOYeomZQJwT8jz2UxQh1JVUDvpbgmvkGSn4o0fFkMDhnwuYTr1V/DiC6p959sO1L+h jcLw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=c3Y+k5fg; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p14si11556925edc.227.2019.10.08.11.16.25; Tue, 08 Oct 2019 11:16:25 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=c3Y+k5fg; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729895AbfJHSQW (ORCPT + 26 others); Tue, 8 Oct 2019 14:16:22 -0400 Received: from fllv0015.ext.ti.com ([198.47.19.141]:54948 "EHLO fllv0015.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726138AbfJHSQW (ORCPT ); Tue, 8 Oct 2019 14:16:22 -0400 Received: from fllv0034.itg.ti.com ([10.64.40.246]) by fllv0015.ext.ti.com (8.15.2/8.15.2) with ESMTP id x98IFZYd055295; Tue, 8 Oct 2019 13:15:35 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1570558535; bh=MHbt/egTxGNc/lCwyNbm8rdYzujVZ7DY1baO8ocVABU=; h=From:To:CC:Subject:Date; b=c3Y+k5fgd7o03DtgIecpJ/TGaYIJGTN0hde/Hu9HP21ivAvfZjAR1Ej1ZJJ/XE1L6 HKJQrAhfAZyVGu4GLaEEjfgtY7u0vlZ5E12Fos/zlSNhfsz9UI38rlD2FwzH/GdKza OtOaDPet+pflnPMTxUc8wzLPMsCDRKOlogeoJTKo= Received: from DFLE100.ent.ti.com (dfle100.ent.ti.com [10.64.6.21]) by fllv0034.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x98IFZ72085052 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 8 Oct 2019 13:15:35 -0500 Received: from DFLE105.ent.ti.com (10.64.6.26) by DFLE100.ent.ti.com (10.64.6.21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1713.5; Tue, 8 Oct 2019 13:15:32 -0500 Received: from fllv0039.itg.ti.com (10.64.41.19) by DFLE105.ent.ti.com (10.64.6.26) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1713.5 via Frontend Transport; Tue, 8 Oct 2019 13:15:35 -0500 Received: from localhost (ileax41-snat.itg.ti.com [10.172.224.153]) by fllv0039.itg.ti.com (8.15.2/8.15.2) with ESMTP id x98IFZD4029023; Tue, 8 Oct 2019 13:15:35 -0500 From: Dan Murphy To: CC: , , , , , , Dan Murphy Subject: [PATCH 1/2] ASoc: Add Texas Instruments TAS2562 amplifier binding Date: Tue, 8 Oct 2019 13:15:16 -0500 Message-ID: <20191008181517.5332-1-dmurphy@ti.com> X-Mailer: git-send-email 2.22.0.214.g8dca754b1e MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add the DT binding for the TAS2562 amplifier. Signed-off-by: Dan Murphy --- .../devicetree/bindings/sound/tas2562.txt | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/tas2562.txt -- 2.22.0.214.g8dca754b1e diff --git a/Documentation/devicetree/bindings/sound/tas2562.txt b/Documentation/devicetree/bindings/sound/tas2562.txt new file mode 100644 index 000000000000..658e1fb18a99 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tas2562.txt @@ -0,0 +1,34 @@ +Texas Instruments TAS2562 Smart PA + +The TAS2562 is a mono, digital input Class-D audio amplifier optimized for +efficiently driving high peak power into small loudspeakers. +Integrated speaker voltage and current sense provides for +real time monitoring of loudspeaker behavior. + +Required properties: + - #address-cells - Should be <1>. + - #size-cells - Should be <0>. + - compatible: - Should contain "ti,tas2562". + - reg: - The i2c address. Should be 0x4c, 0x4d, 0x4e or 0x4f. + - ti,imon-slot-no:- TDM TX current sense time slot. + +Optional properties: +- interrupt-parent: phandle to the interrupt controller which provides + the interrupt. +- interrupts: (GPIO) interrupt to which the chip is connected. +- shut-down: GPIO used to control the state of the device. + +Examples: +tas2562@4c { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,tas2562"; + reg = <0x4c>; + + interrupt-parent = <&gpio1>; + interrupts = <14>; + + shut-down = <&gpio1 15 0>; + ti,imon-slot-no = <0>; +}; + From patchwork Tue Oct 8 18:15:17 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Murphy X-Patchwork-Id: 175550 Delivered-To: patch@linaro.org Received: by 2002:a92:7e96:0:0:0:0:0 with SMTP id q22csp6046985ill; Tue, 8 Oct 2019 11:15:53 -0700 (PDT) X-Google-Smtp-Source: APXvYqwB5YkgEdEmX6OqSGwM8TCN17kMLCyKGEa9ItwINSgpK7skMLmUPHf7oPM794B1uB8qPn+S X-Received: by 2002:a17:906:d8c8:: with SMTP id re8mr30355577ejb.130.1570558553710; Tue, 08 Oct 2019 11:15:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1570558553; cv=none; d=google.com; s=arc-20160816; b=L7cBCHPOi1dDYWVq1iC6B6K7nlDQg3uBvLVBUBtWOHIUgDYjMtnaSJSg+dx5GQT28H RQHE4sq7wSBjYkH0TKqaQxLg+Prbuoqc/Luwdaf+x9iPGcmaBTuBgXza0wiu2Kr41ocw H8EC8YWl26rrUY63dpk3G684Oj6R9Uq09OyZgQ6AXgK53HXo1og9AEJESZTnIFAqiHJQ D7hqTAQW0FQ6y6l6qdXncwolVo+n3gunrEUGRNAhJPQG8WvAy/tJDOZHMYLdD3TCV6y4 uxpyzm6nxdwQYHqn2S1IMx4vp8t1rqJzcwTYn4Q1F5Fq1TXUD9rTaSo3ryDR0Kwkg/6o PBKw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=1H6W8+jWkp7moxoMXT1Egtu0rru/AoyJR+2vilAofyQ=; b=qjq6cRxHGYEq8mutAAXIvNWnpGasZbphQMd+nqeTgVFRkKnz1z5I8PdkCGpBM8Z+rT J7e8zhiFxcV0AhiB3wFvv71MXVfgnBsTASC9z5+7UhGi+JAgh32/lrRuMETI1QFLiU4M C5naORncZxQt7fhyFjMpr3FsxTS5ncJ+loOK6ZnA4pfQesJ/MOd2u108TQ28TiSuNR1t YEoQwwqMZGF2X4LACsVnc0doAkMoRzz/chi6/h7kIfupWmU5jtOrtHFXS6GQKvUikJaV dfkjx2sbQDvh64uVacQje+SxGVcF5uSkbLehIIQQCKnKKM4v/4Syf1x29PSDqqKCZMMh pjsQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b="BXq/Q6X8"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w43si11275254edd.332.2019.10.08.11.15.53; Tue, 08 Oct 2019 11:15:53 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b="BXq/Q6X8"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729872AbfJHSPw (ORCPT + 26 others); Tue, 8 Oct 2019 14:15:52 -0400 Received: from lelv0143.ext.ti.com ([198.47.23.248]:55928 "EHLO lelv0143.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726138AbfJHSPw (ORCPT ); Tue, 8 Oct 2019 14:15:52 -0400 Received: from lelv0266.itg.ti.com ([10.180.67.225]) by lelv0143.ext.ti.com (8.15.2/8.15.2) with ESMTP id x98IFaH0079045; Tue, 8 Oct 2019 13:15:36 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1570558536; bh=1H6W8+jWkp7moxoMXT1Egtu0rru/AoyJR+2vilAofyQ=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=BXq/Q6X8XUn/4vmKnirS4tzoaqOdeuHY4r1wbRmpEhcLbS0Ia19FHhkBsiSZUIR/L w0y4gPn4hd5OngGNz6I3v4c/F4jsWAK0glpjKpXv4h8EeBRgey5r1dUaboZ7i9mz6T MeL3g3PDzHXmXF54MARGxBi1ItEMK84HPlk4fSLA= Received: from DFLE103.ent.ti.com (dfle103.ent.ti.com [10.64.6.24]) by lelv0266.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x98IFaMV077080 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 8 Oct 2019 13:15:36 -0500 Received: from DFLE103.ent.ti.com (10.64.6.24) by DFLE103.ent.ti.com (10.64.6.24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1713.5; Tue, 8 Oct 2019 13:15:35 -0500 Received: from lelv0327.itg.ti.com (10.180.67.183) by DFLE103.ent.ti.com (10.64.6.24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1713.5 via Frontend Transport; Tue, 8 Oct 2019 13:15:35 -0500 Received: from localhost (ileax41-snat.itg.ti.com [10.172.224.153]) by lelv0327.itg.ti.com (8.15.2/8.15.2) with ESMTP id x98IFZ8U074385; Tue, 8 Oct 2019 13:15:35 -0500 From: Dan Murphy To: CC: , , , , , , Dan Murphy Subject: [PATCH 2/2] ASoC: tas2562: Introduce the TAS2562 amplifier Date: Tue, 8 Oct 2019 13:15:17 -0500 Message-ID: <20191008181517.5332-2-dmurphy@ti.com> X-Mailer: git-send-email 2.22.0.214.g8dca754b1e In-Reply-To: <20191008181517.5332-1-dmurphy@ti.com> References: <20191008181517.5332-1-dmurphy@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Introduce the Texas Instruments TAS2562 amplifier driver with I/V sense for loud speaker applications. http://www.ti.com/lit/gpn/tas2562 Signed-off-by: Dan Murphy --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas2562.c | 590 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tas2562.h | 85 ++++++ 4 files changed, 682 insertions(+) create mode 100644 sound/soc/codecs/tas2562.c create mode 100644 sound/soc/codecs/tas2562.h -- 2.22.0.214.g8dca754b1e diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 229cc89f8c5a..51b1a7bdf8e8 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -179,6 +179,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_STI_SAS select SND_SOC_TAS2552 if I2C + select SND_SOC_TAS2562 if I2C select SND_SOC_TAS5086 if I2C select SND_SOC_TAS571X if I2C select SND_SOC_TAS5720 if I2C @@ -1104,6 +1105,10 @@ config SND_SOC_TAS2552 tristate "Texas Instruments TAS2552 Mono Audio amplifier" depends on I2C +config SND_SOC_TAS2562 + tristate "Texas Instruments TAS2562 Mono Audio amplifier" + depends on I2C + config SND_SOC_TAS5086 tristate "Texas Instruments TAS5086 speaker amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index c498373dcc5f..96ba39c119af 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -280,6 +280,7 @@ snd-soc-max98504-objs := max98504.o snd-soc-simple-amplifier-objs := simple-amplifier.o snd-soc-tpa6130a2-objs := tpa6130a2.o snd-soc-tas2552-objs := tas2552.o +snd-soc-tas2562-objs := tas2562.o obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o @@ -474,6 +475,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o +obj-$(CONFIG_SND_SOC_TAS2562) += snd-soc-tas2562.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c new file mode 100644 index 000000000000..729acd874c48 --- /dev/null +++ b/sound/soc/codecs/tas2562.c @@ -0,0 +1,590 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Driver for the Texas Instruments TAS2562 CODEC +// Copyright (C) 2019 Texas Instruments Inc. + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "tas2562.h" + +#define TAS2562_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FORMAT_S32_LE) + +struct tas2562_data { + struct snd_soc_component *component; + struct gpio_desc *sdz_gpio; + struct regmap *regmap; + struct device *dev; + struct i2c_client *client; + int v_sense_slot; + int i_sense_slot; +}; + +static int tas2562_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct tas2562_data *tas2562 = + snd_soc_component_get_drvdata(component); + + switch (level) { + case SND_SOC_BIAS_ON: + snd_soc_component_update_bits(component, + TAS2562_PWR_CTRL, + TAS2562_MODE_MASK, TAS2562_ACTIVE); + break; + case SND_SOC_BIAS_STANDBY: + case SND_SOC_BIAS_PREPARE: + snd_soc_component_update_bits(component, + TAS2562_PWR_CTRL, + TAS2562_MODE_MASK, TAS2562_MUTE); + break; + case SND_SOC_BIAS_OFF: + snd_soc_component_update_bits(component, + TAS2562_PWR_CTRL, + TAS2562_MODE_MASK, TAS2562_SHUTDOWN); + break; + + default: + dev_err(tas2562->dev, + "wrong power level setting %d\n", level); + return -EINVAL; + } + + return 0; +} + +static int tas2562_set_samplerate(struct tas2562_data *tas2562, int samplerate) +{ + int samp_rate; + int ramp_rate; + + switch (samplerate) { + case 7350: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_7305_8KHZ; + break; + case 8000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_7305_8KHZ; + break; + case 14700: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_14_7_16KHZ; + break; + case 16000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_14_7_16KHZ; + break; + case 22050: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_22_05_24KHZ; + break; + case 24000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_22_05_24KHZ; + break; + case 29400: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_29_4_32KHZ; + break; + case 32000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_29_4_32KHZ; + break; + case 44100: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_44_1_48KHZ; + break; + case 48000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_44_1_48KHZ; + break; + case 88200: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_88_2_96KHZ; + break; + case 96000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_88_2_96KHZ; + break; + case 176400: + ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_176_4_192KHZ; + break; + case 192000: + ramp_rate = 0; + samp_rate = TAS2562_TDM_CFG0_SAMPRATE_176_4_192KHZ; + break; + default: + dev_info(tas2562->dev, "%s, unsupported sample rate, %d\n", + __func__, samplerate); + return -EINVAL; + } + + snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG0, + TAS2562_TDM_CFG0_RAMPRATE_MASK, ramp_rate); + snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG0, + TAS2562_TDM_CFG0_SAMPRATE_MASK, samp_rate); + + return 0; +} + +static int tas2562_set_dai_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + int ret = 0; + + switch (slot_width) { + case 16: + ret = snd_soc_component_update_bits(component, + TAS2562_TDM_CFG2, + TAS2562_TDM_CFG2_RXLEN_MASK, + TAS2562_TDM_CFG2_RXLEN_16B); + break; + case 24: + ret = snd_soc_component_update_bits(component, + TAS2562_TDM_CFG2, + TAS2562_TDM_CFG2_RXLEN_MASK, + TAS2562_TDM_CFG2_RXLEN_24B); + break; + case 32: + ret = snd_soc_component_update_bits(component, + TAS2562_TDM_CFG2, + TAS2562_TDM_CFG2_RXLEN_MASK, + TAS2562_TDM_CFG2_RXLEN_32B); + break; + + case 0: + /* Do not change slot width */ + break; + default: + dev_err(tas2562->dev, "slot width not supported"); + ret = -EINVAL; + } + + if (ret < 0) + return ret; + + return 0; +} + +static int tas2562_set_bitwidth(struct tas2562_data *tas2562, int bitwidth) +{ + int ret; + + switch (bitwidth) { + case SNDRV_PCM_FORMAT_S16_LE: + snd_soc_component_update_bits(tas2562->component, + TAS2562_TDM_CFG2, + TAS2562_TDM_CFG2_RXWLEN_MASK, + TAS2562_TDM_CFG2_RXWLEN_16B); + tas2562->v_sense_slot = tas2562->i_sense_slot + 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + snd_soc_component_update_bits(tas2562->component, + TAS2562_TDM_CFG2, + TAS2562_TDM_CFG2_RXWLEN_MASK, + TAS2562_TDM_CFG2_RXWLEN_24B); + tas2562->v_sense_slot = tas2562->i_sense_slot + 4; + break; + case SNDRV_PCM_FORMAT_S32_LE: + snd_soc_component_update_bits(tas2562->component, + TAS2562_TDM_CFG2, + TAS2562_TDM_CFG2_RXWLEN_MASK, + TAS2562_TDM_CFG2_RXWLEN_32B); + tas2562->v_sense_slot = tas2562->i_sense_slot + 4; + break; + + default: + dev_info(tas2562->dev, "Not supported params format\n"); + } + + ret = snd_soc_component_update_bits(tas2562->component, + TAS2562_TDM_CFG5, + TAS2562_TDM_CFG5_VSNS_EN | TAS2562_TDM_CFG5_VSNS_SLOT_MASK, + TAS2562_TDM_CFG5_VSNS_EN | tas2562->v_sense_slot); + if (ret < 0) + return ret; + + ret = snd_soc_component_update_bits(tas2562->component, + TAS2562_TDM_CFG6, + TAS2562_TDM_CFG6_ISNS_EN | TAS2562_TDM_CFG6_ISNS_SLOT_MASK, + TAS2562_TDM_CFG6_ISNS_EN | tas2562->i_sense_slot); + if (ret < 0) + return ret; + + return 0; +} + +static int tas2562_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + int ret; + + ret = tas2562_set_bitwidth(tas2562, params_format(params)); + if (ret) { + dev_err(tas2562->dev, "set bitwidth failed, %d\n", ret); + return ret; + } + + ret = tas2562_set_samplerate(tas2562, params_rate(params)); + if (ret) + dev_err(tas2562->dev, "set bitwidth failed, %d\n", ret); + + return ret; +} + +static int tas2562_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0; + int ret; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + asi_cfg_1 = 0; + break; + case SND_SOC_DAIFMT_IB_NF: + asi_cfg_1 |= TAS2562_TDM_CFG1_RX_FALLING; + break; + default: + dev_err(tas2562->dev, "ASI format Inverse is not found\n"); + return -EINVAL; + } + + ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG1, + TAS2562_TDM_CFG1_RX_EDGE_MASK, + asi_cfg_1); + if (ret < 0) { + dev_err(tas2562->dev, "Failed to set RX edge\n"); + return ret; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case (SND_SOC_DAIFMT_I2S): + case (SND_SOC_DAIFMT_DSP_A): + case (SND_SOC_DAIFMT_DSP_B): + tdm_rx_start_slot = BIT(1); + break; + case (SND_SOC_DAIFMT_LEFT_J): + tdm_rx_start_slot = 0; + break; + default: + dev_err(tas2562->dev, "DAI Format is not found, fmt=0x%x\n", + fmt); + ret = -EINVAL; + break; + } + + ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG1, + TAS2562_TDM_CFG1_RX_OFFSET_MASK, + tdm_rx_start_slot); + + if (ret < 0) + return ret; + + return 0; +} + +static int tas2562_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_component *component = dai->component; + + return snd_soc_component_update_bits(component, TAS2562_PWR_CTRL, + TAS2562_MODE_MASK, + mute ? TAS2562_MUTE : 0); +} + +static int tas2562_codec_probe(struct snd_soc_component *component) +{ + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + int ret; + + tas2562->component = component; + + if (tas2562->sdz_gpio) + gpiod_set_value_cansleep(tas2562->sdz_gpio, 1); + + ret = snd_soc_component_update_bits(component, TAS2562_PWR_CTRL, + TAS2562_MODE_MASK, TAS2562_MUTE); + if (ret < 0) + return ret; + + return 0; +} + +#ifdef CONFIG_PM +static int tas2562_suspend(struct snd_soc_component *component) +{ + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(tas2562->regmap, true); + regcache_mark_dirty(tas2562->regmap); + + if (tas2562->sdz_gpio) + gpiod_set_value_cansleep(tas2562->sdz_gpio, 0); + + return 0; +} + +static int tas2562_resume(struct snd_soc_component *component) +{ + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + + if (tas2562->sdz_gpio) + gpiod_set_value_cansleep(tas2562->sdz_gpio, 1); + + regcache_cache_only(tas2562->regmap, false); + + return regcache_sync(tas2562->regmap); +} +#else +#define tas2562_suspend NULL +#define tas2562_resume NULL +#endif + +static const char * const tas2562_ASI1_src[] = { + "I2C offset", "Left", "Right", "LeftRightDiv2", +}; + +static SOC_ENUM_SINGLE_DECL(tas2562_ASI1_src_enum, TAS2562_TDM_CFG2, 4, + tas2562_ASI1_src); + +static const struct snd_kcontrol_new tas2562_asi1_mux = + SOC_DAPM_ENUM("ASI1 Source", tas2562_ASI1_src_enum); + +static int tas2562_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + dev_info(tas2562->dev, "SND_SOC_DAPM_POST_PMU\n"); + break; + case SND_SOC_DAPM_PRE_PMD: + dev_info(tas2562->dev, "SND_SOC_DAPM_PRE_PMD\n"); + break; + default: + break; + } + + return 0; +} + +static DECLARE_TLV_DB_SCALE(tas2562_dac_tlv, 850, 50, 0); + +static const struct snd_kcontrol_new isense_switch = + SOC_DAPM_SINGLE("Switch", TAS2562_PWR_CTRL, TAS2562_ISENSE_POWER_EN, + 1, 1); + +static const struct snd_kcontrol_new vsense_switch = + SOC_DAPM_SINGLE("Switch", TAS2562_PWR_CTRL, TAS2562_VSENSE_POWER_EN, + 1, 1); + +static const struct snd_kcontrol_new tas2562_snd_controls[] = { + SOC_SINGLE_TLV("Amp Gain Volume", TAS2562_PB_CFG1, 0, 0x1c, 0, + tas2562_dac_tlv), +}; + +static const struct snd_soc_dapm_widget tas2562_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2562_asi1_mux), + SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2562_dac_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SWITCH("ISENSE", TAS2562_PWR_CTRL, 3, 1, &isense_switch), + SND_SOC_DAPM_SWITCH("VSENSE", TAS2562_PWR_CTRL, 2, 1, &vsense_switch), + SND_SOC_DAPM_SIGGEN("VMON"), + SND_SOC_DAPM_SIGGEN("IMON"), + SND_SOC_DAPM_OUTPUT("OUT"), +}; + +static const struct snd_soc_dapm_route tas2562_audio_map[] = { + {"ASI1 Sel", "I2C offset", "ASI1"}, + {"ASI1 Sel", "Left", "ASI1"}, + {"ASI1 Sel", "Right", "ASI1"}, + {"ASI1 Sel", "LeftRightDiv2", "ASI1"}, + { "DAC", NULL, "DAC IN" }, + { "OUT", NULL, "DAC" }, + {"ISENSE", "Switch", "IMON"}, + {"VSENSE", "Switch", "VMON"}, +}; + +static const struct snd_soc_component_driver soc_component_dev_tas2562 = { + .probe = tas2562_codec_probe, + .suspend = tas2562_suspend, + .resume = tas2562_resume, + .set_bias_level = tas2562_set_bias_level, + .controls = tas2562_snd_controls, + .num_controls = ARRAY_SIZE(tas2562_snd_controls), + .dapm_widgets = tas2562_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas2562_dapm_widgets), + .dapm_routes = tas2562_audio_map, + .num_dapm_routes = ARRAY_SIZE(tas2562_audio_map), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static const struct snd_soc_dai_ops tas2562_speaker_dai_ops = { + .hw_params = tas2562_hw_params, + .set_fmt = tas2562_set_dai_fmt, + .set_tdm_slot = tas2562_set_dai_tdm_slot, + .digital_mute = tas2562_mute, +}; + +static struct snd_soc_dai_driver tas2562_dai[] = { + { + .name = "tas2562-amplifier", + .id = 0, + .playback = { + .stream_name = "ASI1 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = TAS2562_FORMATS, + }, + .ops = &tas2562_speaker_dai_ops, + }, +}; + +static const struct regmap_range_cfg tas2562_ranges[] = { + { + .range_min = 0, + .range_max = 5 * 128, + .selector_reg = TAS2562_PAGE_CTRL, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 128, + }, +}; + +static const struct reg_default tas2562_reg_defaults[] = { + { TAS2562_PAGE_CTRL, 0x00 }, + { TAS2562_SW_RESET, 0x00 }, + { TAS2562_PWR_CTRL, 0x0e }, + { TAS2562_PB_CFG1, 0x20 }, + { TAS2562_TDM_CFG0, 0x09 }, + { TAS2562_TDM_CFG1, 0x02 }, +}; + +static const struct regmap_config tas2562_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = 5 * 128, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = tas2562_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tas2562_reg_defaults), + .ranges = tas2562_ranges, + .num_ranges = ARRAY_SIZE(tas2562_ranges), +}; + +static int tas2562_parse_dt(struct tas2562_data *tas2562) +{ + struct device *dev = tas2562->dev; + int ret = 0; + + tas2562->sdz_gpio = devm_gpiod_get_optional(dev, "shut-down-gpio", + GPIOD_OUT_HIGH); + if (IS_ERR(tas2562->sdz_gpio)) { + if (PTR_ERR(tas2562->sdz_gpio) == -EPROBE_DEFER) { + tas2562->sdz_gpio = NULL; + return -EPROBE_DEFER; + } + } + + ret = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no", + &tas2562->i_sense_slot); + if (ret) + dev_err(dev, "Looking up %s property failed %d\n", + "ti,imon-slot-no", ret); + + return ret; +} + +static int tas2562_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct tas2562_data *data; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + data->dev = &client->dev; + + tas2562_parse_dt(data); + + data->regmap = devm_regmap_init_i2c(client, &tas2562_regmap_config); + if (IS_ERR(data->regmap)) { + ret = PTR_ERR(data->regmap); + dev_err(dev, "failed to allocate register map: %d\n", ret); + return ret; + } + + dev_set_drvdata(&client->dev, data); + + return devm_snd_soc_register_component(dev, &soc_component_dev_tas2562, + tas2562_dai, + ARRAY_SIZE(tas2562_dai)); + +} + +static const struct i2c_device_id tas2562_id[] = { + { "tas2562", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tas2562_id); + +static const struct of_device_id tas2562_of_match[] = { + { .compatible = "ti,tas2562", }, + { }, +}; +MODULE_DEVICE_TABLE(of, tas2562_of_match); + +static struct i2c_driver tas2562_i2c_driver = { + .driver = { + .name = "tas2562", + .of_match_table = of_match_ptr(tas2562_of_match), + }, + .probe = tas2562_probe, + .id_table = tas2562_id, +}; + +module_i2c_driver(tas2562_i2c_driver); + +MODULE_AUTHOR("Dan Murphy "); +MODULE_DESCRIPTION("TAS2562 Audio amplifier driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tas2562.h b/sound/soc/codecs/tas2562.h new file mode 100644 index 000000000000..60f2bb1d198b --- /dev/null +++ b/sound/soc/codecs/tas2562.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tas2562.h - ALSA SoC Texas Instruments TAS2562 Mono Audio Amplifier + * + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Dan Murphy + */ + +#ifndef __TAS2562_H__ +#define __TAS2562_H__ + +#define TAS2562_PAGE_CTRL 0x00 + +#define TAS2562_REG(page, reg) ((page * 128) + reg) + +#define TAS2562_SW_RESET TAS2562_REG(0, 0x01) +#define TAS2562_PWR_CTRL TAS2562_REG(0, 0x02) +#define TAS2562_PB_CFG1 TAS2562_REG(0, 0x03) +#define TAS2562_MISC_CFG1 TAS2562_REG(0, 0x04) +#define TAS2562_MISC_CFG2 TAS2562_REG(0, 0x05) + +#define TAS2562_TDM_CFG0 TAS2562_REG(0, 0x06) +#define TAS2562_TDM_CFG1 TAS2562_REG(0, 0x07) +#define TAS2562_TDM_CFG2 TAS2562_REG(0, 0x08) +#define TAS2562_TDM_CFG3 TAS2562_REG(0, 0x09) +#define TAS2562_TDM_CFG4 TAS2562_REG(0, 0x0a) +#define TAS2562_TDM_CFG5 TAS2562_REG(0, 0x0b) +#define TAS2562_TDM_CFG6 TAS2562_REG(0, 0x0c) +#define TAS2562_TDM_CFG7 TAS2562_REG(0, 0x0d) +#define TAS2562_TDM_CFG8 TAS2562_REG(0, 0x0e) +#define TAS2562_TDM_CFG9 TAS2562_REG(0, 0x0f) +#define TAS2562_TDM_CFG10 TAS2562_REG(0, 0x10) +#define TAS2562_TDM_DET TAS2562_REG(0, 0x11) +#define TAS2562_REV_ID TAS2562_REG(0, 0x7d) + +/* Page 2 */ +#define TAS2562_DVC_CFG1 TAS2562_REG(2, 0x01) +#define TAS2562_DVC_CFG2 TAS2562_REG(2, 0x02) + +#define TAS2562_RESET BIT(0) + +#define TAS2562_MODE_MASK 0x3 +#define TAS2562_ACTIVE 0x0 +#define TAS2562_MUTE 0x1 +#define TAS2562_SHUTDOWN 0x2 + +#define TAS2562_TDM_CFG1_RX_EDGE_MASK BIT(0) +#define TAS2562_TDM_CFG1_RX_FALLING 1 +#define TAS2562_TDM_CFG1_RX_OFFSET_MASK GENMASK(4, 0) + +#define TAS2562_TDM_CFG0_RAMPRATE_MASK BIT(5) +#define TAS2562_TDM_CFG0_RAMPRATE_44_1 BIT(5) +#define TAS2562_TDM_CFG0_SAMPRATE_MASK GENMASK(3, 1) +#define TAS2562_TDM_CFG0_SAMPRATE_7305_8KHZ 0x0 +#define TAS2562_TDM_CFG0_SAMPRATE_14_7_16KHZ 0x1 +#define TAS2562_TDM_CFG0_SAMPRATE_22_05_24KHZ 0x2 +#define TAS2562_TDM_CFG0_SAMPRATE_29_4_32KHZ 0x3 +#define TAS2562_TDM_CFG0_SAMPRATE_44_1_48KHZ 0x4 +#define TAS2562_TDM_CFG0_SAMPRATE_88_2_96KHZ 0x5 +#define TAS2562_TDM_CFG0_SAMPRATE_176_4_192KHZ 0x6 + +#define TAS2562_TDM_CFG2_RIGHT_JUSTIFY BIT(6) + +#define TAS2562_TDM_CFG2_RXLEN_MASK GENMASK(0, 1) +#define TAS2562_TDM_CFG2_RXLEN_16B 0x0 +#define TAS2562_TDM_CFG2_RXLEN_24B BIT(0) +#define TAS2562_TDM_CFG2_RXLEN_32B BIT(1) + +#define TAS2562_TDM_CFG2_RXWLEN_MASK GENMASK(3, 2) +#define TAS2562_TDM_CFG2_RXWLEN_16B 0x0 +#define TAS2562_TDM_CFG2_RXWLEN_20B BIT(2) +#define TAS2562_TDM_CFG2_RXWLEN_24B BIT(3) +#define TAS2562_TDM_CFG2_RXWLEN_32B (BIT(2) | BIT(3)) + +#define TAS2562_VSENSE_POWER_EN BIT(2) +#define TAS2562_ISENSE_POWER_EN BIT(3) + +#define TAS2562_TDM_CFG5_VSNS_EN BIT(6) +#define TAS2562_TDM_CFG5_VSNS_SLOT_MASK GENMASK(5, 0) + +#define TAS2562_TDM_CFG6_ISNS_EN BIT(6) +#define TAS2562_TDM_CFG6_ISNS_SLOT_MASK GENMASK(5, 0) + +#endif /* __TAS2562_H__ */