root/drivers/media/spi/cxd2880-spi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cxd2880_write_spi
  2. cxd2880_write_reg
  3. cxd2880_spi_read_ts
  4. cxd2880_spi_read_ts_buffer_info
  5. cxd2880_spi_clear_ts_buffer
  6. cxd2880_set_pid_filter
  7. cxd2880_update_pid_filter
  8. cxd2880_ts_read
  9. cxd2880_start_feed
  10. cxd2880_stop_feed
  11. cxd2880_spi_probe
  12. cxd2880_spi_remove

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

/* [<][>][^][v][top][bottom][index][help] */