1 /* 2 * Copyright (C) STMicroelectronics SA 2015 3 * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com> 4 * for STMicroelectronics. 5 * License terms: GNU General Public License (GPL), version 2 6 */ 7 8 #include <linux/module.h> 9 #include <linux/pinctrl/consumer.h> 10 11 #include "uniperif.h" 12 13 /* 14 * User frame size shall be 2, 4, 6 or 8 32-bits words length 15 * (i.e. 8, 16, 24 or 32 bytes) 16 * This constraint comes from allowed values for 17 * UNIPERIF_I2S_FMT_NUM_CH register 18 */ 19 #define UNIPERIF_MAX_FRAME_SZ 0x20 20 #define UNIPERIF_ALLOWED_FRAME_SZ (0x08 | 0x10 | 0x18 | UNIPERIF_MAX_FRAME_SZ) 21 22 int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 23 unsigned int rx_mask, int slots, 24 int slot_width) 25 { 26 struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); 27 struct uniperif *uni = priv->dai_data.uni; 28 int i, frame_size, avail_slots; 29 30 if (!UNIPERIF_TYPE_IS_TDM(uni)) { 31 dev_err(uni->dev, "cpu dai not in tdm mode\n"); 32 return -EINVAL; 33 } 34 35 /* store info in unip context */ 36 uni->tdm_slot.slots = slots; 37 uni->tdm_slot.slot_width = slot_width; 38 /* unip is unidirectionnal */ 39 uni->tdm_slot.mask = (tx_mask != 0) ? tx_mask : rx_mask; 40 41 /* number of available timeslots */ 42 for (i = 0, avail_slots = 0; i < uni->tdm_slot.slots; i++) { 43 if ((uni->tdm_slot.mask >> i) & 0x01) 44 avail_slots++; 45 } 46 uni->tdm_slot.avail_slots = avail_slots; 47 48 /* frame size in bytes */ 49 frame_size = uni->tdm_slot.avail_slots * uni->tdm_slot.slot_width / 8; 50 51 /* check frame size is allowed */ 52 if ((frame_size > UNIPERIF_MAX_FRAME_SZ) || 53 (frame_size & ~(int)UNIPERIF_ALLOWED_FRAME_SZ)) { 54 dev_err(uni->dev, "frame size not allowed: %d bytes\n", 55 frame_size); 56 return -EINVAL; 57 } 58 59 return 0; 60 } 61 62 int sti_uniperiph_fix_tdm_chan(struct snd_pcm_hw_params *params, 63 struct snd_pcm_hw_rule *rule) 64 { 65 struct uniperif *uni = rule->private; 66 struct snd_interval t; 67 68 t.min = uni->tdm_slot.avail_slots; 69 t.max = uni->tdm_slot.avail_slots; 70 t.openmin = 0; 71 t.openmax = 0; 72 t.integer = 0; 73 74 return snd_interval_refine(hw_param_interval(params, rule->var), &t); 75 } 76 77 int sti_uniperiph_fix_tdm_format(struct snd_pcm_hw_params *params, 78 struct snd_pcm_hw_rule *rule) 79 { 80 struct uniperif *uni = rule->private; 81 struct snd_mask *maskp = hw_param_mask(params, rule->var); 82 u64 format; 83 84 switch (uni->tdm_slot.slot_width) { 85 case 16: 86 format = SNDRV_PCM_FMTBIT_S16_LE; 87 break; 88 case 32: 89 format = SNDRV_PCM_FMTBIT_S32_LE; 90 break; 91 default: 92 dev_err(uni->dev, "format not supported: %d bits\n", 93 uni->tdm_slot.slot_width); 94 return -EINVAL; 95 } 96 97 maskp->bits[0] &= (u_int32_t)format; 98 maskp->bits[1] &= (u_int32_t)(format >> 32); 99 /* clear remaining indexes */ 100 memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX - 64) / 8); 101 102 if (!maskp->bits[0] && !maskp->bits[1]) 103 return -EINVAL; 104 105 return 0; 106 } 107 108 int sti_uniperiph_get_tdm_word_pos(struct uniperif *uni, 109 unsigned int *word_pos) 110 { 111 int slot_width = uni->tdm_slot.slot_width / 8; 112 int slots_num = uni->tdm_slot.slots; 113 unsigned int slots_mask = uni->tdm_slot.mask; 114 int i, j, k; 115 unsigned int word16_pos[4]; 116 117 /* word16_pos: 118 * word16_pos[0] = WORDX_LSB 119 * word16_pos[1] = WORDX_MSB, 120 * word16_pos[2] = WORDX+1_LSB 121 * word16_pos[3] = WORDX+1_MSB 122 */ 123 124 /* set unip word position */ 125 for (i = 0, j = 0, k = 0; (i < slots_num) && (k < WORD_MAX); i++) { 126 if ((slots_mask >> i) & 0x01) { 127 word16_pos[j] = i * slot_width; 128 129 if (slot_width == 4) { 130 word16_pos[j + 1] = word16_pos[j] + 2; 131 j++; 132 } 133 j++; 134 135 if (j > 3) { 136 word_pos[k] = word16_pos[1] | 137 (word16_pos[0] << 8) | 138 (word16_pos[3] << 16) | 139 (word16_pos[2] << 24); 140 j = 0; 141 k++; 142 } 143 } 144 } 145 146 return 0; 147 } 148 149 /* 150 * sti_uniperiph_dai_create_ctrl 151 * This function is used to create Ctrl associated to DAI but also pcm device. 152 * Request is done by front end to associate ctrl with pcm device id 153 */ 154 static int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai) 155 { 156 struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); 157 struct uniperif *uni = priv->dai_data.uni; 158 struct snd_kcontrol_new *ctrl; 159 int i; 160 161 if (!uni->num_ctrls) 162 return 0; 163 164 for (i = 0; i < uni->num_ctrls; i++) { 165 /* 166 * Several Control can have same name. Controls are indexed on 167 * Uniperipheral instance ID 168 */ 169 ctrl = &uni->snd_ctrls[i]; 170 ctrl->index = uni->info->id; 171 ctrl->device = uni->info->id; 172 } 173 174 return snd_soc_add_dai_controls(dai, uni->snd_ctrls, uni->num_ctrls); 175 } 176 177 /* 178 * DAI 179 */ 180 int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, 181 struct snd_pcm_hw_params *params, 182 struct snd_soc_dai *dai) 183 { 184 struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); 185 struct uniperif *uni = priv->dai_data.uni; 186 struct snd_dmaengine_dai_dma_data *dma_data; 187 int transfer_size; 188 189 if (uni->info->type == SND_ST_UNIPERIF_TYPE_TDM) 190 /* transfer size = user frame size (in 32-bits FIFO cell) */ 191 transfer_size = snd_soc_params_to_frame_size(params) / 32; 192 else 193 transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES; 194 195 dma_data = snd_soc_dai_get_dma_data(dai, substream); 196 dma_data->maxburst = transfer_size; 197 198 return 0; 199 } 200 201 int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 202 { 203 struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); 204 205 priv->dai_data.uni->daifmt = fmt; 206 207 return 0; 208 } 209 210 static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai) 211 { 212 struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); 213 struct uniperif *uni = priv->dai_data.uni; 214 int ret; 215 216 /* The uniperipheral should be in stopped state */ 217 if (uni->state != UNIPERIF_STATE_STOPPED) { 218 dev_err(uni->dev, "%s: invalid uni state( %d)", 219 __func__, (int)uni->state); 220 return -EBUSY; 221 } 222 223 /* Pinctrl: switch pinstate to sleep */ 224 ret = pinctrl_pm_select_sleep_state(uni->dev); 225 if (ret) 226 dev_err(uni->dev, "%s: failed to select pinctrl state", 227 __func__); 228 229 return ret; 230 } 231 232 static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai) 233 { 234 struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); 235 struct uniperif *uni = priv->dai_data.uni; 236 int ret; 237 238 if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) { 239 ret = uni_player_resume(uni); 240 if (ret) 241 return ret; 242 } 243 244 /* pinctrl: switch pinstate to default */ 245 ret = pinctrl_pm_select_default_state(uni->dev); 246 if (ret) 247 dev_err(uni->dev, "%s: failed to select pinctrl state", 248 __func__); 249 250 return ret; 251 } 252 253 static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai) 254 { 255 struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); 256 struct sti_uniperiph_dai *dai_data = &priv->dai_data; 257 258 /* DMA settings*/ 259 if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) 260 snd_soc_dai_init_dma_data(dai, &dai_data->dma_data, NULL); 261 else 262 snd_soc_dai_init_dma_data(dai, NULL, &dai_data->dma_data); 263 264 dai_data->dma_data.addr = dai_data->uni->fifo_phys_address; 265 dai_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 266 267 return sti_uniperiph_dai_create_ctrl(dai); 268 } 269 270 static const struct snd_soc_dai_driver sti_uniperiph_dai_template = { 271 .probe = sti_uniperiph_dai_probe, 272 .suspend = sti_uniperiph_dai_suspend, 273 .resume = sti_uniperiph_dai_resume 274 }; 275 276 static const struct snd_soc_component_driver sti_uniperiph_dai_component = { 277 .name = "sti_cpu_dai", 278 }; 279 280 static int sti_uniperiph_cpu_dai_of(struct device_node *node, 281 struct sti_uniperiph_data *priv) 282 { 283 const char *str; 284 int ret; 285 struct device *dev = &priv->pdev->dev; 286 struct sti_uniperiph_dai *dai_data = &priv->dai_data; 287 struct snd_soc_dai_driver *dai = priv->dai; 288 struct snd_soc_pcm_stream *stream; 289 struct uniperif *uni; 290 291 uni = devm_kzalloc(dev, sizeof(*uni), GFP_KERNEL); 292 if (!uni) 293 return -ENOMEM; 294 295 *dai = sti_uniperiph_dai_template; 296 ret = of_property_read_string(node, "dai-name", &str); 297 if (ret < 0) { 298 dev_err(dev, "%s: dai name missing.\n", __func__); 299 return -EINVAL; 300 } 301 dai->name = str; 302 303 /* Get resources */ 304 uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0); 305 306 if (!uni->mem_region) { 307 dev_err(dev, "Failed to get memory resource"); 308 return -ENODEV; 309 } 310 311 uni->base = devm_ioremap_resource(dev, uni->mem_region); 312 313 if (IS_ERR(uni->base)) 314 return PTR_ERR(uni->base); 315 316 uni->fifo_phys_address = uni->mem_region->start + 317 UNIPERIF_FIFO_DATA_OFFSET(uni); 318 319 uni->irq = platform_get_irq(priv->pdev, 0); 320 if (uni->irq < 0) { 321 dev_err(dev, "Failed to get IRQ resource"); 322 return -ENXIO; 323 } 324 325 dai_data->uni = uni; 326 327 if (of_device_is_compatible(node, "st,sti-uni-player")) { 328 uni_player_init(priv->pdev, uni); 329 stream = &dai->playback; 330 } else { 331 uni_reader_init(priv->pdev, uni); 332 stream = &dai->capture; 333 } 334 dai->ops = uni->dai_ops; 335 336 stream->stream_name = dai->name; 337 stream->channels_min = uni->hw->channels_min; 338 stream->channels_max = uni->hw->channels_max; 339 stream->rates = uni->hw->rates; 340 stream->formats = uni->hw->formats; 341 342 return 0; 343 } 344 345 static const struct snd_dmaengine_pcm_config dmaengine_pcm_config = { 346 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, 347 }; 348 349 static int sti_uniperiph_probe(struct platform_device *pdev) 350 { 351 struct sti_uniperiph_data *priv; 352 struct device_node *node = pdev->dev.of_node; 353 int ret; 354 355 /* Allocate the private data and the CPU_DAI array */ 356 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 357 if (!priv) 358 return -ENOMEM; 359 priv->dai = devm_kzalloc(&pdev->dev, sizeof(*priv->dai), GFP_KERNEL); 360 if (!priv->dai) 361 return -ENOMEM; 362 363 priv->pdev = pdev; 364 365 ret = sti_uniperiph_cpu_dai_of(node, priv); 366 367 dev_set_drvdata(&pdev->dev, priv); 368 369 ret = devm_snd_soc_register_component(&pdev->dev, 370 &sti_uniperiph_dai_component, 371 priv->dai, 1); 372 if (ret < 0) 373 return ret; 374 375 return devm_snd_dmaengine_pcm_register(&pdev->dev, 376 &dmaengine_pcm_config, 0); 377 } 378 379 static const struct of_device_id snd_soc_sti_match[] = { 380 { .compatible = "st,sti-uni-player", }, 381 { .compatible = "st,sti-uni-reader", }, 382 {}, 383 }; 384 385 static struct platform_driver sti_uniperiph_driver = { 386 .driver = { 387 .name = "sti-uniperiph-dai", 388 .of_match_table = snd_soc_sti_match, 389 }, 390 .probe = sti_uniperiph_probe, 391 }; 392 module_platform_driver(sti_uniperiph_driver); 393 394 MODULE_DESCRIPTION("uniperipheral DAI driver"); 395 MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>"); 396 MODULE_LICENSE("GPL v2"); 397