LMS 2012
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
d_sound.c
Go to the documentation of this file.
1 /*
2  * LEGO® MINDSTORMS EV3
3  *
4  * Copyright (C) 2010-2013 The LEGO Group
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,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
28 #define HW_ID_SUPPORT
29 
30 #include "../../lms2012/source/lms2012.h"
31 #include "../../lms2012/source/am1808.h"
32 
33 #ifdef DEBUG_D_SOUND
34 #define DEBUG
35 #endif
36 
37 #define MODULE_NAME "sound_module"
38 #define DEVICE1_NAME SOUND_DEVICE
39 
40 static int ModuleInit(void);
41 static void ModuleExit(void);
42 
43 #define __USE_POSIX
44 
45 #include <linux/kernel.h>
46 #include <linux/fs.h>
47 
48 #include <linux/sched.h>
49 
50 
51 #ifndef PCASM
52 #include <linux/hrtimer.h>
53 
54 #include <linux/mm.h>
55 #include <linux/hrtimer.h>
56 
57 #include <linux/init.h>
58 #include <linux/uaccess.h>
59 #include <linux/debugfs.h>
60 
61 #include <linux/ioport.h>
62 #include <asm/gpio.h>
63 #include <asm/io.h>
64 #include <linux/module.h>
65 #include <linux/miscdevice.h>
66 #include <asm/uaccess.h>
67 
68 
69 MODULE_LICENSE("GPL");
70 MODULE_AUTHOR("The LEGO Group");
73 
74 module_init(ModuleInit);
75 module_exit(ModuleExit);
76 
77 #else
78 // Keep Eclipse happy
79 #endif
80 
81 enum
82 {
88 } TIMER_MODES;
89 
90 /*
91  * Variables
92  */
93 static ULONG *SYSCFG0;
94 static ULONG *PSC1;
95 static UWORD *eHRPWM0;
96 static void __iomem *GpioBase;
97 static UWORD Duration;
98 static UWORD Period;
99 static UBYTE Level;
100 static UBYTE TimerMode = READY_FOR_SAMPLES;
101 static SOUND SoundDefault;
102 static SOUND *pSound = &SoundDefault;
103 static struct hrtimer Device1Timer;
104 static ktime_t Device1Time;
105 
106 
107 /*
108  * Defines related to hardware PWM output
109  */
110 
111 #define CFGCHIP0 0x60 // 32 bit wide index into SYSCFG0
112 #define PLL_MASTER_LOCK 0x00001000
113 #define DEFAULT_FREQUENCY 16499 // 16499 should give 8 KHz
114 #define DEFAULT_LEVEL 1000 // 25% D.C.
115 
116 static UWORD SoundBuffers[SOUND_BUFFER_COUNT][SOUND_FILE_BUFFER_SIZE];
117 static UBYTE SoundChunkSize[SOUND_BUFFER_COUNT];
118 static UWORD BufferReadPointer;
119 static UBYTE BufferReadIndex;
120 static UBYTE BufferWriteIndex;
121 
122 // TBCTL (Time-Base Control)
123 // = = = = = = = = = = = = = = = = = = = = = = = = = =
124 #define TB_COUNT_UP 0x0 // TBCNT MODE bits
125 #define TB_DISABLE 0x0 // PHSEN bit
126 #define TB_ENABLE 0x4
127 #define TB_SHADOW 0x0 // PRDLD bit
128 #define TB_IMMEDIATE 0x8
129 #define TB_SYNC_DISABLE 0x30 // SYNCOSEL bits
130 #define TB_HDIV1 0x0 // HSPCLKDIV bits
131 #define TB_DIV1 0x0 // CLKDIV bits
132 #define TB_UP 0x2000 // PHSDIR bit
133 
134 // CMPCTL (Compare Control)
135 // = = = = = = = = = = = = = = = = = = = = = = = = = =
136 #define CC_CTR_A_ZERO 0x0 // LOADAMODE bits
137 #define CC_CTR_B_ZERO 0x0
138 #define CC_A_SHADOW 0x00 // SHDWAMODE and SHDWBMODE bits
139 #define CC_B_SHADOW 0x00
140 #define CC_B_NO_SHADOW 0x40
141 
142 #define TBCTL 0x0
143 #define TBPHS 0x3
144 #define TBCNT 0x4
145 #define TBPRD 0x5
146 #define CMPCTL 0x7
147 #define CMPA 0x9
148 #define CMPB 0xA
149 #define AQCTLA 0xB
150 #define AQCTLB 0xC
151 
152 // Action-Qualifier Output B Control Register AQCTLB:
153 
154 // 1111 11
155 // bit 5432 1098 7654 3210
156 
157 // Bit 15 Reserved R000 0000 0000 0000
158 // Bit 14 - 0R00 0000 0000 0000
159 // Bit 13 - 00R0 0000 0000 0000
160 // Bit 12 - 000R 0000 0000 0000
161 #define SOUND_RESERVED 0x0000
162 
163 // Bit 11 CBD 0000 0000 0000 0000
164 // Bit 10 - 0000 0100 0000 0000 CLEAR Forces EPWM0B LOW
165 #define SOUND_CBD 0x0400
166 
167 // Bit 9 CBU 0000 0000 0000 0000
168 // Bit 8 - 0000 0001 0000 0000 CLEAR Forces EPWM0B LOW
169 #define SOUND_CBU 0x0100
170 
171 // Bit 7 CAD 0000 0000 N000 0000 DO NOTHING
172 // Bit 6 - 0000 0000 0N00 0000 -
173 #define SOUND_CAD 0x0000
174 
175 // Bit 5 CAU 0000 0000 00N0 0000 DO NOTHING
176 // Bit 4 - 0000 0000 000N 0000 -
177 #define SOUND_CAU 0x0000
178 
179 // Bit 3 PRD 0000 00N0 0000 1000 Forces EPWM0B HIGH
180 // Bit 2 - 0000 000N 0000 0000 -
181 #define SOUND_PRD 0x0008
182 
183 // Bit 1 ZRO 0000 00N0 0000 0010 Forces EPWM0B HIGH
184 // Bit 0 - 0000 000N 0000 0000 -
185 #define SOUND_ZRO 0x0002
186 
187 
188 
189 
190 #define SOUND_SYMM_TONE (SOUND_RESERVED +\
191  SOUND_CBD +\
192  SOUND_CBU +\
193  SOUND_CAD +\
194  SOUND_CAU +\
195  SOUND_PRD +\
196  SOUND_ZRO)
197 
198 /*
199  * Macro defines related to hardware PWM output
200  */
201 
202 // Put the "Magic key" into KICK0R and KICK1R to open for manipulation
203 // Stop Time Base Clock (TBCLK) - clear bit TBCLKSYNC in CFGCHIP1
204 // Remove the "Magic key" from KICK0R and KICK1R to lock
205 
206 #define EHRPWMClkDisable {\
207  eHRPWM0[TBCTL] = 0xC033;\
208 /* REGUnlock;\
209  iowrite32((ioread32(&SYSCFG0[CFGCHIP0]) & ~PLL_MASTER_LOCK),&SYSCFG0[0x60]);\
210  REGLock;*/\
211  }
212 
213 // Put the "Magic key" into KICK0R and KICK1R to open for manipulation
214 // Start Time Base Clock (TBCLK) - set bit TBCLKSYNC in CFGCHIP1
215 // Remove the "Magic key" from KICK0R and KICK1R to lock
216 
217 #define EHRPWMClkEnable {\
218  eHRPWM0[TBCTL] = 0xC030; \
219  REGUnlock;\
220  iowrite32((ioread32(&SYSCFG0[CFGCHIP0]) | PLL_MASTER_LOCK),&SYSCFG0[0x60]);\
221  REGLock;\
222  }
223 
224 #define EHRPWMClkEnableTone {\
225  eHRPWM0[TBCTL] = 0xDC30;\
226  REGUnlock;\
227  iowrite32((ioread32(&SYSCFG0[CFGCHIP0]) | PLL_MASTER_LOCK),&SYSCFG0[0x60]);\
228  REGLock;\
229  }
230 
231 #define SETPwmPeriod(Prd) {\
232  eHRPWM0[TBPRD] = Prd; /* A factor of sample-rate */\
233  /* For lowering the quanti- */\
234  /* zation noise (simpler */\
235  /* filtering) */\
236  }
237 
238 #define SETSoundLevel(Level) {\
239  eHRPWM0[CMPB] = Level; /* The amplitude for this */\
240  /* very and/or following */\
241  /* samples/periods */\
242  }
243 
244 #define STOPPwm {\
245  iowrite16(0x00, &eHRPWM0[TBCTL]);\
246  iowrite16(0x00, &eHRPWM0[CMPCTL]);\
247  EHRPWMClkDisable;\
248  }
249 
250 #define SOUNDPwmModuleSetupPcm { \
251  \
252  /* eHRPWM Module */\
253  /* In eHRPWM1[TBCTL] TB_DISABLE, TB_SHADOW, TB_HDIV1, TB_DIV1, TB_COUNT_UP all cleared */\
254  EHRPWMClkDisable;\
255  eHRPWM0[TBPHS] = 0; /* Phase register cleared */\
256  eHRPWM0[TBCNT] = 0; /* Clear TB counter */\
257 /* eHRPWM0[TBCTL] = 0xC030;*/\
258  eHRPWM0[CMPCTL] = (CC_B_SHADOW | CC_CTR_B_ZERO);\
259  eHRPWM0[AQCTLB] = 0x0102;\
260  EHRPWMClkEnable;\
261  }
262 
263 #define SOUNDPwmModuleSetupTone { \
264  \
265  /* eHRPWM Module */\
266  /* In eHRPWM1[TBCTL] TB_DISABLE, TB_SHADOW, TB_HDIV1, TB_DIV1, TB_COUNT_UP all cleared */\
267  EHRPWMClkDisable;\
268  eHRPWM0[TBPHS] = 0; /* Phase register cleared */\
269  eHRPWM0[TBCNT] = 0; /* Clear TB counter */\
270 /* eHRPWM0[TBCTL] = 0xDC30;*/\
271  eHRPWM0[CMPCTL] = (CC_B_SHADOW | CC_CTR_B_ZERO);\
272  eHRPWM0[AQCTLB] = 0x0102;\
273 /* EHRPWMClkEnable;*/\
274  EHRPWMClkEnableTone;\
275  }
276 
277 #define SOUNDEnable {\
278  (*SoundPin[SOUNDEN].pGpio).set_data = SoundPin[SOUNDEN].Mask;\
279  (*SoundPin[SOUNDEN].pGpio).dir &= ~SoundPin[SOUNDEN].Mask;\
280  }
281 
282 #define SOUNDDisable {\
283  (*SoundPin[SOUNDEN].pGpio).clr_data = SoundPin[SOUNDEN].Mask;\
284  (*SoundPin[SOUNDEN].pGpio).dir &= ~SoundPin[SOUNDEN].Mask;\
285  }
286 
287 #define SOUNDPwmPoweron {\
288  iowrite32(0x00000003, &PSC1[0x291]); /* Set ePWM module power on */\
289  iowrite32(0x00000003, &PSC1[0x48]); /* Evaluate all the NEXT fields */\
290  }
291 
293 {
294  SOUNDEN, // Sound Enable to Amp
295  SOUND_ARMA, // PWM audio signal from ARM
297 };
298 
299 
300 //*****************************************************************************
301 #if (HARDWARE == FINAL)
302 //***************************************SETSoundLevel**************************************
303 
311 INPIN SoundPin[SOUND_PINS] =
312 {
313  { GP6_15 , NULL, 0 }, // SOUNDEN
314  { EPWM0B , NULL, 0 }, // SOUND_ARMA
315 };
316 
317 /* \endverbatim
318  * \n
319  */
320 
321 #endif
322 
323 //*****************************************************************************
324 #if (HARDWARE == ONE2ONE)
325 //*****************************************************************************
326 
334 INPIN SoundPin[SOUND_PINS] =
335 {
336  { GP2_8 , NULL, 0 }, // SOUNDEN
337  { EPWM0B , NULL, 0 }, // SOUND_ARMA
338 };
339 
340 /* \endverbatim
341  * \n
342  */
343 
344 #endif
345 
346 //*****************************************************************************
347 #if (HARDWARE == A4)
348 //*****************************************************************************
349 
350 INPIN SoundPin[SOUND_PINS] =
351 {
352  { GP5_6 , NULL, 0 }, // SOUNDEN
353  { EPWM0B , NULL, 0 }, // SOUND_ARMA
354 };
355 
356 #endif
357 
358 //*****************************************************************************
359 #if (HARDWARE == EVALBOARD)
360 //*****************************************************************************
361 
362 INPIN SoundPin[SOUND_PINS] =
363 {
364  { GP7_4 , NULL, 0 }, // SOUNDEN
365  { EPWM0B , NULL, 0 }, // SOUND_ARMA
366 };
367 
368 #endif
369 
370 //*****************************************************************************
371 
372 void SetGpio(int Pin)
373 {
374  int Tmp = 0;
375  void __iomem *Reg;
376 
377  while ((MuxRegMap[Tmp].Pin != -1) && (MuxRegMap[Tmp].Pin != Pin))
378  {
379  Tmp++;
380  }
381  if (MuxRegMap[Tmp].Pin == Pin)
382  {
383  Reg = da8xx_syscfg0_base + 0x120 + (MuxRegMap[Tmp].MuxReg << 2);
384 
385  *(u32*)Reg &= MuxRegMap[Tmp].Mask;
386  *(u32*)Reg |= MuxRegMap[Tmp].Mode;
387 
388  if (Pin < NO_OF_GPIOS)
389  {
390  //#define DEBUG
391  #undef DEBUG
392  #ifdef DEBUG
393  printk(" GP%d_%-2d 0x%08X and 0x%08X or 0x%08X\n",(Pin >> 4),(Pin & 0x0F),(u32)Reg, MuxRegMap[Tmp].Mask, MuxRegMap[Tmp].Mode);
394  #endif
395  }
396  else
397  {
398  //#define DEBUG
399  #undef DEBUG
400  #ifdef DEBUG
401  printk(" FUNCTION 0x%08X and 0x%08X or 0x%08X\n",(u32)Reg, MuxRegMap[Tmp].Mask, MuxRegMap[Tmp].Mode);
402  #endif
403  }
404  }
405  else
406  {
407  //#define DEBUG
408  #undef DEBUG
409  #ifdef DEBUG
410  printk("* GP%d_%-2d ********* ERROR not found *********\n",(Pin >> 4),(Pin & 0x0F));
411  #endif
412  }
413 
414 }
415 
416 
417 void InitGpio(void)
418 {
419  int Pin;
420 
421  // unlock
422  REGUnlock;
423 
424  //#define DEBUG
425  #undef DEBUG
426  #ifdef DEBUG
427  printk(" Sound\n");
428  #endif
429 
430  for (Pin = 0;Pin < SOUND_PINS;Pin++)
431  {
432  SoundPin[Pin].pGpio = (struct gpio_controller *__iomem)(GpioBase + ((SoundPin[Pin].Pin >> 5) * 0x28) + 0x10);
433  SoundPin[Pin].Mask = (1 << (SoundPin[Pin].Pin & 0x1F));
434 
435  SetGpio(SoundPin[Pin].Pin);
436  }
437 
438  // lock
439  REGLock;
440 }
441 
454 void GetPeriphealBasePtr(ULONG Address, ULONG Size, ULONG **Ptr)
455 {
456  /* eCAP0 pointer */
457  if (request_mem_region(Address,Size,MODULE_NAME) >= 0)
458  {
459 
460  *Ptr = (ULONG*)ioremap(Address,Size);
461 
462  if (*Ptr != NULL)
463  {
464  //#define DEBUG
465  #undef DEBUG
466  #ifdef DEBUG
467  printk("%s memory Remapped from 0x%08lX\n",DEVICE1_NAME,(unsigned long)*Ptr);
468  #endif
469  }
470  else
471  {
472  //#define DEBUG
473  #undef DEBUG
474  #ifdef DEBUG
475  printk("Memory remap ERROR");
476  #endif
477  }
478  }
479  else
480  {
481  //#define DEBUG
482  #undef DEBUG
483  #ifdef DEBUG
484  printk("Region request error");
485  #endif
486  }
487 }
488 
489 // DEVICE1 ********************************************************************
490 
491 static void Device1TimerSetTiming(ULONG Secs, ULONG NanoSecs )
492 {
493  Device1Time = ktime_set(Secs, NanoSecs);
494 }
495 
496 static void Device1TimerStart(void) // (Re) start the high-resolution timer
497 {
498  hrtimer_start(&Device1Timer,Device1Time,HRTIMER_MODE_REL);
499 }
500 
501 static void Device1TimerInitDuration(void)
502 {
503  UWORD Sec;
504  ULONG nSec;
505 
506  Sec = (UWORD)(Duration / 1000); // Whole secs
507  nSec = (ULONG)((Duration - Sec * 1000) * 1000000); // Raised to mSec
508  TimerMode = ONE_SHOT;
509  Device1TimerSetTiming(Sec, nSec);
510  Device1TimerStart(); // Start / reStart
511 }
512 
513 static void Device1TimerCancel(void)
514 {
515  TimerMode = IDLE;
516  hrtimer_cancel(&Device1Timer);
517 }
518 
519 static void Device1TimerExit(void)
520 {
521  Device1TimerCancel();
522 }
523 
524 static enum hrtimer_restart Device1TimerInterrupt1(struct hrtimer *pTimer)
525 {
526  UWORD TempLevel;
527 
528  enum hrtimer_restart ret = HRTIMER_RESTART;
529 
530  if (0 < hrtimer_forward_now(pTimer,Device1Time))
531  {
532  // Take care sample missed!!!!!
533  }
534 
535  switch(TimerMode)
536  {
537  case READY_FOR_SAMPLES: if(SoundChunkSize[BufferReadIndex] > 0) // Any samples D/L yet?
538  {
539 
540  TimerMode = TIMING_SAMPLES; // We're ready, next interrupt will
541  // bring the sound alive
542  }
543  break;
544 
545  case TIMING_SAMPLES: // Get new sample - if any
546 
547  if(SoundChunkSize[BufferReadIndex] > 0) // Anything to use in Buffers?
548  {
549  // Get raw sample
550  TempLevel = SoundBuffers[BufferReadIndex][BufferReadPointer++];
551  if(TempLevel == 0) TempLevel++;
552  // Add volume i.e. scale the PWM level
553 
554  TempLevel = (UWORD)(Level * TempLevel);
555  SETSoundLevel(TempLevel);
556 
557  SoundChunkSize[BufferReadIndex]--;
558 
559  if(SoundChunkSize[BufferReadIndex] < 1)
560  {
561  BufferReadPointer = 0;
562  BufferReadIndex++;
563  if(BufferReadIndex >= SOUND_BUFFER_COUNT)
564  BufferReadIndex = 0;
565  }
566  }
567  else
568  {
569  ret = HRTIMER_NORESTART;
570 
571  SOUNDDisable;
572  TimerMode = IDLE;
573  (*pSound).Status = OK;
574  // ret(urn value) already set
575  }
576  break;
577 
578  case ONE_SHOT: // Stop tone - duration elapsed!
579  ret = HRTIMER_NORESTART;
581  SOUNDDisable;
582  TimerMode = IDLE;
583  (*pSound).Status = OK;
584  // ret(urn value) already set
585 
586  case IDLE: break;
587  case MANUAL: break;
588  default: ret = HRTIMER_NORESTART;
589  break;
590  }
591 
592  return (ret); // Keep on or stop doing the job
593 }
594 
595 static void Device1TimerInit8KHz(void)
596 {
597  /* Setup 125 uS timer interrupt*/
598 
599  TimerMode = READY_FOR_SAMPLES; // Allow for D/L to SoundBuffer(s)
600  Device1TimerSetTiming(0, 125000); // 8 KHz. sample-rate
601  Device1TimerStart(); // Start / reStart
602 }
603 
604 static ssize_t Device1Write(struct file *File, const char *Buffer, size_t Count, loff_t *Data)
605 {
606 
607  char CommandBuffer[SOUND_FILE_BUFFER_SIZE + 1]; // Space for command @ byte 0
608  UWORD Frequency;
609  UWORD PwmLevel;
610  int BytesWritten = 0;
611  int i = 0;
612 
613  copy_from_user(CommandBuffer, Buffer, Count);
614 
615  switch(CommandBuffer[0])
616  {
617  case SERVICE:
618  if(Count > 1)
619  {
620  if(SoundChunkSize[BufferWriteIndex] == 0) // Is the requested RingBuffer[Index] ready for write?
621  {
622  for(i = 1; i < Count; i++)
623  SoundBuffers[BufferWriteIndex][i-1] = CommandBuffer[i];
624  SoundChunkSize[BufferWriteIndex] = Count - 1;
625  BufferWriteIndex++;
626  if(BufferWriteIndex >= SOUND_BUFFER_COUNT)
627  BufferWriteIndex = 0;
628  BytesWritten = Count - 1;
629  }
630  }
631  break;
632 
633  case TONE:
634  SOUNDDisable;
636  Level = CommandBuffer[1];
637  Frequency = (UWORD)(CommandBuffer[2] + (CommandBuffer[3] << 8));
638  Duration = (UWORD) (CommandBuffer[4] + (CommandBuffer[5] << 8));
639 
640  if (Frequency < SOUND_MIN_FRQ)
641  {
642  Frequency = SOUND_MIN_FRQ;
643  }
644  else if (Frequency > SOUND_MAX_FRQ)
645  {
646  Frequency = SOUND_MAX_FRQ;
647  }
648 
649  Period = (UWORD)((SOUND_TONE_MASTER_CLOCK / Frequency) - 1);
650  SETPwmPeriod(Period);
651 
652  if (Level > 100) Level = 100;
653 
654  PwmLevel = (UWORD)(((ulong)(Period) * (ulong)(Level)) /(ulong)(200)); // Level from % to ticks (Duty Cycle)
655 
656  SETSoundLevel(PwmLevel);
657 
658  if(Duration > 0) // Infinite or specific?
659  {
660  Device1TimerInitDuration();
661  TimerMode = ONE_SHOT;
662  }
663  else
664  TimerMode = MANUAL;
665 
666  SOUNDEnable;
667 
668  break;
669 
670  case REPEAT: // Handled in Green Layer
671  break;
672 
673  case PLAY:
674  SOUNDDisable;
676  Level = CommandBuffer[1];
677  Period = (UWORD)(SOUND_MASTER_CLOCK / 64000); // 64 KHz => 8 shots of each sample
678  SETPwmPeriod(Period); // helps filtering
679 
680  BufferWriteIndex = 0; // Reset to first ring Buffer
681  BufferReadIndex = 0; // -
682  BufferReadPointer = 0; // Ready for very first sample
683  for (i = 0; i < SOUND_BUFFER_COUNT; i++)
684  SoundChunkSize[i] = 0; // Reset all Buffer sizes
685 
686  Device1TimerInit8KHz(); // TimerMode = READY_FOR_SAMPLES;
687  if(Level != 0)
688  SOUNDEnable;
689  // Else we remove any "selfmade" noise
690  // Better n/s+n ratio ;-)
691  BytesWritten = 2; // CMD and Level
692  break;
693 
694  case BREAK: Device1TimerCancel();
695  SOUNDDisable;
697  TimerMode = IDLE;
698  (*pSound).Status = OK;
699  break;
700 
701  default:
702  break;
703  }
704 
705  return (BytesWritten);
706 }
707 
708 
709 static ssize_t Device1Read(struct file *File,char *Buffer,size_t Count,loff_t *Offset)
710 {
711  int Lng = 0;
712 
713  Lng = snprintf(Buffer,Count,"%s\r",DEVICE1_NAME);
714 
715  return (Lng);
716 }
717 
718 #define SHM_LENGTH (sizeof(SoundDefault))
719 #define NPAGES ((SHM_LENGTH + PAGE_SIZE - 1) / PAGE_SIZE)
720 static void *kmalloc_ptr;
721 
722 static int Device1Mmap(struct file *filp, struct vm_area_struct *vma)
723 {
724  int ret;
725 
726  ret = remap_pfn_range(vma,vma->vm_start,virt_to_phys((void*)((unsigned long)pSound)) >> PAGE_SHIFT,vma->vm_end-vma->vm_start,PAGE_SHARED);
727 
728  if (ret != 0)
729  {
730  ret = -EAGAIN;
731  }
732 
733  return (ret);
734 }
735 
736 static const struct file_operations Device1Entries =
737 {
738  .owner = THIS_MODULE,
739  .read = Device1Read,
740  .write = Device1Write,
741  .mmap = Device1Mmap,
742 };
743 
744 
745 static struct miscdevice Device1 =
746 {
747  MISC_DYNAMIC_MINOR,
748  DEVICE1_NAME,
749  &Device1Entries
750 };
751 
752 
753 static int Device1Init(void)
754 {
755  int Result = -1;
756  int i = 0;
757  UWORD *pTmp;
758 
759  // Get pointers to memory-mapped registers
760  GetPeriphealBasePtr(0x01C14000, 0x190, (ULONG**)&SYSCFG0); /* SYSCFG0 Pointer */
761  GetPeriphealBasePtr(0x01F00000, 0x1042,(ULONG**)&eHRPWM0); /* eHRPWM0 Pointer */
762  GetPeriphealBasePtr(0x01E27000, 0xA80, (ULONG**)&PSC1); /* PSC1 pointer */
763 
764  Result = misc_register(&Device1);
765  if (Result)
766  {
767  //#define DEBUG
768  #undef DEBUG
769  #ifdef DEBUG
770  printk(" %s device register failed\n",DEVICE1_NAME);
771  #endif
772  }
773  else
774  {
775  // allocate kernel shared memory for SoundFlags used by Test etc.
776  // showing the state of the sound-module used by async and waiting
777  // use from VM
778 
779  if ((kmalloc_ptr = kmalloc((NPAGES + 2) * PAGE_SIZE, GFP_KERNEL)) != NULL)
780  {
781  pTmp = (UWORD*)((((unsigned long)kmalloc_ptr) + PAGE_SIZE - 1) & PAGE_MASK);
782  for (i = 0; i < NPAGES * PAGE_SIZE; i += PAGE_SIZE)
783  {
784  SetPageReserved(virt_to_page(((unsigned long)pTmp) + i));
785  }
786  pSound = (SOUND*)pTmp;
787 
789 
790  /* Setup the Sound PWM peripherals */
791 
793 
794  /* Setup 125 uS timer interrupt*/
795  Device1TimerSetTiming(0, 125000); // Default to 8 KHz. sample-rate
796  hrtimer_init(&Device1Timer,CLOCK_MONOTONIC,HRTIMER_MODE_REL);
797  // Timer Callback function - do the sequential job
798  Device1Timer.function = Device1TimerInterrupt1;
799  Device1TimerCancel();
800 
801  SOUNDDisable; // Disable the Sound Power Amp
802 
803  //#define DEBUG
804  #undef DEBUG
805  #ifdef DEBUG
806  printk(" %s device register succes\n",DEVICE1_NAME);
807  #endif
808 
809  (*pSound).Status = OK; // We're ready for making "noise"
810  }
811  }
812 
813  return (Result);
814 }
815 
816 static void Device1Exit(void)
817 {
818  UWORD *pTmp;
819  int i = 0;
820 
821  Device1TimerExit();
822  misc_deregister(&Device1);
823 
824  #define DEBUG
825  #undef DEBUG
826  #ifdef DEBUG
827  printk("%s exit started\n",MODULE_NAME);
828  #endif
829 
830  iounmap(SYSCFG0);
831  iounmap(eHRPWM0);
832  iounmap(PSC1);
833 
834  // free shared memory
835  pTmp = (UWORD*)pSound;
836  pSound = &SoundDefault;
837 
838  for (i = 0; i < NPAGES * PAGE_SIZE; i+= PAGE_SIZE)
839  {
840  ClearPageReserved(virt_to_page(((unsigned long)pTmp) + i));
841 
842  #define DEBUG
843  #undef DEBUG
844  #ifdef DEBUG
845  printk(" %s memory page %d unmapped\n",DEVICE1_NAME,i);
846  #endif
847  }
848 
849  kfree(kmalloc_ptr);
850 
851 
852 }
853 
854 
855 // MODULE *********************************************************************
856 
857 
858 #ifndef PCASM
859 module_param (HwId, charp, 0);
860 #endif
861 
862 static int ModuleInit(void)
863 {
864  //#define DEBUG
865  #undef DEBUG
866  #ifdef DEBUG
867  printk("HwId = %d\n",HWID);
868  #endif
869 
870  //#define DEBUG
871  #undef DEBUG
872  #ifdef DEBUG
873  printk("%s init started\n",MODULE_NAME);
874  #endif
875 
876  if (request_mem_region(DA8XX_GPIO_BASE,0xD8,MODULE_NAME) >= 0)
877  {
878  GpioBase = (void*)ioremap(DA8XX_GPIO_BASE,0xD8);
879  if (GpioBase != NULL)
880  {
881  //#define DEBUG
882  #undef DEBUG
883  #ifdef DEBUG
884  printk("%s gpio address mapped\n",MODULE_NAME);
885  #endif
886 
887  InitGpio();
888  Device1Init();
889 
890  }
891  }
892 
893  return (0);
894 }
895 
896 
897 static void ModuleExit(void)
898 {
899  //#define DEBUG
900  #undef DEBUG
901  #ifdef DEBUG
902  printk("%s exit started\n",MODULE_NAME);
903  #endif
904 
905  SOUNDDisable; // Disable the Sound Power Amp
906  Device1Exit();
907 
908  iounmap(GpioBase);
909 }
#define REGLock
Definition: am1808.h:235
#define SOUNDEnable
Definition: d_sound.c:277
#define SOUNDPwmModuleSetupPcm
Definition: d_sound.c:250
module_init(ModuleInit)
Definition: am1808.h:46
#define snprintf
Definition: c_input.c:141
#define SOUND_MASTER_CLOCK
Definition: lms2012.h:531
MRM MuxRegMap[]
Definition: am1808.h:59
GPIOC pGpio
Definition: am1808.h:225
#define REGUnlock
Definition: am1808.h:230
Definition: am1808.h:222
#define SOUNDDisable
Definition: d_sound.c:282
#define MODULE_NAME
Definition: d_sound.c:37
u16 MuxReg
Definition: am1808.h:53
Definition: am1808.h:38
Definition: d_sound.c:85
unsigned int ULONG
Basic Type used to symbolise 32 bit unsigned values.
Definition: lmstypes.h:31
MODULE_SUPPORTED_DEVICE(DEVICE1_NAME)
Definition: am1808.h:35
#define SOUND_FILE_BUFFER_SIZE
Definition: lms2012.h:536
#define SOUND_BUFFER_COUNT
Definition: lms2012.h:537
int Pin
Definition: am1808.h:224
module_param(HwId, charp, 0)
#define DEVICE1_NAME
Definition: d_sound.c:38
Definition: am1808.h:39
module_exit(ModuleExit)
#define SOUNDPwmPoweron
Definition: d_sound.c:287
MODULE_LICENSE("GPL")
void InitGpio(void)
Definition: d_sound.c:417
int BytesWritten
Definition: c_daisy.c:67
unsigned char UBYTE
Basic Type used to symbolise 8 bit unsigned values.
Definition: lmstypes.h:29
#define SOUND_MAX_FRQ
Definition: lms2012.h:534
u32 Mask
Definition: am1808.h:226
MODULE_DESCRIPTION(MODULE_NAME)
unsigned short UWORD
Basic Type used to symbolise 16 bit unsigned values.
Definition: lmstypes.h:30
char Buffer[1024]
Definition: c_wifi.c:102
#define SOUNDPwmModuleSetupTone
Definition: d_sound.c:263
Definition: d_sound.c:87
SoundPins
Definition: d_sound.c:292
void GetPeriphealBasePtr(ULONG Address, ULONG Size, ULONG **Ptr)
GetPeriphealBasePtr.
Definition: d_sound.c:454
#define SOUND_MIN_FRQ
Definition: lms2012.h:533
#define SETPwmPeriod(Prd)
Definition: d_sound.c:231
void SetGpio(int Pin)
Definition: d_sound.c:372
#define SOUND_TONE_MASTER_CLOCK
Definition: lms2012.h:532
uint32_t u32
Definition: common.h:158
#define NPAGES
Definition: d_sound.c:719
Definition: am1808.h:40
void * Ptr
Definition: tistdtypes.h:56
#define SETSoundLevel(Level)
Definition: d_sound.c:238
MODULE_AUTHOR("The LEGO Group")
enum @47 TIMER_MODES
#define EHRPWMClkDisable
Definition: d_sound.c:206
#define NULL