563 lines
13 KiB
Diff
563 lines
13 KiB
Diff
From 2ade8bdb82733eef35d23e2e930feb97dac42d68 Mon Sep 17 00:00:00 2001
|
|
From: "Wagner, Steffen" <steffen.wagner@intel.com>
|
|
Date: Mon, 8 May 2017 21:19:09 +0530
|
|
Subject: [PATCH 351/743] ASoC: tdf8532: NXP TDF8532 audio class-D amplifier
|
|
driver
|
|
|
|
This is a basic driver to register the codec, expose the
|
|
codec DAI and control the power mode of the amplifier.
|
|
|
|
Change-Id: Ie6ab037cd4d6c87e8e139b6d8af6cd4295445bf2
|
|
Signed-off-by: Mohit Sinha <mohit.sinha@intel.com>
|
|
Signed-off-by: Steffen Wagner <steffen.wagner@intel.com>
|
|
Reviewed-on:
|
|
Reviewed-by: B, Jayachandran <jayachandran.b@intel.com>
|
|
Reviewed-by: Shaik, Kareem M <kareem.m.shaik@intel.com>
|
|
Reviewed-by: Koul, Vinod <vinod.koul@intel.com>
|
|
Tested-by: Sm, Bhadur A <bhadur.a.sm@intel.com>
|
|
---
|
|
sound/soc/codecs/Kconfig | 5 +
|
|
sound/soc/codecs/Makefile | 2 +
|
|
sound/soc/codecs/tdf8532.c | 377 +++++++++++++++++++++++++++++++++++++
|
|
sound/soc/codecs/tdf8532.h | 101 ++++++++++
|
|
4 files changed, 485 insertions(+)
|
|
create mode 100644 sound/soc/codecs/tdf8532.c
|
|
create mode 100644 sound/soc/codecs/tdf8532.h
|
|
|
|
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
|
|
index b002d79d910e..006be9a90286 100644
|
|
--- a/sound/soc/codecs/Kconfig
|
|
+++ b/sound/soc/codecs/Kconfig
|
|
@@ -163,6 +163,7 @@ config SND_SOC_ALL_CODECS
|
|
select SND_SOC_TAS5720 if I2C
|
|
select SND_SOC_TAS6424 if I2C
|
|
select SND_SOC_TDA7419 if I2C
|
|
+ select SND_SOC_TDF8532 if I2C
|
|
select SND_SOC_TFA9879 if I2C
|
|
select SND_SOC_TLV320AIC23_I2C if I2C
|
|
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
|
|
@@ -1015,6 +1016,10 @@ config SND_SOC_TDA7419
|
|
depends on I2C
|
|
select REGMAP_I2C
|
|
|
|
+config SND_SOC_TDF8532
|
|
+ tristate
|
|
+ depends on I2C
|
|
+
|
|
config SND_SOC_TFA9879
|
|
tristate "NXP Semiconductors TFA9879 amplifier"
|
|
depends on I2C
|
|
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
|
|
index 5aed74a73acf..b9ec39dfc960 100644
|
|
--- a/sound/soc/codecs/Makefile
|
|
+++ b/sound/soc/codecs/Makefile
|
|
@@ -179,6 +179,7 @@ snd-soc-tas571x-objs := tas571x.o
|
|
snd-soc-tas5720-objs := tas5720.o
|
|
snd-soc-tas6424-objs := tas6424.o
|
|
snd-soc-tda7419-objs := tda7419.o
|
|
+snd-soc-tdf8532-objs := tdf8532.o
|
|
snd-soc-tfa9879-objs := tfa9879.o
|
|
snd-soc-tlv320aic23-objs := tlv320aic23.o
|
|
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
|
|
@@ -443,6 +444,7 @@ obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
|
|
obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o
|
|
obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o
|
|
obj-$(CONFIG_SND_SOC_TDA7419) += snd-soc-tda7419.o
|
|
+obj-$(CONFIG_SND_SOC_TDF8532) += snd-soc-tdf8532.o
|
|
obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
|
|
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
|
|
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
|
|
diff --git a/sound/soc/codecs/tdf8532.c b/sound/soc/codecs/tdf8532.c
|
|
new file mode 100644
|
|
index 000000000000..7a3cca073845
|
|
--- /dev/null
|
|
+++ b/sound/soc/codecs/tdf8532.c
|
|
@@ -0,0 +1,377 @@
|
|
+/*
|
|
+ * Codec driver for NXP Semiconductors - TDF8532
|
|
+ * Copyright (c) 2017, Intel Corporation.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms and conditions of the GNU General Public License,
|
|
+ * version 2, as published by the Free Software Foundation.
|
|
+ *
|
|
+ * This program is distributed in the hope 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/init.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/jiffies.h>
|
|
+#include <linux/time.h>
|
|
+#include <linux/acpi.h>
|
|
+#include <sound/soc.h>
|
|
+#include <sound/tlv.h>
|
|
+#include <sound/pcm_params.h>
|
|
+#include "tdf8532.h"
|
|
+
|
|
+static int __tdf8532_build_pkt(struct tdf8532_priv *dev_data,
|
|
+ va_list valist, u8 *payload)
|
|
+{
|
|
+ int param;
|
|
+ u8 len;
|
|
+ u8 *cmd_payload;
|
|
+ const u8 cmd_offset = 3;
|
|
+
|
|
+ payload[HEADER_TYPE] = MSG_TYPE_STX;
|
|
+ payload[HEADER_PKTID] = dev_data->pkt_id;
|
|
+
|
|
+ cmd_payload = &(payload[cmd_offset]);
|
|
+
|
|
+ param = va_arg(valist, int);
|
|
+ len = 0;
|
|
+
|
|
+ while (param != END) {
|
|
+ cmd_payload[len] = param;
|
|
+
|
|
+ len++;
|
|
+
|
|
+ param = va_arg(valist, int);
|
|
+ }
|
|
+
|
|
+ payload[HEADER_LEN] = len;
|
|
+
|
|
+ return len + cmd_offset;
|
|
+}
|
|
+
|
|
+static int __tdf8532_single_write(struct tdf8532_priv *dev_data,
|
|
+ int dummy, ...)
|
|
+{
|
|
+ va_list valist;
|
|
+ int ret;
|
|
+ u8 len;
|
|
+ u8 payload[255];
|
|
+
|
|
+ va_start(valist, dummy);
|
|
+
|
|
+ len = __tdf8532_build_pkt(dev_data, valist, payload);
|
|
+
|
|
+ va_end(valist);
|
|
+
|
|
+ print_hex_dump_debug("tdf8532-codec: Tx:", DUMP_PREFIX_NONE, 32, 1,
|
|
+ payload, len, false);
|
|
+ ret = i2c_master_send(dev_data->i2c, payload, len);
|
|
+
|
|
+ dev_data->pkt_id++;
|
|
+
|
|
+ if (ret < 0) {
|
|
+ dev_err(&(dev_data->i2c->dev),
|
|
+ "i2c send packet returned: %d\n", ret);
|
|
+
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static uint8_t tdf8532_read_wait_ack(struct tdf8532_priv *dev_data,
|
|
+ unsigned long timeout)
|
|
+{
|
|
+ uint8_t ack_repl[HEADER_SIZE] = {0, 0, 0};
|
|
+ unsigned long timeout_point = jiffies + timeout;
|
|
+ int ret;
|
|
+
|
|
+ do {
|
|
+ ret = i2c_master_recv(dev_data->i2c, ack_repl, HEADER_SIZE);
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+ } while (time_before(jiffies, timeout_point) &&
|
|
+ ack_repl[0] != MSG_TYPE_ACK);
|
|
+
|
|
+ if (ack_repl[0] != MSG_TYPE_ACK)
|
|
+ return -ETIME;
|
|
+ else
|
|
+ return ack_repl[2];
|
|
+
|
|
+out:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static uint8_t tdf8532_single_read(struct tdf8532_priv *dev_data,
|
|
+ char **repl_buff)
|
|
+{
|
|
+ int ret;
|
|
+ uint8_t len;
|
|
+
|
|
+ struct device *dev = &(dev_data->i2c->dev);
|
|
+
|
|
+ ret = tdf8532_read_wait_ack(dev_data, msecs_to_jiffies(ACK_TIMEOUT));
|
|
+
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev,
|
|
+ "Error waiting for ACK reply: %d\n", ret);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ len = ret + HEADER_SIZE;
|
|
+
|
|
+ *repl_buff = kzalloc(len, GFP_KERNEL);
|
|
+
|
|
+ ret = i2c_master_recv(dev_data->i2c, *repl_buff, len);
|
|
+
|
|
+ print_hex_dump_debug("tdf8532-codec: Rx:", DUMP_PREFIX_NONE, 32, 1,
|
|
+ *repl_buff, len, false);
|
|
+
|
|
+ if (ret < 0 || ret != len) {
|
|
+ dev_err(dev,
|
|
+ "i2c recv packet returned: %d (expected: %d)\n",
|
|
+ ret, len);
|
|
+ goto out_free;
|
|
+ }
|
|
+
|
|
+ return len;
|
|
+
|
|
+out_free:
|
|
+ kfree(*repl_buff);
|
|
+ repl_buff = NULL;
|
|
+out:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int tdf8532_get_state(struct tdf8532_priv *dev_data,
|
|
+ struct get_dev_status_repl **status_repl)
|
|
+{
|
|
+ int ret = 0;
|
|
+ char *repl_buff = NULL;
|
|
+
|
|
+ ret = tdf8532_amp_write(dev_data, GET_DEV_STATUS);
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+
|
|
+ ret = tdf8532_single_read(dev_data, &repl_buff);
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+
|
|
+ *status_repl = (struct get_dev_status_repl *) repl_buff;
|
|
+
|
|
+out:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int tdf8532_wait_state(struct tdf8532_priv *dev_data, u8 req_state,
|
|
+ unsigned long timeout)
|
|
+{
|
|
+ unsigned long timeout_point = jiffies + msecs_to_jiffies(timeout);
|
|
+ int ret;
|
|
+ struct get_dev_status_repl *status_repl;
|
|
+ struct device *dev = &(dev_data->i2c->dev);
|
|
+
|
|
+ do {
|
|
+ ret = tdf8532_get_state(dev_data, &status_repl);
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+
|
|
+ print_hex_dump_debug("tdf8532-codec: wait_state: ",
|
|
+ DUMP_PREFIX_NONE, 32, 1, status_repl,
|
|
+ 6, false);
|
|
+ } while (time_before(jiffies, timeout_point)
|
|
+ && status_repl->state != req_state);
|
|
+
|
|
+ if (status_repl->state == req_state)
|
|
+ return 0;
|
|
+
|
|
+ ret = -ETIME;
|
|
+
|
|
+ dev_err(dev, "tdf8532-codec: state: %u, req_state: %u, ret: %d\n",
|
|
+ status_repl->state, req_state, ret);
|
|
+
|
|
+out:
|
|
+ kfree(status_repl);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int tdf8532_start_play(struct tdf8532_priv *tdf8532)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = tdf8532_amp_write(tdf8532, SET_CLK_STATE, CLK_CONNECT);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ ret = tdf8532_amp_write(tdf8532, SET_CHNL_ENABLE,
|
|
+ CHNL_MASK(tdf8532->channels));
|
|
+
|
|
+ if (ret >= 0)
|
|
+ ret = tdf8532_wait_state(tdf8532, STATE_PLAY, ACK_TIMEOUT);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+
|
|
+static int tdf8532_stop_play(struct tdf8532_priv *tdf8532)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = tdf8532_amp_write(tdf8532, SET_CHNL_DISABLE,
|
|
+ CHNL_MASK(tdf8532->channels));
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+
|
|
+ ret = tdf8532_wait_state(tdf8532, STATE_STBY, ACK_TIMEOUT);
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+
|
|
+ ret = tdf8532_amp_write(tdf8532, SET_CLK_STATE, CLK_DISCONNECT);
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+
|
|
+ ret = tdf8532_wait_state(tdf8532, STATE_IDLE, ACK_TIMEOUT);
|
|
+
|
|
+out:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+
|
|
+static int tdf8532_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
|
+ struct snd_soc_dai *dai)
|
|
+{
|
|
+ int ret = 0;
|
|
+ struct snd_soc_component *component = dai->component;
|
|
+ struct tdf8532_priv *tdf8532 = snd_soc_component_get_drvdata(component);
|
|
+
|
|
+ dev_dbg(component->dev, "%s: cmd = %d\n", __func__, cmd);
|
|
+
|
|
+ switch (cmd) {
|
|
+ case SNDRV_PCM_TRIGGER_START:
|
|
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
|
+ case SNDRV_PCM_TRIGGER_RESUME:
|
|
+ ret = tdf8532_start_play(tdf8532);
|
|
+ break;
|
|
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
|
+ case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
+ case SNDRV_PCM_TRIGGER_STOP:
|
|
+ ret = tdf8532_stop_play(tdf8532);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int tdf8532_mute(struct snd_soc_dai *dai, int mute)
|
|
+{
|
|
+ struct snd_soc_component *component = dai->component;
|
|
+ struct tdf8532_priv *tdf8532 = snd_soc_component_get_drvdata(component);
|
|
+
|
|
+ dev_dbg(component->dev, "%s\n", __func__);
|
|
+
|
|
+ if (mute)
|
|
+ return tdf8532_amp_write(tdf8532, SET_CHNL_MUTE,
|
|
+ CHNL_MASK(CHNL_MAX));
|
|
+ else
|
|
+ return tdf8532_amp_write(tdf8532, SET_CHNL_UNMUTE,
|
|
+ CHNL_MASK(CHNL_MAX));
|
|
+}
|
|
+
|
|
+static const struct snd_soc_dai_ops tdf8532_dai_ops = {
|
|
+ .trigger = tdf8532_dai_trigger,
|
|
+ .digital_mute = tdf8532_mute,
|
|
+};
|
|
+
|
|
+static struct snd_soc_component_driver soc_component_tdf8532;
|
|
+
|
|
+static struct snd_soc_dai_driver tdf8532_dai[] = {
|
|
+ {
|
|
+ .name = "tdf8532-hifi",
|
|
+ .playback = {
|
|
+ .stream_name = "Playback",
|
|
+ .channels_min = 4,
|
|
+ .channels_max = 4,
|
|
+ .rates = SNDRV_PCM_RATE_48000,
|
|
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
|
|
+ },
|
|
+ .ops = &tdf8532_dai_ops,
|
|
+ }
|
|
+};
|
|
+
|
|
+static int tdf8532_i2c_probe(struct i2c_client *i2c,
|
|
+ const struct i2c_device_id *id)
|
|
+{
|
|
+ int ret;
|
|
+ struct tdf8532_priv *dev_data;
|
|
+ struct device *dev = &(i2c->dev);
|
|
+
|
|
+ dev_dbg(&i2c->dev, "%s\n", __func__);
|
|
+
|
|
+ dev_data = devm_kzalloc(dev, sizeof(struct tdf8532_priv), GFP_KERNEL);
|
|
+
|
|
+ if (!dev_data) {
|
|
+ ret = -ENOMEM;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (ret < 0)
|
|
+ dev_err(&i2c->dev, "Failed to set fast mute option: %d\n", ret);
|
|
+
|
|
+ dev_data->i2c = i2c;
|
|
+ dev_data->pkt_id = 0;
|
|
+ dev_data->channels = 4;
|
|
+
|
|
+ i2c_set_clientdata(i2c, dev_data);
|
|
+
|
|
+ ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_tdf8532,
|
|
+ tdf8532_dai, ARRAY_SIZE(tdf8532_dai));
|
|
+ if (ret != 0) {
|
|
+ dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int tdf8532_i2c_remove(struct i2c_client *i2c)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct i2c_device_id tdf8532_i2c_id[] = {
|
|
+ { "tdf8532", 0 },
|
|
+ { }
|
|
+};
|
|
+
|
|
+MODULE_DEVICE_TABLE(i2c, tdf8532_i2c_id);
|
|
+
|
|
+#if CONFIG_ACPI
|
|
+static const struct acpi_device_id tdf8532_acpi_match[] = {
|
|
+ {"INT34C3", 0},
|
|
+ {},
|
|
+};
|
|
+
|
|
+MODULE_DEVICE_TABLE(acpi, tdf8532_acpi_match);
|
|
+#endif
|
|
+
|
|
+static struct i2c_driver tdf8532_i2c_driver = {
|
|
+ .driver = {
|
|
+ .name = "tdf8532-codec",
|
|
+ .owner = THIS_MODULE,
|
|
+ .acpi_match_table = ACPI_PTR(tdf8532_acpi_match),
|
|
+ },
|
|
+ .probe = tdf8532_i2c_probe,
|
|
+ .remove = tdf8532_i2c_remove,
|
|
+ .id_table = tdf8532_i2c_id,
|
|
+};
|
|
+
|
|
+module_i2c_driver(tdf8532_i2c_driver);
|
|
+
|
|
+MODULE_DESCRIPTION("ASoC NXP Semiconductors TDF8532 driver");
|
|
+MODULE_AUTHOR("Steffen Wagner <steffen.wagner@intel.com>");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/sound/soc/codecs/tdf8532.h b/sound/soc/codecs/tdf8532.h
|
|
new file mode 100644
|
|
index 000000000000..6e3f2c147eac
|
|
--- /dev/null
|
|
+++ b/sound/soc/codecs/tdf8532.h
|
|
@@ -0,0 +1,101 @@
|
|
+/*
|
|
+ * tdf8532.h - Codec driver for NXP Semiconductors
|
|
+ * Copyright (c) 2017, Intel Corporation.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms and conditions of the GNU General Public License,
|
|
+ * version 2, as published by the Free Software Foundation.
|
|
+ *
|
|
+ * This program is distributed in the hope 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 __TDF8532_H_
|
|
+#define __TDF8532_H_
|
|
+
|
|
+#define ACK_TIMEOUT 300
|
|
+
|
|
+#define CHNL_MAX 5
|
|
+
|
|
+#define AMP_MOD 0x80
|
|
+#define END -1
|
|
+
|
|
+#define MSG_TYPE_STX 0x02
|
|
+#define MSG_TYPE_NAK 0x15
|
|
+#define MSG_TYPE_ACK 0x6
|
|
+
|
|
+#define HEADER_SIZE 3
|
|
+#define HEADER_TYPE 0
|
|
+#define HEADER_PKTID 1
|
|
+#define HEADER_LEN 2
|
|
+
|
|
+/* Set commands */
|
|
+#define SET_CLK_STATE 0x1A
|
|
+#define CLK_DISCONNECT 0x00
|
|
+#define CLK_CONNECT 0x01
|
|
+
|
|
+#define SET_CHNL_ENABLE 0x26
|
|
+#define SET_CHNL_DISABLE 0x27
|
|
+
|
|
+#define SET_CHNL_MUTE 0x42
|
|
+#define SET_CHNL_UNMUTE 0x43
|
|
+
|
|
+struct header_repl {
|
|
+ u8 msg_type;
|
|
+ u8 pkt_id;
|
|
+ u8 len;
|
|
+} __packed;
|
|
+
|
|
+#define GET_IDENT 0xE0
|
|
+
|
|
+struct get_ident_repl {
|
|
+ struct header_repl header;
|
|
+ u8 module_id;
|
|
+ u8 cmd_id;
|
|
+ u8 type_name;
|
|
+ u8 hw_major;
|
|
+ u8 hw_minor;
|
|
+ u8 sw_major;
|
|
+ u8 sw_minor;
|
|
+ u8 sw_sub;
|
|
+} __packed;
|
|
+
|
|
+#define GET_ERROR 0xE2
|
|
+
|
|
+struct get_error_repl {
|
|
+ struct header_repl header;
|
|
+ u8 module_id;
|
|
+ u8 cmd_id;
|
|
+ u8 last_cmd_id;
|
|
+ u8 error;
|
|
+ u8 status;
|
|
+} __packed;
|
|
+
|
|
+#define GET_DEV_STATUS 0x80
|
|
+
|
|
+enum dev_state {STATE_BOOT, STATE_IDLE, STATE_STBY, STATE_LDAG, STATE_PLAY,
|
|
+ STATE_PROT, STATE_SDWN, STATE_CLFA, STATE_NONE };
|
|
+
|
|
+struct get_dev_status_repl {
|
|
+ struct header_repl header;
|
|
+ u8 module_id;
|
|
+ u8 cmd_id;
|
|
+ u8 state;
|
|
+} __packed;
|
|
+
|
|
+/* Helpers */
|
|
+#define CHNL_MASK(channels) (u8)((0x00FF << channels) >> 8)
|
|
+
|
|
+#define tdf8532_amp_write(dev_data, ...)\
|
|
+ __tdf8532_single_write(dev_data, 0, AMP_MOD, __VA_ARGS__, END)
|
|
+
|
|
+struct tdf8532_priv {
|
|
+ struct i2c_client *i2c;
|
|
+ u8 channels;
|
|
+ u8 pkt_id;
|
|
+};
|
|
+
|
|
+#endif
|
|
--
|
|
2.19.2
|
|
|