Add all phase bits to a control register for atomic phase changes.
[SCSI2SD-V6.git] / software / SCSI2SD / SCSI2SD.cydsn / Generated_Source / PSoC5 / SCSI_CLK.c
1 /*******************************************************************************
2 * File Name: SCSI_CLK.c
3 * Version 2.10
4 *
5 *  Description:
6 *   This file provides the source code to the API for the clock component.
7 *
8 *  Note:
9 *
10 ********************************************************************************
11 * Copyright 2008-2012, Cypress Semiconductor Corporation.  All rights reserved.
12 * You may use this file only in accordance with the license, terms, conditions, 
13 * disclaimers, and limitations in the end user license agreement accompanying 
14 * the software package with which this file was provided.
15 *******************************************************************************/
16
17 #include <cydevice_trm.h>
18 #include "SCSI_CLK.h"
19
20 /* Clock Distribution registers. */
21 #define CLK_DIST_LD              (* (reg8 *) CYREG_CLKDIST_LD)
22 #define CLK_DIST_BCFG2           (* (reg8 *) CYREG_CLKDIST_BCFG2)
23 #define BCFG2_MASK               (0x80u)
24 #define CLK_DIST_DMASK           (* (reg8 *) CYREG_CLKDIST_DMASK)
25 #define CLK_DIST_AMASK           (* (reg8 *) CYREG_CLKDIST_AMASK)
26
27 #define HAS_CLKDIST_LD_DISABLE   (CY_PSOC3 || CY_PSOC5LP)
28
29
30 /*******************************************************************************
31 * Function Name: SCSI_CLK_Start
32 ********************************************************************************
33 *
34 * Summary:
35 *  Starts the clock. Note that on startup, clocks may be already running if the
36 *  "Start on Reset" option is enabled in the DWR.
37 *
38 * Parameters:
39 *  None
40 *
41 * Returns:
42 *  None
43 *
44 *******************************************************************************/
45 void SCSI_CLK_Start(void) 
46 {
47     /* Set the bit to enable the clock. */
48     SCSI_CLK_CLKEN |= SCSI_CLK_CLKEN_MASK;
49         SCSI_CLK_CLKSTBY |= SCSI_CLK_CLKSTBY_MASK;
50 }
51
52
53 /*******************************************************************************
54 * Function Name: SCSI_CLK_Stop
55 ********************************************************************************
56 *
57 * Summary:
58 *  Stops the clock and returns immediately. This API does not require the
59 *  source clock to be running but may return before the hardware is actually
60 *  disabled. If the settings of the clock are changed after calling this
61 *  function, the clock may glitch when it is started. To avoid the clock
62 *  glitch, use the StopBlock function.
63 *
64 * Parameters:
65 *  None
66 *
67 * Returns:
68 *  None
69 *
70 *******************************************************************************/
71 void SCSI_CLK_Stop(void) 
72 {
73     /* Clear the bit to disable the clock. */
74     SCSI_CLK_CLKEN &= (uint8)(~SCSI_CLK_CLKEN_MASK);
75         SCSI_CLK_CLKSTBY &= (uint8)(~SCSI_CLK_CLKSTBY_MASK);
76 }
77
78
79 #if(CY_PSOC3 || CY_PSOC5LP)
80
81
82 /*******************************************************************************
83 * Function Name: SCSI_CLK_StopBlock
84 ********************************************************************************
85 *
86 * Summary:
87 *  Stops the clock and waits for the hardware to actually be disabled before
88 *  returning. This ensures that the clock is never truncated (high part of the
89 *  cycle will terminate before the clock is disabled and the API returns).
90 *  Note that the source clock must be running or this API will never return as
91 *  a stopped clock cannot be disabled.
92 *
93 * Parameters:
94 *  None
95 *
96 * Returns:
97 *  None
98 *
99 *******************************************************************************/
100 void SCSI_CLK_StopBlock(void) 
101 {
102     if ((SCSI_CLK_CLKEN & SCSI_CLK_CLKEN_MASK) != 0u)
103     {
104 #if HAS_CLKDIST_LD_DISABLE
105         uint16 oldDivider;
106
107         CLK_DIST_LD = 0u;
108
109         /* Clear all the mask bits except ours. */
110 #if defined(SCSI_CLK__CFG3)
111         CLK_DIST_AMASK = SCSI_CLK_CLKEN_MASK;
112         CLK_DIST_DMASK = 0x00u;
113 #else
114         CLK_DIST_DMASK = SCSI_CLK_CLKEN_MASK;
115         CLK_DIST_AMASK = 0x00u;
116 #endif /* SCSI_CLK__CFG3 */
117
118         /* Clear mask of bus clock. */
119         CLK_DIST_BCFG2 &= (uint8)(~BCFG2_MASK);
120
121         oldDivider = CY_GET_REG16(SCSI_CLK_DIV_PTR);
122         CY_SET_REG16(CYREG_CLKDIST_WRK0, oldDivider);
123         CLK_DIST_LD = CYCLK_LD_DISABLE | CYCLK_LD_SYNC_EN | CYCLK_LD_LOAD;
124
125         /* Wait for clock to be disabled */
126         while ((CLK_DIST_LD & CYCLK_LD_LOAD) != 0u) { }
127 #endif /* HAS_CLKDIST_LD_DISABLE */
128
129         /* Clear the bit to disable the clock. */
130         SCSI_CLK_CLKEN &= (uint8)(~SCSI_CLK_CLKEN_MASK);
131         SCSI_CLK_CLKSTBY &= (uint8)(~SCSI_CLK_CLKSTBY_MASK);
132
133 #if HAS_CLKDIST_LD_DISABLE
134         /* Clear the disable bit */
135         CLK_DIST_LD = 0x00u;
136         CY_SET_REG16(SCSI_CLK_DIV_PTR, oldDivider);
137 #endif /* HAS_CLKDIST_LD_DISABLE */
138     }
139 }
140 #endif /* (CY_PSOC3 || CY_PSOC5LP) */
141
142
143 /*******************************************************************************
144 * Function Name: SCSI_CLK_StandbyPower
145 ********************************************************************************
146 *
147 * Summary:
148 *  Sets whether the clock is active in standby mode.
149 *
150 * Parameters:
151 *  state:  0 to disable clock during standby, nonzero to enable.
152 *
153 * Returns:
154 *  None
155 *
156 *******************************************************************************/
157 void SCSI_CLK_StandbyPower(uint8 state) 
158 {
159     if(state == 0u)
160     {
161         SCSI_CLK_CLKSTBY &= (uint8)(~SCSI_CLK_CLKSTBY_MASK);
162     }
163     else
164     {
165         SCSI_CLK_CLKSTBY |= SCSI_CLK_CLKSTBY_MASK;
166     }
167 }
168
169
170 /*******************************************************************************
171 * Function Name: SCSI_CLK_SetDividerRegister
172 ********************************************************************************
173 *
174 * Summary:
175 *  Modifies the clock divider and, thus, the frequency. When the clock divider
176 *  register is set to zero or changed from zero, the clock will be temporarily
177 *  disabled in order to change the SSS mode bit. If the clock is enabled when
178 *  SetDividerRegister is called, then the source clock must be running.
179 *
180 * Parameters:
181 *  clkDivider:  Divider register value (0-65,535). This value is NOT the
182 *    divider; the clock hardware divides by clkDivider plus one. For example,
183 *    to divide the clock by 2, this parameter should be set to 1.
184 *  restart:  If nonzero, restarts the clock divider: the current clock cycle
185 *   will be truncated and the new divide value will take effect immediately. If
186 *   zero, the new divide value will take effect at the end of the current clock
187 *   cycle.
188 *
189 * Returns:
190 *  None
191 *
192 *******************************************************************************/
193 void SCSI_CLK_SetDividerRegister(uint16 clkDivider, uint8 restart)
194                                 
195 {
196     uint8 enabled;
197
198     uint8 currSrc = SCSI_CLK_GetSourceRegister();
199     uint16 oldDivider = SCSI_CLK_GetDividerRegister();
200
201     if (clkDivider != oldDivider)
202     {
203         enabled = SCSI_CLK_CLKEN & SCSI_CLK_CLKEN_MASK;
204
205         if ((currSrc == (uint8)CYCLK_SRC_SEL_CLK_SYNC_D) && ((oldDivider == 0u) || (clkDivider == 0u)))
206         {
207             /* Moving to/from SSS requires correct ordering to prevent halting the clock    */
208             if (oldDivider == 0u)
209             {
210                 /* Moving away from SSS, set the divider first so when SSS is cleared we    */
211                 /* don't halt the clock.  Using the shadow load isn't required as the       */
212                 /* divider is ignored while SSS is set.                                     */
213                 CY_SET_REG16(SCSI_CLK_DIV_PTR, clkDivider);
214                 SCSI_CLK_MOD_SRC &= (uint8)(~CYCLK_SSS);
215             }
216             else
217             {
218                 /* Moving to SSS, set SSS which then ignores the divider and we can set     */
219                 /* it without bothering with the shadow load.                               */
220                 SCSI_CLK_MOD_SRC |= CYCLK_SSS;
221                 CY_SET_REG16(SCSI_CLK_DIV_PTR, clkDivider);
222             }
223         }
224         else
225         {
226                         
227             if (enabled != 0u)
228             {
229                 CLK_DIST_LD = 0x00u;
230
231                 /* Clear all the mask bits except ours. */
232 #if defined(SCSI_CLK__CFG3)
233                 CLK_DIST_AMASK = SCSI_CLK_CLKEN_MASK;
234                 CLK_DIST_DMASK = 0x00u;
235 #else
236                 CLK_DIST_DMASK = SCSI_CLK_CLKEN_MASK;
237                 CLK_DIST_AMASK = 0x00u;
238 #endif /* SCSI_CLK__CFG3 */
239                 /* Clear mask of bus clock. */
240                 CLK_DIST_BCFG2 &= (uint8)(~BCFG2_MASK);
241
242                 /* If clock is currently enabled, disable it if async or going from N-to-1*/
243                 if (((SCSI_CLK_MOD_SRC & CYCLK_SYNC) == 0u) || (clkDivider == 0u))
244                 {
245 #if HAS_CLKDIST_LD_DISABLE
246                     CY_SET_REG16(CYREG_CLKDIST_WRK0, oldDivider);
247                     CLK_DIST_LD = CYCLK_LD_DISABLE|CYCLK_LD_SYNC_EN|CYCLK_LD_LOAD;
248
249                     /* Wait for clock to be disabled */
250                     while ((CLK_DIST_LD & CYCLK_LD_LOAD) != 0u) { }
251 #endif /* HAS_CLKDIST_LD_DISABLE */
252
253                     SCSI_CLK_CLKEN &= (uint8)(~SCSI_CLK_CLKEN_MASK);
254
255 #if HAS_CLKDIST_LD_DISABLE
256                     /* Clear the disable bit */
257                     CLK_DIST_LD = 0x00u;
258 #endif /* HAS_CLKDIST_LD_DISABLE */
259                 }
260             }
261
262             /* Load divide value. */
263             if ((SCSI_CLK_CLKEN & SCSI_CLK_CLKEN_MASK) != 0u)
264             {
265                 /* If the clock is still enabled, use the shadow registers */
266                 CY_SET_REG16(CYREG_CLKDIST_WRK0, clkDivider);
267
268                 CLK_DIST_LD = (CYCLK_LD_LOAD | ((restart != 0u) ? CYCLK_LD_SYNC_EN : 0x00u));
269                 while ((CLK_DIST_LD & CYCLK_LD_LOAD) != 0u) { }
270             }
271             else
272             {
273                 /* If the clock is disabled, set the divider directly */
274                 CY_SET_REG16(SCSI_CLK_DIV_PTR, clkDivider);
275                                 SCSI_CLK_CLKEN |= enabled;
276             }
277         }
278     }
279 }
280
281
282 /*******************************************************************************
283 * Function Name: SCSI_CLK_GetDividerRegister
284 ********************************************************************************
285 *
286 * Summary:
287 *  Gets the clock divider register value.
288 *
289 * Parameters:
290 *  None
291 *
292 * Returns:
293 *  Divide value of the clock minus 1. For example, if the clock is set to
294 *  divide by 2, the return value will be 1.
295 *
296 *******************************************************************************/
297 uint16 SCSI_CLK_GetDividerRegister(void) 
298 {
299     return CY_GET_REG16(SCSI_CLK_DIV_PTR);
300 }
301
302
303 /*******************************************************************************
304 * Function Name: SCSI_CLK_SetModeRegister
305 ********************************************************************************
306 *
307 * Summary:
308 *  Sets flags that control the operating mode of the clock. This function only
309 *  changes flags from 0 to 1; flags that are already 1 will remain unchanged.
310 *  To clear flags, use the ClearModeRegister function. The clock must be
311 *  disabled before changing the mode.
312 *
313 * Parameters:
314 *  clkMode: Bit mask containing the bits to set. For PSoC 3 and PSoC 5,
315 *   clkMode should be a set of the following optional bits or'ed together.
316 *   - CYCLK_EARLY Enable early phase mode. Rising edge of output clock will
317 *                 occur when the divider count reaches half of the divide
318 *                 value.
319 *   - CYCLK_DUTY  Enable 50% duty cycle output. When enabled, the output clock
320 *                 is asserted for approximately half of its period. When
321 *                 disabled, the output clock is asserted for one period of the
322 *                 source clock.
323 *   - CYCLK_SYNC  Enable output synchronization to master clock. This should
324 *                 be enabled for all synchronous clocks.
325 *   See the Technical Reference Manual for details about setting the mode of
326 *   the clock. Specifically, see the CLKDIST.DCFG.CFG2 register.
327 *
328 * Returns:
329 *  None
330 *
331 *******************************************************************************/
332 void SCSI_CLK_SetModeRegister(uint8 modeBitMask) 
333 {
334     SCSI_CLK_MOD_SRC |= modeBitMask & (uint8)SCSI_CLK_MODE_MASK;
335 }
336
337
338 /*******************************************************************************
339 * Function Name: SCSI_CLK_ClearModeRegister
340 ********************************************************************************
341 *
342 * Summary:
343 *  Clears flags that control the operating mode of the clock. This function
344 *  only changes flags from 1 to 0; flags that are already 0 will remain
345 *  unchanged. To set flags, use the SetModeRegister function. The clock must be
346 *  disabled before changing the mode.
347 *
348 * Parameters:
349 *  clkMode: Bit mask containing the bits to clear. For PSoC 3 and PSoC 5,
350 *   clkMode should be a set of the following optional bits or'ed together.
351 *   - CYCLK_EARLY Enable early phase mode. Rising edge of output clock will
352 *                 occur when the divider count reaches half of the divide
353 *                 value.
354 *   - CYCLK_DUTY  Enable 50% duty cycle output. When enabled, the output clock
355 *                 is asserted for approximately half of its period. When
356 *                 disabled, the output clock is asserted for one period of the
357 *                 source clock.
358 *   - CYCLK_SYNC  Enable output synchronization to master clock. This should
359 *                 be enabled for all synchronous clocks.
360 *   See the Technical Reference Manual for details about setting the mode of
361 *   the clock. Specifically, see the CLKDIST.DCFG.CFG2 register.
362 *
363 * Returns:
364 *  None
365 *
366 *******************************************************************************/
367 void SCSI_CLK_ClearModeRegister(uint8 modeBitMask) 
368 {
369     SCSI_CLK_MOD_SRC &= (uint8)(~modeBitMask) | (uint8)(~(uint8)(SCSI_CLK_MODE_MASK));
370 }
371
372
373 /*******************************************************************************
374 * Function Name: SCSI_CLK_GetModeRegister
375 ********************************************************************************
376 *
377 * Summary:
378 *  Gets the clock mode register value.
379 *
380 * Parameters:
381 *  None
382 *
383 * Returns:
384 *  Bit mask representing the enabled mode bits. See the SetModeRegister and
385 *  ClearModeRegister descriptions for details about the mode bits.
386 *
387 *******************************************************************************/
388 uint8 SCSI_CLK_GetModeRegister(void) 
389 {
390     return SCSI_CLK_MOD_SRC & (uint8)(SCSI_CLK_MODE_MASK);
391 }
392
393
394 /*******************************************************************************
395 * Function Name: SCSI_CLK_SetSourceRegister
396 ********************************************************************************
397 *
398 * Summary:
399 *  Sets the input source of the clock. The clock must be disabled before
400 *  changing the source. The old and new clock sources must be running.
401 *
402 * Parameters:
403 *  clkSource:  For PSoC 3 and PSoC 5 devices, clkSource should be one of the
404 *   following input sources:
405 *   - CYCLK_SRC_SEL_SYNC_DIG
406 *   - CYCLK_SRC_SEL_IMO
407 *   - CYCLK_SRC_SEL_XTALM
408 *   - CYCLK_SRC_SEL_ILO
409 *   - CYCLK_SRC_SEL_PLL
410 *   - CYCLK_SRC_SEL_XTALK
411 *   - CYCLK_SRC_SEL_DSI_G
412 *   - CYCLK_SRC_SEL_DSI_D/CYCLK_SRC_SEL_DSI_A
413 *   See the Technical Reference Manual for details on clock sources.
414 *
415 * Returns:
416 *  None
417 *
418 *******************************************************************************/
419 void SCSI_CLK_SetSourceRegister(uint8 clkSource) 
420 {
421     uint16 currDiv = SCSI_CLK_GetDividerRegister();
422     uint8 oldSrc = SCSI_CLK_GetSourceRegister();
423
424     if (((oldSrc != ((uint8)CYCLK_SRC_SEL_CLK_SYNC_D)) && 
425         (clkSource == ((uint8)CYCLK_SRC_SEL_CLK_SYNC_D))) && (currDiv == 0u))
426     {
427         /* Switching to Master and divider is 1, set SSS, which will output master, */
428         /* then set the source so we are consistent.                                */
429         SCSI_CLK_MOD_SRC |= CYCLK_SSS;
430         SCSI_CLK_MOD_SRC =
431             (SCSI_CLK_MOD_SRC & (uint8)(~SCSI_CLK_SRC_SEL_MSK)) | clkSource;
432     }
433     else if (((oldSrc == ((uint8)CYCLK_SRC_SEL_CLK_SYNC_D)) && 
434             (clkSource != ((uint8)CYCLK_SRC_SEL_CLK_SYNC_D))) && (currDiv == 0u))
435     {
436         /* Switching from Master to not and divider is 1, set source, so we don't   */
437         /* lock when we clear SSS.                                                  */
438         SCSI_CLK_MOD_SRC =
439             (SCSI_CLK_MOD_SRC & (uint8)(~SCSI_CLK_SRC_SEL_MSK)) | clkSource;
440         SCSI_CLK_MOD_SRC &= (uint8)(~CYCLK_SSS);
441     }
442     else
443     {
444         SCSI_CLK_MOD_SRC =
445             (SCSI_CLK_MOD_SRC & (uint8)(~SCSI_CLK_SRC_SEL_MSK)) | clkSource;
446     }
447 }
448
449
450 /*******************************************************************************
451 * Function Name: SCSI_CLK_GetSourceRegister
452 ********************************************************************************
453 *
454 * Summary:
455 *  Gets the input source of the clock.
456 *
457 * Parameters:
458 *  None
459 *
460 * Returns:
461 *  The input source of the clock. See SetSourceRegister for details.
462 *
463 *******************************************************************************/
464 uint8 SCSI_CLK_GetSourceRegister(void) 
465 {
466     return SCSI_CLK_MOD_SRC & SCSI_CLK_SRC_SEL_MSK;
467 }
468
469
470 #if defined(SCSI_CLK__CFG3)
471
472
473 /*******************************************************************************
474 * Function Name: SCSI_CLK_SetPhaseRegister
475 ********************************************************************************
476 *
477 * Summary:
478 *  Sets the phase delay of the analog clock. This function is only available
479 *  for analog clocks. The clock must be disabled before changing the phase
480 *  delay to avoid glitches.
481 *
482 * Parameters:
483 *  clkPhase: Amount to delay the phase of the clock, in 1.0ns increments.
484 *   clkPhase must be from 1 to 11 inclusive. Other values, including 0,
485 *   disable the clock. clkPhase = 1 produces a 0ns delay and clkPhase = 11 
486 *   produces a 10ns delay.
487 *
488 * Returns:
489 *  None
490 *
491 *******************************************************************************/
492 void SCSI_CLK_SetPhaseRegister(uint8 clkPhase) 
493 {
494     SCSI_CLK_PHASE = clkPhase & SCSI_CLK_PHASE_MASK;
495 }
496
497
498 /*******************************************************************************
499 * Function Name: SCSI_CLK_GetPhase
500 ********************************************************************************
501 *
502 * Summary:
503 *  Gets the phase delay of the analog clock. This function is only available
504 *  for analog clocks.
505 *
506 * Parameters:
507 *  None
508 *
509 * Returns:
510 *  Phase of the analog clock. See SetPhaseRegister for details.
511 *
512 *******************************************************************************/
513 uint8 SCSI_CLK_GetPhaseRegister(void) 
514 {
515     return SCSI_CLK_PHASE & SCSI_CLK_PHASE_MASK;
516 }
517
518 #endif /* SCSI_CLK__CFG3 */
519
520
521 /* [] END OF FILE */