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