Advertisement
Guest User

sunxi-i2s channel select and channel mapping

a guest
Oct 16th, 2014
248
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.82 KB | None | 0 0
  1. static int sunxi_i2s_hw_params(struct snd_pcm_substream *substream,
  2.                                 struct snd_pcm_hw_params *params,
  3.                                 struct snd_soc_dai *cpu_dai)
  4. {
  5.     u32 reg_val1, reg_val2, reg_val3;
  6.     struct snd_soc_pcm_runtime *rtd = substream->private_data;
  7.     struct sunxi_dma_params *dma_data;
  8.  
  9.     printk("[I2S]Entered %s\n", __func__);
  10.  
  11.     // Play or Capture
  12.     if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) // Play
  13.     {
  14.         printk("[I2S]sunxi_i2s_hw_params: SNDRV_PCM_STREAM_PLAYBACK.\n");
  15.         dma_data = &sunxi_i2s_pcm_stereo_out;
  16.         printk("[I2S]sunxi_i2s_hw_params: dma_data = &sunxi_i2s_pcm_stereo_out.\n");
  17.  
  18.         reg_val1 = readl(sunxi_iis.regs + SUNXI_IISCTL);
  19.         reg_val2 = readl(sunxi_iis.regs + SUNXI_TXCHSEL);
  20.         reg_val3 = readl(sunxi_iis.regs + SUNXI_TXCHMAP);
  21.  
  22.         #if defined CONFIG_ARCH_SUN7I || CONFIG_ARCH_SUN4I  // A10 and A20
  23.         reg_val1 &= ~(SUNXI_IISCTL_SDO0EN | SUNXI_IISCTL_SDO1EN | SUNXI_IISCTL_SDO2EN | SUNXI_IISCTL_SDO3EN);   // Disable all output channels.
  24.         reg_val2 &= ~(0x7 << 0);
  25.         reg_val3 &= ~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) | (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28));
  26.         switch (params_channels(params))    // Enables the outputs and sets the map of the samples, on crescent order.
  27.         {
  28.             case 1: // ! channel
  29.                 reg_val1 |= SUNXI_IISCTL_SDO0EN;
  30.                 reg_val2 |= SUNXI_TXCHSEL_CHNUM(1); // TX Channel Select 1-ch.
  31.                 reg_val3 |= (0x0 << 0); // TX Channel0 Mapping 1st sample.
  32.                 printk("[I2S]sunxi_i2s_hw_params: SDO0 enabled, 1 channel selected.\n");
  33.                 break;
  34.             case 2:
  35.                 reg_val1 |= SUNXI_IISCTL_SDO0EN;
  36.                 reg_val2 |= SUNXI_TXCHSEL_CHNUM(2); // TX Channel Select 2-ch.
  37.                 reg_val3 |= ((0x0 << 0) | (0x1 << 4));  // TX Channel0 Mapping 1st sample, TX Channel1 Mapping 2nd sample.
  38.                 printk("[I2S]sunxi_i2s_hw_params: SDO0 enabled, 2 channels selected.\n");
  39.                 break;
  40.             case 3:
  41.                 reg_val1 |= (SUNXI_IISCTL_SDO0EN | SUNXI_IISCTL_SDO1EN);
  42.                 reg_val2 |= SUNXI_TXCHSEL_CHNUM(3); // TX Channel Select 3-ch.
  43.                 reg_val3 |= ((0x0 << 0) | (0x1 << 4) | (0x2 << 8)); // TX Channel0 Mapping 1st sample, TX Channel1 Mapping 2nd sample, TX Channel3 Mapping 3rd sample.
  44.                 printk("[I2S]sunxi_i2s_hw_params: SDO0 and SDO1 enabled, 3 channels selected.\n");
  45.                 break;
  46.             case 4:
  47.                 reg_val1 |= (SUNXI_IISCTL_SDO0EN | SUNXI_IISCTL_SDO1EN);
  48.                 reg_val2 |= SUNXI_TXCHSEL_CHNUM(4); // TX Channel Select 4-ch.
  49.                 reg_val3 |= ((0x0 << 0) | (0x1 << 4) | (0x2 << 8) | (0x3 << 12)); // TX Channel0 Mapping 1st sample, TX Channel1 Mapping 2nd sample, TX Channel3 Mapping 3rd sample, TX Channel4 Mapping 4th sample
  50.                 printk("[I2S]sunxi_i2s_hw_params: SDO0 and SDO1 enabled, 4 channels selected.\n");
  51.                 break;
  52.             case 5:
  53.                 reg_val1 |= (SUNXI_IISCTL_SDO0EN | SUNXI_IISCTL_SDO1EN | SUNXI_IISCTL_SDO2EN);
  54.                 reg_val2 |= SUNXI_TXCHSEL_CHNUM(5); // TX Channel Select 5-ch.
  55.                 reg_val3 |= ((0x0 << 0) | (0x1 << 4) | (0x2 << 8) | (0x3 << 12) | (0x4 << 16)); // TX Channel0 Mapping 1st sample, TX Channel1 Mapping 2nd sample, TX Channel3 Mapping 3rd sample, TX Channel4 Mapping 4th sample, TX Channel5 Mapping 5th sample.
  56.                 printk("[I2S]sunxi_i2s_hw_params: SDO0, SDO1 and SDO2 enabled, 5 channels selected.\n");
  57.                 break;
  58.             case 6:
  59.                 reg_val1 |= (SUNXI_IISCTL_SDO0EN | SUNXI_IISCTL_SDO1EN | SUNXI_IISCTL_SDO2EN);
  60.                 reg_val2 |= SUNXI_TXCHSEL_CHNUM(6); // TX Channel Select 6-ch.
  61.                 reg_val3 |= ((0x0 << 0) | (0x1 << 4) | (0x2 << 8) | (0x3 << 12) | (0x4 << 16) | (0x5 << 20)); // TX Channel0 Mapping 1st sample, TX Channel1 Mapping 2nd sample, TX Channel3 Mapping 3rd sample, TX Channel4 Mapping 4th sample, TX Channel5 Mapping 5th sample, TX Channel6 Mapping 6th sample.
  62.                 printk("[I2S]sunxi_i2s_hw_params: SDO0, SDO1 and SDO2 enabled, 6 channels selected.\n");
  63.                 break;
  64.             case 7:
  65.                 reg_val1 |= (SUNXI_IISCTL_SDO0EN | SUNXI_IISCTL_SDO1EN | SUNXI_IISCTL_SDO2EN | SUNXI_IISCTL_SDO3EN);
  66.                 reg_val2 |= SUNXI_TXCHSEL_CHNUM(7); // TX Channel Select 7-ch.
  67.                 reg_val3 |= ((0x0 << 0) | (0x1 << 4) | (0x2 << 8) | (0x3 << 12) | (0x4 << 16) | (0x5 << 20) | (0x6 << 24)); // TX Channel0 Mapping 1st sample, TX Channel1 Mapping 2nd sample, TX Channel3 Mapping 3rd sample, TX Channel4 Mapping 4th sample, TX Channel5 Mapping 5th sample, TX Channel6 Mapping 6th sample, TX Channel7 Mapping 7th sample.
  68.                 printk("[I2S]sunxi_i2s_hw_params: SDO0, SDO1, SDO2 and SDO3 enabled, 7 channels selected.\n");
  69.                 break;
  70.             case 8:
  71.                 reg_val1 |= (SUNXI_IISCTL_SDO0EN | SUNXI_IISCTL_SDO1EN | SUNXI_IISCTL_SDO2EN | SUNXI_IISCTL_SDO3EN);
  72.                 reg_val2 |= SUNXI_TXCHSEL_CHNUM(8); // TX Channel Select 8-ch.
  73.                 reg_val3 |= ((0x0 << 0) | (0x1 << 4) | (0x2 << 8) | (0x3 << 12) | (0x4 << 16) | (0x5 << 20) | (0x6 << 24) | (0x7 << 28)); // TX Channel0 Mapping 1st sample, TX Channel1 Mapping 2nd sample, TX Channel3 Mapping 3rd sample, TX Channel4 Mapping 4th sample, TX Channel5 Mapping 5th sample, TX Channel6 Mapping 6th sample, TX Channel7 Mapping 7th sample, TX Channel8 Mapping 8th sample.
  74.                 printk("[I2S]sunxi_i2s_hw_params: SDO0, SDO1, SDO2 and SDO3 enabled, 8 channels selected.\n");
  75.                 break;
  76.             default:
  77.                 reg_val1 |= SUNXI_IISCTL_SDO0EN;
  78.                 reg_val2 |= SUNXI_TXCHSEL_CHNUM(1); // TX Channel Select 1-ch.
  79.                 reg_val3 |= (0x0 << 0); // TX Channel0 Mapping 1st sample.
  80.                 printk("[I2S]sunxi_i2s_hw_params: Wrong number of channels. Default: SDO0 enabled, 1 channel selected.\n");
  81.         }
  82.         #elif defined defined CONFIG_ARCH_SUN5I // A10s - TODO: How to know if its A10s or A13 if both are sun5i? A13 doesn't have Digital Audio (I2S/PCM)
  83.  
  84.         reg_val1 &= ~(SUNXI_IISCTL_SDO0EN); // Disable all output channels.
  85.         reg_val2 &= ~(0x7 << 0);
  86.         reg_val3 &= ~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) | (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28));
  87.  
  88.         switch (params_channels(params))
  89.         {
  90.             case 1:
  91.                 reg_val1 |= SUNXI_IISCTL_SDO0EN;
  92.                 reg_val2 |= SUNXI_TXCHSEL_CHNUM(1); // TX Channel Select 1-ch.
  93.                 reg_val3 |= (0x0 << 0); // TX Channel0 Mapping 1st sample.
  94.                 printk("[I2S] sunxi_i2s_hw_params: SDO0 enabled, 1 channel selected.\n");
  95.                 break;             
  96.             case 2:
  97.                 reg_val1 |= SUNXI_IISCTL_SDO0EN;
  98.                 reg_val2 |= SUNXI_TXCHSEL_CHNUM(2); // TX Channel Select 2-ch.
  99.                 reg_val3 |= ((0x0 << 0) | (0x1 << 4));  // TX Channel0 Mapping 1st sample, TX Channel1 Mapping 2nd sample.
  100.                 printk("[I2S] sunxi_i2s_hw_params: SDO0 enabled, 2 channels selected.\n");
  101.                 break; 
  102.             default:
  103.                 reg_val1 |= SUNXI_IISCTL_SDO0EN;
  104.                 reg_val2 |= SUNXI_TXCHSEL_CHNUM(1); // TX Channel Select 1-ch.
  105.                 reg_val3 |= (0x0 << 0); // TX Channel0 Mapping 1st sample.
  106.                 printk("[I2S]sunxi_i2s_hw_params: Wrong number of channels. Default: SDO0 enabled, 1 channel selected.\n");
  107.         }
  108.         #endif
  109.         writel(reg_val1, sunxi_iis.regs + SUNXI_IISCTL);
  110.         writel(reg_val2, sunxi_iis.regs + SUNXI_TXCHSEL);
  111.         writel(reg_val3, sunxi_iis.regs + SUNXI_TXCHMAP);
  112.     }
  113.     else {  // Record
  114.         printk("[I2S] sunxi_i2s_hw_params: SNDRV_PCM_STREAM_CAPTURE.\n");
  115.         dma_data = &sunxi_i2s_pcm_stereo_in;
  116.         printk("[I2S] sunxi_i2s_hw_params: dma_data = &sunxi_i2s_pcm_stereo_in\n");
  117.  
  118.         reg_val1 = readl(sunxi_iis.regs + SUNXI_RXCHSEL);
  119.         reg_val2 = readl(sunxi_iis.regs + SUNXI_RXCHMAP);
  120.  
  121.         #if defined CONFIG_ARCH_SUN7I || CONFIG_ARCH_SUN4I  // A10 and A20
  122.         reg_val1 &= ~(0x7 << 0);
  123.         reg_val2 &= ~((0x7 << 0) | (0x7 << 4));
  124.  
  125.         switch (params_channels(params))
  126.         {
  127.             case 1:
  128.                 reg_val1 |= SUNXI_RXCHSEL_CHNUM(1); // RX Channel Select 1-ch.
  129.                 reg_val2 |= (0x0 << 0); // RX Channel0 Mapping 1st sample.
  130.                 printk("[I2S] sunxi_i2s_hw_params: SDO0 enabled, 1 channel selected.\n");
  131.                 break;             
  132.             case 2:
  133.                 reg_val1 |= SUNXI_RXCHSEL_CHNUM(2); // RX Channel Select 2-ch.
  134.                 reg_val2 |= ((0x0 << 0) | (0x1 << 4));  // RX Channel0 Mapping 1st sample, RX Channel1 Mapping 2nd sample.
  135.                 printk("[I2S] sunxi_i2s_hw_params: SDO0 enabled, 2 channels selected.\n");
  136.                 break; 
  137.             default:
  138.                 reg_val1 |= SUNXI_RXCHSEL_CHNUM(1); // RX Channel Select 1-ch.
  139.                 reg_val2 |= (0x0 << 0); // RX Channel0 Mapping 1st sample.
  140.                 printk("[I2S]sunxi_i2s_hw_params: Wrong number of channels. Default: SDO0 enabled, 1 channel selected.\n");
  141.         }
  142.  
  143.         writel(reg_val1, sunxi_iis.regs + SUNXI_RXCHSEL);
  144.         writel(reg_val2, sunxi_iis.regs + SUNXI_RXCHMAP);
  145.  
  146.     }
  147.  
  148.     // Sample Resolution. TODO: Support SNDRV_PCM_FORMAT_S20_3LE and SNDRV_PCM_FMTBIT_S24_3LE formats. Must check the Word Size and change it for 24bits ("3LE").  
  149.     reg_val1 = readl(sunxi_iis.regs + SUNXI_IISFAT0);
  150.     reg_val1 &= ~SUNXI_IISFAT0_SR_RVD;      // Clear sample resolution select size
  151.     switch (params_format(params))
  152.     {
  153.         case SNDRV_PCM_FORMAT_S16_LE:
  154.             reg_val1 |= SUNXI_IISFAT0_SR_16BIT;
  155.             sunxi_iis.samp_res = 16;
  156.             printk("[I2S] sunxi_i2s_hw_params: format 16 bit\n");
  157.             break;
  158.         case SNDRV_PCM_FORMAT_S24_LE:
  159.             reg_val1 |= SUNXI_IISFAT0_SR_24BIT;
  160.             sunxi_iis.samp_res = 24;
  161.             if(sunxi_iis.ws_size != 32) // If the Word Size is not equal to 32, sets word size to 32.
  162.             {
  163.                 reg_val1 = readl(sunxi_iis.regs + SUNXI_IISFAT0);
  164.                 reg_val1 |= SUNXI_IISFAT0_WSS_32BCLK;
  165.                 writel(reg_val1, sunxi_iis.regs + SUNXI_IISFAT0);
  166.                 sunxi_iis.ws_size = 32;
  167.                 printk("[I2S] sunxi_i2s_hw_params: Changing word slect size to 32bit.\n");
  168.             }
  169.             printk("[I2S] sunxi_i2s_hw_params: format 24 bit\n");
  170.             break;
  171.         default:
  172.             printk("[I2S] sunxi_i2s_hw_params: Unsupported format (%d). Setting 16 bit format.\n", (int)params_format(params));
  173.             reg_val1 |= SUNXI_IISFAT0_SR_16BIT;
  174.             sunxi_iis.samp_res = 16;
  175.             break;
  176.     }
  177.     writel(reg_val1, sunxi_iis.regs + SUNXI_IISFAT0);
  178.  
  179.     // Samplign Rate. TODO.
  180.     if(sunxi_iis.slave == 0)    // If is MASTER.
  181.     {
  182.         sunxi_iis.samp_fs = params_rate(params);
  183.         sunxi_i2s_set_clkdiv(cpu_dai, SUNXI_SAMPLING_FREQ, sunxi_iis.samp_fs);
  184.     }
  185.  
  186.     snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);    // TODO: Place this call in a more apropriate place, like trigger, then test. Printk the cpu->dai name to understand "who" is it?
  187.  
  188. //  sunxi_i2s_printk_register_values();
  189.  
  190.     return 0;
  191. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement