1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * cxd2880-spi.c
4  * Sony CXD2880 DVB-T2/T tuner + demodulator driver
5  * SPI adapter
6  *
7  * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
8  */
9 
10 #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
11 
12 #include <linux/spi/spi.h>
13 #include <linux/ktime.h>
14 
15 #include <media/dvb_demux.h>
16 #include <media/dmxdev.h>
17 #include <media/dvb_frontend.h>
18 #include "cxd2880.h"
19 
20 #define CXD2880_MAX_FILTER_SIZE 32
21 #define BURST_WRITE_MAX 128
22 #define MAX_TRANS_PKT 300
23 
24 struct cxd2880_ts_buf_info {
25 	u8 read_ready:1;
26 	u8 almost_full:1;
27 	u8 almost_empty:1;
28 	u8 overflow:1;
29 	u8 underflow:1;
30 	u16 pkt_num;
31 };
32 
33 struct cxd2880_pid_config {
34 	u8 is_enable;
35 	u16 pid;
36 };
37 
38 struct cxd2880_pid_filter_config {
39 	u8 is_negative;
40 	struct cxd2880_pid_config pid_config[CXD2880_MAX_FILTER_SIZE];
41 };
42 
43 struct cxd2880_dvb_spi {
44 	struct dvb_frontend dvb_fe;
45 	struct dvb_adapter adapter;
46 	struct dvb_demux demux;
47 	struct dmxdev dmxdev;
48 	struct dmx_frontend dmx_fe;
49 	struct task_struct *cxd2880_ts_read_thread;
50 	struct spi_device *spi;
51 	struct mutex spi_mutex; /* For SPI access exclusive control */
52 	int feed_count;
53 	int all_pid_feed_count;
54 	u8 *ts_buf;
55 	struct cxd2880_pid_filter_config filter_config;
56 };
57 
58 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
59 
cxd2880_write_spi(struct spi_device * spi,u8 * data,u32 size)60 static int cxd2880_write_spi(struct spi_device *spi, u8 *data, u32 size)
61 {
62 	struct spi_message msg;
63 	struct spi_transfer tx = {};
64 
65 	if (!spi || !data) {
66 		pr_err("invalid arg\n");
67 		return -EINVAL;
68 	}
69 
70 	tx.tx_buf = data;
71 	tx.len = size;
72 
73 	spi_message_init(&msg);
74 	spi_message_add_tail(&tx, &msg);
75 
76 	return spi_sync(spi, &msg);
77 }
78 
cxd2880_write_reg(struct spi_device * spi,u8 sub_address,const u8 * data,u32 size)79 static int cxd2880_write_reg(struct spi_device *spi,
80 			     u8 sub_address, const u8 *data, u32 size)
81 {
82 	u8 send_data[BURST_WRITE_MAX + 4];
83 	const u8 *write_data_top = NULL;
84 	int ret = 0;
85 
86 	if (!spi || !data) {
87 		pr_err("invalid arg\n");
88 		return -EINVAL;
89 	}
90 	if (size > BURST_WRITE_MAX || size > U8_MAX) {
91 		pr_err("data size > WRITE_MAX\n");
92 		return -EINVAL;
93 	}
94 
95 	if (sub_address + size > 0x100) {
96 		pr_err("out of range\n");
97 		return -EINVAL;
98 	}
99 
100 	send_data[0] = 0x0e;
101 	write_data_top = data;
102 
103 	send_data[1] = sub_address;
104 	send_data[2] = (u8)size;
105 
106 	memcpy(&send_data[3], write_data_top, send_data[2]);
107 
108 	ret = cxd2880_write_spi(spi, send_data, send_data[2] + 3);
109 	if (ret)
110 		pr_err("write spi failed %d\n", ret);
111 
112 	return ret;
113 }
114 
cxd2880_spi_read_ts(struct spi_device * spi,u8 * read_data,u32 packet_num)115 static int cxd2880_spi_read_ts(struct spi_device *spi,
116 			       u8 *read_data,
117 			       u32 packet_num)
118 {
119 	int ret;
120 	u8 data[3];
121 	struct spi_message message;
122 	struct spi_transfer transfer[2] = {};
123 
124 	if (!spi || !read_data || !packet_num) {
125 		pr_err("invalid arg\n");
126 		return -EINVAL;
127 	}
128 	if (packet_num > 0xffff) {
129 		pr_err("packet num > 0xffff\n");
130 		return -EINVAL;
131 	}
132 
133 	data[0] = 0x10;
134 	data[1] = packet_num >> 8;
135 	data[2] = packet_num;
136 
137 	spi_message_init(&message);
138 
139 	transfer[0].len = 3;
140 	transfer[0].tx_buf = data;
141 	spi_message_add_tail(&transfer[0], &message);
142 	transfer[1].len = packet_num * 188;
143 	transfer[1].rx_buf = read_data;
144 	spi_message_add_tail(&transfer[1], &message);
145 
146 	ret = spi_sync(spi, &message);
147 	if (ret)
148 		pr_err("spi_write_then_read failed\n");
149 
150 	return ret;
151 }
152 
cxd2880_spi_read_ts_buffer_info(struct spi_device * spi,struct cxd2880_ts_buf_info * info)153 static int cxd2880_spi_read_ts_buffer_info(struct spi_device *spi,
154 					   struct cxd2880_ts_buf_info *info)
155 {
156 	u8 send_data = 0x20;
157 	u8 recv_data[2];
158 	int ret;
159 
160 	if (!spi || !info) {
161 		pr_err("invalid arg\n");
162 		return -EINVAL;
163 	}
164 
165 	ret = spi_write_then_read(spi, &send_data, 1,
166 				  recv_data, sizeof(recv_data));
167 	if (ret)
168 		pr_err("spi_write_then_read failed\n");
169 
170 	info->read_ready = (recv_data[0] & 0x80) ? 1 : 0;
171 	info->almost_full = (recv_data[0] & 0x40) ? 1 : 0;
172 	info->almost_empty = (recv_data[0] & 0x20) ? 1 : 0;
173 	info->overflow = (recv_data[0] & 0x10) ? 1 : 0;
174 	info->underflow = (recv_data[0] & 0x08) ? 1 : 0;
175 	info->pkt_num = ((recv_data[0] & 0x07) << 8) | recv_data[1];
176 
177 	return ret;
178 }
179 
cxd2880_spi_clear_ts_buffer(struct spi_device * spi)180 static int cxd2880_spi_clear_ts_buffer(struct spi_device *spi)
181 {
182 	u8 data = 0x03;
183 	int ret;
184 
185 	ret = cxd2880_write_spi(spi, &data, 1);
186 
187 	if (ret)
188 		pr_err("write spi failed\n");
189 
190 	return ret;
191 }
192 
cxd2880_set_pid_filter(struct spi_device * spi,struct cxd2880_pid_filter_config * cfg)193 static int cxd2880_set_pid_filter(struct spi_device *spi,
194 				  struct cxd2880_pid_filter_config *cfg)
195 {
196 	u8 data[65];
197 	int i;
198 	u16 pid = 0;
199 	int ret;
200 
201 	if (!spi) {
202 		pr_err("invalid arg\n");
203 		return -EINVAL;
204 	}
205 
206 	data[0] = 0x00;
207 	ret = cxd2880_write_reg(spi, 0x00, &data[0], 1);
208 	if (ret)
209 		return ret;
210 	if (!cfg) {
211 		data[0] = 0x02;
212 		ret = cxd2880_write_reg(spi, 0x50, &data[0], 1);
213 	} else {
214 		data[0] = cfg->is_negative ? 0x01 : 0x00;
215 
216 		for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
217 			pid = cfg->pid_config[i].pid;
218 			if (cfg->pid_config[i].is_enable) {
219 				data[1 + (i * 2)] = (pid >> 8) | 0x20;
220 				data[2 + (i * 2)] = pid & 0xff;
221 			} else {
222 				data[1 + (i * 2)] = 0x00;
223 				data[2 + (i * 2)] = 0x00;
224 			}
225 		}
226 		ret = cxd2880_write_reg(spi, 0x50, data, 65);
227 	}
228 
229 	return ret;
230 }
231 
cxd2880_update_pid_filter(struct cxd2880_dvb_spi * dvb_spi,struct cxd2880_pid_filter_config * cfg,bool is_all_pid_filter)232 static int cxd2880_update_pid_filter(struct cxd2880_dvb_spi *dvb_spi,
233 				     struct cxd2880_pid_filter_config *cfg,
234 				     bool is_all_pid_filter)
235 {
236 	int ret;
237 
238 	if (!dvb_spi || !cfg) {
239 		pr_err("invalid arg.\n");
240 		return -EINVAL;
241 	}
242 
243 	mutex_lock(&dvb_spi->spi_mutex);
244 	if (is_all_pid_filter) {
245 		struct cxd2880_pid_filter_config tmpcfg;
246 
247 		memset(&tmpcfg, 0, sizeof(tmpcfg));
248 		tmpcfg.is_negative = 1;
249 		tmpcfg.pid_config[0].is_enable = 1;
250 		tmpcfg.pid_config[0].pid = 0x1fff;
251 
252 		ret = cxd2880_set_pid_filter(dvb_spi->spi, &tmpcfg);
253 	} else {
254 		ret = cxd2880_set_pid_filter(dvb_spi->spi, cfg);
255 	}
256 	mutex_unlock(&dvb_spi->spi_mutex);
257 
258 	if (ret)
259 		pr_err("set_pid_filter failed\n");
260 
261 	return ret;
262 }
263 
cxd2880_ts_read(void * arg)264 static int cxd2880_ts_read(void *arg)
265 {
266 	struct cxd2880_dvb_spi *dvb_spi = NULL;
267 	struct cxd2880_ts_buf_info info;
268 	ktime_t start;
269 	u32 i;
270 	int ret;
271 
272 	dvb_spi = arg;
273 	if (!dvb_spi) {
274 		pr_err("invalid arg\n");
275 		return -EINVAL;
276 	}
277 
278 	ret = cxd2880_spi_clear_ts_buffer(dvb_spi->spi);
279 	if (ret) {
280 		pr_err("set_clear_ts_buffer failed\n");
281 		return ret;
282 	}
283 
284 	start = ktime_get();
285 	while (!kthread_should_stop()) {
286 		ret = cxd2880_spi_read_ts_buffer_info(dvb_spi->spi,
287 						      &info);
288 		if (ret) {
289 			pr_err("spi_read_ts_buffer_info error\n");
290 			return ret;
291 		}
292 
293 		if (info.pkt_num > MAX_TRANS_PKT) {
294 			for (i = 0; i < info.pkt_num / MAX_TRANS_PKT; i++) {
295 				cxd2880_spi_read_ts(dvb_spi->spi,
296 						    dvb_spi->ts_buf,
297 						    MAX_TRANS_PKT);
298 				dvb_dmx_swfilter(&dvb_spi->demux,
299 						 dvb_spi->ts_buf,
300 						 MAX_TRANS_PKT * 188);
301 			}
302 			start = ktime_get();
303 		} else if ((info.pkt_num > 0) &&
304 			   (ktime_to_ms(ktime_sub(ktime_get(), start)) >= 500)) {
305 			cxd2880_spi_read_ts(dvb_spi->spi,
306 					    dvb_spi->ts_buf,
307 					    info.pkt_num);
308 			dvb_dmx_swfilter(&dvb_spi->demux,
309 					 dvb_spi->ts_buf,
310 					 info.pkt_num * 188);
311 			start = ktime_get();
312 		} else {
313 			usleep_range(10000, 11000);
314 		}
315 	}
316 
317 	return 0;
318 }
319 
cxd2880_start_feed(struct dvb_demux_feed * feed)320 static int cxd2880_start_feed(struct dvb_demux_feed *feed)
321 {
322 	int ret = 0;
323 	int i = 0;
324 	struct dvb_demux *demux = NULL;
325 	struct cxd2880_dvb_spi *dvb_spi = NULL;
326 
327 	if (!feed) {
328 		pr_err("invalid arg\n");
329 		return -EINVAL;
330 	}
331 
332 	demux = feed->demux;
333 	if (!demux) {
334 		pr_err("feed->demux is NULL\n");
335 		return -EINVAL;
336 	}
337 	dvb_spi = demux->priv;
338 
339 	if (dvb_spi->feed_count == CXD2880_MAX_FILTER_SIZE) {
340 		pr_err("Exceeded maximum PID count (32).");
341 		pr_err("Selected PID cannot be enabled.\n");
342 		return -EINVAL;
343 	}
344 
345 	if (feed->pid == 0x2000) {
346 		if (dvb_spi->all_pid_feed_count == 0) {
347 			ret = cxd2880_update_pid_filter(dvb_spi,
348 							&dvb_spi->filter_config,
349 							true);
350 			if (ret) {
351 				pr_err("update pid filter failed\n");
352 				return ret;
353 			}
354 		}
355 		dvb_spi->all_pid_feed_count++;
356 
357 		pr_debug("all PID feed (count = %d)\n",
358 			 dvb_spi->all_pid_feed_count);
359 	} else {
360 		struct cxd2880_pid_filter_config cfgtmp;
361 
362 		cfgtmp = dvb_spi->filter_config;
363 
364 		for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
365 			if (cfgtmp.pid_config[i].is_enable == 0) {
366 				cfgtmp.pid_config[i].is_enable = 1;
367 				cfgtmp.pid_config[i].pid = feed->pid;
368 				pr_debug("store PID %d to #%d\n",
369 					 feed->pid, i);
370 				break;
371 			}
372 		}
373 		if (i == CXD2880_MAX_FILTER_SIZE) {
374 			pr_err("PID filter is full.\n");
375 			return -EINVAL;
376 		}
377 		if (!dvb_spi->all_pid_feed_count)
378 			ret = cxd2880_update_pid_filter(dvb_spi,
379 							&cfgtmp,
380 							false);
381 		if (ret)
382 			return ret;
383 
384 		dvb_spi->filter_config = cfgtmp;
385 	}
386 
387 	if (dvb_spi->feed_count == 0) {
388 		dvb_spi->ts_buf =
389 			kmalloc(MAX_TRANS_PKT * 188,
390 				GFP_KERNEL | GFP_DMA);
391 		if (!dvb_spi->ts_buf) {
392 			pr_err("ts buffer allocate failed\n");
393 			memset(&dvb_spi->filter_config, 0,
394 			       sizeof(dvb_spi->filter_config));
395 			dvb_spi->all_pid_feed_count = 0;
396 			return -ENOMEM;
397 		}
398 		dvb_spi->cxd2880_ts_read_thread = kthread_run(cxd2880_ts_read,
399 							      dvb_spi,
400 							      "cxd2880_ts_read");
401 		if (IS_ERR(dvb_spi->cxd2880_ts_read_thread)) {
402 			pr_err("kthread_run failed/\n");
403 			kfree(dvb_spi->ts_buf);
404 			dvb_spi->ts_buf = NULL;
405 			memset(&dvb_spi->filter_config, 0,
406 			       sizeof(dvb_spi->filter_config));
407 			dvb_spi->all_pid_feed_count = 0;
408 			return PTR_ERR(dvb_spi->cxd2880_ts_read_thread);
409 		}
410 	}
411 
412 	dvb_spi->feed_count++;
413 
414 	pr_debug("start feed (count %d)\n", dvb_spi->feed_count);
415 	return 0;
416 }
417 
cxd2880_stop_feed(struct dvb_demux_feed * feed)418 static int cxd2880_stop_feed(struct dvb_demux_feed *feed)
419 {
420 	int i = 0;
421 	int ret;
422 	struct dvb_demux *demux = NULL;
423 	struct cxd2880_dvb_spi *dvb_spi = NULL;
424 
425 	if (!feed) {
426 		pr_err("invalid arg\n");
427 		return -EINVAL;
428 	}
429 
430 	demux = feed->demux;
431 	if (!demux) {
432 		pr_err("feed->demux is NULL\n");
433 		return -EINVAL;
434 	}
435 	dvb_spi = demux->priv;
436 
437 	if (!dvb_spi->feed_count) {
438 		pr_err("no feed is started\n");
439 		return -EINVAL;
440 	}
441 
442 	if (feed->pid == 0x2000) {
443 		/*
444 		 * Special PID case.
445 		 * Number of 0x2000 feed request was stored
446 		 * in dvb_spi->all_pid_feed_count.
447 		 */
448 		if (dvb_spi->all_pid_feed_count <= 0) {
449 			pr_err("PID %d not found.\n", feed->pid);
450 			return -EINVAL;
451 		}
452 		dvb_spi->all_pid_feed_count--;
453 	} else {
454 		struct cxd2880_pid_filter_config cfgtmp;
455 
456 		cfgtmp = dvb_spi->filter_config;
457 
458 		for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
459 			if (feed->pid == cfgtmp.pid_config[i].pid &&
460 			    cfgtmp.pid_config[i].is_enable != 0) {
461 				cfgtmp.pid_config[i].is_enable = 0;
462 				cfgtmp.pid_config[i].pid = 0;
463 				pr_debug("removed PID %d from #%d\n",
464 					 feed->pid, i);
465 				break;
466 			}
467 		}
468 		dvb_spi->filter_config = cfgtmp;
469 
470 		if (i == CXD2880_MAX_FILTER_SIZE) {
471 			pr_err("PID %d not found\n", feed->pid);
472 			return -EINVAL;
473 		}
474 	}
475 
476 	ret = cxd2880_update_pid_filter(dvb_spi,
477 					&dvb_spi->filter_config,
478 					dvb_spi->all_pid_feed_count > 0);
479 	dvb_spi->feed_count--;
480 
481 	if (dvb_spi->feed_count == 0) {
482 		int ret_stop = 0;
483 
484 		ret_stop = kthread_stop(dvb_spi->cxd2880_ts_read_thread);
485 		if (ret_stop) {
486 			pr_err("'kthread_stop failed. (%d)\n", ret_stop);
487 			ret = ret_stop;
488 		}
489 		kfree(dvb_spi->ts_buf);
490 		dvb_spi->ts_buf = NULL;
491 	}
492 
493 	pr_debug("stop feed ok.(count %d)\n", dvb_spi->feed_count);
494 
495 	return ret;
496 }
497 
498 static const struct of_device_id cxd2880_spi_of_match[] = {
499 	{ .compatible = "sony,cxd2880" },
500 	{ /* sentinel */ }
501 };
502 
503 MODULE_DEVICE_TABLE(of, cxd2880_spi_of_match);
504 
505 static int
cxd2880_spi_probe(struct spi_device * spi)506 cxd2880_spi_probe(struct spi_device *spi)
507 {
508 	int ret;
509 	struct cxd2880_dvb_spi *dvb_spi = NULL;
510 	struct cxd2880_config config;
511 
512 	if (!spi) {
513 		pr_err("invalid arg.\n");
514 		return -EINVAL;
515 	}
516 
517 	dvb_spi = kzalloc(sizeof(struct cxd2880_dvb_spi), GFP_KERNEL);
518 	if (!dvb_spi)
519 		return -ENOMEM;
520 
521 	dvb_spi->spi = spi;
522 	mutex_init(&dvb_spi->spi_mutex);
523 	dev_set_drvdata(&spi->dev, dvb_spi);
524 	config.spi = spi;
525 	config.spi_mutex = &dvb_spi->spi_mutex;
526 
527 	ret = dvb_register_adapter(&dvb_spi->adapter,
528 				   "CXD2880",
529 				   THIS_MODULE,
530 				   &spi->dev,
531 				   adapter_nr);
532 	if (ret < 0) {
533 		pr_err("dvb_register_adapter() failed\n");
534 		goto fail_adapter;
535 	}
536 
537 	if (!dvb_attach(cxd2880_attach, &dvb_spi->dvb_fe, &config)) {
538 		pr_err("cxd2880_attach failed\n");
539 		ret = -ENODEV;
540 		goto fail_attach;
541 	}
542 
543 	ret = dvb_register_frontend(&dvb_spi->adapter,
544 				    &dvb_spi->dvb_fe);
545 	if (ret < 0) {
546 		pr_err("dvb_register_frontend() failed\n");
547 		goto fail_frontend;
548 	}
549 
550 	dvb_spi->demux.dmx.capabilities = DMX_TS_FILTERING;
551 	dvb_spi->demux.priv = dvb_spi;
552 	dvb_spi->demux.filternum = CXD2880_MAX_FILTER_SIZE;
553 	dvb_spi->demux.feednum = CXD2880_MAX_FILTER_SIZE;
554 	dvb_spi->demux.start_feed = cxd2880_start_feed;
555 	dvb_spi->demux.stop_feed = cxd2880_stop_feed;
556 
557 	ret = dvb_dmx_init(&dvb_spi->demux);
558 	if (ret < 0) {
559 		pr_err("dvb_dmx_init() failed\n");
560 		goto fail_dmx;
561 	}
562 
563 	dvb_spi->dmxdev.filternum = CXD2880_MAX_FILTER_SIZE;
564 	dvb_spi->dmxdev.demux = &dvb_spi->demux.dmx;
565 	dvb_spi->dmxdev.capabilities = 0;
566 	ret = dvb_dmxdev_init(&dvb_spi->dmxdev,
567 			      &dvb_spi->adapter);
568 	if (ret < 0) {
569 		pr_err("dvb_dmxdev_init() failed\n");
570 		goto fail_dmxdev;
571 	}
572 
573 	dvb_spi->dmx_fe.source = DMX_FRONTEND_0;
574 	ret = dvb_spi->demux.dmx.add_frontend(&dvb_spi->demux.dmx,
575 					      &dvb_spi->dmx_fe);
576 	if (ret < 0) {
577 		pr_err("add_frontend() failed\n");
578 		goto fail_dmx_fe;
579 	}
580 
581 	ret = dvb_spi->demux.dmx.connect_frontend(&dvb_spi->demux.dmx,
582 						  &dvb_spi->dmx_fe);
583 	if (ret < 0) {
584 		pr_err("dvb_register_frontend() failed\n");
585 		goto fail_fe_conn;
586 	}
587 
588 	pr_info("Sony CXD2880 has successfully attached.\n");
589 
590 	return 0;
591 
592 fail_fe_conn:
593 	dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx,
594 					   &dvb_spi->dmx_fe);
595 fail_dmx_fe:
596 	dvb_dmxdev_release(&dvb_spi->dmxdev);
597 fail_dmxdev:
598 	dvb_dmx_release(&dvb_spi->demux);
599 fail_dmx:
600 	dvb_unregister_frontend(&dvb_spi->dvb_fe);
601 fail_frontend:
602 	dvb_frontend_detach(&dvb_spi->dvb_fe);
603 fail_attach:
604 	dvb_unregister_adapter(&dvb_spi->adapter);
605 fail_adapter:
606 	kfree(dvb_spi);
607 	return ret;
608 }
609 
610 static int
cxd2880_spi_remove(struct spi_device * spi)611 cxd2880_spi_remove(struct spi_device *spi)
612 {
613 	struct cxd2880_dvb_spi *dvb_spi;
614 
615 	if (!spi) {
616 		pr_err("invalid arg\n");
617 		return -EINVAL;
618 	}
619 
620 	dvb_spi = dev_get_drvdata(&spi->dev);
621 
622 	if (!dvb_spi) {
623 		pr_err("failed\n");
624 		return -EINVAL;
625 	}
626 	dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx,
627 					   &dvb_spi->dmx_fe);
628 	dvb_dmxdev_release(&dvb_spi->dmxdev);
629 	dvb_dmx_release(&dvb_spi->demux);
630 	dvb_unregister_frontend(&dvb_spi->dvb_fe);
631 	dvb_frontend_detach(&dvb_spi->dvb_fe);
632 	dvb_unregister_adapter(&dvb_spi->adapter);
633 
634 	kfree(dvb_spi);
635 	pr_info("cxd2880_spi remove ok.\n");
636 
637 	return 0;
638 }
639 
640 static const struct spi_device_id cxd2880_spi_id[] = {
641 	{ "cxd2880", 0 },
642 	{ /* sentinel */ }
643 };
644 MODULE_DEVICE_TABLE(spi, cxd2880_spi_id);
645 
646 static struct spi_driver cxd2880_spi_driver = {
647 	.driver	= {
648 		.name	= "cxd2880",
649 		.of_match_table = cxd2880_spi_of_match,
650 	},
651 	.id_table = cxd2880_spi_id,
652 	.probe    = cxd2880_spi_probe,
653 	.remove   = cxd2880_spi_remove,
654 };
655 module_spi_driver(cxd2880_spi_driver);
656 
657 MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver SPI adapter");
658 MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
659 MODULE_LICENSE("GPL v2");
660