Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | /* SPDX-License-Identifier: GPL-2.0 */ /* * Socionext UniPhier AIO ALSA driver. * * Copyright (c) 2016-2018 Socionext Inc. */ #ifndef SND_UNIPHIER_AIO_H__ #define SND_UNIPHIER_AIO_H__ #include <linux/spinlock.h> #include <linux/types.h> #include <sound/pcm.h> #include <sound/soc.h> #include <sound/soc-dai.h> struct platform_device; enum ID_PORT_TYPE { PORT_TYPE_UNKNOWN, PORT_TYPE_I2S, PORT_TYPE_SPDIF, PORT_TYPE_EVE, PORT_TYPE_CONV, }; enum ID_PORT_DIR { PORT_DIR_OUTPUT, PORT_DIR_INPUT, }; enum IEC61937_PC { IEC61937_PC_AC3 = 0x0001, IEC61937_PC_PAUSE = 0x0003, IEC61937_PC_MPA = 0x0004, IEC61937_PC_MP3 = 0x0005, IEC61937_PC_DTS1 = 0x000b, IEC61937_PC_DTS2 = 0x000c, IEC61937_PC_DTS3 = 0x000d, IEC61937_PC_AAC = 0x0007, }; /* IEC61937 Repetition period of data-burst in IEC60958 frames */ #define IEC61937_FRM_STR_AC3 1536 #define IEC61937_FRM_STR_MPA 1152 #define IEC61937_FRM_STR_MP3 1152 #define IEC61937_FRM_STR_DTS1 512 #define IEC61937_FRM_STR_DTS2 1024 #define IEC61937_FRM_STR_DTS3 2048 #define IEC61937_FRM_STR_AAC 1024 /* IEC61937 Repetition period of Pause data-burst in IEC60958 frames */ #define IEC61937_FRM_PAU_AC3 3 #define IEC61937_FRM_PAU_MPA 32 #define IEC61937_FRM_PAU_MP3 32 #define IEC61937_FRM_PAU_DTS1 3 #define IEC61937_FRM_PAU_DTS2 3 #define IEC61937_FRM_PAU_DTS3 3 #define IEC61937_FRM_PAU_AAC 32 /* IEC61937 Pa and Pb */ #define IEC61937_HEADER_SIGN 0x1f4e72f8 #define AUD_HW_PCMIN1 0 #define AUD_HW_PCMIN2 1 #define AUD_HW_PCMIN3 2 #define AUD_HW_IECIN1 3 #define AUD_HW_DIECIN1 4 #define AUD_NAME_PCMIN1 "aio-pcmin1" #define AUD_NAME_PCMIN2 "aio-pcmin2" #define AUD_NAME_PCMIN3 "aio-pcmin3" #define AUD_NAME_IECIN1 "aio-iecin1" #define AUD_NAME_DIECIN1 "aio-diecin1" #define AUD_HW_HPCMOUT1 0 #define AUD_HW_PCMOUT1 1 #define AUD_HW_PCMOUT2 2 #define AUD_HW_PCMOUT3 3 #define AUD_HW_EPCMOUT1 4 #define AUD_HW_EPCMOUT2 5 #define AUD_HW_EPCMOUT3 6 #define AUD_HW_EPCMOUT6 9 #define AUD_HW_HIECOUT1 10 #define AUD_HW_IECOUT1 11 #define AUD_HW_CMASTER 31 #define AUD_NAME_HPCMOUT1 "aio-hpcmout1" #define AUD_NAME_PCMOUT1 "aio-pcmout1" #define AUD_NAME_PCMOUT2 "aio-pcmout2" #define AUD_NAME_PCMOUT3 "aio-pcmout3" #define AUD_NAME_EPCMOUT1 "aio-epcmout1" #define AUD_NAME_EPCMOUT2 "aio-epcmout2" #define AUD_NAME_EPCMOUT3 "aio-epcmout3" #define AUD_NAME_EPCMOUT6 "aio-epcmout6" #define AUD_NAME_HIECOUT1 "aio-hiecout1" #define AUD_NAME_IECOUT1 "aio-iecout1" #define AUD_NAME_CMASTER "aio-cmaster" #define AUD_NAME_HIECCOMPOUT1 "aio-hieccompout1" #define AUD_NAME_IECCOMPOUT1 "aio-ieccompout1" #define AUD_GNAME_HDMI "aio-hdmi" #define AUD_GNAME_LINE "aio-line" #define AUD_GNAME_AUX "aio-aux" #define AUD_GNAME_IEC "aio-iec" #define AUD_CLK_IO 0 #define AUD_CLK_A1 1 #define AUD_CLK_F1 2 #define AUD_CLK_A2 3 #define AUD_CLK_F2 4 #define AUD_CLK_A 5 #define AUD_CLK_F 6 #define AUD_CLK_APLL 7 #define AUD_CLK_RX0 8 #define AUD_CLK_USB0 9 #define AUD_CLK_HSC0 10 #define AUD_PLL_A1 0 #define AUD_PLL_F1 1 #define AUD_PLL_A2 2 #define AUD_PLL_F2 3 #define AUD_PLL_APLL 4 #define AUD_PLL_RX0 5 #define AUD_PLL_USB0 6 #define AUD_PLL_HSC0 7 #define AUD_PLLDIV_1_2 0 #define AUD_PLLDIV_1_3 1 #define AUD_PLLDIV_1_1 2 #define AUD_PLLDIV_2_3 3 #define AUD_VOL_INIT 0x4000 /* +0dB */ #define AUD_VOL_MAX 0xffff /* +6dB */ #define AUD_VOL_FADE_TIME 20 /* 20ms */ #define AUD_RING_SIZE (128 * 1024) #define AUD_MIN_FRAGMENT 4 #define AUD_MAX_FRAGMENT 8 #define AUD_MIN_FRAGMENT_SIZE (4 * 1024) #define AUD_MAX_FRAGMENT_SIZE (16 * 1024) /* max 5 slots, 10 channels, 2 channel in 1 slot */ #define AUD_MAX_SLOTSEL 5 /* * This is a selector for virtual register map of AIO. * * map: Specify the index of virtual register map. * hw : Specify the ID of real register map, selector uses this value. * A meaning of this value depends specification of SoC. */ struct uniphier_aio_selector { int map; int hw; }; /** * 'SoftWare MAPping' setting of UniPhier AIO registers. * * We have to setup 'virtual' register maps to access 'real' registers of AIO. * This feature is legacy and meaningless but AIO needs this to work. * * Each hardware blocks have own virtual register maps as following: * * Address Virtual Real * ------- --------- --------------- * 0x12000 DMAC map0 --> [selector] --> DMAC hardware 3 * 0x12080 DMAC map1 --> [selector] --> DMAC hardware 1 * ... * 0x42000 Port map0 --> [selector] --> Port hardware 1 * 0x42400 Port map1 --> [selector] --> Port hardware 2 * ... * * ch : Input or output channel of DMAC * rb : Ring buffer * iport: PCM input port * iif : Input interface * oport: PCM output port * oif : Output interface * och : Output channel of DMAC for sampling rate converter * * These are examples for sound data paths: * * For caputure device: * (outer of AIO) -> iport -> iif -> ch -> rb -> (CPU) * For playback device: * (CPU) -> rb -> ch -> oif -> oport -> (outer of AIO) * For sampling rate converter device: * (CPU) -> rb -> ch -> oif -> (HW SRC) -> iif -> och -> orb -> (CPU) */ struct uniphier_aio_swmap { int type; int dir; struct uniphier_aio_selector ch; struct uniphier_aio_selector rb; struct uniphier_aio_selector iport; struct uniphier_aio_selector iif; struct uniphier_aio_selector oport; struct uniphier_aio_selector oif; struct uniphier_aio_selector och; }; struct uniphier_aio_spec { const char *name; const char *gname; struct uniphier_aio_swmap swm; }; struct uniphier_aio_pll { bool enable; unsigned int freq; }; struct uniphier_aio_chip_spec { const struct uniphier_aio_spec *specs; int num_specs; const struct uniphier_aio_pll *plls; int num_plls; struct snd_soc_dai_driver *dais; int num_dais; /* DMA access mode, this is workaround for DMA hungup */ int addr_ext; }; struct uniphier_aio_sub { struct uniphier_aio *aio; /* Guard sub->rd_offs and wr_offs from IRQ handler. */ spinlock_t lock; const struct uniphier_aio_swmap *swm; const struct uniphier_aio_spec *spec; /* For PCM audio */ struct snd_pcm_substream *substream; struct snd_pcm_hw_params params; int vol; /* For compress audio */ struct snd_compr_stream *cstream; struct snd_compr_params cparams; unsigned char *compr_area; dma_addr_t compr_addr; size_t compr_bytes; int pass_through; enum IEC61937_PC iec_pc; bool iec_header; /* Both PCM and compress audio */ bool use_mmap; int setting; int running; u64 rd_offs; u64 wr_offs; u32 threshold; u64 rd_org; u64 wr_org; u64 rd_total; u64 wr_total; }; struct uniphier_aio { struct uniphier_aio_chip *chip; struct uniphier_aio_sub sub[2]; unsigned int fmt; /* Set one of AUD_CLK_X */ int clk_in; int clk_out; /* Set one of AUD_PLL_X */ int pll_in; int pll_out; /* Set one of AUD_PLLDIV_X */ int plldiv; }; struct uniphier_aio_chip { struct platform_device *pdev; const struct uniphier_aio_chip_spec *chip_spec; struct uniphier_aio *aios; int num_aios; int num_wup_aios; struct uniphier_aio_pll *plls; int num_plls; struct clk *clk; struct reset_control *rst; struct regmap *regmap; struct regmap *regmap_sg; int active; }; static inline struct uniphier_aio *uniphier_priv(struct snd_soc_dai *dai) { struct uniphier_aio_chip *chip = snd_soc_dai_get_drvdata(dai); return &chip->aios[dai->id]; } int uniphier_aiodma_soc_register_platform(struct platform_device *pdev); extern const struct snd_compr_ops uniphier_aio_compr_ops; int uniphier_aio_dai_probe(struct snd_soc_dai *dai); int uniphier_aio_dai_remove(struct snd_soc_dai *dai); int uniphier_aio_probe(struct platform_device *pdev); int uniphier_aio_remove(struct platform_device *pdev); extern const struct snd_soc_dai_ops uniphier_aio_i2s_ops; extern const struct snd_soc_dai_ops uniphier_aio_spdif_ops; u64 aio_rb_cnt(struct uniphier_aio_sub *sub); u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub); u64 aio_rb_space(struct uniphier_aio_sub *sub); u64 aio_rb_space_to_end(struct uniphier_aio_sub *sub); void aio_iecout_set_enable(struct uniphier_aio_chip *chip, bool enable); int aio_chip_set_pll(struct uniphier_aio_chip *chip, int pll_id, unsigned int freq); void aio_chip_init(struct uniphier_aio_chip *chip); int aio_init(struct uniphier_aio_sub *sub); void aio_port_reset(struct uniphier_aio_sub *sub); int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through, const struct snd_pcm_hw_params *params); void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable); int aio_port_get_volume(struct uniphier_aio_sub *sub); void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol); int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through); int aio_oport_set_stream_type(struct uniphier_aio_sub *sub, enum IEC61937_PC pc); void aio_src_reset(struct uniphier_aio_sub *sub); int aio_src_set_param(struct uniphier_aio_sub *sub, const struct snd_pcm_hw_params *params); int aio_srcif_set_param(struct uniphier_aio_sub *sub); int aio_srcch_set_param(struct uniphier_aio_sub *sub); void aio_srcch_set_enable(struct uniphier_aio_sub *sub, int enable); int aiodma_ch_set_param(struct uniphier_aio_sub *sub); void aiodma_ch_set_enable(struct uniphier_aio_sub *sub, int enable); int aiodma_rb_set_threshold(struct uniphier_aio_sub *sub, u64 size, u32 th); int aiodma_rb_set_buffer(struct uniphier_aio_sub *sub, u64 start, u64 end, int period); void aiodma_rb_sync(struct uniphier_aio_sub *sub, u64 start, u64 size, int period); bool aiodma_rb_is_irq(struct uniphier_aio_sub *sub); void aiodma_rb_clear_irq(struct uniphier_aio_sub *sub); #endif /* SND_UNIPHIER_AIO_H__ */ |