^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * IMG parallel output controller driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2015 Imagination Technologies Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: Damien Horsley <Damien.Horsley@imgtec.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/reset.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <sound/dmaengine_pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <sound/initval.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <sound/pcm_params.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define IMG_PRL_OUT_TX_FIFO 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define IMG_PRL_OUT_CTL 0x4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define IMG_PRL_OUT_CTL_CH_MASK BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define IMG_PRL_OUT_CTL_PACKH_MASK BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define IMG_PRL_OUT_CTL_EDGE_MASK BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define IMG_PRL_OUT_CTL_ME_MASK BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define IMG_PRL_OUT_CTL_SRST_MASK BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct img_prl_out {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct clk *clk_sys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct clk *clk_ref;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct snd_dmaengine_dai_dma_data dma_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct reset_control *rst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static int img_prl_out_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct img_prl_out *prl = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) clk_disable_unprepare(prl->clk_ref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static int img_prl_out_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct img_prl_out *prl = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) ret = clk_prepare_enable(prl->clk_ref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) dev_err(dev, "clk_enable failed: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static inline void img_prl_out_writel(struct img_prl_out *prl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) u32 val, u32 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) writel(val, prl->base + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static inline u32 img_prl_out_readl(struct img_prl_out *prl, u32 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return readl(prl->base + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static void img_prl_out_reset(struct img_prl_out *prl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) u32 ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) ctl = img_prl_out_readl(prl, IMG_PRL_OUT_CTL) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) ~IMG_PRL_OUT_CTL_ME_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) reset_control_assert(prl->rst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) reset_control_deassert(prl->rst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) img_prl_out_writel(prl, ctl, IMG_PRL_OUT_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static int img_prl_out_trigger(struct snd_pcm_substream *substream, int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) case SNDRV_PCM_TRIGGER_RESUME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) reg |= IMG_PRL_OUT_CTL_ME_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) case SNDRV_PCM_TRIGGER_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) img_prl_out_reset(prl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static int img_prl_out_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) unsigned int rate, channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) u32 reg, control_set = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) rate = params_rate(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) channels = params_channels(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) switch (params_format(params)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) case SNDRV_PCM_FORMAT_S32_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) control_set |= IMG_PRL_OUT_CTL_PACKH_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) case SNDRV_PCM_FORMAT_S24_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (channels != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) clk_set_rate(prl->clk_ref, rate * 256);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) reg = (reg & ~IMG_PRL_OUT_CTL_PACKH_MASK) | control_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) u32 reg, control_set = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) case SND_SOC_DAIFMT_NB_NF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) case SND_SOC_DAIFMT_NB_IF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) control_set |= IMG_PRL_OUT_CTL_EDGE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) ret = pm_runtime_get_sync(prl->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) pm_runtime_put_noidle(prl->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) reg = (reg & ~IMG_PRL_OUT_CTL_EDGE_MASK) | control_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) pm_runtime_put(prl->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static const struct snd_soc_dai_ops img_prl_out_dai_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .trigger = img_prl_out_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .hw_params = img_prl_out_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) .set_fmt = img_prl_out_set_fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static int img_prl_out_dai_probe(struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) snd_soc_dai_init_dma_data(dai, &prl->dma_data, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) static struct snd_soc_dai_driver img_prl_out_dai = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) .probe = img_prl_out_dai_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) .playback = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) .channels_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) .channels_max = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) .rates = SNDRV_PCM_RATE_8000_192000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) .ops = &img_prl_out_dai_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static const struct snd_soc_component_driver img_prl_out_component = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) .name = "img-prl-out"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static int img_prl_out_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) struct img_prl_out *prl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) prl = devm_kzalloc(&pdev->dev, sizeof(*prl), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (!prl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) platform_set_drvdata(pdev, prl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) prl->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) base = devm_ioremap_resource(&pdev->dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (IS_ERR(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return PTR_ERR(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) prl->base = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) prl->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (IS_ERR(prl->rst)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (PTR_ERR(prl->rst) != -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) dev_err(&pdev->dev, "No top level reset found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return PTR_ERR(prl->rst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) prl->clk_sys = devm_clk_get(&pdev->dev, "sys");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (IS_ERR(prl->clk_sys)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (PTR_ERR(prl->clk_sys) != -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) dev_err(dev, "Failed to acquire clock 'sys'\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return PTR_ERR(prl->clk_sys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) prl->clk_ref = devm_clk_get(&pdev->dev, "ref");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (IS_ERR(prl->clk_ref)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (PTR_ERR(prl->clk_ref) != -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) dev_err(dev, "Failed to acquire clock 'ref'\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) return PTR_ERR(prl->clk_ref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) ret = clk_prepare_enable(prl->clk_sys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) img_prl_out_writel(prl, IMG_PRL_OUT_CTL_EDGE_MASK, IMG_PRL_OUT_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) img_prl_out_reset(prl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) pm_runtime_enable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (!pm_runtime_enabled(&pdev->dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) ret = img_prl_out_resume(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) goto err_pm_disable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) prl->dma_data.addr = res->start + IMG_PRL_OUT_TX_FIFO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) prl->dma_data.addr_width = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) prl->dma_data.maxburst = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) ret = devm_snd_soc_register_component(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) &img_prl_out_component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) &img_prl_out_dai, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) goto err_suspend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) goto err_suspend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) err_suspend:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (!pm_runtime_status_suspended(&pdev->dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) img_prl_out_suspend(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) err_pm_disable:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) pm_runtime_disable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) clk_disable_unprepare(prl->clk_sys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) static int img_prl_out_dev_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct img_prl_out *prl = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) pm_runtime_disable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (!pm_runtime_status_suspended(&pdev->dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) img_prl_out_suspend(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) clk_disable_unprepare(prl->clk_sys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) static const struct of_device_id img_prl_out_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) { .compatible = "img,parallel-out" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) MODULE_DEVICE_TABLE(of, img_prl_out_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) static const struct dev_pm_ops img_prl_out_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) SET_RUNTIME_PM_OPS(img_prl_out_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) img_prl_out_resume, NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static struct platform_driver img_prl_out_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .name = "img-parallel-out",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .of_match_table = img_prl_out_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .pm = &img_prl_out_pm_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .probe = img_prl_out_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) .remove = img_prl_out_dev_remove
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) module_platform_driver(img_prl_out_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) MODULE_DESCRIPTION("IMG Parallel Output Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) MODULE_LICENSE("GPL v2");