612 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * linux/sound/soc/m8m/hi6210_i2s.c - I2S IP driver4 *5 * Copyright (C) 2015 Linaro, Ltd6 * Author: Andy Green <andy.green@linaro.org>7 *8 * This driver only deals with S2 interface (BT)9 */10 11#include <linux/init.h>12#include <linux/module.h>13#include <linux/device.h>14#include <linux/delay.h>15#include <linux/clk.h>16#include <linux/jiffies.h>17#include <linux/io.h>18#include <sound/core.h>19#include <sound/pcm.h>20#include <sound/pcm_params.h>21#include <sound/dmaengine_pcm.h>22#include <sound/initval.h>23#include <sound/soc.h>24#include <linux/interrupt.h>25#include <linux/reset.h>26#include <linux/of_address.h>27#include <linux/of_irq.h>28#include <linux/mfd/syscon.h>29#include <linux/reset-controller.h>30 31#include "hi6210-i2s.h"32 33struct hi6210_i2s {34 struct device *dev;35 struct reset_control *rc;36 struct clk *clk[8];37 int clocks;38 struct snd_soc_dai_driver dai;39 void __iomem *base;40 struct regmap *sysctrl;41 phys_addr_t base_phys;42 struct snd_dmaengine_dai_dma_data dma_data[2];43 int clk_rate;44 spinlock_t lock;45 int rate;46 int format;47 u8 bits;48 u8 channels;49 u8 id;50 u8 channel_length;51 u8 use;52 u32 master:1;53 u32 status:1;54};55 56#define SC_PERIPH_CLKEN1 0x21057#define SC_PERIPH_CLKDIS1 0x21458 59#define SC_PERIPH_CLKEN3 0x23060#define SC_PERIPH_CLKDIS3 0x23461 62#define SC_PERIPH_CLKEN12 0x27063#define SC_PERIPH_CLKDIS12 0x27464 65#define SC_PERIPH_RSTEN1 0x31066#define SC_PERIPH_RSTDIS1 0x31467#define SC_PERIPH_RSTSTAT1 0x31868 69#define SC_PERIPH_RSTEN2 0x32070#define SC_PERIPH_RSTDIS2 0x32471#define SC_PERIPH_RSTSTAT2 0x32872 73#define SOC_PMCTRL_BBPPLLALIAS 0x4874 75enum {76 CLK_DACODEC,77 CLK_I2S_BASE,78};79 80static inline void hi6210_write_reg(struct hi6210_i2s *i2s, int reg, u32 val)81{82 writel(val, i2s->base + reg);83}84 85static inline u32 hi6210_read_reg(struct hi6210_i2s *i2s, int reg)86{87 return readl(i2s->base + reg);88}89 90static int hi6210_i2s_startup(struct snd_pcm_substream *substream,91 struct snd_soc_dai *cpu_dai)92{93 struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);94 int ret, n;95 u32 val;96 97 /* deassert reset on ABB */98 regmap_read(i2s->sysctrl, SC_PERIPH_RSTSTAT2, &val);99 if (val & BIT(4))100 regmap_write(i2s->sysctrl, SC_PERIPH_RSTDIS2, BIT(4));101 102 for (n = 0; n < i2s->clocks; n++) {103 ret = clk_prepare_enable(i2s->clk[n]);104 if (ret)105 goto err_unprepare_clk;106 }107 108 ret = clk_set_rate(i2s->clk[CLK_I2S_BASE], 49152000);109 if (ret) {110 dev_err(i2s->dev, "%s: setting 49.152MHz base rate failed %d\n",111 __func__, ret);112 goto err_unprepare_clk;113 }114 115 /* enable clock before frequency division */116 regmap_write(i2s->sysctrl, SC_PERIPH_CLKEN12, BIT(9));117 118 /* enable codec working clock / == "codec bus clock" */119 regmap_write(i2s->sysctrl, SC_PERIPH_CLKEN1, BIT(5));120 121 /* deassert reset on codec / interface clock / working clock */122 regmap_write(i2s->sysctrl, SC_PERIPH_RSTEN1, BIT(5));123 regmap_write(i2s->sysctrl, SC_PERIPH_RSTDIS1, BIT(5));124 125 /* not interested in i2s irqs */126 val = hi6210_read_reg(i2s, HII2S_CODEC_IRQ_MASK);127 val |= 0x3f;128 hi6210_write_reg(i2s, HII2S_CODEC_IRQ_MASK, val);129 130 131 /* reset the stereo downlink fifo */132 val = hi6210_read_reg(i2s, HII2S_APB_AFIFO_CFG_1);133 val |= (BIT(5) | BIT(4));134 hi6210_write_reg(i2s, HII2S_APB_AFIFO_CFG_1, val);135 136 val = hi6210_read_reg(i2s, HII2S_APB_AFIFO_CFG_1);137 val &= ~(BIT(5) | BIT(4));138 hi6210_write_reg(i2s, HII2S_APB_AFIFO_CFG_1, val);139 140 141 val = hi6210_read_reg(i2s, HII2S_SW_RST_N);142 val &= ~(HII2S_SW_RST_N__ST_DL_WORDLEN_MASK <<143 HII2S_SW_RST_N__ST_DL_WORDLEN_SHIFT);144 val |= (HII2S_BITS_16 << HII2S_SW_RST_N__ST_DL_WORDLEN_SHIFT);145 hi6210_write_reg(i2s, HII2S_SW_RST_N, val);146 147 val = hi6210_read_reg(i2s, HII2S_MISC_CFG);148 /* mux 11/12 = APB not i2s */149 val &= ~HII2S_MISC_CFG__ST_DL_TEST_SEL;150 /* BT R ch 0 = mixer op of DACR ch */151 val &= ~HII2S_MISC_CFG__S2_DOUT_RIGHT_SEL;152 val &= ~HII2S_MISC_CFG__S2_DOUT_TEST_SEL;153 154 val |= HII2S_MISC_CFG__S2_DOUT_RIGHT_SEL;155 /* BT L ch = 1 = mux 7 = "mixer output of DACL */156 val |= HII2S_MISC_CFG__S2_DOUT_TEST_SEL;157 hi6210_write_reg(i2s, HII2S_MISC_CFG, val);158 159 val = hi6210_read_reg(i2s, HII2S_SW_RST_N);160 val |= HII2S_SW_RST_N__SW_RST_N;161 hi6210_write_reg(i2s, HII2S_SW_RST_N, val);162 163 return 0;164 165err_unprepare_clk:166 while (n--)167 clk_disable_unprepare(i2s->clk[n]);168 return ret;169}170 171static void hi6210_i2s_shutdown(struct snd_pcm_substream *substream,172 struct snd_soc_dai *cpu_dai)173{174 struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);175 int n;176 177 for (n = 0; n < i2s->clocks; n++)178 clk_disable_unprepare(i2s->clk[n]);179 180 regmap_write(i2s->sysctrl, SC_PERIPH_RSTEN1, BIT(5));181}182 183static void hi6210_i2s_txctrl(struct snd_soc_dai *cpu_dai, int on)184{185 struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);186 u32 val;187 188 spin_lock(&i2s->lock);189 if (on) {190 /* enable S2 TX */191 val = hi6210_read_reg(i2s, HII2S_I2S_CFG);192 val |= HII2S_I2S_CFG__S2_IF_TX_EN;193 hi6210_write_reg(i2s, HII2S_I2S_CFG, val);194 } else {195 /* disable S2 TX */196 val = hi6210_read_reg(i2s, HII2S_I2S_CFG);197 val &= ~HII2S_I2S_CFG__S2_IF_TX_EN;198 hi6210_write_reg(i2s, HII2S_I2S_CFG, val);199 }200 spin_unlock(&i2s->lock);201}202 203static void hi6210_i2s_rxctrl(struct snd_soc_dai *cpu_dai, int on)204{205 struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);206 u32 val;207 208 spin_lock(&i2s->lock);209 if (on) {210 val = hi6210_read_reg(i2s, HII2S_I2S_CFG);211 val |= HII2S_I2S_CFG__S2_IF_RX_EN;212 hi6210_write_reg(i2s, HII2S_I2S_CFG, val);213 } else {214 val = hi6210_read_reg(i2s, HII2S_I2S_CFG);215 val &= ~HII2S_I2S_CFG__S2_IF_RX_EN;216 hi6210_write_reg(i2s, HII2S_I2S_CFG, val);217 }218 spin_unlock(&i2s->lock);219}220 221static int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)222{223 struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);224 225 /*226 * We don't actually set the hardware until the hw_params227 * call, but we need to validate the user input here.228 */229 switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {230 case SND_SOC_DAIFMT_BC_FC:231 case SND_SOC_DAIFMT_BP_FP:232 break;233 default:234 return -EINVAL;235 }236 237 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {238 case SND_SOC_DAIFMT_I2S:239 case SND_SOC_DAIFMT_LEFT_J:240 case SND_SOC_DAIFMT_RIGHT_J:241 break;242 default:243 return -EINVAL;244 }245 246 i2s->format = fmt;247 i2s->master = (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) ==248 SND_SOC_DAIFMT_BP_FP;249 250 return 0;251}252 253static int hi6210_i2s_hw_params(struct snd_pcm_substream *substream,254 struct snd_pcm_hw_params *params,255 struct snd_soc_dai *cpu_dai)256{257 struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);258 u32 bits = 0, rate = 0, signed_data = 0, fmt = 0;259 u32 val;260 struct snd_dmaengine_dai_dma_data *dma_data;261 262 switch (params_format(params)) {263 case SNDRV_PCM_FORMAT_U16_LE:264 signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;265 fallthrough;266 case SNDRV_PCM_FORMAT_S16_LE:267 bits = HII2S_BITS_16;268 break;269 case SNDRV_PCM_FORMAT_U24_LE:270 signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;271 fallthrough;272 case SNDRV_PCM_FORMAT_S24_LE:273 bits = HII2S_BITS_24;274 break;275 default:276 dev_err(cpu_dai->dev, "Bad format\n");277 return -EINVAL;278 }279 280 281 switch (params_rate(params)) {282 case 8000:283 rate = HII2S_FS_RATE_8KHZ;284 break;285 case 16000:286 rate = HII2S_FS_RATE_16KHZ;287 break;288 case 32000:289 rate = HII2S_FS_RATE_32KHZ;290 break;291 case 48000:292 rate = HII2S_FS_RATE_48KHZ;293 break;294 case 96000:295 rate = HII2S_FS_RATE_96KHZ;296 break;297 case 192000:298 rate = HII2S_FS_RATE_192KHZ;299 break;300 default:301 dev_err(cpu_dai->dev, "Bad rate: %d\n", params_rate(params));302 return -EINVAL;303 }304 305 if (!(params_channels(params))) {306 dev_err(cpu_dai->dev, "Bad channels\n");307 return -EINVAL;308 }309 310 dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);311 312 switch (bits) {313 case HII2S_BITS_24:314 i2s->bits = 32;315 dma_data->addr_width = 3;316 break;317 default:318 i2s->bits = 16;319 dma_data->addr_width = 2;320 break;321 }322 i2s->rate = params_rate(params);323 i2s->channels = params_channels(params);324 i2s->channel_length = i2s->channels * i2s->bits;325 326 val = hi6210_read_reg(i2s, HII2S_ST_DL_FIFO_TH_CFG);327 val &= ~((HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_MASK <<328 HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_SHIFT) |329 (HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_MASK <<330 HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_SHIFT) |331 (HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_MASK <<332 HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_SHIFT) |333 (HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_MASK <<334 HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_SHIFT));335 val |= ((16 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_SHIFT) |336 (30 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_SHIFT) |337 (16 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_SHIFT) |338 (30 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_SHIFT));339 hi6210_write_reg(i2s, HII2S_ST_DL_FIFO_TH_CFG, val);340 341 342 val = hi6210_read_reg(i2s, HII2S_IF_CLK_EN_CFG);343 val |= (BIT(19) | BIT(18) | BIT(17) |344 HII2S_IF_CLK_EN_CFG__S2_IF_CLK_EN |345 HII2S_IF_CLK_EN_CFG__S2_OL_MIXER_EN |346 HII2S_IF_CLK_EN_CFG__S2_OL_SRC_EN |347 HII2S_IF_CLK_EN_CFG__ST_DL_R_EN |348 HII2S_IF_CLK_EN_CFG__ST_DL_L_EN);349 hi6210_write_reg(i2s, HII2S_IF_CLK_EN_CFG, val);350 351 352 val = hi6210_read_reg(i2s, HII2S_DIG_FILTER_CLK_EN_CFG);353 val &= ~(HII2S_DIG_FILTER_CLK_EN_CFG__DACR_SDM_EN |354 HII2S_DIG_FILTER_CLK_EN_CFG__DACR_HBF2I_EN |355 HII2S_DIG_FILTER_CLK_EN_CFG__DACR_AGC_EN |356 HII2S_DIG_FILTER_CLK_EN_CFG__DACL_SDM_EN |357 HII2S_DIG_FILTER_CLK_EN_CFG__DACL_HBF2I_EN |358 HII2S_DIG_FILTER_CLK_EN_CFG__DACL_AGC_EN);359 val |= (HII2S_DIG_FILTER_CLK_EN_CFG__DACR_MIXER_EN |360 HII2S_DIG_FILTER_CLK_EN_CFG__DACL_MIXER_EN);361 hi6210_write_reg(i2s, HII2S_DIG_FILTER_CLK_EN_CFG, val);362 363 364 val = hi6210_read_reg(i2s, HII2S_DIG_FILTER_MODULE_CFG);365 val &= ~(HII2S_DIG_FILTER_MODULE_CFG__DACR_MIXER_IN2_MUTE |366 HII2S_DIG_FILTER_MODULE_CFG__DACL_MIXER_IN2_MUTE);367 hi6210_write_reg(i2s, HII2S_DIG_FILTER_MODULE_CFG, val);368 369 val = hi6210_read_reg(i2s, HII2S_MUX_TOP_MODULE_CFG);370 val &= ~(HII2S_MUX_TOP_MODULE_CFG__S2_OL_MIXER_IN1_MUTE |371 HII2S_MUX_TOP_MODULE_CFG__S2_OL_MIXER_IN2_MUTE |372 HII2S_MUX_TOP_MODULE_CFG__VOICE_DLINK_MIXER_IN1_MUTE |373 HII2S_MUX_TOP_MODULE_CFG__VOICE_DLINK_MIXER_IN2_MUTE);374 hi6210_write_reg(i2s, HII2S_MUX_TOP_MODULE_CFG, val);375 376 377 switch (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {378 case SND_SOC_DAIFMT_BC_FC:379 i2s->master = false;380 val = hi6210_read_reg(i2s, HII2S_I2S_CFG);381 val |= HII2S_I2S_CFG__S2_MST_SLV;382 hi6210_write_reg(i2s, HII2S_I2S_CFG, val);383 break;384 case SND_SOC_DAIFMT_BP_FP:385 i2s->master = true;386 val = hi6210_read_reg(i2s, HII2S_I2S_CFG);387 val &= ~HII2S_I2S_CFG__S2_MST_SLV;388 hi6210_write_reg(i2s, HII2S_I2S_CFG, val);389 break;390 default:391 WARN_ONCE(1, "Invalid i2s->fmt CLOCK_PROVIDER_MASK. This shouldn't happen\n");392 return -EINVAL;393 }394 395 switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {396 case SND_SOC_DAIFMT_I2S:397 fmt = HII2S_FORMAT_I2S;398 break;399 case SND_SOC_DAIFMT_LEFT_J:400 fmt = HII2S_FORMAT_LEFT_JUST;401 break;402 case SND_SOC_DAIFMT_RIGHT_J:403 fmt = HII2S_FORMAT_RIGHT_JUST;404 break;405 default:406 WARN_ONCE(1, "Invalid i2s->fmt FORMAT_MASK. This shouldn't happen\n");407 return -EINVAL;408 }409 410 val = hi6210_read_reg(i2s, HII2S_I2S_CFG);411 val &= ~(HII2S_I2S_CFG__S2_FUNC_MODE_MASK <<412 HII2S_I2S_CFG__S2_FUNC_MODE_SHIFT);413 val |= fmt << HII2S_I2S_CFG__S2_FUNC_MODE_SHIFT;414 hi6210_write_reg(i2s, HII2S_I2S_CFG, val);415 416 417 val = hi6210_read_reg(i2s, HII2S_CLK_SEL);418 val &= ~(HII2S_CLK_SEL__I2S_BT_FM_SEL | /* BT gets the I2S */419 HII2S_CLK_SEL__EXT_12_288MHZ_SEL);420 hi6210_write_reg(i2s, HII2S_CLK_SEL, val);421 422 dma_data->maxburst = 2;423 424 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)425 dma_data->addr = i2s->base_phys + HII2S_ST_DL_CHANNEL;426 else427 dma_data->addr = i2s->base_phys + HII2S_STEREO_UPLINK_CHANNEL;428 429 switch (i2s->channels) {430 case 1:431 val = hi6210_read_reg(i2s, HII2S_I2S_CFG);432 val |= HII2S_I2S_CFG__S2_FRAME_MODE;433 hi6210_write_reg(i2s, HII2S_I2S_CFG, val);434 break;435 default:436 val = hi6210_read_reg(i2s, HII2S_I2S_CFG);437 val &= ~HII2S_I2S_CFG__S2_FRAME_MODE;438 hi6210_write_reg(i2s, HII2S_I2S_CFG, val);439 break;440 }441 442 /* clear loopback, set signed type and word length */443 val = hi6210_read_reg(i2s, HII2S_I2S_CFG);444 val &= ~HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;445 val &= ~(HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_MASK <<446 HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_SHIFT);447 val &= ~(HII2S_I2S_CFG__S2_DIRECT_LOOP_MASK <<448 HII2S_I2S_CFG__S2_DIRECT_LOOP_SHIFT);449 val |= signed_data;450 val |= (bits << HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_SHIFT);451 hi6210_write_reg(i2s, HII2S_I2S_CFG, val);452 453 454 if (!i2s->master)455 return 0;456 457 /* set DAC and related units to correct rate */458 val = hi6210_read_reg(i2s, HII2S_FS_CFG);459 val &= ~(HII2S_FS_CFG__FS_S2_MASK << HII2S_FS_CFG__FS_S2_SHIFT);460 val &= ~(HII2S_FS_CFG__FS_DACLR_MASK << HII2S_FS_CFG__FS_DACLR_SHIFT);461 val &= ~(HII2S_FS_CFG__FS_ST_DL_R_MASK <<462 HII2S_FS_CFG__FS_ST_DL_R_SHIFT);463 val &= ~(HII2S_FS_CFG__FS_ST_DL_L_MASK <<464 HII2S_FS_CFG__FS_ST_DL_L_SHIFT);465 val |= (rate << HII2S_FS_CFG__FS_S2_SHIFT);466 val |= (rate << HII2S_FS_CFG__FS_DACLR_SHIFT);467 val |= (rate << HII2S_FS_CFG__FS_ST_DL_R_SHIFT);468 val |= (rate << HII2S_FS_CFG__FS_ST_DL_L_SHIFT);469 hi6210_write_reg(i2s, HII2S_FS_CFG, val);470 471 return 0;472}473 474static int hi6210_i2s_trigger(struct snd_pcm_substream *substream, int cmd,475 struct snd_soc_dai *cpu_dai)476{477 pr_debug("%s\n", __func__);478 switch (cmd) {479 case SNDRV_PCM_TRIGGER_START:480 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:481 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)482 hi6210_i2s_rxctrl(cpu_dai, 1);483 else484 hi6210_i2s_txctrl(cpu_dai, 1);485 break;486 case SNDRV_PCM_TRIGGER_STOP:487 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:488 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)489 hi6210_i2s_rxctrl(cpu_dai, 0);490 else491 hi6210_i2s_txctrl(cpu_dai, 0);492 break;493 default:494 dev_err(cpu_dai->dev, "unknown cmd\n");495 return -EINVAL;496 }497 return 0;498}499 500static int hi6210_i2s_dai_probe(struct snd_soc_dai *dai)501{502 struct hi6210_i2s *i2s = snd_soc_dai_get_drvdata(dai);503 504 snd_soc_dai_init_dma_data(dai,505 &i2s->dma_data[SNDRV_PCM_STREAM_PLAYBACK],506 &i2s->dma_data[SNDRV_PCM_STREAM_CAPTURE]);507 508 return 0;509}510 511 512static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {513 .probe = hi6210_i2s_dai_probe,514 .trigger = hi6210_i2s_trigger,515 .hw_params = hi6210_i2s_hw_params,516 .set_fmt = hi6210_i2s_set_fmt,517 .startup = hi6210_i2s_startup,518 .shutdown = hi6210_i2s_shutdown,519};520 521static const struct snd_soc_dai_driver hi6210_i2s_dai_init = {522 .playback = {523 .channels_min = 2,524 .channels_max = 2,525 .formats = SNDRV_PCM_FMTBIT_S16_LE |526 SNDRV_PCM_FMTBIT_U16_LE,527 .rates = SNDRV_PCM_RATE_48000,528 },529 .capture = {530 .channels_min = 2,531 .channels_max = 2,532 .formats = SNDRV_PCM_FMTBIT_S16_LE |533 SNDRV_PCM_FMTBIT_U16_LE,534 .rates = SNDRV_PCM_RATE_48000,535 },536 .ops = &hi6210_i2s_dai_ops,537};538 539static const struct snd_soc_component_driver hi6210_i2s_i2s_comp = {540 .name = "hi6210_i2s-i2s",541 .legacy_dai_naming = 1,542};543 544static int hi6210_i2s_probe(struct platform_device *pdev)545{546 struct device_node *node = pdev->dev.of_node;547 struct device *dev = &pdev->dev;548 struct hi6210_i2s *i2s;549 struct resource *res;550 int ret;551 552 i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);553 if (!i2s)554 return -ENOMEM;555 556 i2s->dev = dev;557 spin_lock_init(&i2s->lock);558 559 i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);560 if (IS_ERR(i2s->base))561 return PTR_ERR(i2s->base);562 563 i2s->base_phys = (phys_addr_t)res->start;564 i2s->dai = hi6210_i2s_dai_init;565 566 dev_set_drvdata(dev, i2s);567 568 i2s->sysctrl = syscon_regmap_lookup_by_phandle(node,569 "hisilicon,sysctrl-syscon");570 if (IS_ERR(i2s->sysctrl))571 return PTR_ERR(i2s->sysctrl);572 573 i2s->clk[CLK_DACODEC] = devm_clk_get(dev, "dacodec");574 if (IS_ERR(i2s->clk[CLK_DACODEC]))575 return PTR_ERR(i2s->clk[CLK_DACODEC]);576 i2s->clocks++;577 578 i2s->clk[CLK_I2S_BASE] = devm_clk_get(dev, "i2s-base");579 if (IS_ERR(i2s->clk[CLK_I2S_BASE]))580 return PTR_ERR(i2s->clk[CLK_I2S_BASE]);581 i2s->clocks++;582 583 ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);584 if (ret)585 return ret;586 587 ret = devm_snd_soc_register_component(dev, &hi6210_i2s_i2s_comp,588 &i2s->dai, 1);589 return ret;590}591 592static const struct of_device_id hi6210_i2s_dt_ids[] = {593 { .compatible = "hisilicon,hi6210-i2s" },594 { /* sentinel */ }595};596 597MODULE_DEVICE_TABLE(of, hi6210_i2s_dt_ids);598 599static struct platform_driver hi6210_i2s_driver = {600 .probe = hi6210_i2s_probe,601 .driver = {602 .name = "hi6210_i2s",603 .of_match_table = hi6210_i2s_dt_ids,604 },605};606 607module_platform_driver(hi6210_i2s_driver);608 609MODULE_DESCRIPTION("Hisilicon HI6210 I2S driver");610MODULE_AUTHOR("Andy Green <andy.green@linaro.org>");611MODULE_LICENSE("GPL");612