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 
23 static const struct regmap_config davinci_vc_regmap = {
24 	.reg_bits = 32,
25 	.val_bits = 32,
26 };
27 
davinci_vc_probe(struct platform_device * pdev)28 static 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 
108 fail:
109 	clk_disable(davinci_vc->clk);
110 
111 	return ret;
112 }
113 
davinci_vc_remove(struct platform_device * pdev)114 static 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 
125 static struct platform_driver davinci_vc_driver = {
126 	.driver	= {
127 		.name = "davinci_voicecodec",
128 	},
129 	.remove	= davinci_vc_remove,
130 };
131 
132 module_platform_driver_probe(davinci_vc_driver, davinci_vc_probe);
133 
134 MODULE_AUTHOR("Miguel Aguilar");
135 MODULE_DESCRIPTION("Texas Instruments DaVinci Voice Codec Core Interface");
136 MODULE_LICENSE("GPL");
137