1d1802d59SHal Feng // SPDX-License-Identifier: GPL-2.0 2d1802d59SHal Feng /* 3d1802d59SHal Feng * jh7110_pwmdac.c -- StarFive JH7110 PWM-DAC driver 4d1802d59SHal Feng * 5d1802d59SHal Feng * Copyright (C) 2021-2023 StarFive Technology Co., Ltd. 6d1802d59SHal Feng * 7d1802d59SHal Feng * Authors: Jenny Zhang 8d1802d59SHal Feng * Curry Zhang 9d1802d59SHal Feng * Xingyu Wu <xingyu.wu@starfivetech.com> 10d1802d59SHal Feng * Hal Feng <hal.feng@starfivetech.com> 11d1802d59SHal Feng */ 12d1802d59SHal Feng 13d1802d59SHal Feng #include <linux/clk.h> 14d1802d59SHal Feng #include <linux/device.h> 15d1802d59SHal Feng #include <linux/init.h> 16d1802d59SHal Feng #include <linux/interrupt.h> 17d1802d59SHal Feng #include <linux/io.h> 18d1802d59SHal Feng #include <linux/module.h> 19d1802d59SHal Feng #include <linux/pm_runtime.h> 20d1802d59SHal Feng #include <linux/reset.h> 21d1802d59SHal Feng #include <linux/slab.h> 22d1802d59SHal Feng #include <linux/types.h> 23d1802d59SHal Feng #include <sound/dmaengine_pcm.h> 24d1802d59SHal Feng #include <sound/pcm.h> 25d1802d59SHal Feng #include <sound/pcm_params.h> 26d1802d59SHal Feng #include <sound/soc.h> 27d1802d59SHal Feng 28d1802d59SHal Feng #define JH7110_PWMDAC_WDATA 0x00 29d1802d59SHal Feng #define JH7110_PWMDAC_CTRL 0x04 30d1802d59SHal Feng #define JH7110_PWMDAC_ENABLE BIT(0) 31d1802d59SHal Feng #define JH7110_PWMDAC_SHIFT BIT(1) 32d1802d59SHal Feng #define JH7110_PWMDAC_DUTY_CYCLE_SHIFT 2 33d1802d59SHal Feng #define JH7110_PWMDAC_DUTY_CYCLE_MASK GENMASK(3, 2) 34d1802d59SHal Feng #define JH7110_PWMDAC_CNT_N_SHIFT 4 35d1802d59SHal Feng #define JH7110_PWMDAC_CNT_N_MASK GENMASK(12, 4) 36d1802d59SHal Feng #define JH7110_PWMDAC_DATA_CHANGE BIT(13) 37d1802d59SHal Feng #define JH7110_PWMDAC_DATA_MODE BIT(14) 38d1802d59SHal Feng #define JH7110_PWMDAC_DATA_SHIFT_SHIFT 15 39d1802d59SHal Feng #define JH7110_PWMDAC_DATA_SHIFT_MASK GENMASK(17, 15) 40d1802d59SHal Feng 41d1802d59SHal Feng enum JH7110_PWMDAC_SHIFT_VAL { 42d1802d59SHal Feng PWMDAC_SHIFT_8 = 0, 43d1802d59SHal Feng PWMDAC_SHIFT_10, 44d1802d59SHal Feng }; 45d1802d59SHal Feng 46d1802d59SHal Feng enum JH7110_PWMDAC_DUTY_CYCLE_VAL { 47d1802d59SHal Feng PWMDAC_CYCLE_LEFT = 0, 48d1802d59SHal Feng PWMDAC_CYCLE_RIGHT, 49d1802d59SHal Feng PWMDAC_CYCLE_CENTER, 50d1802d59SHal Feng }; 51d1802d59SHal Feng 52d1802d59SHal Feng enum JH7110_PWMDAC_CNT_N_VAL { 53d1802d59SHal Feng PWMDAC_SAMPLE_CNT_1 = 1, 54d1802d59SHal Feng PWMDAC_SAMPLE_CNT_2, 55d1802d59SHal Feng PWMDAC_SAMPLE_CNT_3, 56d1802d59SHal Feng PWMDAC_SAMPLE_CNT_512 = 512, /* max */ 57d1802d59SHal Feng }; 58d1802d59SHal Feng 59d1802d59SHal Feng enum JH7110_PWMDAC_DATA_CHANGE_VAL { 60d1802d59SHal Feng NO_CHANGE = 0, 61d1802d59SHal Feng CHANGE, 62d1802d59SHal Feng }; 63d1802d59SHal Feng 64d1802d59SHal Feng enum JH7110_PWMDAC_DATA_MODE_VAL { 65d1802d59SHal Feng UNSIGNED_DATA = 0, 66d1802d59SHal Feng INVERTER_DATA_MSB, 67d1802d59SHal Feng }; 68d1802d59SHal Feng 69d1802d59SHal Feng enum JH7110_PWMDAC_DATA_SHIFT_VAL { 70d1802d59SHal Feng PWMDAC_DATA_LEFT_SHIFT_BIT_0 = 0, 71d1802d59SHal Feng PWMDAC_DATA_LEFT_SHIFT_BIT_1, 72d1802d59SHal Feng PWMDAC_DATA_LEFT_SHIFT_BIT_2, 73d1802d59SHal Feng PWMDAC_DATA_LEFT_SHIFT_BIT_3, 74d1802d59SHal Feng PWMDAC_DATA_LEFT_SHIFT_BIT_4, 75d1802d59SHal Feng PWMDAC_DATA_LEFT_SHIFT_BIT_5, 76d1802d59SHal Feng PWMDAC_DATA_LEFT_SHIFT_BIT_6, 77d1802d59SHal Feng PWMDAC_DATA_LEFT_SHIFT_BIT_7, 78d1802d59SHal Feng }; 79d1802d59SHal Feng 80d1802d59SHal Feng struct jh7110_pwmdac_cfg { 81d1802d59SHal Feng enum JH7110_PWMDAC_SHIFT_VAL shift; 82d1802d59SHal Feng enum JH7110_PWMDAC_DUTY_CYCLE_VAL duty_cycle; 83d1802d59SHal Feng u16 cnt_n; 84d1802d59SHal Feng enum JH7110_PWMDAC_DATA_CHANGE_VAL data_change; 85d1802d59SHal Feng enum JH7110_PWMDAC_DATA_MODE_VAL data_mode; 86d1802d59SHal Feng enum JH7110_PWMDAC_DATA_SHIFT_VAL data_shift; 87d1802d59SHal Feng }; 88d1802d59SHal Feng 89d1802d59SHal Feng struct jh7110_pwmdac_dev { 90d1802d59SHal Feng void __iomem *base; 91d1802d59SHal Feng resource_size_t mapbase; 92d1802d59SHal Feng struct jh7110_pwmdac_cfg cfg; 93d1802d59SHal Feng 94d1802d59SHal Feng struct clk_bulk_data clks[2]; 95d1802d59SHal Feng struct reset_control *rst_apb; 96d1802d59SHal Feng struct device *dev; 97d1802d59SHal Feng struct snd_dmaengine_dai_dma_data play_dma_data; 98d1802d59SHal Feng u32 saved_ctrl; 99d1802d59SHal Feng }; 100d1802d59SHal Feng 101d1802d59SHal Feng static inline void jh7110_pwmdac_write_reg(void __iomem *io_base, int reg, u32 val) 102d1802d59SHal Feng { 103d1802d59SHal Feng writel(val, io_base + reg); 104d1802d59SHal Feng } 105d1802d59SHal Feng 106d1802d59SHal Feng static inline u32 jh7110_pwmdac_read_reg(void __iomem *io_base, int reg) 107d1802d59SHal Feng { 108d1802d59SHal Feng return readl(io_base + reg); 109d1802d59SHal Feng } 110d1802d59SHal Feng 111d1802d59SHal Feng static void jh7110_pwmdac_set_enable(struct jh7110_pwmdac_dev *dev, bool enable) 112d1802d59SHal Feng { 113d1802d59SHal Feng u32 value; 114d1802d59SHal Feng 115d1802d59SHal Feng value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL); 116d1802d59SHal Feng if (enable) 117d1802d59SHal Feng value |= JH7110_PWMDAC_ENABLE; 118d1802d59SHal Feng else 119d1802d59SHal Feng value &= ~JH7110_PWMDAC_ENABLE; 120d1802d59SHal Feng 121d1802d59SHal Feng jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value); 122d1802d59SHal Feng } 123d1802d59SHal Feng 124d1802d59SHal Feng static void jh7110_pwmdac_set_shift(struct jh7110_pwmdac_dev *dev) 125d1802d59SHal Feng { 126d1802d59SHal Feng u32 value; 127d1802d59SHal Feng 128d1802d59SHal Feng value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL); 129d1802d59SHal Feng if (dev->cfg.shift == PWMDAC_SHIFT_8) 130d1802d59SHal Feng value &= ~JH7110_PWMDAC_SHIFT; 131d1802d59SHal Feng else if (dev->cfg.shift == PWMDAC_SHIFT_10) 132d1802d59SHal Feng value |= JH7110_PWMDAC_SHIFT; 133d1802d59SHal Feng 134d1802d59SHal Feng jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value); 135d1802d59SHal Feng } 136d1802d59SHal Feng 137d1802d59SHal Feng static void jh7110_pwmdac_set_duty_cycle(struct jh7110_pwmdac_dev *dev) 138d1802d59SHal Feng { 139d1802d59SHal Feng u32 value; 140d1802d59SHal Feng 141d1802d59SHal Feng value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL); 142d1802d59SHal Feng value &= ~JH7110_PWMDAC_DUTY_CYCLE_MASK; 143d1802d59SHal Feng value |= (dev->cfg.duty_cycle & 0x3) << JH7110_PWMDAC_DUTY_CYCLE_SHIFT; 144d1802d59SHal Feng 145d1802d59SHal Feng jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value); 146d1802d59SHal Feng } 147d1802d59SHal Feng 148d1802d59SHal Feng static void jh7110_pwmdac_set_cnt_n(struct jh7110_pwmdac_dev *dev) 149d1802d59SHal Feng { 150d1802d59SHal Feng u32 value; 151d1802d59SHal Feng 152d1802d59SHal Feng value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL); 153d1802d59SHal Feng value &= ~JH7110_PWMDAC_CNT_N_MASK; 154d1802d59SHal Feng value |= ((dev->cfg.cnt_n - 1) & 0x1ff) << JH7110_PWMDAC_CNT_N_SHIFT; 155d1802d59SHal Feng 156d1802d59SHal Feng jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value); 157d1802d59SHal Feng } 158d1802d59SHal Feng 159d1802d59SHal Feng static void jh7110_pwmdac_set_data_change(struct jh7110_pwmdac_dev *dev) 160d1802d59SHal Feng { 161d1802d59SHal Feng u32 value; 162d1802d59SHal Feng 163d1802d59SHal Feng value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL); 164d1802d59SHal Feng if (dev->cfg.data_change == NO_CHANGE) 165d1802d59SHal Feng value &= ~JH7110_PWMDAC_DATA_CHANGE; 166d1802d59SHal Feng else if (dev->cfg.data_change == CHANGE) 167d1802d59SHal Feng value |= JH7110_PWMDAC_DATA_CHANGE; 168d1802d59SHal Feng 169d1802d59SHal Feng jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value); 170d1802d59SHal Feng } 171d1802d59SHal Feng 172d1802d59SHal Feng static void jh7110_pwmdac_set_data_mode(struct jh7110_pwmdac_dev *dev) 173d1802d59SHal Feng { 174d1802d59SHal Feng u32 value; 175d1802d59SHal Feng 176d1802d59SHal Feng value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL); 177d1802d59SHal Feng if (dev->cfg.data_mode == UNSIGNED_DATA) 178d1802d59SHal Feng value &= ~JH7110_PWMDAC_DATA_MODE; 179d1802d59SHal Feng else if (dev->cfg.data_mode == INVERTER_DATA_MSB) 180d1802d59SHal Feng value |= JH7110_PWMDAC_DATA_MODE; 181d1802d59SHal Feng 182d1802d59SHal Feng jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value); 183d1802d59SHal Feng } 184d1802d59SHal Feng 185d1802d59SHal Feng static void jh7110_pwmdac_set_data_shift(struct jh7110_pwmdac_dev *dev) 186d1802d59SHal Feng { 187d1802d59SHal Feng u32 value; 188d1802d59SHal Feng 189d1802d59SHal Feng value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL); 190d1802d59SHal Feng value &= ~JH7110_PWMDAC_DATA_SHIFT_MASK; 191d1802d59SHal Feng value |= (dev->cfg.data_shift & 0x7) << JH7110_PWMDAC_DATA_SHIFT_SHIFT; 192d1802d59SHal Feng 193d1802d59SHal Feng jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value); 194d1802d59SHal Feng } 195d1802d59SHal Feng 196d1802d59SHal Feng static void jh7110_pwmdac_set(struct jh7110_pwmdac_dev *dev) 197d1802d59SHal Feng { 198d1802d59SHal Feng jh7110_pwmdac_set_shift(dev); 199d1802d59SHal Feng jh7110_pwmdac_set_duty_cycle(dev); 200d1802d59SHal Feng jh7110_pwmdac_set_cnt_n(dev); 201d1802d59SHal Feng jh7110_pwmdac_set_enable(dev, true); 202d1802d59SHal Feng 203d1802d59SHal Feng jh7110_pwmdac_set_data_change(dev); 204d1802d59SHal Feng jh7110_pwmdac_set_data_mode(dev); 205d1802d59SHal Feng jh7110_pwmdac_set_data_shift(dev); 206d1802d59SHal Feng } 207d1802d59SHal Feng 208d1802d59SHal Feng static void jh7110_pwmdac_stop(struct jh7110_pwmdac_dev *dev) 209d1802d59SHal Feng { 210d1802d59SHal Feng jh7110_pwmdac_set_enable(dev, false); 211d1802d59SHal Feng } 212d1802d59SHal Feng 213d1802d59SHal Feng static int jh7110_pwmdac_startup(struct snd_pcm_substream *substream, 214d1802d59SHal Feng struct snd_soc_dai *dai) 215d1802d59SHal Feng { 2161a543d2aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 217d1802d59SHal Feng struct snd_soc_dai_link *dai_link = rtd->dai_link; 218d1802d59SHal Feng 219d1802d59SHal Feng dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC; 220d1802d59SHal Feng 221d1802d59SHal Feng return 0; 222d1802d59SHal Feng } 223d1802d59SHal Feng 224d1802d59SHal Feng static int jh7110_pwmdac_hw_params(struct snd_pcm_substream *substream, 225d1802d59SHal Feng struct snd_pcm_hw_params *params, 226d1802d59SHal Feng struct snd_soc_dai *dai) 227d1802d59SHal Feng { 228d1802d59SHal Feng struct jh7110_pwmdac_dev *dev = dev_get_drvdata(dai->dev); 229d1802d59SHal Feng unsigned long core_clk_rate; 230d1802d59SHal Feng int ret; 231d1802d59SHal Feng 232d1802d59SHal Feng switch (params_rate(params)) { 233d1802d59SHal Feng case 8000: 234d1802d59SHal Feng dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_3; 235d1802d59SHal Feng core_clk_rate = 6144000; 236d1802d59SHal Feng break; 237d1802d59SHal Feng case 11025: 238d1802d59SHal Feng dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_2; 239d1802d59SHal Feng core_clk_rate = 5644800; 240d1802d59SHal Feng break; 241d1802d59SHal Feng case 16000: 242d1802d59SHal Feng dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_3; 243d1802d59SHal Feng core_clk_rate = 12288000; 244d1802d59SHal Feng break; 245d1802d59SHal Feng case 22050: 246d1802d59SHal Feng dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_1; 247d1802d59SHal Feng core_clk_rate = 5644800; 248d1802d59SHal Feng break; 249d1802d59SHal Feng case 32000: 250d1802d59SHal Feng dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_1; 251d1802d59SHal Feng core_clk_rate = 8192000; 252d1802d59SHal Feng break; 253d1802d59SHal Feng case 44100: 254d1802d59SHal Feng dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_1; 255d1802d59SHal Feng core_clk_rate = 11289600; 256d1802d59SHal Feng break; 257d1802d59SHal Feng case 48000: 258d1802d59SHal Feng dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_1; 259d1802d59SHal Feng core_clk_rate = 12288000; 260d1802d59SHal Feng break; 261d1802d59SHal Feng default: 262d1802d59SHal Feng dev_err(dai->dev, "%d rate not supported\n", 263d1802d59SHal Feng params_rate(params)); 264d1802d59SHal Feng return -EINVAL; 265d1802d59SHal Feng } 266d1802d59SHal Feng 267d1802d59SHal Feng switch (params_channels(params)) { 268d1802d59SHal Feng case 1: 269d1802d59SHal Feng dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 270d1802d59SHal Feng break; 271d1802d59SHal Feng case 2: 272d1802d59SHal Feng dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 273d1802d59SHal Feng break; 274d1802d59SHal Feng default: 275d1802d59SHal Feng dev_err(dai->dev, "%d channels not supported\n", 276d1802d59SHal Feng params_channels(params)); 277d1802d59SHal Feng return -EINVAL; 278d1802d59SHal Feng } 279d1802d59SHal Feng 280d1802d59SHal Feng /* 281d1802d59SHal Feng * The clock rate always rounds down when using clk_set_rate() 282d1802d59SHal Feng * so increase the rate a bit 283d1802d59SHal Feng */ 284d1802d59SHal Feng core_clk_rate += 64; 285d1802d59SHal Feng jh7110_pwmdac_set(dev); 286d1802d59SHal Feng 287d1802d59SHal Feng ret = clk_set_rate(dev->clks[1].clk, core_clk_rate); 288d1802d59SHal Feng if (ret) 289d1802d59SHal Feng return dev_err_probe(dai->dev, ret, 290d1802d59SHal Feng "failed to set rate %lu for core clock\n", 291d1802d59SHal Feng core_clk_rate); 292d1802d59SHal Feng 293d1802d59SHal Feng return 0; 294d1802d59SHal Feng } 295d1802d59SHal Feng 296d1802d59SHal Feng static int jh7110_pwmdac_trigger(struct snd_pcm_substream *substream, int cmd, 297d1802d59SHal Feng struct snd_soc_dai *dai) 298d1802d59SHal Feng { 299d1802d59SHal Feng struct jh7110_pwmdac_dev *dev = snd_soc_dai_get_drvdata(dai); 300d1802d59SHal Feng int ret = 0; 301d1802d59SHal Feng 302d1802d59SHal Feng switch (cmd) { 303d1802d59SHal Feng case SNDRV_PCM_TRIGGER_START: 304d1802d59SHal Feng case SNDRV_PCM_TRIGGER_RESUME: 305d1802d59SHal Feng case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 306d1802d59SHal Feng jh7110_pwmdac_set(dev); 307d1802d59SHal Feng break; 308d1802d59SHal Feng 309d1802d59SHal Feng case SNDRV_PCM_TRIGGER_STOP: 310d1802d59SHal Feng case SNDRV_PCM_TRIGGER_SUSPEND: 311d1802d59SHal Feng case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 312d1802d59SHal Feng jh7110_pwmdac_stop(dev); 313d1802d59SHal Feng break; 314d1802d59SHal Feng default: 315d1802d59SHal Feng ret = -EINVAL; 316d1802d59SHal Feng break; 317d1802d59SHal Feng } 318d1802d59SHal Feng 319d1802d59SHal Feng return ret; 320d1802d59SHal Feng } 321d1802d59SHal Feng 322d1802d59SHal Feng static int jh7110_pwmdac_crg_enable(struct jh7110_pwmdac_dev *dev, bool enable) 323d1802d59SHal Feng { 324d1802d59SHal Feng int ret; 325d1802d59SHal Feng 326d1802d59SHal Feng if (enable) { 327d1802d59SHal Feng ret = clk_bulk_prepare_enable(ARRAY_SIZE(dev->clks), dev->clks); 328d1802d59SHal Feng if (ret) 329d1802d59SHal Feng return dev_err_probe(dev->dev, ret, 330d1802d59SHal Feng "failed to enable pwmdac clocks\n"); 331d1802d59SHal Feng 332d1802d59SHal Feng ret = reset_control_deassert(dev->rst_apb); 333d1802d59SHal Feng if (ret) { 334d1802d59SHal Feng dev_err(dev->dev, "failed to deassert pwmdac apb reset\n"); 335d1802d59SHal Feng goto err_rst_apb; 336d1802d59SHal Feng } 337d1802d59SHal Feng } else { 338d1802d59SHal Feng clk_bulk_disable_unprepare(ARRAY_SIZE(dev->clks), dev->clks); 339d1802d59SHal Feng } 340d1802d59SHal Feng 341d1802d59SHal Feng return 0; 342d1802d59SHal Feng 343d1802d59SHal Feng err_rst_apb: 344d1802d59SHal Feng clk_bulk_disable_unprepare(ARRAY_SIZE(dev->clks), dev->clks); 345d1802d59SHal Feng 346d1802d59SHal Feng return ret; 347d1802d59SHal Feng } 348d1802d59SHal Feng 349d1802d59SHal Feng static int jh7110_pwmdac_dai_probe(struct snd_soc_dai *dai) 350d1802d59SHal Feng { 351d1802d59SHal Feng struct jh7110_pwmdac_dev *dev = dev_get_drvdata(dai->dev); 352d1802d59SHal Feng 353d1802d59SHal Feng snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, NULL); 354d1802d59SHal Feng snd_soc_dai_set_drvdata(dai, dev); 355d1802d59SHal Feng 356d1802d59SHal Feng return 0; 357d1802d59SHal Feng } 358d1802d59SHal Feng 359d1802d59SHal Feng static const struct snd_soc_dai_ops jh7110_pwmdac_dai_ops = { 3600ed30d3fSMark Brown .probe = jh7110_pwmdac_dai_probe, 361d1802d59SHal Feng .startup = jh7110_pwmdac_startup, 362d1802d59SHal Feng .hw_params = jh7110_pwmdac_hw_params, 363d1802d59SHal Feng .trigger = jh7110_pwmdac_trigger, 364d1802d59SHal Feng }; 365d1802d59SHal Feng 366d1802d59SHal Feng static const struct snd_soc_component_driver jh7110_pwmdac_component = { 367d1802d59SHal Feng .name = "jh7110-pwmdac", 368d1802d59SHal Feng }; 369d1802d59SHal Feng 370d1802d59SHal Feng static struct snd_soc_dai_driver jh7110_pwmdac_dai = { 371d1802d59SHal Feng .name = "jh7110-pwmdac", 372d1802d59SHal Feng .id = 0, 373d1802d59SHal Feng .playback = { 374d1802d59SHal Feng .channels_min = 1, 375d1802d59SHal Feng .channels_max = 2, 376d1802d59SHal Feng .rates = SNDRV_PCM_RATE_8000_48000, 377d1802d59SHal Feng .formats = SNDRV_PCM_FMTBIT_S16_LE, 378d1802d59SHal Feng }, 379d1802d59SHal Feng .ops = &jh7110_pwmdac_dai_ops, 380d1802d59SHal Feng }; 381d1802d59SHal Feng 382d1802d59SHal Feng static int jh7110_pwmdac_runtime_suspend(struct device *dev) 383d1802d59SHal Feng { 384d1802d59SHal Feng struct jh7110_pwmdac_dev *pwmdac = dev_get_drvdata(dev); 385d1802d59SHal Feng 386d1802d59SHal Feng return jh7110_pwmdac_crg_enable(pwmdac, false); 387d1802d59SHal Feng } 388d1802d59SHal Feng 389d1802d59SHal Feng static int jh7110_pwmdac_runtime_resume(struct device *dev) 390d1802d59SHal Feng { 391d1802d59SHal Feng struct jh7110_pwmdac_dev *pwmdac = dev_get_drvdata(dev); 392d1802d59SHal Feng 393d1802d59SHal Feng return jh7110_pwmdac_crg_enable(pwmdac, true); 394d1802d59SHal Feng } 395d1802d59SHal Feng 396d1802d59SHal Feng static int jh7110_pwmdac_system_suspend(struct device *dev) 397d1802d59SHal Feng { 398d1802d59SHal Feng struct jh7110_pwmdac_dev *pwmdac = dev_get_drvdata(dev); 399d1802d59SHal Feng 400d1802d59SHal Feng /* save the CTRL register value */ 401d1802d59SHal Feng pwmdac->saved_ctrl = jh7110_pwmdac_read_reg(pwmdac->base, 402d1802d59SHal Feng JH7110_PWMDAC_CTRL); 403d1802d59SHal Feng return pm_runtime_force_suspend(dev); 404d1802d59SHal Feng } 405d1802d59SHal Feng 406d1802d59SHal Feng static int jh7110_pwmdac_system_resume(struct device *dev) 407d1802d59SHal Feng { 408d1802d59SHal Feng struct jh7110_pwmdac_dev *pwmdac = dev_get_drvdata(dev); 409d1802d59SHal Feng int ret; 410d1802d59SHal Feng 411d1802d59SHal Feng ret = pm_runtime_force_resume(dev); 412d1802d59SHal Feng if (ret) 413d1802d59SHal Feng return ret; 414d1802d59SHal Feng 415d1802d59SHal Feng /* restore the CTRL register value */ 416d1802d59SHal Feng jh7110_pwmdac_write_reg(pwmdac->base, JH7110_PWMDAC_CTRL, 417d1802d59SHal Feng pwmdac->saved_ctrl); 418d1802d59SHal Feng return 0; 419d1802d59SHal Feng } 420d1802d59SHal Feng 421d1802d59SHal Feng static const struct dev_pm_ops jh7110_pwmdac_pm_ops = { 422d1802d59SHal Feng RUNTIME_PM_OPS(jh7110_pwmdac_runtime_suspend, 423d1802d59SHal Feng jh7110_pwmdac_runtime_resume, NULL) 424d1802d59SHal Feng SYSTEM_SLEEP_PM_OPS(jh7110_pwmdac_system_suspend, 425d1802d59SHal Feng jh7110_pwmdac_system_resume) 426d1802d59SHal Feng }; 427d1802d59SHal Feng 428d1802d59SHal Feng static void jh7110_pwmdac_init_params(struct jh7110_pwmdac_dev *dev) 429d1802d59SHal Feng { 430d1802d59SHal Feng dev->cfg.shift = PWMDAC_SHIFT_8; 431d1802d59SHal Feng dev->cfg.duty_cycle = PWMDAC_CYCLE_CENTER; 432d1802d59SHal Feng dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_1; 433d1802d59SHal Feng dev->cfg.data_change = NO_CHANGE; 434d1802d59SHal Feng dev->cfg.data_mode = INVERTER_DATA_MSB; 435d1802d59SHal Feng dev->cfg.data_shift = PWMDAC_DATA_LEFT_SHIFT_BIT_0; 436d1802d59SHal Feng 437d1802d59SHal Feng dev->play_dma_data.addr = dev->mapbase + JH7110_PWMDAC_WDATA; 438d1802d59SHal Feng dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 439d1802d59SHal Feng dev->play_dma_data.fifo_size = 1; 440d1802d59SHal Feng dev->play_dma_data.maxburst = 16; 441d1802d59SHal Feng } 442d1802d59SHal Feng 443d1802d59SHal Feng static int jh7110_pwmdac_probe(struct platform_device *pdev) 444d1802d59SHal Feng { 445d1802d59SHal Feng struct jh7110_pwmdac_dev *dev; 446d1802d59SHal Feng struct resource *res; 447d1802d59SHal Feng int ret; 448d1802d59SHal Feng 449d1802d59SHal Feng dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); 450d1802d59SHal Feng if (!dev) 451d1802d59SHal Feng return -ENOMEM; 452d1802d59SHal Feng 453d1802d59SHal Feng dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 454d1802d59SHal Feng if (IS_ERR(dev->base)) 455d1802d59SHal Feng return PTR_ERR(dev->base); 456d1802d59SHal Feng 457d1802d59SHal Feng dev->mapbase = res->start; 458d1802d59SHal Feng 459d1802d59SHal Feng dev->clks[0].id = "apb"; 460d1802d59SHal Feng dev->clks[1].id = "core"; 461d1802d59SHal Feng 462d1802d59SHal Feng ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(dev->clks), dev->clks); 463d1802d59SHal Feng if (ret) 464d1802d59SHal Feng return dev_err_probe(&pdev->dev, ret, 465d1802d59SHal Feng "failed to get pwmdac clocks\n"); 466d1802d59SHal Feng 467d1802d59SHal Feng dev->rst_apb = devm_reset_control_get_exclusive(&pdev->dev, NULL); 468d1802d59SHal Feng if (IS_ERR(dev->rst_apb)) 469d1802d59SHal Feng return dev_err_probe(&pdev->dev, PTR_ERR(dev->rst_apb), 470d1802d59SHal Feng "failed to get pwmdac apb reset\n"); 471d1802d59SHal Feng 472d1802d59SHal Feng jh7110_pwmdac_init_params(dev); 473d1802d59SHal Feng 474d1802d59SHal Feng dev->dev = &pdev->dev; 475d1802d59SHal Feng dev_set_drvdata(&pdev->dev, dev); 476d1802d59SHal Feng ret = devm_snd_soc_register_component(&pdev->dev, 477d1802d59SHal Feng &jh7110_pwmdac_component, 478d1802d59SHal Feng &jh7110_pwmdac_dai, 1); 479d1802d59SHal Feng if (ret) 480d1802d59SHal Feng return dev_err_probe(&pdev->dev, ret, "failed to register dai\n"); 481d1802d59SHal Feng 482d1802d59SHal Feng ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 483d1802d59SHal Feng if (ret) 484d1802d59SHal Feng return dev_err_probe(&pdev->dev, ret, "failed to register pcm\n"); 485d1802d59SHal Feng 486d1802d59SHal Feng pm_runtime_enable(dev->dev); 487d1802d59SHal Feng if (!pm_runtime_enabled(&pdev->dev)) { 488d1802d59SHal Feng ret = jh7110_pwmdac_runtime_resume(&pdev->dev); 489d1802d59SHal Feng if (ret) 490d1802d59SHal Feng goto err_pm_disable; 491d1802d59SHal Feng } 492d1802d59SHal Feng 493d1802d59SHal Feng return 0; 494d1802d59SHal Feng 495d1802d59SHal Feng err_pm_disable: 496d1802d59SHal Feng pm_runtime_disable(&pdev->dev); 497d1802d59SHal Feng 498d1802d59SHal Feng return ret; 499d1802d59SHal Feng } 500d1802d59SHal Feng 501*6b02f5a6SUwe Kleine-König static void jh7110_pwmdac_remove(struct platform_device *pdev) 502d1802d59SHal Feng { 503d1802d59SHal Feng pm_runtime_disable(&pdev->dev); 504d1802d59SHal Feng } 505d1802d59SHal Feng 506d1802d59SHal Feng static const struct of_device_id jh7110_pwmdac_of_match[] = { 507d1802d59SHal Feng { .compatible = "starfive,jh7110-pwmdac" }, 508d1802d59SHal Feng { /* sentinel */ } 509d1802d59SHal Feng }; 510d1802d59SHal Feng MODULE_DEVICE_TABLE(of, jh7110_pwmdac_of_match); 511d1802d59SHal Feng 512d1802d59SHal Feng static struct platform_driver jh7110_pwmdac_driver = { 513d1802d59SHal Feng .driver = { 514d1802d59SHal Feng .name = "jh7110-pwmdac", 515d1802d59SHal Feng .of_match_table = jh7110_pwmdac_of_match, 516d1802d59SHal Feng .pm = pm_ptr(&jh7110_pwmdac_pm_ops), 517d1802d59SHal Feng }, 518d1802d59SHal Feng .probe = jh7110_pwmdac_probe, 519*6b02f5a6SUwe Kleine-König .remove_new = jh7110_pwmdac_remove, 520d1802d59SHal Feng }; 521d1802d59SHal Feng module_platform_driver(jh7110_pwmdac_driver); 522d1802d59SHal Feng 523d1802d59SHal Feng MODULE_AUTHOR("Jenny Zhang"); 524d1802d59SHal Feng MODULE_AUTHOR("Curry Zhang"); 525d1802d59SHal Feng MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>"); 526d1802d59SHal Feng MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>"); 527d1802d59SHal Feng MODULE_DESCRIPTION("StarFive JH7110 PWM-DAC driver"); 528d1802d59SHal Feng MODULE_LICENSE("GPL"); 529