Commit 842860f4 authored by Mark Brown's avatar Mark Brown

Merge series "Add I2S-MCC support for Microchip's SAMA7G5" from Codrin...

Merge series "Add I2S-MCC support for Microchip's SAMA7G5" from Codrin Ciubotariu <codrin.ciubotariu@microchip.com>:

SAMA7G5 includes an updated version of I2S-MCC, found previously on
SAM9X60. This controller includes 8 data pins, 4 for playback and 4 for
capture. For I2S and LEFT_J formats, these pins can be used to
send/receive up to 8 audio channels. For DSP_A, with TDM, any pins pair
(DIN/DOUT) from these 4 can be selected to send/receive data. This
version also includes 2 FIFOs (send and receive).
This patch set starts by moving the driver's bindings to yaml and
continues with adding a new compatible for the SAMA7G5 variant, followed
by the changes needed for I2S/LEFT_J support, TDM pin pair selection and
FIFO support, exclusively for SAMA7G5.

Changes in v2:
- moved DT binding conversion patch from the beginning to the end of the
  patch serieses
- patches that update the DT binding are modified to change .txt file
  instead of .yaml

Codrin Ciubotariu (7):
  dt-bindings: mchp,i2s-mcc: Add SAMA7G5 to binding
  ASoC: mchp-i2s-mcc: Add compatible for SAMA7G5
  ASoC: mchp-i2s-mcc: Add multi-channel support for I2S and LEFT_J
    formats
  dt-bindings: mchp,i2s-mcc: Add property to specify pin pair for TDM
  ASoC: mchp-i2s-mcc: Add support to select TDM pins
  ASoC: mchp-i2s-mcc: Add FIFOs support
  ASoC: convert Microchip I2SMCC binding to yaml

 .../bindings/sound/mchp,i2s-mcc.yaml          | 108 ++++++++++++
 .../bindings/sound/mchp-i2s-mcc.txt           |  43 -----
 sound/soc/atmel/Kconfig                       |   3 +
 sound/soc/atmel/mchp-i2s-mcc.c                | 161 +++++++++++++++---
 4 files changed, 252 insertions(+), 63 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/mchp,i2s-mcc.yaml
 delete mode 100644 Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt

