116216333SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 227cfc85eSAntti Palosaari /* 327cfc85eSAntti Palosaari * Sony CXD2820R demodulator driver 427cfc85eSAntti Palosaari * 527cfc85eSAntti Palosaari * Copyright (C) 2010 Antti Palosaari <crope@iki.fi> 627cfc85eSAntti Palosaari */ 727cfc85eSAntti Palosaari 827cfc85eSAntti Palosaari 99ac51c5eSSteve Kerrison #include "cxd2820r_priv.h" 109ac51c5eSSteve Kerrison 11f311f68aSMauro Carvalho Chehab int cxd2820r_set_frontend_c(struct dvb_frontend *fe) 1227cfc85eSAntti Palosaari { 1327cfc85eSAntti Palosaari struct cxd2820r_priv *priv = fe->demodulator_priv; 14c98975f9SAntti Palosaari struct i2c_client *client = priv->client[0]; 1527cfc85eSAntti Palosaari struct dtv_frontend_properties *c = &fe->dtv_property_cache; 1643e2ea63SAntti Palosaari int ret; 17fcd09f65SAntti Palosaari unsigned int utmp; 1827cfc85eSAntti Palosaari u8 buf[2]; 19fcd09f65SAntti Palosaari u32 if_frequency; 2027cfc85eSAntti Palosaari struct reg_val_mask tab[] = { 2127cfc85eSAntti Palosaari { 0x00080, 0x01, 0xff }, 2227cfc85eSAntti Palosaari { 0x00081, 0x05, 0xff }, 2327cfc85eSAntti Palosaari { 0x00085, 0x07, 0xff }, 2427cfc85eSAntti Palosaari { 0x00088, 0x01, 0xff }, 2527cfc85eSAntti Palosaari 2627cfc85eSAntti Palosaari { 0x00082, 0x20, 0x60 }, 2727cfc85eSAntti Palosaari { 0x1016a, 0x48, 0xff }, 2827cfc85eSAntti Palosaari { 0x100a5, 0x00, 0x01 }, 2927cfc85eSAntti Palosaari { 0x10020, 0x06, 0x07 }, 3027cfc85eSAntti Palosaari { 0x10059, 0x50, 0xff }, 3127cfc85eSAntti Palosaari { 0x10087, 0x0c, 0x3c }, 3227cfc85eSAntti Palosaari { 0x1008b, 0x07, 0xff }, 3307fdf7d9SAntti Palosaari { 0x1001f, priv->if_agc_polarity << 7, 0x80 }, 3407fdf7d9SAntti Palosaari { 0x10070, priv->ts_mode, 0xff }, 3507fdf7d9SAntti Palosaari { 0x10071, !priv->ts_clk_inv << 4, 0x10 }, 3627cfc85eSAntti Palosaari }; 3727cfc85eSAntti Palosaari 38c98975f9SAntti Palosaari dev_dbg(&client->dev, 39c98975f9SAntti Palosaari "delivery_system=%d modulation=%d frequency=%u symbol_rate=%u inversion=%d\n", 40c98975f9SAntti Palosaari c->delivery_system, c->modulation, c->frequency, 41c98975f9SAntti Palosaari c->symbol_rate, c->inversion); 4227cfc85eSAntti Palosaari 4327cfc85eSAntti Palosaari /* program tuner */ 4427cfc85eSAntti Palosaari if (fe->ops.tuner_ops.set_params) 4514d24d14SMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe); 4627cfc85eSAntti Palosaari 470349471bSMauro Carvalho Chehab if (priv->delivery_system != SYS_DVBC_ANNEX_A) { 4843e2ea63SAntti Palosaari ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab)); 4927cfc85eSAntti Palosaari if (ret) 5027cfc85eSAntti Palosaari goto error; 5127cfc85eSAntti Palosaari } 5227cfc85eSAntti Palosaari 530349471bSMauro Carvalho Chehab priv->delivery_system = SYS_DVBC_ANNEX_A; 54285c0b00SMauro Carvalho Chehab priv->ber_running = false; /* tune stops BER counter */ 5527cfc85eSAntti Palosaari 56fda23faaSAntti Palosaari /* program IF frequency */ 57fda23faaSAntti Palosaari if (fe->ops.tuner_ops.get_if_frequency) { 58fcd09f65SAntti Palosaari ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); 59fda23faaSAntti Palosaari if (ret) 60fda23faaSAntti Palosaari goto error; 61c98975f9SAntti Palosaari dev_dbg(&client->dev, "if_frequency=%u\n", if_frequency); 62fcd09f65SAntti Palosaari } else { 63fcd09f65SAntti Palosaari ret = -EINVAL; 64fcd09f65SAntti Palosaari goto error; 65fcd09f65SAntti Palosaari } 66fda23faaSAntti Palosaari 67fcd09f65SAntti Palosaari utmp = 0x4000 - DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x4000, CXD2820R_CLK); 68fcd09f65SAntti Palosaari buf[0] = (utmp >> 8) & 0xff; 69fcd09f65SAntti Palosaari buf[1] = (utmp >> 0) & 0xff; 7043e2ea63SAntti Palosaari ret = regmap_bulk_write(priv->regmap[1], 0x0042, buf, 2); 7127cfc85eSAntti Palosaari if (ret) 7227cfc85eSAntti Palosaari goto error; 7327cfc85eSAntti Palosaari 7443e2ea63SAntti Palosaari ret = regmap_write(priv->regmap[0], 0x00ff, 0x08); 7527cfc85eSAntti Palosaari if (ret) 7627cfc85eSAntti Palosaari goto error; 7727cfc85eSAntti Palosaari 7843e2ea63SAntti Palosaari ret = regmap_write(priv->regmap[0], 0x00fe, 0x01); 7927cfc85eSAntti Palosaari if (ret) 8027cfc85eSAntti Palosaari goto error; 8127cfc85eSAntti Palosaari 8227cfc85eSAntti Palosaari return ret; 8327cfc85eSAntti Palosaari error: 84c98975f9SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 8527cfc85eSAntti Palosaari return ret; 8627cfc85eSAntti Palosaari } 8727cfc85eSAntti Palosaari 887e3e68bcSMauro Carvalho Chehab int cxd2820r_get_frontend_c(struct dvb_frontend *fe, 897e3e68bcSMauro Carvalho Chehab struct dtv_frontend_properties *c) 9027cfc85eSAntti Palosaari { 9127cfc85eSAntti Palosaari struct cxd2820r_priv *priv = fe->demodulator_priv; 92c98975f9SAntti Palosaari struct i2c_client *client = priv->client[0]; 9327cfc85eSAntti Palosaari int ret; 9443e2ea63SAntti Palosaari unsigned int utmp; 9527cfc85eSAntti Palosaari u8 buf[2]; 9627cfc85eSAntti Palosaari 97c98975f9SAntti Palosaari dev_dbg(&client->dev, "\n"); 98c98975f9SAntti Palosaari 9943e2ea63SAntti Palosaari ret = regmap_bulk_read(priv->regmap[1], 0x001a, buf, 2); 10027cfc85eSAntti Palosaari if (ret) 10127cfc85eSAntti Palosaari goto error; 10227cfc85eSAntti Palosaari 10327cfc85eSAntti Palosaari c->symbol_rate = 2500 * ((buf[0] & 0x0f) << 8 | buf[1]); 10427cfc85eSAntti Palosaari 10543e2ea63SAntti Palosaari ret = regmap_read(priv->regmap[1], 0x0019, &utmp); 10627cfc85eSAntti Palosaari if (ret) 10727cfc85eSAntti Palosaari goto error; 10827cfc85eSAntti Palosaari 10943e2ea63SAntti Palosaari switch ((utmp >> 0) & 0x07) { 11027cfc85eSAntti Palosaari case 0: 11127cfc85eSAntti Palosaari c->modulation = QAM_16; 11227cfc85eSAntti Palosaari break; 11327cfc85eSAntti Palosaari case 1: 11427cfc85eSAntti Palosaari c->modulation = QAM_32; 11527cfc85eSAntti Palosaari break; 11627cfc85eSAntti Palosaari case 2: 11727cfc85eSAntti Palosaari c->modulation = QAM_64; 11827cfc85eSAntti Palosaari break; 11927cfc85eSAntti Palosaari case 3: 12027cfc85eSAntti Palosaari c->modulation = QAM_128; 12127cfc85eSAntti Palosaari break; 12227cfc85eSAntti Palosaari case 4: 12327cfc85eSAntti Palosaari c->modulation = QAM_256; 12427cfc85eSAntti Palosaari break; 12527cfc85eSAntti Palosaari } 12627cfc85eSAntti Palosaari 12743e2ea63SAntti Palosaari switch ((utmp >> 7) & 0x01) { 12827cfc85eSAntti Palosaari case 0: 12927cfc85eSAntti Palosaari c->inversion = INVERSION_OFF; 13027cfc85eSAntti Palosaari break; 13127cfc85eSAntti Palosaari case 1: 13227cfc85eSAntti Palosaari c->inversion = INVERSION_ON; 13327cfc85eSAntti Palosaari break; 13427cfc85eSAntti Palosaari } 13527cfc85eSAntti Palosaari 13627cfc85eSAntti Palosaari return ret; 13727cfc85eSAntti Palosaari error: 138c98975f9SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 13927cfc85eSAntti Palosaari return ret; 14027cfc85eSAntti Palosaari } 14127cfc85eSAntti Palosaari 1420df289a2SMauro Carvalho Chehab int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) 14327cfc85eSAntti Palosaari { 14427cfc85eSAntti Palosaari struct cxd2820r_priv *priv = fe->demodulator_priv; 145c98975f9SAntti Palosaari struct i2c_client *client = priv->client[0]; 14690d5d2e3SAntti Palosaari struct dtv_frontend_properties *c = &fe->dtv_property_cache; 14727cfc85eSAntti Palosaari int ret; 148d51dc917SAntti Palosaari unsigned int utmp, utmp1, utmp2; 14990d5d2e3SAntti Palosaari u8 buf[3]; 15027cfc85eSAntti Palosaari 151d51dc917SAntti Palosaari /* Lock detection */ 15243e2ea63SAntti Palosaari ret = regmap_bulk_read(priv->regmap[1], 0x0088, &buf[0], 1); 153d51dc917SAntti Palosaari if (ret) 154d51dc917SAntti Palosaari goto error; 15543e2ea63SAntti Palosaari ret = regmap_bulk_read(priv->regmap[1], 0x0073, &buf[1], 1); 15627cfc85eSAntti Palosaari if (ret) 15727cfc85eSAntti Palosaari goto error; 15827cfc85eSAntti Palosaari 159d51dc917SAntti Palosaari utmp1 = (buf[0] >> 0) & 0x01; 160d51dc917SAntti Palosaari utmp2 = (buf[1] >> 3) & 0x01; 16127cfc85eSAntti Palosaari 162d51dc917SAntti Palosaari if (utmp1 == 1 && utmp2 == 1) { 163d51dc917SAntti Palosaari *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | 16427cfc85eSAntti Palosaari FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; 165d51dc917SAntti Palosaari } else if (utmp1 == 1 || utmp2 == 1) { 166d51dc917SAntti Palosaari *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | 167d51dc917SAntti Palosaari FE_HAS_VITERBI | FE_HAS_SYNC; 168d51dc917SAntti Palosaari } else { 169d51dc917SAntti Palosaari *status = 0; 17027cfc85eSAntti Palosaari } 17127cfc85eSAntti Palosaari 172d51dc917SAntti Palosaari dev_dbg(&client->dev, "status=%02x raw=%*ph sync=%u ts=%u\n", 173d51dc917SAntti Palosaari *status, 2, buf, utmp1, utmp2); 17427cfc85eSAntti Palosaari 17590d5d2e3SAntti Palosaari /* Signal strength */ 17690d5d2e3SAntti Palosaari if (*status & FE_HAS_SIGNAL) { 17790d5d2e3SAntti Palosaari unsigned int strength; 17890d5d2e3SAntti Palosaari 17943e2ea63SAntti Palosaari ret = regmap_bulk_read(priv->regmap[1], 0x0049, buf, 2); 18090d5d2e3SAntti Palosaari if (ret) 18190d5d2e3SAntti Palosaari goto error; 18290d5d2e3SAntti Palosaari 18390d5d2e3SAntti Palosaari utmp = buf[0] << 8 | buf[1] << 0; 18490d5d2e3SAntti Palosaari utmp = 511 - sign_extend32(utmp, 9); 18590d5d2e3SAntti Palosaari /* Scale value to 0x0000-0xffff */ 18690d5d2e3SAntti Palosaari strength = utmp << 6 | utmp >> 4; 18790d5d2e3SAntti Palosaari 18890d5d2e3SAntti Palosaari c->strength.len = 1; 18990d5d2e3SAntti Palosaari c->strength.stat[0].scale = FE_SCALE_RELATIVE; 19090d5d2e3SAntti Palosaari c->strength.stat[0].uvalue = strength; 19190d5d2e3SAntti Palosaari } else { 19290d5d2e3SAntti Palosaari c->strength.len = 1; 19390d5d2e3SAntti Palosaari c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 19490d5d2e3SAntti Palosaari } 19590d5d2e3SAntti Palosaari 19690d5d2e3SAntti Palosaari /* CNR */ 19790d5d2e3SAntti Palosaari if (*status & FE_HAS_VITERBI) { 19890d5d2e3SAntti Palosaari unsigned int cnr, const_a, const_b; 19990d5d2e3SAntti Palosaari 20043e2ea63SAntti Palosaari ret = regmap_read(priv->regmap[1], 0x0019, &utmp); 20190d5d2e3SAntti Palosaari if (ret) 20290d5d2e3SAntti Palosaari goto error; 20390d5d2e3SAntti Palosaari 20443e2ea63SAntti Palosaari if (((utmp >> 0) & 0x03) % 2) { 20590d5d2e3SAntti Palosaari const_a = 8750; 20690d5d2e3SAntti Palosaari const_b = 650; 20790d5d2e3SAntti Palosaari } else { 20890d5d2e3SAntti Palosaari const_a = 9500; 20990d5d2e3SAntti Palosaari const_b = 760; 21090d5d2e3SAntti Palosaari } 21190d5d2e3SAntti Palosaari 21243e2ea63SAntti Palosaari ret = regmap_read(priv->regmap[1], 0x004d, &utmp); 21390d5d2e3SAntti Palosaari if (ret) 21490d5d2e3SAntti Palosaari goto error; 21590d5d2e3SAntti Palosaari 21690d5d2e3SAntti Palosaari #define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */ 21790d5d2e3SAntti Palosaari if (utmp) 21890d5d2e3SAntti Palosaari cnr = div_u64((u64)(intlog2(const_b) - intlog2(utmp)) 21990d5d2e3SAntti Palosaari * const_a, CXD2820R_LOG2_E_24); 22090d5d2e3SAntti Palosaari else 22190d5d2e3SAntti Palosaari cnr = 0; 22290d5d2e3SAntti Palosaari 22390d5d2e3SAntti Palosaari c->cnr.len = 1; 22490d5d2e3SAntti Palosaari c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 22590d5d2e3SAntti Palosaari c->cnr.stat[0].svalue = cnr; 22690d5d2e3SAntti Palosaari } else { 22790d5d2e3SAntti Palosaari c->cnr.len = 1; 22890d5d2e3SAntti Palosaari c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 22990d5d2e3SAntti Palosaari } 23090d5d2e3SAntti Palosaari 23190d5d2e3SAntti Palosaari /* BER */ 23290d5d2e3SAntti Palosaari if (*status & FE_HAS_SYNC) { 23390d5d2e3SAntti Palosaari unsigned int post_bit_error; 23490d5d2e3SAntti Palosaari bool start_ber; 23590d5d2e3SAntti Palosaari 23690d5d2e3SAntti Palosaari if (priv->ber_running) { 23743e2ea63SAntti Palosaari ret = regmap_bulk_read(priv->regmap[1], 0x0076, buf, 3); 23890d5d2e3SAntti Palosaari if (ret) 23990d5d2e3SAntti Palosaari goto error; 24090d5d2e3SAntti Palosaari 24190d5d2e3SAntti Palosaari if ((buf[2] >> 7) & 0x01) { 24290d5d2e3SAntti Palosaari post_bit_error = buf[2] << 16 | buf[1] << 8 | 24390d5d2e3SAntti Palosaari buf[0] << 0; 24490d5d2e3SAntti Palosaari post_bit_error &= 0x0fffff; 24590d5d2e3SAntti Palosaari start_ber = true; 24690d5d2e3SAntti Palosaari } else { 24790d5d2e3SAntti Palosaari post_bit_error = 0; 24890d5d2e3SAntti Palosaari start_ber = false; 24990d5d2e3SAntti Palosaari } 25090d5d2e3SAntti Palosaari } else { 25190d5d2e3SAntti Palosaari post_bit_error = 0; 25290d5d2e3SAntti Palosaari start_ber = true; 25390d5d2e3SAntti Palosaari } 25490d5d2e3SAntti Palosaari 25590d5d2e3SAntti Palosaari if (start_ber) { 25643e2ea63SAntti Palosaari ret = regmap_write(priv->regmap[1], 0x0079, 0x01); 25790d5d2e3SAntti Palosaari if (ret) 25890d5d2e3SAntti Palosaari goto error; 25990d5d2e3SAntti Palosaari priv->ber_running = true; 26090d5d2e3SAntti Palosaari } 26190d5d2e3SAntti Palosaari 26290d5d2e3SAntti Palosaari priv->post_bit_error += post_bit_error; 26390d5d2e3SAntti Palosaari 26490d5d2e3SAntti Palosaari c->post_bit_error.len = 1; 26590d5d2e3SAntti Palosaari c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; 26690d5d2e3SAntti Palosaari c->post_bit_error.stat[0].uvalue = priv->post_bit_error; 26790d5d2e3SAntti Palosaari } else { 26890d5d2e3SAntti Palosaari c->post_bit_error.len = 1; 26990d5d2e3SAntti Palosaari c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 27090d5d2e3SAntti Palosaari } 27190d5d2e3SAntti Palosaari 27227cfc85eSAntti Palosaari return ret; 27327cfc85eSAntti Palosaari error: 274c98975f9SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 27527cfc85eSAntti Palosaari return ret; 27627cfc85eSAntti Palosaari } 27727cfc85eSAntti Palosaari 2789ac51c5eSSteve Kerrison int cxd2820r_init_c(struct dvb_frontend *fe) 27927cfc85eSAntti Palosaari { 28027cfc85eSAntti Palosaari struct cxd2820r_priv *priv = fe->demodulator_priv; 281c98975f9SAntti Palosaari struct i2c_client *client = priv->client[0]; 28227cfc85eSAntti Palosaari int ret; 28327cfc85eSAntti Palosaari 284c98975f9SAntti Palosaari dev_dbg(&client->dev, "\n"); 285c98975f9SAntti Palosaari 28643e2ea63SAntti Palosaari ret = regmap_write(priv->regmap[0], 0x0085, 0x07); 28727cfc85eSAntti Palosaari if (ret) 28827cfc85eSAntti Palosaari goto error; 28927cfc85eSAntti Palosaari 29027cfc85eSAntti Palosaari return ret; 29127cfc85eSAntti Palosaari error: 292c98975f9SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 29327cfc85eSAntti Palosaari return ret; 29427cfc85eSAntti Palosaari } 29527cfc85eSAntti Palosaari 2969ac51c5eSSteve Kerrison int cxd2820r_sleep_c(struct dvb_frontend *fe) 29727cfc85eSAntti Palosaari { 29827cfc85eSAntti Palosaari struct cxd2820r_priv *priv = fe->demodulator_priv; 299c98975f9SAntti Palosaari struct i2c_client *client = priv->client[0]; 30043e2ea63SAntti Palosaari int ret; 301*ed4e1569SColin Ian King static const struct reg_val_mask tab[] = { 30227cfc85eSAntti Palosaari { 0x000ff, 0x1f, 0xff }, 30327cfc85eSAntti Palosaari { 0x00085, 0x00, 0xff }, 30427cfc85eSAntti Palosaari { 0x00088, 0x01, 0xff }, 30527cfc85eSAntti Palosaari { 0x00081, 0x00, 0xff }, 30627cfc85eSAntti Palosaari { 0x00080, 0x00, 0xff }, 30727cfc85eSAntti Palosaari }; 30827cfc85eSAntti Palosaari 309c98975f9SAntti Palosaari dev_dbg(&client->dev, "\n"); 31027cfc85eSAntti Palosaari 31127cfc85eSAntti Palosaari priv->delivery_system = SYS_UNDEFINED; 31227cfc85eSAntti Palosaari 31343e2ea63SAntti Palosaari ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab)); 31427cfc85eSAntti Palosaari if (ret) 31527cfc85eSAntti Palosaari goto error; 31627cfc85eSAntti Palosaari 31727cfc85eSAntti Palosaari return ret; 31827cfc85eSAntti Palosaari error: 319c98975f9SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 32027cfc85eSAntti Palosaari return ret; 32127cfc85eSAntti Palosaari } 32227cfc85eSAntti Palosaari 3239ac51c5eSSteve Kerrison int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe, 32427cfc85eSAntti Palosaari struct dvb_frontend_tune_settings *s) 32527cfc85eSAntti Palosaari { 32627cfc85eSAntti Palosaari s->min_delay_ms = 500; 32727cfc85eSAntti Palosaari s->step_size = 0; /* no zigzag */ 32827cfc85eSAntti Palosaari s->max_drift = 0; 32927cfc85eSAntti Palosaari 33027cfc85eSAntti Palosaari return 0; 33127cfc85eSAntti Palosaari } 332