blob: 220c888c9a48726fc4cd5362dd4ad76d39cc6914
1 | /* |
2 | * drivers/amlogic/media/stream_input/amports/adec.c |
3 | * |
4 | * Copyright (C) 2016 Amlogic, Inc. All rights reserved. |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
14 | * more details. |
15 | * |
16 | */ |
17 | |
18 | #include <linux/kernel.h> |
19 | #include <linux/types.h> |
20 | #include <linux/errno.h> |
21 | #include <linux/platform_device.h> |
22 | #include <linux/slab.h> |
23 | #include <linux/uio_driver.h> |
24 | |
25 | #include <linux/amlogic/media/utils/aformat.h> |
26 | #include <linux/amlogic/media/frame_sync/ptsserv.h> |
27 | |
28 | #include <linux/amlogic/media/registers/register.h> |
29 | |
30 | #include "../parser/streambuf.h" |
31 | #include <linux/module.h> |
32 | #include "amports_priv.h" |
33 | |
34 | #define INFO_VALID ((astream_dev) && (astream_dev->format)) |
35 | |
36 | struct astream_device_s { |
37 | char *name; |
38 | char *format; |
39 | s32 channum; |
40 | s32 samplerate; |
41 | s32 datawidth; |
42 | |
43 | struct device dev; |
44 | }; |
45 | |
46 | static char *astream_format[] = { |
47 | "amadec_mpeg", |
48 | "amadec_pcm_s16le", |
49 | "amadec_aac", |
50 | "amadec_ac3", |
51 | "amadec_alaw", |
52 | "amadec_mulaw", |
53 | "amadec_dts", |
54 | "amadec_pcm_s16be", |
55 | "amadec_flac", |
56 | "amadec_cook", |
57 | "amadec_pcm_u8", |
58 | "amadec_adpcm", |
59 | "amadec_amr", |
60 | "amadec_raac", |
61 | "amadec_wma", |
62 | "amadec_wmapro", |
63 | "amadec_pcm_bluray", |
64 | "amadec_alac", |
65 | "amadec_vorbis", |
66 | "amadec_aac_latm", |
67 | "amadec_ape", |
68 | "amadec_eac3", |
69 | "amadec_pcm_widi", |
70 | "amadec_wmavoi" |
71 | }; |
72 | |
73 | static const char *na_string = "NA"; |
74 | static struct astream_device_s *astream_dev; |
75 | |
76 | static ssize_t format_show(struct class *class, struct class_attribute *attr, |
77 | char *buf) |
78 | { |
79 | if (INFO_VALID && astream_dev->format) |
80 | return sprintf(buf, "%s\n", astream_dev->format); |
81 | else |
82 | return sprintf(buf, "%s\n", na_string); |
83 | } |
84 | |
85 | static ssize_t channum_show(struct class *class, struct class_attribute *attr, |
86 | char *buf) |
87 | { |
88 | if (INFO_VALID) |
89 | return sprintf(buf, "%u\n", astream_dev->channum); |
90 | else |
91 | return sprintf(buf, "%s\n", na_string); |
92 | } |
93 | |
94 | static ssize_t samplerate_show(struct class *class, |
95 | struct class_attribute *attr, char *buf) |
96 | { |
97 | if (INFO_VALID) |
98 | return sprintf(buf, "%u\n", astream_dev->samplerate); |
99 | else |
100 | return sprintf(buf, "%s\n", na_string); |
101 | } |
102 | |
103 | static ssize_t datawidth_show(struct class *class, |
104 | struct class_attribute *attr, |
105 | char *buf) |
106 | { |
107 | if (INFO_VALID) |
108 | return sprintf(buf, "%u\n", astream_dev->datawidth); |
109 | else |
110 | return sprintf(buf, "%s\n", na_string); |
111 | } |
112 | |
113 | static ssize_t pts_show(struct class *class, struct class_attribute *attr, |
114 | char *buf) |
115 | { |
116 | u32 pts; |
117 | u32 pts_margin = 0; |
118 | |
119 | if (astream_dev->samplerate <= 12000) |
120 | pts_margin = 512; |
121 | |
122 | if (INFO_VALID && (pts_lookup(PTS_TYPE_AUDIO, &pts, pts_margin) >= 0)) |
123 | return sprintf(buf, "0x%x\n", pts); |
124 | else |
125 | return sprintf(buf, "%s\n", na_string); |
126 | } |
127 | |
128 | static struct class_attribute astream_class_attrs[] = { |
129 | __ATTR_RO(format), |
130 | __ATTR_RO(samplerate), |
131 | __ATTR_RO(channum), |
132 | __ATTR_RO(datawidth), |
133 | __ATTR_RO(pts), |
134 | __ATTR_NULL |
135 | }; |
136 | |
137 | static struct class astream_class = { |
138 | .name = "astream", |
139 | .class_attrs = astream_class_attrs, |
140 | }; |
141 | |
142 | #if 1 |
143 | #define IO_CBUS_PHY_BASE 0xc1100000 |
144 | #define CBUS_REG_OFFSET(reg) ((reg) << 2) |
145 | #define IO_SECBUS_PHY_BASE 0xda000000 |
146 | |
147 | static struct uio_info astream_uio_info = { |
148 | .name = "astream_uio", |
149 | .version = "0.1", |
150 | .irq = UIO_IRQ_NONE, |
151 | |
152 | .mem = { |
153 | [0] = { |
154 | .name = "AIFIFO", |
155 | .memtype = UIO_MEM_PHYS, |
156 | .addr = |
157 | (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(AIU_AIFIFO_CTRL)) |
158 | &(PAGE_MASK), |
159 | .size = PAGE_SIZE, |
160 | }, |
161 | [1] = { |
162 | .memtype = UIO_MEM_PHYS, |
163 | .addr = |
164 | (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(VCOP_CTRL_REG)), |
165 | .size = PAGE_SIZE, |
166 | }, |
167 | [2] = { |
168 | .name = "SECBUS", |
169 | .memtype = UIO_MEM_PHYS, |
170 | .addr = (IO_SECBUS_PHY_BASE), |
171 | .size = PAGE_SIZE, |
172 | }, |
173 | [3] = { |
174 | .name = "CBUS", |
175 | .memtype = UIO_MEM_PHYS, |
176 | .addr = |
177 | (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(ASSIST_HW_REV)) |
178 | &(PAGE_MASK), |
179 | .size = PAGE_SIZE, |
180 | }, |
181 | [4] = { |
182 | .name = "CBUS-START", |
183 | .memtype = UIO_MEM_PHYS, |
184 | .addr = (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(0x1000)), |
185 | .size = PAGE_SIZE * 4, |
186 | }, |
187 | }, |
188 | }; |
189 | #endif |
190 | |
191 | static void astream_release(struct device *dev) |
192 | { |
193 | kfree(astream_dev); |
194 | |
195 | astream_dev = NULL; |
196 | } |
197 | |
198 | s32 adec_init(struct stream_port_s *port) |
199 | { |
200 | enum aformat_e af; |
201 | |
202 | if (!astream_dev) |
203 | return -ENODEV; |
204 | |
205 | af = port->aformat; |
206 | |
207 | astream_dev->channum = port->achanl; |
208 | astream_dev->samplerate = port->asamprate; |
209 | astream_dev->datawidth = port->adatawidth; |
210 | |
211 | /*wmb();don't need it...*/ |
212 | if (af <= ARRAY_SIZE(astream_format)) |
213 | astream_dev->format = astream_format[af]; |
214 | else |
215 | astream_dev->format = NULL; |
216 | return 0; |
217 | } |
218 | |
219 | s32 adec_release(enum aformat_e vf) |
220 | { |
221 | pr_info("adec_release\n"); |
222 | |
223 | if (!astream_dev) |
224 | return -ENODEV; |
225 | |
226 | astream_dev->format = NULL; |
227 | |
228 | return 0; |
229 | } |
230 | |
231 | s32 astream_dev_register(void) |
232 | { |
233 | s32 r; |
234 | |
235 | r = class_register(&astream_class); |
236 | if (r) { |
237 | pr_info("astream class create fail.\n"); |
238 | return r; |
239 | } |
240 | |
241 | astream_dev = kzalloc(sizeof(struct astream_device_s), GFP_KERNEL); |
242 | |
243 | if (!astream_dev) { |
244 | r = -ENOMEM; |
245 | goto err_3; |
246 | } |
247 | |
248 | astream_dev->dev.class = &astream_class; |
249 | astream_dev->dev.release = astream_release; |
250 | |
251 | dev_set_name(&astream_dev->dev, "astream-dev"); |
252 | |
253 | dev_set_drvdata(&astream_dev->dev, astream_dev); |
254 | |
255 | r = device_register(&astream_dev->dev); |
256 | if (r) { |
257 | pr_info("astream device register fail.\n"); |
258 | goto err_2; |
259 | } |
260 | |
261 | #if 1 |
262 | if (uio_register_device(&astream_dev->dev, &astream_uio_info)) { |
263 | pr_info("astream UIO device register fail.\n"); |
264 | r = -ENODEV; |
265 | goto err_1; |
266 | } |
267 | #endif |
268 | |
269 | return 0; |
270 | |
271 | err_1: |
272 | device_unregister(&astream_dev->dev); |
273 | |
274 | err_2: |
275 | kfree(astream_dev); |
276 | astream_dev = NULL; |
277 | |
278 | err_3: |
279 | class_unregister(&astream_class); |
280 | |
281 | return r; |
282 | } |
283 | |
284 | void astream_dev_unregister(void) |
285 | { |
286 | if (astream_dev) { |
287 | #if 1 |
288 | uio_unregister_device(&astream_uio_info); |
289 | #endif |
290 | |
291 | device_unregister(&astream_dev->dev); |
292 | |
293 | class_unregister(&astream_class); |
294 | } |
295 | } |
296 |