Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright © 2010 Intel Corporation
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a
  5 * copy of this software and associated documentation files (the "Software"),
  6 * to deal in the Software without restriction, including without limitation
  7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 * and/or sell copies of the Software, and to permit persons to whom the
  9 * Software is furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice (including the next
 12 * paragraph) shall be included in all copies or substantial portions of the
 13 * Software.
 14 *
 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 21 * DEALINGS IN THE SOFTWARE.
 22 *
 23 * Authors:
 24 * Jackie Li<yaodong.li@intel.com>
 25 */
 26
 27#include <linux/delay.h>
 28#include <linux/freezer.h>
 29
 30#include <video/mipi_display.h>
 31
 32#include "mdfld_dsi_dpi.h"
 33#include "mdfld_dsi_output.h"
 34#include "mdfld_dsi_pkg_sender.h"
 35
 36#define MDFLD_DSI_READ_MAX_COUNT		5000
 37
 38enum {
 39	MDFLD_DSI_PANEL_MODE_SLEEP = 0x1,
 40};
 41
 42enum {
 43	MDFLD_DSI_PKG_SENDER_FREE = 0x0,
 44	MDFLD_DSI_PKG_SENDER_BUSY = 0x1,
 45};
 46
 47static const char *const dsi_errors[] = {
 48	"RX SOT Error",
 49	"RX SOT Sync Error",
 50	"RX EOT Sync Error",
 51	"RX Escape Mode Entry Error",
 52	"RX LP TX Sync Error",
 53	"RX HS Receive Timeout Error",
 54	"RX False Control Error",
 55	"RX ECC Single Bit Error",
 56	"RX ECC Multibit Error",
 57	"RX Checksum Error",
 58	"RX DSI Data Type Not Recognised",
 59	"RX DSI VC ID Invalid",
 60	"TX False Control Error",
 61	"TX ECC Single Bit Error",
 62	"TX ECC Multibit Error",
 63	"TX Checksum Error",
 64	"TX DSI Data Type Not Recognised",
 65	"TX DSI VC ID invalid",
 66	"High Contention",
 67	"Low contention",
 68	"DPI FIFO Under run",
 69	"HS TX Timeout",
 70	"LP RX Timeout",
 71	"Turn Around ACK Timeout",
 72	"ACK With No Error",
 73	"RX Invalid TX Length",
 74	"RX Prot Violation",
 75	"HS Generic Write FIFO Full",
 76	"LP Generic Write FIFO Full",
 77	"Generic Read Data Avail",
 78	"Special Packet Sent",
 79	"Tearing Effect",
 80};
 81
 82static inline int wait_for_gen_fifo_empty(struct mdfld_dsi_pkg_sender *sender,
 83						u32 mask)
 84{
 85	struct drm_device *dev = sender->dev;
 86	u32 gen_fifo_stat_reg = sender->mipi_gen_fifo_stat_reg;
 87	int retry = 0xffff;
 88
 89	while (retry--) {
 90		if ((mask & REG_READ(gen_fifo_stat_reg)) == mask)
 91			return 0;
 92		udelay(100);
 93	}
 94	DRM_ERROR("fifo is NOT empty 0x%08x\n", REG_READ(gen_fifo_stat_reg));
 95	return -EIO;
 96}
 97
 98static int wait_for_all_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
 99{
100	return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(10) | BIT(18) |
101						BIT(26) | BIT(27) | BIT(28)));
102}
103
104static int wait_for_lp_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
105{
106	return wait_for_gen_fifo_empty(sender, (BIT(10) | BIT(26)));
107}
108
109static int wait_for_hs_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
110{
111	return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(18)));
112}
113
114static int handle_dsi_error(struct mdfld_dsi_pkg_sender *sender, u32 mask)
115{
116	u32 intr_stat_reg = sender->mipi_intr_stat_reg;
117	struct drm_device *dev = sender->dev;
118
119	dev_dbg(sender->dev->dev, "Handling error 0x%08x\n", mask);
120
121	switch (mask) {
122	case BIT(0):
123	case BIT(1):
124	case BIT(2):
125	case BIT(3):
126	case BIT(4):
127	case BIT(5):
128	case BIT(6):
129	case BIT(7):
130	case BIT(8):
131	case BIT(9):
132	case BIT(10):
133	case BIT(11):
134	case BIT(12):
135	case BIT(13):
136		dev_dbg(sender->dev->dev, "No Action required\n");
137		break;
138	case BIT(14):
139		/*wait for all fifo empty*/
140		/*wait_for_all_fifos_empty(sender)*/
141		break;
142	case BIT(15):
143		dev_dbg(sender->dev->dev, "No Action required\n");
144		break;
145	case BIT(16):
146		break;
147	case BIT(17):
148		break;
149	case BIT(18):
150	case BIT(19):
151		dev_dbg(sender->dev->dev, "High/Low contention detected\n");
152		/*wait for contention recovery time*/
153		/*mdelay(10);*/
154		/*wait for all fifo empty*/
155		if (0)
156			wait_for_all_fifos_empty(sender);
157		break;
158	case BIT(20):
159		dev_dbg(sender->dev->dev, "No Action required\n");
160		break;
161	case BIT(21):
162		/*wait for all fifo empty*/
163		/*wait_for_all_fifos_empty(sender);*/
164		break;
165	case BIT(22):
166		break;
167	case BIT(23):
168	case BIT(24):
169	case BIT(25):
170	case BIT(26):
171	case BIT(27):
172		dev_dbg(sender->dev->dev, "HS Gen fifo full\n");
173		REG_WRITE(intr_stat_reg, mask);
174		wait_for_hs_fifos_empty(sender);
175		break;
176	case BIT(28):
177		dev_dbg(sender->dev->dev, "LP Gen fifo full\n");
178		REG_WRITE(intr_stat_reg, mask);
179		wait_for_lp_fifos_empty(sender);
180		break;
181	case BIT(29):
182	case BIT(30):
183	case BIT(31):
184		dev_dbg(sender->dev->dev, "No Action required\n");
185		break;
186	}
187
188	if (mask & REG_READ(intr_stat_reg))
189		dev_dbg(sender->dev->dev,
190				"Cannot clean interrupt 0x%08x\n", mask);
191	return 0;
192}
193
194static int dsi_error_handler(struct mdfld_dsi_pkg_sender *sender)
195{
196	struct drm_device *dev = sender->dev;
197	u32 intr_stat_reg = sender->mipi_intr_stat_reg;
198	u32 mask;
199	u32 intr_stat;
200	int i;
201	int err = 0;
202
203	intr_stat = REG_READ(intr_stat_reg);
204
205	for (i = 0; i < 32; i++) {
206		mask = (0x00000001UL) << i;
207		if (intr_stat & mask) {
208			dev_dbg(sender->dev->dev, "[DSI]: %s\n", dsi_errors[i]);
209			err = handle_dsi_error(sender, mask);
210			if (err)
211				DRM_ERROR("Cannot handle error\n");
212		}
213	}
214	return err;
215}
216
217static int send_short_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
218			u8 cmd, u8 param, bool hs)
219{
220	struct drm_device *dev = sender->dev;
221	u32 ctrl_reg;
222	u32 val;
223	u8 virtual_channel = 0;
224
225	if (hs) {
226		ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
227
228		/* FIXME: wait_for_hs_fifos_empty(sender); */
229	} else {
230		ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
231
232		/* FIXME: wait_for_lp_fifos_empty(sender); */
233	}
234
235	val = FLD_VAL(param, 23, 16) | FLD_VAL(cmd, 15, 8) |
236		FLD_VAL(virtual_channel, 7, 6) | FLD_VAL(data_type, 5, 0);
237
238	REG_WRITE(ctrl_reg, val);
239
240	return 0;
241}
242
243static int send_long_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
244			u8 *data, int len, bool hs)
245{
246	struct drm_device *dev = sender->dev;
247	u32 ctrl_reg;
248	u32 data_reg;
249	u32 val;
250	u8 *p;
251	u8 b1, b2, b3, b4;
252	u8 virtual_channel = 0;
253	int i;
254
255	if (hs) {
256		ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
257		data_reg = sender->mipi_hs_gen_data_reg;
258
259		/* FIXME: wait_for_hs_fifos_empty(sender); */
260	} else {
261		ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
262		data_reg = sender->mipi_lp_gen_data_reg;
263
264		/* FIXME: wait_for_lp_fifos_empty(sender); */
265	}
266
267	p = data;
268	for (i = 0; i < len / 4; i++) {
269		b1 = *p++;
270		b2 = *p++;
271		b3 = *p++;
272		b4 = *p++;
273
274		REG_WRITE(data_reg, b4 << 24 | b3 << 16 | b2 << 8 | b1);
275	}
276
277	i = len % 4;
278	if (i) {
279		b1 = 0; b2 = 0; b3 = 0;
280
281		switch (i) {
282		case 3:
283			b1 = *p++;
284			b2 = *p++;
285			b3 = *p++;
286			break;
287		case 2:
288			b1 = *p++;
289			b2 = *p++;
290			break;
291		case 1:
292			b1 = *p++;
293			break;
294		}
295
296		REG_WRITE(data_reg, b3 << 16 | b2 << 8 | b1);
297	}
298
299	val = FLD_VAL(len, 23, 8) | FLD_VAL(virtual_channel, 7, 6) |
300		FLD_VAL(data_type, 5, 0);
301
302	REG_WRITE(ctrl_reg, val);
303
304	return 0;
305}
306
307static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
308			u8 *data, u16 len)
309{
310	u8 cmd;
311
312	switch (data_type) {
313	case MIPI_DSI_DCS_SHORT_WRITE:
314	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
315	case MIPI_DSI_DCS_LONG_WRITE:
316		cmd = *data;
317		break;
318	default:
319		return 0;
320	}
321
322	/*this prevents other package sending while doing msleep*/
323	sender->status = MDFLD_DSI_PKG_SENDER_BUSY;
324
325	/*wait for 120 milliseconds in case exit_sleep_mode just be sent*/
326	if (unlikely(cmd == MIPI_DCS_ENTER_SLEEP_MODE)) {
327		/*TODO: replace it with msleep later*/
328		mdelay(120);
329	}
330
331	if (unlikely(cmd == MIPI_DCS_EXIT_SLEEP_MODE)) {
332		/*TODO: replace it with msleep later*/
333		mdelay(120);
334	}
335	return 0;
336}
337
338static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
339			u8 *data, u16 len)
340{
341	u8 cmd;
342
343	switch (data_type) {
344	case MIPI_DSI_DCS_SHORT_WRITE:
345	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
346	case MIPI_DSI_DCS_LONG_WRITE:
347		cmd = *data;
348		break;
349	default:
350		return 0;
351	}
352
353	/*update panel status*/
354	if (unlikely(cmd == MIPI_DCS_ENTER_SLEEP_MODE)) {
355		sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP;
356		/*TODO: replace it with msleep later*/
357		mdelay(120);
358	} else if (unlikely(cmd == MIPI_DCS_EXIT_SLEEP_MODE)) {
359		sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP;
360		/*TODO: replace it with msleep later*/
361		mdelay(120);
362	} else if (unlikely(cmd == MIPI_DCS_SOFT_RESET)) {
363		/*TODO: replace it with msleep later*/
364		mdelay(5);
365	}
366
367	sender->status = MDFLD_DSI_PKG_SENDER_FREE;
368
369	return 0;
370}
371
372static int send_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
373		u8 *data, u16 len, bool hs)
374{
375	int ret;
376
377	/*handle DSI error*/
378	ret = dsi_error_handler(sender);
379	if (ret) {
380		DRM_ERROR("Error handling failed\n");
381		return -EAGAIN;
382	}
383
384	/* send pkg */
385	if (sender->status == MDFLD_DSI_PKG_SENDER_BUSY) {
386		DRM_ERROR("sender is busy\n");
387		return -EAGAIN;
388	}
389
390	ret = send_pkg_prepare(sender, data_type, data, len);
391	if (ret) {
392		DRM_ERROR("send_pkg_prepare error\n");
393		return ret;
394	}
395
396	switch (data_type) {
397	case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
398	case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
399	case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
400	case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
401	case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
402	case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
403	case MIPI_DSI_DCS_SHORT_WRITE:
404	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
405	case MIPI_DSI_DCS_READ:
406		ret = send_short_pkg(sender, data_type, data[0], data[1], hs);
407		break;
408	case MIPI_DSI_GENERIC_LONG_WRITE:
409	case MIPI_DSI_DCS_LONG_WRITE:
410		ret = send_long_pkg(sender, data_type, data, len, hs);
411		break;
412	}
413
414	send_pkg_done(sender, data_type, data, len);
415
416	/*FIXME: should I query complete and fifo empty here?*/
417
418	return ret;
419}
420
421int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
422			u32 len, bool hs)
423{
424	unsigned long flags;
425
426	if (!sender || !data || !len) {
427		DRM_ERROR("Invalid parameters\n");
428		return -EINVAL;
429	}
430
431	spin_lock_irqsave(&sender->lock, flags);
432	send_pkg(sender, MIPI_DSI_DCS_LONG_WRITE, data, len, hs);
433	spin_unlock_irqrestore(&sender->lock, flags);
434
435	return 0;
436}
437
438int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
439			u8 param, u8 param_num, bool hs)
440{
441	u8 data[2];
442	unsigned long flags;
443	u8 data_type;
444
445	if (!sender) {
446		DRM_ERROR("Invalid parameter\n");
447		return -EINVAL;
448	}
449
450	data[0] = cmd;
451
452	if (param_num) {
453		data_type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
454		data[1] = param;
455	} else {
456		data_type = MIPI_DSI_DCS_SHORT_WRITE;
457		data[1] = 0;
458	}
459
460	spin_lock_irqsave(&sender->lock, flags);
461	send_pkg(sender, data_type, data, sizeof(data), hs);
462	spin_unlock_irqrestore(&sender->lock, flags);
463
464	return 0;
465}
466
467int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0,
468			u8 param1, u8 param_num, bool hs)
469{
470	u8 data[2];
471	unsigned long flags;
472	u8 data_type;
473
474	if (!sender || param_num > 2) {
475		DRM_ERROR("Invalid parameter\n");
476		return -EINVAL;
477	}
478
479	switch (param_num) {
480	case 0:
481		data_type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM;
482		data[0] = 0;
483		data[1] = 0;
484		break;
485	case 1:
486		data_type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM;
487		data[0] = param0;
488		data[1] = 0;
489		break;
490	case 2:
491		data_type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM;
492		data[0] = param0;
493		data[1] = param1;
494		break;
495	}
496
497	spin_lock_irqsave(&sender->lock, flags);
498	send_pkg(sender, data_type, data, sizeof(data), hs);
499	spin_unlock_irqrestore(&sender->lock, flags);
500
501	return 0;
502}
503
504int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
505			u32 len, bool hs)
506{
507	unsigned long flags;
508
509	if (!sender || !data || !len) {
510		DRM_ERROR("Invalid parameters\n");
511		return -EINVAL;
512	}
513
514	spin_lock_irqsave(&sender->lock, flags);
515	send_pkg(sender, MIPI_DSI_GENERIC_LONG_WRITE, data, len, hs);
516	spin_unlock_irqrestore(&sender->lock, flags);
517
518	return 0;
519}
520
521static int __read_panel_data(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
522			u8 *data, u16 len, u32 *data_out, u16 len_out, bool hs)
523{
524	unsigned long flags;
525	struct drm_device *dev;
526	int i;
527	u32 gen_data_reg;
528	int retry = MDFLD_DSI_READ_MAX_COUNT;
529
530	if (!sender || !data_out || !len_out) {
531		DRM_ERROR("Invalid parameters\n");
532		return -EINVAL;
533	}
534
535	dev = sender->dev;
536
537	/**
538	 * do reading.
539	 * 0) send out generic read request
540	 * 1) polling read data avail interrupt
541	 * 2) read data
542	 */
543	spin_lock_irqsave(&sender->lock, flags);
544
545	REG_WRITE(sender->mipi_intr_stat_reg, BIT(29));
546
547	if ((REG_READ(sender->mipi_intr_stat_reg) & BIT(29)))
548		DRM_ERROR("Can NOT clean read data valid interrupt\n");
549
550	/*send out read request*/
551	send_pkg(sender, data_type, data, len, hs);
552
553	/*polling read data avail interrupt*/
554	while (retry && !(REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) {
555		udelay(100);
556		retry--;
557	}
558
559	if (!retry) {
560		spin_unlock_irqrestore(&sender->lock, flags);
561		return -ETIMEDOUT;
562	}
563
564	REG_WRITE(sender->mipi_intr_stat_reg, BIT(29));
565
566	/*read data*/
567	if (hs)
568		gen_data_reg = sender->mipi_hs_gen_data_reg;
569	else
570		gen_data_reg = sender->mipi_lp_gen_data_reg;
571
572	for (i = 0; i < len_out; i++)
573		*(data_out + i) = REG_READ(gen_data_reg);
574
575	spin_unlock_irqrestore(&sender->lock, flags);
576
577	return 0;
578}
579
580int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
581		u32 *data, u16 len, bool hs)
582{
583	if (!sender || !data || !len) {
584		DRM_ERROR("Invalid parameters\n");
585		return -EINVAL;
586	}
587
588	return __read_panel_data(sender, MIPI_DSI_DCS_READ, &cmd, 1,
589				data, len, hs);
590}
591
592int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
593								int pipe)
594{
595	struct mdfld_dsi_pkg_sender *pkg_sender;
596	struct mdfld_dsi_config *dsi_config =
597				mdfld_dsi_get_config(dsi_connector);
598	struct drm_device *dev = dsi_config->dev;
599	struct drm_psb_private *dev_priv = dev->dev_private;
600	const struct psb_offset *map = &dev_priv->regmap[pipe];
601	u32 mipi_val = 0;
602
603	if (!dsi_connector) {
604		DRM_ERROR("Invalid parameter\n");
605		return -EINVAL;
606	}
607
608	pkg_sender = dsi_connector->pkg_sender;
609
610	if (!pkg_sender || IS_ERR(pkg_sender)) {
611		pkg_sender = kzalloc(sizeof(struct mdfld_dsi_pkg_sender),
612								GFP_KERNEL);
613		if (!pkg_sender) {
614			DRM_ERROR("Create DSI pkg sender failed\n");
615			return -ENOMEM;
616		}
617		dsi_connector->pkg_sender = (void *)pkg_sender;
618	}
619
620	pkg_sender->dev = dev;
621	pkg_sender->dsi_connector = dsi_connector;
622	pkg_sender->pipe = pipe;
623	pkg_sender->pkg_num = 0;
624	pkg_sender->panel_mode = 0;
625	pkg_sender->status = MDFLD_DSI_PKG_SENDER_FREE;
626
627	/*init regs*/
628	/* FIXME: should just copy the regmap ptr ? */
629	pkg_sender->dpll_reg = map->dpll;
630	pkg_sender->dspcntr_reg = map->cntr;
631	pkg_sender->pipeconf_reg = map->conf;
632	pkg_sender->dsplinoff_reg = map->linoff;
633	pkg_sender->dspsurf_reg = map->surf;
634	pkg_sender->pipestat_reg = map->status;
635
636	pkg_sender->mipi_intr_stat_reg = MIPI_INTR_STAT_REG(pipe);
637	pkg_sender->mipi_lp_gen_data_reg = MIPI_LP_GEN_DATA_REG(pipe);
638	pkg_sender->mipi_hs_gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe);
639	pkg_sender->mipi_lp_gen_ctrl_reg = MIPI_LP_GEN_CTRL_REG(pipe);
640	pkg_sender->mipi_hs_gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe);
641	pkg_sender->mipi_gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe);
642	pkg_sender->mipi_data_addr_reg = MIPI_DATA_ADD_REG(pipe);
643	pkg_sender->mipi_data_len_reg = MIPI_DATA_LEN_REG(pipe);
644	pkg_sender->mipi_cmd_addr_reg = MIPI_CMD_ADD_REG(pipe);
645	pkg_sender->mipi_cmd_len_reg = MIPI_CMD_LEN_REG(pipe);
646
647	/*init lock*/
648	spin_lock_init(&pkg_sender->lock);
649
650	if (mdfld_get_panel_type(dev, pipe) != TC35876X) {
651		/**
652		 * For video mode, don't enable DPI timing output here,
653		 * will init the DPI timing output during mode setting.
654		 */
655		mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
656
657		if (pipe == 0)
658			mipi_val |= 0x2;
659
660		REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi_val);
661		REG_READ(MIPI_PORT_CONTROL(pipe));
662
663		/* do dsi controller init */
664		mdfld_dsi_controller_init(dsi_config, pipe);
665	}
666
667	return 0;
668}
669
670void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender)
671{
672	if (!sender || IS_ERR(sender))
673		return;
674
675	/*free*/
676	kfree(sender);
677}
678
679