linux/drivers/media/spi/cxd2880-spi.c
<<
>>
Prefs
   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
  24struct 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
  33struct cxd2880_pid_config {
  34        u8 is_enable;
  35        u16 pid;
  36};
  37
  38struct cxd2880_pid_filter_config {
  39        u8 is_negative;
  40        struct cxd2880_pid_config pid_config[CXD2880_MAX_FILTER_SIZE];
  41};
  42
  43struct 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
  58DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  59
  60static 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
  79static 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
 115static 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
 153static 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
 180static 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
 193static 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
 232static 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
 264static 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
 320static 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
 418static 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
 498static const struct of_device_id cxd2880_spi_of_match[] = {
 499        { .compatible = "sony,cxd2880" },
 500        { /* sentinel */ }
 501};
 502
 503MODULE_DEVICE_TABLE(of, cxd2880_spi_of_match);
 504
 505static int
 506cxd2880_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                goto fail_attach;
 540        }
 541
 542        ret = dvb_register_frontend(&dvb_spi->adapter,
 543                                    &dvb_spi->dvb_fe);
 544        if (ret < 0) {
 545                pr_err("dvb_register_frontend() failed\n");
 546                goto fail_frontend;
 547        }
 548
 549        dvb_spi->demux.dmx.capabilities = DMX_TS_FILTERING;
 550        dvb_spi->demux.priv = dvb_spi;
 551        dvb_spi->demux.filternum = CXD2880_MAX_FILTER_SIZE;
 552        dvb_spi->demux.feednum = CXD2880_MAX_FILTER_SIZE;
 553        dvb_spi->demux.start_feed = cxd2880_start_feed;
 554        dvb_spi->demux.stop_feed = cxd2880_stop_feed;
 555
 556        ret = dvb_dmx_init(&dvb_spi->demux);
 557        if (ret < 0) {
 558                pr_err("dvb_dmx_init() failed\n");
 559                goto fail_dmx;
 560        }
 561
 562        dvb_spi->dmxdev.filternum = CXD2880_MAX_FILTER_SIZE;
 563        dvb_spi->dmxdev.demux = &dvb_spi->demux.dmx;
 564        dvb_spi->dmxdev.capabilities = 0;
 565        ret = dvb_dmxdev_init(&dvb_spi->dmxdev,
 566                              &dvb_spi->adapter);
 567        if (ret < 0) {
 568                pr_err("dvb_dmxdev_init() failed\n");
 569                goto fail_dmxdev;
 570        }
 571
 572        dvb_spi->dmx_fe.source = DMX_FRONTEND_0;
 573        ret = dvb_spi->demux.dmx.add_frontend(&dvb_spi->demux.dmx,
 574                                              &dvb_spi->dmx_fe);
 575        if (ret < 0) {
 576                pr_err("add_frontend() failed\n");
 577                goto fail_dmx_fe;
 578        }
 579
 580        ret = dvb_spi->demux.dmx.connect_frontend(&dvb_spi->demux.dmx,
 581                                                  &dvb_spi->dmx_fe);
 582        if (ret < 0) {
 583                pr_err("dvb_register_frontend() failed\n");
 584                goto fail_fe_conn;
 585        }
 586
 587        pr_info("Sony CXD2880 has successfully attached.\n");
 588
 589        return 0;
 590
 591fail_fe_conn:
 592        dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx,
 593                                           &dvb_spi->dmx_fe);
 594fail_dmx_fe:
 595        dvb_dmxdev_release(&dvb_spi->dmxdev);
 596fail_dmxdev:
 597        dvb_dmx_release(&dvb_spi->demux);
 598fail_dmx:
 599        dvb_unregister_frontend(&dvb_spi->dvb_fe);
 600fail_frontend:
 601        dvb_frontend_detach(&dvb_spi->dvb_fe);
 602fail_attach:
 603        dvb_unregister_adapter(&dvb_spi->adapter);
 604fail_adapter:
 605        kfree(dvb_spi);
 606        return ret;
 607}
 608
 609static int
 610cxd2880_spi_remove(struct spi_device *spi)
 611{
 612        struct cxd2880_dvb_spi *dvb_spi;
 613
 614        if (!spi) {
 615                pr_err("invalid arg\n");
 616                return -EINVAL;
 617        }
 618
 619        dvb_spi = dev_get_drvdata(&spi->dev);
 620
 621        if (!dvb_spi) {
 622                pr_err("failed\n");
 623                return -EINVAL;
 624        }
 625        dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx,
 626                                           &dvb_spi->dmx_fe);
 627        dvb_dmxdev_release(&dvb_spi->dmxdev);
 628        dvb_dmx_release(&dvb_spi->demux);
 629        dvb_unregister_frontend(&dvb_spi->dvb_fe);
 630        dvb_frontend_detach(&dvb_spi->dvb_fe);
 631        dvb_unregister_adapter(&dvb_spi->adapter);
 632
 633        kfree(dvb_spi);
 634        pr_info("cxd2880_spi remove ok.\n");
 635
 636        return 0;
 637}
 638
 639static const struct spi_device_id cxd2880_spi_id[] = {
 640        { "cxd2880", 0 },
 641        { /* sentinel */ }
 642};
 643MODULE_DEVICE_TABLE(spi, cxd2880_spi_id);
 644
 645static struct spi_driver cxd2880_spi_driver = {
 646        .driver = {
 647                .name   = "cxd2880",
 648                .of_match_table = cxd2880_spi_of_match,
 649        },
 650        .id_table = cxd2880_spi_id,
 651        .probe    = cxd2880_spi_probe,
 652        .remove   = cxd2880_spi_remove,
 653};
 654module_spi_driver(cxd2880_spi_driver);
 655
 656MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver SPI adapter");
 657MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
 658MODULE_LICENSE("GPL v2");
 659