]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/protocol/arm_atsam/i2c_master.c
Massdrop keyboard support (#3780)
[qmk_firmware.git] / tmk_core / protocol / arm_atsam / i2c_master.c
1 /*
2 Copyright 2018 Massdrop Inc.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "arm_atsam_protocol.h"
19
20 #ifndef MD_BOOTLOADER
21
22 #include <string.h>
23
24 //From keyboard
25 #include "config.h"
26 #include "config_led.h"
27 #include "matrix.h"
28
29 #define I2C_LED_USE_DMA 1               //Set 1 to use background DMA transfers for leds, Set 0 to use inline software transfers
30
31 static uint8_t i2c_led_q[I2C_Q_SIZE];   //I2C queue circular buffer
32 static uint8_t i2c_led_q_s;             //Start of circular buffer
33 static uint8_t i2c_led_q_e;             //End of circular buffer
34 static uint8_t i2c_led_q_full;          //Queue full counter for reset
35
36 static uint8_t dma_sendbuf[I2C_DMA_MAX_SEND]; //Data being written to I2C
37
38 volatile uint8_t i2c_led_q_running;
39
40 #endif //MD_BOOTLOADER
41
42 void i2c0_init(void)
43 {
44     DBGC(DC_I2C0_INIT_BEGIN);
45
46     CLK_set_i2c0_freq(CHAN_SERCOM_I2C0, FREQ_I2C0_DEFAULT);
47
48     //MCU
49     PORT->Group[0].PMUX[4].bit.PMUXE = 2;
50     PORT->Group[0].PMUX[4].bit.PMUXO = 2;
51     PORT->Group[0].PINCFG[8].bit.PMUXEN = 1;
52     PORT->Group[0].PINCFG[9].bit.PMUXEN = 1;
53
54     //I2C
55     //Note: SW Reset handled in CLK_set_i2c0_freq clks.c
56
57     SERCOM0->I2CM.CTRLA.bit.MODE = 5;                           //Set master mode
58
59     SERCOM0->I2CM.CTRLA.bit.SPEED = 0;                          //Set to 1 for Fast-mode Plus (FM+) up to 1 MHz
60     SERCOM0->I2CM.CTRLA.bit.RUNSTDBY = 1;                       //Enabled
61
62     SERCOM0->I2CM.CTRLA.bit.ENABLE = 1;                         //Enable the device
63     while (SERCOM0->I2CM.SYNCBUSY.bit.ENABLE) { DBGC(DC_I2C0_INIT_SYNC_ENABLING); }                //Wait for SYNCBUSY.ENABLE to clear
64
65     SERCOM0->I2CM.STATUS.bit.BUSSTATE = 1;                      //Force into IDLE state
66     while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) { DBGC(DC_I2C0_INIT_SYNC_SYSOP); }
67     while (SERCOM0->I2CM.STATUS.bit.BUSSTATE != 1) { DBGC(DC_I2C0_INIT_WAIT_IDLE); }           //Wait while not idle
68
69     DBGC(DC_I2C0_INIT_COMPLETE);
70 }
71
72 uint8_t i2c0_start(uint8_t address)
73 {
74     SERCOM0->I2CM.ADDR.bit.ADDR = address;
75     while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) {}
76     while (SERCOM0->I2CM.INTFLAG.bit.MB == 0) {}
77     while (SERCOM0->I2CM.STATUS.bit.RXNACK) {}
78
79     return 1;
80 }
81
82 uint8_t i2c0_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout)
83 {
84     if (!length) return 0;
85
86     i2c0_start(address);
87
88     while (length)
89     {
90         SERCOM0->I2CM.DATA.bit.DATA = *data;
91         while (SERCOM0->I2CM.INTFLAG.bit.MB == 0) {}
92         while (SERCOM0->I2CM.STATUS.bit.RXNACK) {}
93
94         data++;
95         length--;
96     }
97
98     i2c0_stop();
99
100     return 1;
101 }
102
103 void i2c0_stop(void)
104 {
105     if (SERCOM0->I2CM.STATUS.bit.CLKHOLD || SERCOM0->I2CM.INTFLAG.bit.MB == 1 || SERCOM0->I2CM.STATUS.bit.BUSSTATE != 1)
106     {
107         SERCOM0->I2CM.CTRLB.bit.CMD = 3;
108         while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP);
109         while (SERCOM0->I2CM.STATUS.bit.CLKHOLD);
110         while (SERCOM0->I2CM.INTFLAG.bit.MB);
111         while (SERCOM0->I2CM.STATUS.bit.BUSSTATE != 1);
112     }
113 }
114
115 #ifndef MD_BOOTLOADER
116 void i2c1_init(void)
117 {
118     DBGC(DC_I2C1_INIT_BEGIN);
119
120     CLK_set_i2c1_freq(CHAN_SERCOM_I2C1, FREQ_I2C1_DEFAULT);
121
122     /* MCU */
123     PORT->Group[0].PMUX[8].bit.PMUXE = 2;
124     PORT->Group[0].PMUX[8].bit.PMUXO = 2;
125     PORT->Group[0].PINCFG[16].bit.PMUXEN = 1;
126     PORT->Group[0].PINCFG[17].bit.PMUXEN = 1;
127
128     /* I2C */
129     //Note: SW Reset handled in CLK_set_i2c1_freq clks.c
130
131     SERCOM1->I2CM.CTRLA.bit.MODE = 5;                   //MODE: Set master mode (No sync)
132     SERCOM1->I2CM.CTRLA.bit.SPEED = 1;                  //SPEED: Fm+ up to 1MHz (No sync)
133     SERCOM1->I2CM.CTRLA.bit.RUNSTDBY = 1;               //RUNSTBY: Enabled (No sync)
134
135     SERCOM1->I2CM.CTRLB.bit.SMEN = 1;                   //SMEN: Smart mode enabled (For DMA)(No sync)
136
137     NVIC_EnableIRQ(SERCOM1_0_IRQn);
138     SERCOM1->I2CM.INTENSET.bit.ERROR = 1;
139
140     SERCOM1->I2CM.CTRLA.bit.ENABLE = 1;                 //ENABLE: Enable the device (sync SYNCBUSY.ENABLE)
141     while (SERCOM1->I2CM.SYNCBUSY.bit.ENABLE) { DBGC(DC_I2C1_INIT_SYNC_ENABLING); }        //Wait for SYNCBUSY.ENABLE to clear
142
143     SERCOM1->I2CM.STATUS.bit.BUSSTATE = 1;              //BUSSTATE: Force into IDLE state (sync SYNCBUSY.SYSOP)
144     while (SERCOM1->I2CM.SYNCBUSY.bit.SYSOP) { DBGC(DC_I2C1_INIT_SYNC_SYSOP); }
145     while (SERCOM1->I2CM.STATUS.bit.BUSSTATE != 1) { DBGC(DC_I2C1_INIT_WAIT_IDLE); }  //Wait while not idle
146
147     DBGC(DC_I2C1_INIT_COMPLETE);
148 }
149
150 uint8_t i2c1_start(uint8_t address)
151 {
152     SERCOM1->I2CM.ADDR.bit.ADDR = address;
153     while (SERCOM1->I2CM.SYNCBUSY.bit.SYSOP) {}
154     while (SERCOM1->I2CM.INTFLAG.bit.MB == 0) {}
155     while (SERCOM1->I2CM.STATUS.bit.RXNACK) {}
156
157     return 1;
158 }
159
160 uint8_t i2c1_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout)
161 {
162     if (!length) return 0;
163
164     i2c1_start(address);
165
166     while (length)
167     {
168         SERCOM1->I2CM.DATA.bit.DATA = *data;
169         while (SERCOM1->I2CM.INTFLAG.bit.MB == 0) {}
170         while (SERCOM1->I2CM.STATUS.bit.RXNACK) {}
171
172         data++;
173         length--;
174     }
175
176     i2c1_stop();
177
178     return 1;
179 }
180
181 void i2c1_stop(void)
182 {
183     if (SERCOM1->I2CM.STATUS.bit.CLKHOLD || SERCOM1->I2CM.INTFLAG.bit.MB == 1 || SERCOM1->I2CM.STATUS.bit.BUSSTATE != 1)
184     {
185         SERCOM1->I2CM.CTRLB.bit.CMD = 3;
186         while (SERCOM1->I2CM.SYNCBUSY.bit.SYSOP);
187         while (SERCOM1->I2CM.STATUS.bit.CLKHOLD);
188         while (SERCOM1->I2CM.INTFLAG.bit.MB);
189         while (SERCOM1->I2CM.STATUS.bit.BUSSTATE != 1);
190     }
191 }
192
193 void i2c_led_send_CRWL(uint8_t drvid)
194 {
195     uint8_t i2cdata[] = { ISSI3733_CMDRWL, ISSI3733_CMDRWL_WRITE_ENABLE_ONCE };
196     i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0);
197 }
198
199 void i2c_led_select_page(uint8_t drvid, uint8_t pageno)
200 {
201     uint8_t i2cdata[] = { ISSI3733_CMDR, pageno };
202     i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0);
203 }
204
205 void i2c_led_send_GCR(uint8_t drvid)
206 {
207     uint8_t i2cdata[] = { ISSI3733_GCCR, 0x00 };
208
209     if (gcr_actual > LED_GCR_MAX) gcr_actual = LED_GCR_MAX;
210     i2cdata[1] = gcr_actual;
211
212     i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0);
213 }
214
215 void i2c_led_send_onoff(uint8_t drvid)
216 {
217 #if I2C_LED_USE_DMA != 1
218     if (!i2c_led_q_running)
219     {
220 #endif
221         i2c_led_send_CRWL(drvid);
222         i2c_led_select_page(drvid, 0);
223 #if I2C_LED_USE_DMA != 1
224     }
225 #endif
226
227     *issidrv[drvid].onoff = 0; //Force start location offset to zero
228     i2c1_transmit(issidrv[drvid].addr, issidrv[drvid].onoff, ISSI3733_PG0_BYTES, 0);
229 }
230
231 void i2c_led_send_mode_op_gcr(uint8_t drvid, uint8_t mode, uint8_t operation)
232 {
233     uint8_t i2cdata[] = { ISSI3733_CR, mode | operation, gcr_actual};
234     i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0);
235 }
236
237 void i2c_led_send_pur_pdr(uint8_t drvid, uint8_t pur, uint8_t pdr)
238 {
239     uint8_t i2cdata[] = { ISSI3733_SWYR_PUR, pur, pdr };
240
241     i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0);
242 }
243
244 void i2c_led_send_pwm(uint8_t drvid)
245 {
246 #if I2C_LED_USE_DMA != 1
247     if (!i2c_led_q_running)
248     {
249 #endif
250         i2c_led_send_CRWL(drvid);
251         i2c_led_select_page(drvid, 0);
252 #if I2C_LED_USE_DMA != 1
253     }
254 #endif
255
256     *issidrv[drvid].pwm = 0; //Force start location offset to zero
257     i2c1_transmit(issidrv[drvid].addr, issidrv[drvid].pwm, ISSI3733_PG1_BYTES, 0);
258 }
259
260 uint8_t I2C3733_Init_Control(void)
261 {
262     DBGC(DC_I2C3733_INIT_CONTROL_BEGIN);
263
264     srdata.bit.SDB_N = 1;
265     SPI_WriteSRData();
266
267     CLK_delay_ms(1);
268
269     srdata.bit.IRST = 0;
270     SPI_WriteSRData();
271
272     CLK_delay_ms(1);
273
274     DBGC(DC_I2C3733_INIT_CONTROL_COMPLETE);
275
276     return 1;
277 }
278
279 uint8_t I2C3733_Init_Drivers(void)
280 {
281     DBGC(DC_I2C3733_INIT_DRIVERS_BEGIN);
282
283     gcr_actual = ISSI3733_GCR_DEFAULT;
284     gcr_actual_last = gcr_actual;
285
286     if (gcr_actual > LED_GCR_MAX) gcr_actual = LED_GCR_MAX;
287     gcr_desired = gcr_actual;
288
289     //Set up master device
290     i2c_led_send_CRWL(0);
291     i2c_led_select_page(0, 3);
292     i2c_led_send_mode_op_gcr(0, ISSI3733_CR_SYNC_MASTER, ISSI3733_CR_SSD_NORMAL);
293
294     //Set up slave device
295     i2c_led_send_CRWL(1);
296     i2c_led_select_page(1, 3);
297     i2c_led_send_mode_op_gcr(1, ISSI3733_CR_SYNC_SLAVE, ISSI3733_CR_SSD_NORMAL);
298
299     i2c_led_send_CRWL(0);
300     i2c_led_select_page(0, 3);
301     i2c_led_send_pur_pdr(0, ISSI3733_SWYR_PUR_8000, ISSI3733_CSXR_PDR_8000);
302
303     i2c_led_send_CRWL(1);
304     i2c_led_select_page(1, 3);
305     i2c_led_send_pur_pdr(1, ISSI3733_SWYR_PUR_8000, ISSI3733_CSXR_PDR_8000);
306
307     DBGC(DC_I2C3733_INIT_DRIVERS_COMPLETE);
308
309     return 1;
310 }
311
312 void I2C_DMAC_LED_Init(void)
313 {
314     Dmac *dmac = DMAC;
315
316     DBGC(DC_I2C_DMAC_LED_INIT_BEGIN);
317
318     //Disable device
319     dmac->CTRL.bit.DMAENABLE = 0;                   //Disable DMAC
320     while (dmac->CTRL.bit.DMAENABLE) {}             //Wait for disabled state in case of ongoing transfers
321     dmac->CTRL.bit.SWRST = 1;                       //Software Reset DMAC
322     while (dmac->CTRL.bit.SWRST) {}                 //Wait for software reset to complete
323
324     //Configure device
325     dmac->BASEADDR.reg = (uint32_t)&dmac_desc;      //Set descriptor base address
326     dmac->WRBADDR.reg = (uint32_t)&dmac_desc_wb;    //Set descriptor write back address
327     dmac->CTRL.reg |= 0x0f00;                       //Handle all priorities (LVL0-3)
328
329     //Disable channel
330     dmac->Channel[0].CHCTRLA.bit.ENABLE = 0;        //Disable the channel
331     while (dmac->Channel[0].CHCTRLA.bit.ENABLE) {}  //Wait for disabled state in case of ongoing transfers
332     dmac->Channel[0].CHCTRLA.bit.SWRST = 1;         //Software Reset the channel
333     while (dmac->Channel[0].CHCTRLA.bit.SWRST) {}   //Wait for software reset to complete
334
335     //Configure channel
336     dmac->Channel[0].CHCTRLA.bit.THRESHOLD = 0;     //1BEAT
337     dmac->Channel[0].CHCTRLA.bit.BURSTLEN = 0;      //SINGLE
338     dmac->Channel[0].CHCTRLA.bit.TRIGACT = 2;       //BURST
339     dmac->Channel[0].CHCTRLA.bit.TRIGSRC = SERCOM1_DMAC_ID_TX;  //Trigger source
340     dmac->Channel[0].CHCTRLA.bit.RUNSTDBY = 1;      //Run in standby
341
342     NVIC_EnableIRQ(DMAC_0_IRQn);
343     dmac->Channel[0].CHINTENSET.bit.TCMPL = 1;
344     dmac->Channel[0].CHINTENSET.bit.TERR = 1;
345
346     //Enable device
347     dmac->CTRL.bit.DMAENABLE = 1;                   //Enable DMAC
348     while (dmac->CTRL.bit.DMAENABLE == 0) {}        //Wait for enable state
349
350     DBGC(DC_I2C_DMAC_LED_INIT_COMPLETE);
351 }
352
353 //state = 1 enable
354 //state = 0 disable
355 void I2C3733_Control_Set(uint8_t state)
356 {
357     DBGC(DC_I2C3733_CONTROL_SET_BEGIN);
358
359     srdata.bit.SDB_N = (state == 1 ? 1 : 0);
360     SPI_WriteSRData();
361
362     DBGC(DC_I2C3733_CONTROL_SET_COMPLETE);
363 }
364
365 void i2c_led_desc_defaults(void)
366 {
367     dmac_desc.BTCTRL.bit.STEPSIZE = 0;      //SRCINC used in favor for auto 1 inc
368     dmac_desc.BTCTRL.bit.STEPSEL = 0;       //SRCINC used in favor for auto 1 inc
369     dmac_desc.BTCTRL.bit.DSTINC = 0;        //The Destination Address Increment is disabled
370     dmac_desc.BTCTRL.bit.SRCINC = 1;        //The Source Address Increment is enabled (Inc by 1)
371     dmac_desc.BTCTRL.bit.BEATSIZE = 0;      //8-bit bus transfer
372     dmac_desc.BTCTRL.bit.BLOCKACT = 0;      //Channel will be disabled if it is the last block transfer in the transaction
373     dmac_desc.BTCTRL.bit.EVOSEL = 0;        //Event generation disabled
374     dmac_desc.BTCTRL.bit.VALID = 1;         //Set dmac valid
375 }
376
377 void i2c_led_prepare_send_dma(uint8_t *data, uint8_t len)
378 {
379     i2c_led_desc_defaults();
380
381     dmac_desc.BTCNT.reg = len;
382     dmac_desc.SRCADDR.reg = (uint32_t)data + len;
383     dmac_desc.DSTADDR.reg = (uint32_t)&SERCOM1->I2CM.DATA.reg;
384     dmac_desc.DESCADDR.reg = 0;
385 }
386
387 void i2c_led_begin_dma(uint8_t drvid)
388 {
389     DMAC->Channel[0].CHCTRLA.bit.ENABLE = 1; //Enable the channel
390
391     SERCOM1->I2CM.ADDR.reg = (dmac_desc.BTCNT.reg << 16) | 0x2000 | issidrv[drvid].addr; //Begin transfer
392 }
393
394 void i2c_led_send_CRWL_dma(uint8_t drvid)
395 {
396     *(dma_sendbuf+0) = ISSI3733_CMDRWL;
397     *(dma_sendbuf+1) = ISSI3733_CMDRWL_WRITE_ENABLE_ONCE;
398     i2c_led_prepare_send_dma(dma_sendbuf, 2);
399
400     i2c_led_begin_dma(drvid);
401 }
402
403 void i2c_led_select_page_dma(uint8_t drvid, uint8_t pageno)
404 {
405     *(dma_sendbuf+0) = ISSI3733_CMDR;
406     *(dma_sendbuf+1) = pageno;
407     i2c_led_prepare_send_dma(dma_sendbuf, 2);
408
409     i2c_led_begin_dma(drvid);
410 }
411
412 void i2c_led_send_GCR_dma(uint8_t drvid)
413 {
414     *(dma_sendbuf+0) = ISSI3733_GCCR;
415     *(dma_sendbuf+1) = gcr_actual;
416     i2c_led_prepare_send_dma(dma_sendbuf, 2);
417
418     i2c_led_begin_dma(drvid);
419 }
420
421 void i2c_led_send_pwm_dma(uint8_t drvid)
422 {
423     //Note: This copies the CURRENT pwm buffer, which may be getting modified
424     memcpy(dma_sendbuf, issidrv[drvid].pwm, ISSI3733_PG1_BYTES);
425     *dma_sendbuf = 0; //Force start location offset to zero
426     i2c_led_prepare_send_dma(dma_sendbuf, ISSI3733_PG1_BYTES);
427
428     i2c_led_begin_dma(drvid);
429 }
430
431 void i2c_led_send_onoff_dma(uint8_t drvid)
432 {
433     //Note: This copies the CURRENT onoff buffer, which may be getting modified
434     memcpy(dma_sendbuf, issidrv[drvid].onoff, ISSI3733_PG0_BYTES);
435     *dma_sendbuf = 0; //Force start location offset to zero
436     i2c_led_prepare_send_dma(dma_sendbuf, ISSI3733_PG0_BYTES);
437
438     i2c_led_begin_dma(drvid);
439 }
440
441 void i2c_led_q_init(void)
442 {
443     memset(i2c_led_q, 0, I2C_Q_SIZE);
444     i2c_led_q_s = 0;
445     i2c_led_q_e = 0;
446     i2c_led_q_running = 0;
447     i2c_led_q_full = 0;
448 }
449
450 uint8_t i2c_led_q_isempty(void)
451 {
452     return i2c_led_q_s == i2c_led_q_e;
453 }
454
455 uint8_t i2c_led_q_size(void)
456 {
457     return (i2c_led_q_e - i2c_led_q_s) % I2C_Q_SIZE;
458 }
459
460 uint8_t i2c_led_q_available(void)
461 {
462     return I2C_Q_SIZE - i2c_led_q_size() - 1; //Never allow end to meet start
463 }
464
465 void i2c_led_q_add(uint8_t cmd)
466 {
467     //WARNING: Always request room before adding commands!
468
469     //Assign command
470     i2c_led_q[i2c_led_q_e] = cmd;
471
472     i2c_led_q_e = (i2c_led_q_e + 1) % I2C_Q_SIZE; //Move end up one or wrap
473 }
474
475 void i2c_led_q_s_advance(void)
476 {
477     i2c_led_q_s = (i2c_led_q_s + 1) % I2C_Q_SIZE; //Move start up one or wrap
478 }
479
480 //Always request room before adding commands
481 //PS: In case the queue somehow gets filled, it will reset if it can not clear up
482 //PS: Could only get this to happen through unrealistic timings to overload the I2C bus
483 uint8_t i2c_led_q_request_room(uint8_t request_size)
484 {
485     if (request_size > i2c_led_q_available())
486     {
487         i2c_led_q_full++;
488
489         if (i2c_led_q_full >= 100) //Give the queue a chance to clear up
490         {
491             led_on;
492             I2C_DMAC_LED_Init();
493             i2c_led_q_init();
494             return 1;
495         }
496
497         return 0;
498     }
499
500     i2c_led_q_full = 0;
501
502     return 1;
503 }
504
505 uint8_t i2c_led_q_run(void)
506 {
507     if (i2c_led_q_isempty())
508     {
509         i2c_led_q_running = 0;
510         return 0;
511     }
512
513     if (i2c_led_q_running) return 1;
514
515     i2c_led_q_running = 1;
516
517 #if I2C_LED_USE_DMA != 1
518     while (!i2c_led_q_isempty())
519     {
520 #endif
521         //run command
522         if (i2c_led_q[i2c_led_q_s] == I2C_Q_CRWL)
523         {
524             i2c_led_q_s_advance();
525             uint8_t drvid = i2c_led_q[i2c_led_q_s];
526 #if I2C_LED_USE_DMA == 1
527             i2c_led_send_CRWL_dma(drvid);
528 #else
529             i2c_led_send_CRWL(drvid);
530 #endif
531         }
532         else if (i2c_led_q[i2c_led_q_s] == I2C_Q_PAGE_SELECT)
533         {
534             i2c_led_q_s_advance();
535             uint8_t drvid = i2c_led_q[i2c_led_q_s];
536             i2c_led_q_s_advance();
537             uint8_t page = i2c_led_q[i2c_led_q_s];
538 #if I2C_LED_USE_DMA == 1
539             i2c_led_select_page_dma(drvid, page);
540 #else
541             i2c_led_select_page(drvid, page);
542 #endif
543         }
544         else if (i2c_led_q[i2c_led_q_s] == I2C_Q_PWM)
545         {
546             i2c_led_q_s_advance();
547             uint8_t drvid = i2c_led_q[i2c_led_q_s];
548 #if I2C_LED_USE_DMA == 1
549             i2c_led_send_pwm_dma(drvid);
550 #else
551             i2c_led_send_pwm(drvid);
552 #endif
553         }
554         else if (i2c_led_q[i2c_led_q_s] == I2C_Q_GCR)
555         {
556             i2c_led_q_s_advance();
557             uint8_t drvid = i2c_led_q[i2c_led_q_s];
558 #if I2C_LED_USE_DMA == 1
559             i2c_led_send_GCR_dma(drvid);
560 #else
561             i2c_led_send_GCR(drvid);
562 #endif
563         }
564         else if (i2c_led_q[i2c_led_q_s] == I2C_Q_ONOFF)
565         {
566             i2c_led_q_s_advance();
567             uint8_t drvid = i2c_led_q[i2c_led_q_s];
568 #if I2C_LED_USE_DMA == 1
569             i2c_led_send_onoff_dma(drvid);
570 #else
571             i2c_led_send_onoff(drvid);
572 #endif
573         }
574
575         i2c_led_q_s_advance(); //Advance last run command or if the command byte was not serviced
576
577 #if I2C_LED_USE_DMA != 1
578     }
579
580     i2c_led_q_running = 0;
581 #endif
582
583     return 1;
584 }
585 #endif //MD_BOOTLOADER