davinci_voicecodec.c (3281B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * DaVinci Voice Codec Core Interface for TI platforms 4 * 5 * Copyright (C) 2010 Texas Instruments, Inc 6 * 7 * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com> 8 */ 9 10#include <linux/init.h> 11#include <linux/module.h> 12#include <linux/device.h> 13#include <linux/slab.h> 14#include <linux/delay.h> 15#include <linux/io.h> 16#include <linux/clk.h> 17#include <linux/regmap.h> 18 19#include <sound/pcm.h> 20 21#include <linux/mfd/davinci_voicecodec.h> 22 23static const struct regmap_config davinci_vc_regmap = { 24 .reg_bits = 32, 25 .val_bits = 32, 26}; 27 28static int __init davinci_vc_probe(struct platform_device *pdev) 29{ 30 struct davinci_vc *davinci_vc; 31 struct resource *res; 32 struct mfd_cell *cell = NULL; 33 dma_addr_t fifo_base; 34 int ret; 35 36 davinci_vc = devm_kzalloc(&pdev->dev, 37 sizeof(struct davinci_vc), GFP_KERNEL); 38 if (!davinci_vc) 39 return -ENOMEM; 40 41 davinci_vc->clk = devm_clk_get(&pdev->dev, NULL); 42 if (IS_ERR(davinci_vc->clk)) { 43 dev_dbg(&pdev->dev, 44 "could not get the clock for voice codec\n"); 45 return -ENODEV; 46 } 47 clk_enable(davinci_vc->clk); 48 49 davinci_vc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 50 if (IS_ERR(davinci_vc->base)) { 51 ret = PTR_ERR(davinci_vc->base); 52 goto fail; 53 } 54 fifo_base = (dma_addr_t)res->start; 55 56 davinci_vc->regmap = devm_regmap_init_mmio(&pdev->dev, 57 davinci_vc->base, 58 &davinci_vc_regmap); 59 if (IS_ERR(davinci_vc->regmap)) { 60 ret = PTR_ERR(davinci_vc->regmap); 61 goto fail; 62 } 63 64 res = platform_get_resource(pdev, IORESOURCE_DMA, 0); 65 if (!res) { 66 dev_err(&pdev->dev, "no DMA resource\n"); 67 ret = -ENXIO; 68 goto fail; 69 } 70 71 davinci_vc->davinci_vcif.dma_tx_channel = res->start; 72 davinci_vc->davinci_vcif.dma_tx_addr = fifo_base + DAVINCI_VC_WFIFO; 73 74 res = platform_get_resource(pdev, IORESOURCE_DMA, 1); 75 if (!res) { 76 dev_err(&pdev->dev, "no DMA resource\n"); 77 ret = -ENXIO; 78 goto fail; 79 } 80 81 davinci_vc->davinci_vcif.dma_rx_channel = res->start; 82 davinci_vc->davinci_vcif.dma_rx_addr = fifo_base + DAVINCI_VC_RFIFO; 83 84 davinci_vc->dev = &pdev->dev; 85 davinci_vc->pdev = pdev; 86 87 /* Voice codec interface client */ 88 cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL]; 89 cell->name = "davinci-vcif"; 90 cell->platform_data = davinci_vc; 91 cell->pdata_size = sizeof(*davinci_vc); 92 93 /* Voice codec CQ93VC client */ 94 cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL]; 95 cell->name = "cq93vc-codec"; 96 cell->platform_data = davinci_vc; 97 cell->pdata_size = sizeof(*davinci_vc); 98 99 ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells, 100 DAVINCI_VC_CELLS, NULL, 0, NULL); 101 if (ret != 0) { 102 dev_err(&pdev->dev, "fail to register client devices\n"); 103 goto fail; 104 } 105 106 return 0; 107 108fail: 109 clk_disable(davinci_vc->clk); 110 111 return ret; 112} 113 114static int davinci_vc_remove(struct platform_device *pdev) 115{ 116 struct davinci_vc *davinci_vc = platform_get_drvdata(pdev); 117 118 mfd_remove_devices(&pdev->dev); 119 120 clk_disable(davinci_vc->clk); 121 122 return 0; 123} 124 125static struct platform_driver davinci_vc_driver = { 126 .driver = { 127 .name = "davinci_voicecodec", 128 }, 129 .remove = davinci_vc_remove, 130}; 131 132module_platform_driver_probe(davinci_vc_driver, davinci_vc_probe); 133 134MODULE_AUTHOR("Miguel Aguilar"); 135MODULE_DESCRIPTION("Texas Instruments DaVinci Voice Codec Core Interface"); 136MODULE_LICENSE("GPL");