--
2.27.0
parents e4438582 ead2a3e4
* Microchip I2S Multi-Channel Controller * Microchip I2S Multi-Channel Controller
Required properties: Required properties:
- compatible: Should be "microchip,sam9x60-i2smcc". - compatible: Should be "microchip,sam9x60-i2smcc" or
"microchip,sama7g5-i2smcc".
- reg: Should be the physical base address of the controller and the - reg: Should be the physical base address of the controller and the
length of memory mapped region. length of memory mapped region.
- interrupts: Should contain the interrupt for the controller. - interrupts: Should contain the interrupt for the controller.
...@@ -18,7 +19,12 @@ Required properties: ...@@ -18,7 +19,12 @@ Required properties:
Optional properties: Optional properties:
- pinctrl-0: Should specify pin control groups used for this controller. - pinctrl-0: Should specify pin control groups used for this controller.
- princtrl-names: Should contain only one value - "default". - princtrl-names: Should contain only one value - "default".
- microchip,tdm-data-pair: 8 bit value that represents the DIN/DOUT pair pins
which are used to receive/send TDM data. It is optional
and it is only needed if the controller uses the TDM
mode. Not available for "microchip,sam9x60-i2smcc"
compatible. If it's not present, the default value is 0,
so the DIN/DOUT 0 pins are used.
(1) : Only the peripheral clock is required. The generated clock is optional (1) : Only the peripheral clock is required. The generated clock is optional
and should be set mostly when Master Mode is required. and should be set mostly when Master Mode is required.
......
...@@ -127,10 +127,13 @@ config SND_MCHP_SOC_I2S_MCC ...@@ -127,10 +127,13 @@ config SND_MCHP_SOC_I2S_MCC
Say Y or M if you want to add support for I2S Multi-Channel ASoC Say Y or M if you want to add support for I2S Multi-Channel ASoC
driver on the following Microchip platforms: driver on the following Microchip platforms:
- sam9x60 - sam9x60
- sama7g5
The I2SMCC complies with the Inter-IC Sound (I2S) bus specification The I2SMCC complies with the Inter-IC Sound (I2S) bus specification
and supports a Time Division Multiplexed (TDM) interface with and supports a Time Division Multiplexed (TDM) interface with
external multi-channel audio codecs. external multi-channel audio codecs.
Starting with sama7g5, I2S and Left-Justified multi-channel is
supported by using multiple data pins, output and input, without TDM.
config SND_MCHP_SOC_SPDIFTX config SND_MCHP_SOC_SPDIFTX
tristate "Microchip ASoC driver for boards using S/PDIF TX" tristate "Microchip ASoC driver for boards using S/PDIF TX"
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/lcm.h> #include <linux/lcm.h>
#include <linux/of_device.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
...@@ -99,6 +100,8 @@ ...@@ -99,6 +100,8 @@
#define MCHP_I2SMCC_MRA_DATALENGTH_8_BITS_COMPACT (7 << 1) #define MCHP_I2SMCC_MRA_DATALENGTH_8_BITS_COMPACT (7 << 1)
#define MCHP_I2SMCC_MRA_WIRECFG_MASK GENMASK(5, 4) #define MCHP_I2SMCC_MRA_WIRECFG_MASK GENMASK(5, 4)
#define MCHP_I2SMCC_MRA_WIRECFG_TDM(pin) (((pin) << 4) & \
MCHP_I2SMCC_MRA_WIRECFG_MASK)
#define MCHP_I2SMCC_MRA_WIRECFG_I2S_1_TDM_0 (0 << 4) #define MCHP_I2SMCC_MRA_WIRECFG_I2S_1_TDM_0 (0 << 4)
#define MCHP_I2SMCC_MRA_WIRECFG_I2S_2_TDM_1 (1 << 4) #define MCHP_I2SMCC_MRA_WIRECFG_I2S_2_TDM_1 (1 << 4)
#define MCHP_I2SMCC_MRA_WIRECFG_I2S_4_TDM_2 (2 << 4) #define MCHP_I2SMCC_MRA_WIRECFG_I2S_4_TDM_2 (2 << 4)
...@@ -173,7 +176,7 @@ ...@@ -173,7 +176,7 @@
*/ */
#define MCHP_I2SMCC_MRB_CRAMODE_REGULAR (1 << 0) #define MCHP_I2SMCC_MRB_CRAMODE_REGULAR (1 << 0)
#define MCHP_I2SMCC_MRB_FIFOEN BIT(1) #define MCHP_I2SMCC_MRB_FIFOEN BIT(4)
#define MCHP_I2SMCC_MRB_DMACHUNK_MASK GENMASK(9, 8) #define MCHP_I2SMCC_MRB_DMACHUNK_MASK GENMASK(9, 8)
#define MCHP_I2SMCC_MRB_DMACHUNK(no_words) \ #define MCHP_I2SMCC_MRB_DMACHUNK(no_words) \
...@@ -225,6 +228,11 @@ static const struct regmap_config mchp_i2s_mcc_regmap_config = { ...@@ -225,6 +228,11 @@ static const struct regmap_config mchp_i2s_mcc_regmap_config = {
.max_register = MCHP_I2SMCC_VERSION, .max_register = MCHP_I2SMCC_VERSION,
}; };
struct mchp_i2s_mcc_soc_data {
unsigned int data_pin_pair_num;
bool has_fifo;
};
struct mchp_i2s_mcc_dev { struct mchp_i2s_mcc_dev {
struct wait_queue_head wq_txrdy; struct wait_queue_head wq_txrdy;
struct wait_queue_head wq_rxrdy; struct wait_queue_head wq_rxrdy;
...@@ -232,6 +240,7 @@ struct mchp_i2s_mcc_dev { ...@@ -232,6 +240,7 @@ struct mchp_i2s_mcc_dev {
struct regmap *regmap; struct regmap *regmap;
struct clk *pclk; struct clk *pclk;
struct clk *gclk; struct clk *gclk;
const struct mchp_i2s_mcc_soc_data *soc;
struct snd_dmaengine_dai_dma_data playback; struct snd_dmaengine_dai_dma_data playback;
struct snd_dmaengine_dai_dma_data capture; struct snd_dmaengine_dai_dma_data capture;
unsigned int fmt; unsigned int fmt;
...@@ -239,6 +248,7 @@ struct mchp_i2s_mcc_dev { ...@@ -239,6 +248,7 @@ struct mchp_i2s_mcc_dev {
unsigned int frame_length; unsigned int frame_length;
int tdm_slots; int tdm_slots;
int channels; int channels;
u8 tdm_data_pair;
unsigned int gclk_use:1; unsigned int gclk_use:1;
unsigned int gclk_running:1; unsigned int gclk_running:1;
unsigned int tx_rdy:1; unsigned int tx_rdy:1;
...@@ -248,7 +258,7 @@ struct mchp_i2s_mcc_dev { ...@@ -248,7 +258,7 @@ struct mchp_i2s_mcc_dev {
static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id) static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id)
{ {
struct mchp_i2s_mcc_dev *dev = dev_id; struct mchp_i2s_mcc_dev *dev = dev_id;
u32 sra, imra, srb, imrb, pendinga, pendingb, idra = 0; u32 sra, imra, srb, imrb, pendinga, pendingb, idra = 0, idrb = 0;
irqreturn_t ret = IRQ_NONE; irqreturn_t ret = IRQ_NONE;
regmap_read(dev->regmap, MCHP_I2SMCC_IMRA, &imra); regmap_read(dev->regmap, MCHP_I2SMCC_IMRA, &imra);
...@@ -266,23 +276,35 @@ static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id) ...@@ -266,23 +276,35 @@ static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id)
* Tx/Rx ready interrupts are enabled when stopping only, to assure * Tx/Rx ready interrupts are enabled when stopping only, to assure
* availability and to disable clocks if necessary * availability and to disable clocks if necessary
*/ */
if (dev->soc->has_fifo) {
idrb |= pendingb & (MCHP_I2SMCC_INT_TXFFRDY |
MCHP_I2SMCC_INT_RXFFRDY);
} else {
idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) | idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) |
MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
if (idra) }
if (idra || idrb)
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
if ((imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) && if ((!dev->soc->has_fifo &&
(imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) &&
(imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) == (imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) ==
(idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) { (idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) ||
(dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_TXFFRDY)) {
dev->tx_rdy = 1; dev->tx_rdy = 1;
wake_up_interruptible(&dev->wq_txrdy); wake_up_interruptible(&dev->wq_txrdy);
} }
if ((imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) && if ((!dev->soc->has_fifo &&
(imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) &&
(imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) == (imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) ==
(idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) { (idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) ||
(dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_RXFFRDY)) {
dev->rx_rdy = 1; dev->rx_rdy = 1;
wake_up_interruptible(&dev->wq_rxrdy); wake_up_interruptible(&dev->wq_rxrdy);
} }
if (dev->soc->has_fifo)
regmap_write(dev->regmap, MCHP_I2SMCC_IDRB, idrb);
else
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra); regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra);
return ret; return ret;
...@@ -549,6 +571,17 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, ...@@ -549,6 +571,17 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
} }
if (dev->fmt & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) { if (dev->fmt & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
/* for I2S and LEFT_J one pin is needed for every 2 channels */
if (channels > dev->soc->data_pin_pair_num * 2) {
dev_err(dev->dev,
"unsupported number of audio channels: %d\n",
channels);
return -EINVAL;
}
/* enable for interleaved format */
mrb |= MCHP_I2SMCC_MRB_CRAMODE_REGULAR;
switch (channels) { switch (channels) {
case 1: case 1:
if (is_playback) if (is_playback)
...@@ -558,6 +591,12 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, ...@@ -558,6 +591,12 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
break; break;
case 2: case 2:
break; break;
case 4:
mra |= MCHP_I2SMCC_MRA_WIRECFG_I2S_2_TDM_1;
break;
case 8:
mra |= MCHP_I2SMCC_MRA_WIRECFG_I2S_4_TDM_2;
break;
default: default:
dev_err(dev->dev, "unsupported number of audio channels\n"); dev_err(dev->dev, "unsupported number of audio channels\n");
return -EINVAL; return -EINVAL;
...@@ -566,6 +605,8 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, ...@@ -566,6 +605,8 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
if (!frame_length) if (!frame_length)
frame_length = 2 * params_physical_width(params); frame_length = 2 * params_physical_width(params);
} else if (dev->fmt & SND_SOC_DAIFMT_DSP_A) { } else if (dev->fmt & SND_SOC_DAIFMT_DSP_A) {
mra |= MCHP_I2SMCC_MRA_WIRECFG_TDM(dev->tdm_data_pair);
if (dev->tdm_slots) { if (dev->tdm_slots) {
if (channels % 2 && channels * 2 <= dev->tdm_slots) { if (channels % 2 && channels * 2 <= dev->tdm_slots) {
/* /*
...@@ -636,6 +677,10 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, ...@@ -636,6 +677,10 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
} }
} }
/* enable FIFO if available */
if (dev->soc->has_fifo)
mrb |= MCHP_I2SMCC_MRB_FIFOEN;
/* /*
* If we are already running, the wanted setup must be * If we are already running, the wanted setup must be
* the same with the one that's currently ongoing * the same with the one that's currently ongoing
...@@ -698,8 +743,13 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream, ...@@ -698,8 +743,13 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream,
if (err == 0) { if (err == 0) {
dev_warn_once(dev->dev, dev_warn_once(dev->dev,
"Timeout waiting for Tx ready\n"); "Timeout waiting for Tx ready\n");
if (dev->soc->has_fifo)
regmap_write(dev->regmap, MCHP_I2SMCC_IDRB,
MCHP_I2SMCC_INT_TXFFRDY);
else
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)); MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels));
dev->tx_rdy = 1; dev->tx_rdy = 1;
} }
} else { } else {
...@@ -709,6 +759,10 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream, ...@@ -709,6 +759,10 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream,
if (err == 0) { if (err == 0) {
dev_warn_once(dev->dev, dev_warn_once(dev->dev,
"Timeout waiting for Rx ready\n"); "Timeout waiting for Rx ready\n");
if (dev->soc->has_fifo)
regmap_write(dev->regmap, MCHP_I2SMCC_IDRB,
MCHP_I2SMCC_INT_RXFFRDY);
else
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
dev->rx_rdy = 1; dev->rx_rdy = 1;
...@@ -737,7 +791,7 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -737,7 +791,7 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
u32 cr = 0; u32 cr = 0;
u32 iera = 0; u32 iera = 0, ierb = 0;
u32 sr; u32 sr;
int err; int err;
...@@ -761,6 +815,9 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -761,6 +815,9 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
* Enable Tx Ready interrupts on all channels * Enable Tx Ready interrupts on all channels
* to assure all data is sent * to assure all data is sent
*/ */
if (dev->soc->has_fifo)
ierb = MCHP_I2SMCC_INT_TXFFRDY;
else
iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels); iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels);
} else if (!is_playback && (sr & MCHP_I2SMCC_SR_RXEN)) { } else if (!is_playback && (sr & MCHP_I2SMCC_SR_RXEN)) {
cr = MCHP_I2SMCC_CR_RXDIS; cr = MCHP_I2SMCC_CR_RXDIS;
...@@ -769,6 +826,9 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -769,6 +826,9 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
* Enable Rx Ready interrupts on all channels * Enable Rx Ready interrupts on all channels
* to assure all data is received * to assure all data is received
*/ */
if (dev->soc->has_fifo)
ierb = MCHP_I2SMCC_INT_RXFFRDY;
else
iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels); iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels);
} }
break; break;
...@@ -787,6 +847,9 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -787,6 +847,9 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
} }
} }
if (dev->soc->has_fifo)
regmap_write(dev->regmap, MCHP_I2SMCC_IERB, ierb);
else
regmap_write(dev->regmap, MCHP_I2SMCC_IERA, iera); regmap_write(dev->regmap, MCHP_I2SMCC_IERA, iera);
regmap_write(dev->regmap, MCHP_I2SMCC_CR, cr); regmap_write(dev->regmap, MCHP_I2SMCC_CR, cr);
...@@ -869,15 +932,68 @@ static const struct snd_soc_component_driver mchp_i2s_mcc_component = { ...@@ -869,15 +932,68 @@ static const struct snd_soc_component_driver mchp_i2s_mcc_component = {
}; };
#ifdef CONFIG_OF #ifdef CONFIG_OF
static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sam9x60 = {
.data_pin_pair_num = 1,
};
static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sama7g5 = {
.data_pin_pair_num = 4,
.has_fifo = true,
};
static const struct of_device_id mchp_i2s_mcc_dt_ids[] = { static const struct of_device_id mchp_i2s_mcc_dt_ids[] = {
{ {
.compatible = "microchip,sam9x60-i2smcc", .compatible = "microchip,sam9x60-i2smcc",
.data = &mchp_i2s_mcc_sam9x60,
},
{
.compatible = "microchip,sama7g5-i2smcc",
.data = &mchp_i2s_mcc_sama7g5,
}, },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, mchp_i2s_mcc_dt_ids); MODULE_DEVICE_TABLE(of, mchp_i2s_mcc_dt_ids);
#endif #endif
static int mchp_i2s_mcc_soc_data_parse(struct platform_device *pdev,
struct mchp_i2s_mcc_dev *dev)
{
int err;
if (!dev->soc) {
dev_err(&pdev->dev, "failed to get soc data\n");
return -ENODEV;
}
if (dev->soc->data_pin_pair_num == 1)
return 0;
err = of_property_read_u8(pdev->dev.of_node, "microchip,tdm-data-pair",
&dev->tdm_data_pair);
if (err < 0 && err != -EINVAL) {
dev_err(&pdev->dev,
"bad property data for 'microchip,tdm-data-pair': %d",
err);
return err;
}
if (err == -EINVAL) {
dev_info(&pdev->dev,
"'microchip,tdm-data-pair' not found; assuming DIN/DOUT 0 for TDM\n");
dev->tdm_data_pair = 0;
} else {
if (dev->tdm_data_pair > dev->soc->data_pin_pair_num - 1) {
dev_err(&pdev->dev,
"invalid value for 'microchip,tdm-data-pair': %d\n",
dev->tdm_data_pair);
return -EINVAL;
}
dev_dbg(&pdev->dev, "TMD format on DIN/DOUT %d pins\n",
dev->tdm_data_pair);
}
return 0;
}
static int mchp_i2s_mcc_probe(struct platform_device *pdev) static int mchp_i2s_mcc_probe(struct platform_device *pdev)
{ {
struct mchp_i2s_mcc_dev *dev; struct mchp_i2s_mcc_dev *dev;
...@@ -929,6 +1045,11 @@ static int mchp_i2s_mcc_probe(struct platform_device *pdev) ...@@ -929,6 +1045,11 @@ static int mchp_i2s_mcc_probe(struct platform_device *pdev)
dev->gclk = NULL; dev->gclk = NULL;
} }
dev->soc = of_device_get_match_data(&pdev->dev);
err = mchp_i2s_mcc_soc_data_parse(pdev, dev);
if (err < 0)
return err;
dev->dev = &pdev->dev; dev->dev = &pdev->dev;
dev->regmap = regmap; dev->regmap = regmap;
platform_set_drvdata(pdev, dev); platform_set_drvdata(pdev, dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment