1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
294d0eaa4SAntti Palosaari /*
394d0eaa4SAntti Palosaari  * Panasonic MN88472 DVB-T/T2/C demodulator driver
494d0eaa4SAntti Palosaari  *
594d0eaa4SAntti Palosaari  * Copyright (C) 2013 Antti Palosaari <crope@iki.fi>
694d0eaa4SAntti Palosaari  */
794d0eaa4SAntti Palosaari 
894d0eaa4SAntti Palosaari #include "mn88472_priv.h"
994d0eaa4SAntti Palosaari 
mn88472_get_tune_settings(struct dvb_frontend * fe,struct dvb_frontend_tune_settings * s)1094d0eaa4SAntti Palosaari static int mn88472_get_tune_settings(struct dvb_frontend *fe,
1194d0eaa4SAntti Palosaari 				     struct dvb_frontend_tune_settings *s)
1294d0eaa4SAntti Palosaari {
1394d0eaa4SAntti Palosaari 	s->min_delay_ms = 1000;
1494d0eaa4SAntti Palosaari 	return 0;
1594d0eaa4SAntti Palosaari }
1694d0eaa4SAntti Palosaari 
mn88472_read_status(struct dvb_frontend * fe,enum fe_status * status)1794d0eaa4SAntti Palosaari static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status)
1894d0eaa4SAntti Palosaari {
1994d0eaa4SAntti Palosaari 	struct i2c_client *client = fe->demodulator_priv;
2094d0eaa4SAntti Palosaari 	struct mn88472_dev *dev = i2c_get_clientdata(client);
2194d0eaa4SAntti Palosaari 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
22c635a5e2SAntti Palosaari 	int ret, i, stmp;
23c635a5e2SAntti Palosaari 	unsigned int utmp, utmp1, utmp2;
24c635a5e2SAntti Palosaari 	u8 buf[5];
2594d0eaa4SAntti Palosaari 
2694d0eaa4SAntti Palosaari 	if (!dev->active) {
2794d0eaa4SAntti Palosaari 		ret = -EAGAIN;
2894d0eaa4SAntti Palosaari 		goto err;
2994d0eaa4SAntti Palosaari 	}
3094d0eaa4SAntti Palosaari 
3194d0eaa4SAntti Palosaari 	switch (c->delivery_system) {
3294d0eaa4SAntti Palosaari 	case SYS_DVBT:
3394d0eaa4SAntti Palosaari 		ret = regmap_read(dev->regmap[0], 0x7f, &utmp);
3494d0eaa4SAntti Palosaari 		if (ret)
3594d0eaa4SAntti Palosaari 			goto err;
3694d0eaa4SAntti Palosaari 		if ((utmp & 0x0f) >= 0x09)
3794d0eaa4SAntti Palosaari 			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
3894d0eaa4SAntti Palosaari 				  FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
3994d0eaa4SAntti Palosaari 		else
4094d0eaa4SAntti Palosaari 			*status = 0;
4194d0eaa4SAntti Palosaari 		break;
4294d0eaa4SAntti Palosaari 	case SYS_DVBT2:
4394d0eaa4SAntti Palosaari 		ret = regmap_read(dev->regmap[2], 0x92, &utmp);
4494d0eaa4SAntti Palosaari 		if (ret)
4594d0eaa4SAntti Palosaari 			goto err;
4694d0eaa4SAntti Palosaari 		if ((utmp & 0x0f) >= 0x0d)
4794d0eaa4SAntti Palosaari 			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
4894d0eaa4SAntti Palosaari 				  FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
4994d0eaa4SAntti Palosaari 		else if ((utmp & 0x0f) >= 0x0a)
5094d0eaa4SAntti Palosaari 			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
5194d0eaa4SAntti Palosaari 				  FE_HAS_VITERBI;
5294d0eaa4SAntti Palosaari 		else if ((utmp & 0x0f) >= 0x07)
5394d0eaa4SAntti Palosaari 			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
5494d0eaa4SAntti Palosaari 		else
5594d0eaa4SAntti Palosaari 			*status = 0;
5694d0eaa4SAntti Palosaari 		break;
5794d0eaa4SAntti Palosaari 	case SYS_DVBC_ANNEX_A:
5894d0eaa4SAntti Palosaari 		ret = regmap_read(dev->regmap[1], 0x84, &utmp);
5994d0eaa4SAntti Palosaari 		if (ret)
6094d0eaa4SAntti Palosaari 			goto err;
6194d0eaa4SAntti Palosaari 		if ((utmp & 0x0f) >= 0x08)
6294d0eaa4SAntti Palosaari 			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
6394d0eaa4SAntti Palosaari 				  FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
6494d0eaa4SAntti Palosaari 		else
6594d0eaa4SAntti Palosaari 			*status = 0;
6694d0eaa4SAntti Palosaari 		break;
6794d0eaa4SAntti Palosaari 	default:
6894d0eaa4SAntti Palosaari 		ret = -EINVAL;
6994d0eaa4SAntti Palosaari 		goto err;
7094d0eaa4SAntti Palosaari 	}
7194d0eaa4SAntti Palosaari 
7261d7c6aaSAntti Palosaari 	/* Signal strength */
7361d7c6aaSAntti Palosaari 	if (*status & FE_HAS_SIGNAL) {
7461d7c6aaSAntti Palosaari 		for (i = 0; i < 2; i++) {
7561d7c6aaSAntti Palosaari 			ret = regmap_bulk_read(dev->regmap[2], 0x8e + i,
7661d7c6aaSAntti Palosaari 					       &buf[i], 1);
7761d7c6aaSAntti Palosaari 			if (ret)
7861d7c6aaSAntti Palosaari 				goto err;
7961d7c6aaSAntti Palosaari 		}
8061d7c6aaSAntti Palosaari 
8161d7c6aaSAntti Palosaari 		utmp1 = buf[0] << 8 | buf[1] << 0 | buf[0] >> 2;
8261d7c6aaSAntti Palosaari 		dev_dbg(&client->dev, "strength=%u\n", utmp1);
8361d7c6aaSAntti Palosaari 
8461d7c6aaSAntti Palosaari 		c->strength.stat[0].scale = FE_SCALE_RELATIVE;
8561d7c6aaSAntti Palosaari 		c->strength.stat[0].uvalue = utmp1;
8661d7c6aaSAntti Palosaari 	} else {
8761d7c6aaSAntti Palosaari 		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
8861d7c6aaSAntti Palosaari 	}
8961d7c6aaSAntti Palosaari 
90c635a5e2SAntti Palosaari 	/* CNR */
91c635a5e2SAntti Palosaari 	if (*status & FE_HAS_VITERBI && c->delivery_system == SYS_DVBT) {
92c635a5e2SAntti Palosaari 		/* DVB-T CNR */
93c635a5e2SAntti Palosaari 		ret = regmap_bulk_read(dev->regmap[0], 0x9c, buf, 2);
94c635a5e2SAntti Palosaari 		if (ret)
95c635a5e2SAntti Palosaari 			goto err;
96c635a5e2SAntti Palosaari 
97c635a5e2SAntti Palosaari 		utmp = buf[0] << 8 | buf[1] << 0;
98c635a5e2SAntti Palosaari 		if (utmp) {
99c635a5e2SAntti Palosaari 			/* CNR[dB]: 10 * log10(65536 / value) + 2 */
100c635a5e2SAntti Palosaari 			/* log10(65536) = 80807124, 0.2 = 3355443 */
101c635a5e2SAntti Palosaari 			stmp = ((u64)80807124 - intlog10(utmp) + 3355443)
102c635a5e2SAntti Palosaari 			       * 10000 >> 24;
103c635a5e2SAntti Palosaari 
104c635a5e2SAntti Palosaari 			dev_dbg(&client->dev, "cnr=%d value=%u\n", stmp, utmp);
105c635a5e2SAntti Palosaari 		} else {
106c635a5e2SAntti Palosaari 			stmp = 0;
107c635a5e2SAntti Palosaari 		}
108c635a5e2SAntti Palosaari 
109c635a5e2SAntti Palosaari 		c->cnr.stat[0].svalue = stmp;
110c635a5e2SAntti Palosaari 		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
111c635a5e2SAntti Palosaari 	} else if (*status & FE_HAS_VITERBI &&
112c635a5e2SAntti Palosaari 		   c->delivery_system == SYS_DVBT2) {
113c635a5e2SAntti Palosaari 		/* DVB-T2 CNR */
114c635a5e2SAntti Palosaari 		for (i = 0; i < 3; i++) {
115c635a5e2SAntti Palosaari 			ret = regmap_bulk_read(dev->regmap[2], 0xbc + i,
116c635a5e2SAntti Palosaari 					       &buf[i], 1);
117c635a5e2SAntti Palosaari 			if (ret)
118c635a5e2SAntti Palosaari 				goto err;
119c635a5e2SAntti Palosaari 		}
120c635a5e2SAntti Palosaari 
121c635a5e2SAntti Palosaari 		utmp = buf[1] << 8 | buf[2] << 0;
122c635a5e2SAntti Palosaari 		utmp1 = (buf[0] >> 2) & 0x01; /* 0=SISO, 1=MISO */
123c635a5e2SAntti Palosaari 		if (utmp) {
124c635a5e2SAntti Palosaari 			if (utmp1) {
125c635a5e2SAntti Palosaari 				/* CNR[dB]: 10 * log10(16384 / value) - 6 */
126c635a5e2SAntti Palosaari 				/* log10(16384) = 70706234, 0.6 = 10066330 */
127c635a5e2SAntti Palosaari 				stmp = ((u64)70706234 - intlog10(utmp)
128c635a5e2SAntti Palosaari 				       - 10066330) * 10000 >> 24;
129c635a5e2SAntti Palosaari 				dev_dbg(&client->dev, "cnr=%d value=%u MISO\n",
130c635a5e2SAntti Palosaari 					stmp, utmp);
131c635a5e2SAntti Palosaari 			} else {
132c635a5e2SAntti Palosaari 				/* CNR[dB]: 10 * log10(65536 / value) + 2 */
133c635a5e2SAntti Palosaari 				/* log10(65536) = 80807124, 0.2 = 3355443 */
134c635a5e2SAntti Palosaari 				stmp = ((u64)80807124 - intlog10(utmp)
135c635a5e2SAntti Palosaari 				       + 3355443) * 10000 >> 24;
136c635a5e2SAntti Palosaari 
137c635a5e2SAntti Palosaari 				dev_dbg(&client->dev, "cnr=%d value=%u SISO\n",
138c635a5e2SAntti Palosaari 					stmp, utmp);
139c635a5e2SAntti Palosaari 			}
140c635a5e2SAntti Palosaari 		} else {
141c635a5e2SAntti Palosaari 			stmp = 0;
142c635a5e2SAntti Palosaari 		}
143c635a5e2SAntti Palosaari 
144c635a5e2SAntti Palosaari 		c->cnr.stat[0].svalue = stmp;
145c635a5e2SAntti Palosaari 		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
146c635a5e2SAntti Palosaari 	} else if (*status & FE_HAS_VITERBI &&
147c635a5e2SAntti Palosaari 		   c->delivery_system == SYS_DVBC_ANNEX_A) {
148c635a5e2SAntti Palosaari 		/* DVB-C CNR */
149c635a5e2SAntti Palosaari 		ret = regmap_bulk_read(dev->regmap[1], 0xa1, buf, 4);
150c635a5e2SAntti Palosaari 		if (ret)
151c635a5e2SAntti Palosaari 			goto err;
152c635a5e2SAntti Palosaari 
153c635a5e2SAntti Palosaari 		utmp1 = buf[0] << 8 | buf[1] << 0; /* signal */
154c635a5e2SAntti Palosaari 		utmp2 = buf[2] << 8 | buf[3] << 0; /* noise */
155c635a5e2SAntti Palosaari 		if (utmp1 && utmp2) {
156c635a5e2SAntti Palosaari 			/* CNR[dB]: 10 * log10(8 * (signal / noise)) */
157c635a5e2SAntti Palosaari 			/* log10(8) = 15151336 */
158c635a5e2SAntti Palosaari 			stmp = ((u64)15151336 + intlog10(utmp1)
159c635a5e2SAntti Palosaari 			       - intlog10(utmp2)) * 10000 >> 24;
160c635a5e2SAntti Palosaari 
161c635a5e2SAntti Palosaari 			dev_dbg(&client->dev, "cnr=%d signal=%u noise=%u\n",
162c635a5e2SAntti Palosaari 				stmp, utmp1, utmp2);
163c635a5e2SAntti Palosaari 		} else {
164c635a5e2SAntti Palosaari 			stmp = 0;
165c635a5e2SAntti Palosaari 		}
166c635a5e2SAntti Palosaari 
167c635a5e2SAntti Palosaari 		c->cnr.stat[0].svalue = stmp;
168c635a5e2SAntti Palosaari 		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
169c635a5e2SAntti Palosaari 	} else {
170c635a5e2SAntti Palosaari 		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
171c635a5e2SAntti Palosaari 	}
172c635a5e2SAntti Palosaari 
1730fc66c19SAntti Palosaari 	/* PER */
1740fc66c19SAntti Palosaari 	if (*status & FE_HAS_SYNC) {
1750fc66c19SAntti Palosaari 		ret = regmap_bulk_read(dev->regmap[0], 0xe1, buf, 4);
1760fc66c19SAntti Palosaari 		if (ret)
1770fc66c19SAntti Palosaari 			goto err;
1780fc66c19SAntti Palosaari 
1790fc66c19SAntti Palosaari 		utmp1 = buf[0] << 8 | buf[1] << 0;
1800fc66c19SAntti Palosaari 		utmp2 = buf[2] << 8 | buf[3] << 0;
1810fc66c19SAntti Palosaari 		dev_dbg(&client->dev, "block_error=%u block_count=%u\n",
1820fc66c19SAntti Palosaari 			utmp1, utmp2);
1830fc66c19SAntti Palosaari 
1840fc66c19SAntti Palosaari 		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1850fc66c19SAntti Palosaari 		c->block_error.stat[0].uvalue += utmp1;
1860fc66c19SAntti Palosaari 		c->block_count.stat[0].scale = FE_SCALE_COUNTER;
1870fc66c19SAntti Palosaari 		c->block_count.stat[0].uvalue += utmp2;
1880fc66c19SAntti Palosaari 	} else {
1890fc66c19SAntti Palosaari 		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1900fc66c19SAntti Palosaari 		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1910fc66c19SAntti Palosaari 	}
1920fc66c19SAntti Palosaari 
19394d0eaa4SAntti Palosaari 	return 0;
19494d0eaa4SAntti Palosaari err:
19594d0eaa4SAntti Palosaari 	dev_dbg(&client->dev, "failed=%d\n", ret);
19694d0eaa4SAntti Palosaari 	return ret;
19794d0eaa4SAntti Palosaari }
19894d0eaa4SAntti Palosaari 
mn88472_set_frontend(struct dvb_frontend * fe)19994d0eaa4SAntti Palosaari static int mn88472_set_frontend(struct dvb_frontend *fe)
20094d0eaa4SAntti Palosaari {
20194d0eaa4SAntti Palosaari 	struct i2c_client *client = fe->demodulator_priv;
20294d0eaa4SAntti Palosaari 	struct mn88472_dev *dev = i2c_get_clientdata(client);
20394d0eaa4SAntti Palosaari 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
20494d0eaa4SAntti Palosaari 	int ret, i;
20594d0eaa4SAntti Palosaari 	unsigned int utmp;
20694d0eaa4SAntti Palosaari 	u32 if_frequency;
20794d0eaa4SAntti Palosaari 	u8 buf[3], delivery_system_val, bandwidth_val, *bandwidth_vals_ptr;
20894d0eaa4SAntti Palosaari 	u8 reg_bank0_b4_val, reg_bank0_cd_val, reg_bank0_d4_val;
20994d0eaa4SAntti Palosaari 	u8 reg_bank0_d6_val;
21094d0eaa4SAntti Palosaari 
21194d0eaa4SAntti Palosaari 	dev_dbg(&client->dev,
21294d0eaa4SAntti Palosaari 		"delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%d stream_id=%d\n",
21394d0eaa4SAntti Palosaari 		c->delivery_system, c->modulation, c->frequency,
21494d0eaa4SAntti Palosaari 		c->bandwidth_hz, c->symbol_rate, c->inversion, c->stream_id);
21594d0eaa4SAntti Palosaari 
21694d0eaa4SAntti Palosaari 	if (!dev->active) {
21794d0eaa4SAntti Palosaari 		ret = -EAGAIN;
21894d0eaa4SAntti Palosaari 		goto err;
21994d0eaa4SAntti Palosaari 	}
22094d0eaa4SAntti Palosaari 
22194d0eaa4SAntti Palosaari 	switch (c->delivery_system) {
22294d0eaa4SAntti Palosaari 	case SYS_DVBT:
22394d0eaa4SAntti Palosaari 		delivery_system_val = 0x02;
22494d0eaa4SAntti Palosaari 		reg_bank0_b4_val = 0x00;
22594d0eaa4SAntti Palosaari 		reg_bank0_cd_val = 0x1f;
22694d0eaa4SAntti Palosaari 		reg_bank0_d4_val = 0x0a;
22794d0eaa4SAntti Palosaari 		reg_bank0_d6_val = 0x48;
22894d0eaa4SAntti Palosaari 		break;
22994d0eaa4SAntti Palosaari 	case SYS_DVBT2:
23094d0eaa4SAntti Palosaari 		delivery_system_val = 0x03;
23194d0eaa4SAntti Palosaari 		reg_bank0_b4_val = 0xf6;
23294d0eaa4SAntti Palosaari 		reg_bank0_cd_val = 0x01;
23394d0eaa4SAntti Palosaari 		reg_bank0_d4_val = 0x09;
23494d0eaa4SAntti Palosaari 		reg_bank0_d6_val = 0x46;
23594d0eaa4SAntti Palosaari 		break;
23694d0eaa4SAntti Palosaari 	case SYS_DVBC_ANNEX_A:
23794d0eaa4SAntti Palosaari 		delivery_system_val = 0x04;
23894d0eaa4SAntti Palosaari 		reg_bank0_b4_val = 0x00;
23994d0eaa4SAntti Palosaari 		reg_bank0_cd_val = 0x17;
24094d0eaa4SAntti Palosaari 		reg_bank0_d4_val = 0x09;
24194d0eaa4SAntti Palosaari 		reg_bank0_d6_val = 0x48;
24294d0eaa4SAntti Palosaari 		break;
24394d0eaa4SAntti Palosaari 	default:
24494d0eaa4SAntti Palosaari 		ret = -EINVAL;
24594d0eaa4SAntti Palosaari 		goto err;
24694d0eaa4SAntti Palosaari 	}
24794d0eaa4SAntti Palosaari 
24894d0eaa4SAntti Palosaari 	switch (c->delivery_system) {
24994d0eaa4SAntti Palosaari 	case SYS_DVBT:
25094d0eaa4SAntti Palosaari 	case SYS_DVBT2:
25194d0eaa4SAntti Palosaari 		switch (c->bandwidth_hz) {
25294d0eaa4SAntti Palosaari 		case 5000000:
25394d0eaa4SAntti Palosaari 			bandwidth_vals_ptr = "\xe5\x99\x9a\x1b\xa9\x1b\xa9";
25494d0eaa4SAntti Palosaari 			bandwidth_val = 0x03;
25594d0eaa4SAntti Palosaari 			break;
25694d0eaa4SAntti Palosaari 		case 6000000:
25794d0eaa4SAntti Palosaari 			bandwidth_vals_ptr = "\xbf\x55\x55\x15\x6b\x15\x6b";
25894d0eaa4SAntti Palosaari 			bandwidth_val = 0x02;
25994d0eaa4SAntti Palosaari 			break;
26094d0eaa4SAntti Palosaari 		case 7000000:
26194d0eaa4SAntti Palosaari 			bandwidth_vals_ptr = "\xa4\x00\x00\x0f\x2c\x0f\x2c";
26294d0eaa4SAntti Palosaari 			bandwidth_val = 0x01;
26394d0eaa4SAntti Palosaari 			break;
26494d0eaa4SAntti Palosaari 		case 8000000:
26594d0eaa4SAntti Palosaari 			bandwidth_vals_ptr = "\x8f\x80\x00\x08\xee\x08\xee";
26694d0eaa4SAntti Palosaari 			bandwidth_val = 0x00;
26794d0eaa4SAntti Palosaari 			break;
26894d0eaa4SAntti Palosaari 		default:
26994d0eaa4SAntti Palosaari 			ret = -EINVAL;
27094d0eaa4SAntti Palosaari 			goto err;
27194d0eaa4SAntti Palosaari 		}
27294d0eaa4SAntti Palosaari 		break;
27394d0eaa4SAntti Palosaari 	case SYS_DVBC_ANNEX_A:
27494d0eaa4SAntti Palosaari 		bandwidth_vals_ptr = NULL;
27594d0eaa4SAntti Palosaari 		bandwidth_val = 0x00;
27694d0eaa4SAntti Palosaari 		break;
27794d0eaa4SAntti Palosaari 	default:
27894d0eaa4SAntti Palosaari 		break;
27994d0eaa4SAntti Palosaari 	}
28094d0eaa4SAntti Palosaari 
28194d0eaa4SAntti Palosaari 	/* Program tuner */
28294d0eaa4SAntti Palosaari 	if (fe->ops.tuner_ops.set_params) {
28394d0eaa4SAntti Palosaari 		ret = fe->ops.tuner_ops.set_params(fe);
28494d0eaa4SAntti Palosaari 		if (ret)
28594d0eaa4SAntti Palosaari 			goto err;
28694d0eaa4SAntti Palosaari 	}
28794d0eaa4SAntti Palosaari 
28894d0eaa4SAntti Palosaari 	if (fe->ops.tuner_ops.get_if_frequency) {
28994d0eaa4SAntti Palosaari 		ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
29094d0eaa4SAntti Palosaari 		if (ret)
29194d0eaa4SAntti Palosaari 			goto err;
29294d0eaa4SAntti Palosaari 
29394d0eaa4SAntti Palosaari 		dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency);
29494d0eaa4SAntti Palosaari 	} else {
29594d0eaa4SAntti Palosaari 		ret = -EINVAL;
29694d0eaa4SAntti Palosaari 		goto err;
29794d0eaa4SAntti Palosaari 	}
29894d0eaa4SAntti Palosaari 
29994d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0x00, 0x66);
30094d0eaa4SAntti Palosaari 	if (ret)
30194d0eaa4SAntti Palosaari 		goto err;
30294d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0x01, 0x00);
30394d0eaa4SAntti Palosaari 	if (ret)
30494d0eaa4SAntti Palosaari 		goto err;
30594d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0x02, 0x01);
30694d0eaa4SAntti Palosaari 	if (ret)
30794d0eaa4SAntti Palosaari 		goto err;
30894d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val);
30994d0eaa4SAntti Palosaari 	if (ret)
31094d0eaa4SAntti Palosaari 		goto err;
31194d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0x04, bandwidth_val);
31294d0eaa4SAntti Palosaari 	if (ret)
31394d0eaa4SAntti Palosaari 		goto err;
31494d0eaa4SAntti Palosaari 
31594d0eaa4SAntti Palosaari 	/* IF */
31694d0eaa4SAntti Palosaari 	utmp = DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x1000000, dev->clk);
31794d0eaa4SAntti Palosaari 	buf[0] = (utmp >> 16) & 0xff;
31894d0eaa4SAntti Palosaari 	buf[1] = (utmp >>  8) & 0xff;
31994d0eaa4SAntti Palosaari 	buf[2] = (utmp >>  0) & 0xff;
32094d0eaa4SAntti Palosaari 	for (i = 0; i < 3; i++) {
32194d0eaa4SAntti Palosaari 		ret = regmap_write(dev->regmap[2], 0x10 + i, buf[i]);
32294d0eaa4SAntti Palosaari 		if (ret)
32394d0eaa4SAntti Palosaari 			goto err;
32494d0eaa4SAntti Palosaari 	}
32594d0eaa4SAntti Palosaari 
32694d0eaa4SAntti Palosaari 	/* Bandwidth */
32794d0eaa4SAntti Palosaari 	if (bandwidth_vals_ptr) {
32894d0eaa4SAntti Palosaari 		for (i = 0; i < 7; i++) {
32994d0eaa4SAntti Palosaari 			ret = regmap_write(dev->regmap[2], 0x13 + i,
33094d0eaa4SAntti Palosaari 					   bandwidth_vals_ptr[i]);
33194d0eaa4SAntti Palosaari 			if (ret)
33294d0eaa4SAntti Palosaari 				goto err;
33394d0eaa4SAntti Palosaari 		}
33494d0eaa4SAntti Palosaari 	}
33594d0eaa4SAntti Palosaari 
33694d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[0], 0xb4, reg_bank0_b4_val);
33794d0eaa4SAntti Palosaari 	if (ret)
33894d0eaa4SAntti Palosaari 		goto err;
33994d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[0], 0xcd, reg_bank0_cd_val);
34094d0eaa4SAntti Palosaari 	if (ret)
34194d0eaa4SAntti Palosaari 		goto err;
34294d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[0], 0xd4, reg_bank0_d4_val);
34394d0eaa4SAntti Palosaari 	if (ret)
34494d0eaa4SAntti Palosaari 		goto err;
34594d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[0], 0xd6, reg_bank0_d6_val);
34694d0eaa4SAntti Palosaari 	if (ret)
34794d0eaa4SAntti Palosaari 		goto err;
34894d0eaa4SAntti Palosaari 
34994d0eaa4SAntti Palosaari 	switch (c->delivery_system) {
35094d0eaa4SAntti Palosaari 	case SYS_DVBT:
35194d0eaa4SAntti Palosaari 		ret = regmap_write(dev->regmap[0], 0x07, 0x26);
35294d0eaa4SAntti Palosaari 		if (ret)
35394d0eaa4SAntti Palosaari 			goto err;
35494d0eaa4SAntti Palosaari 		ret = regmap_write(dev->regmap[0], 0x00, 0xba);
35594d0eaa4SAntti Palosaari 		if (ret)
35694d0eaa4SAntti Palosaari 			goto err;
35794d0eaa4SAntti Palosaari 		ret = regmap_write(dev->regmap[0], 0x01, 0x13);
35894d0eaa4SAntti Palosaari 		if (ret)
35994d0eaa4SAntti Palosaari 			goto err;
36094d0eaa4SAntti Palosaari 		break;
36194d0eaa4SAntti Palosaari 	case SYS_DVBT2:
36294d0eaa4SAntti Palosaari 		ret = regmap_write(dev->regmap[2], 0x2b, 0x13);
36394d0eaa4SAntti Palosaari 		if (ret)
36494d0eaa4SAntti Palosaari 			goto err;
36594d0eaa4SAntti Palosaari 		ret = regmap_write(dev->regmap[2], 0x4f, 0x05);
36694d0eaa4SAntti Palosaari 		if (ret)
36794d0eaa4SAntti Palosaari 			goto err;
36894d0eaa4SAntti Palosaari 		ret = regmap_write(dev->regmap[1], 0xf6, 0x05);
36994d0eaa4SAntti Palosaari 		if (ret)
37094d0eaa4SAntti Palosaari 			goto err;
37107d45a42SOlli Salonen 		ret = regmap_write(dev->regmap[2], 0x32,
37207d45a42SOlli Salonen 				(c->stream_id == NO_STREAM_ID_FILTER) ? 0 :
37307d45a42SOlli Salonen 				c->stream_id );
37494d0eaa4SAntti Palosaari 		if (ret)
37594d0eaa4SAntti Palosaari 			goto err;
37694d0eaa4SAntti Palosaari 		break;
37794d0eaa4SAntti Palosaari 	case SYS_DVBC_ANNEX_A:
37894d0eaa4SAntti Palosaari 		break;
37994d0eaa4SAntti Palosaari 	default:
38094d0eaa4SAntti Palosaari 		break;
38194d0eaa4SAntti Palosaari 	}
38294d0eaa4SAntti Palosaari 
38394d0eaa4SAntti Palosaari 	/* Reset FSM */
38494d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0xf8, 0x9f);
38594d0eaa4SAntti Palosaari 	if (ret)
38694d0eaa4SAntti Palosaari 		goto err;
38794d0eaa4SAntti Palosaari 
38894d0eaa4SAntti Palosaari 	return 0;
38994d0eaa4SAntti Palosaari err:
39094d0eaa4SAntti Palosaari 	dev_dbg(&client->dev, "failed=%d\n", ret);
39194d0eaa4SAntti Palosaari 	return ret;
39294d0eaa4SAntti Palosaari }
39394d0eaa4SAntti Palosaari 
mn88472_init(struct dvb_frontend * fe)39494d0eaa4SAntti Palosaari static int mn88472_init(struct dvb_frontend *fe)
39594d0eaa4SAntti Palosaari {
39694d0eaa4SAntti Palosaari 	struct i2c_client *client = fe->demodulator_priv;
39794d0eaa4SAntti Palosaari 	struct mn88472_dev *dev = i2c_get_clientdata(client);
39894d0eaa4SAntti Palosaari 	int ret, len, rem;
39994d0eaa4SAntti Palosaari 	unsigned int utmp;
40094d0eaa4SAntti Palosaari 	const struct firmware *firmware;
40194d0eaa4SAntti Palosaari 	const char *name = MN88472_FIRMWARE;
40294d0eaa4SAntti Palosaari 
40394d0eaa4SAntti Palosaari 	dev_dbg(&client->dev, "\n");
40494d0eaa4SAntti Palosaari 
40594d0eaa4SAntti Palosaari 	/* Power up */
40694d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0x05, 0x00);
40794d0eaa4SAntti Palosaari 	if (ret)
40894d0eaa4SAntti Palosaari 		goto err;
40994d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0x0b, 0x00);
41094d0eaa4SAntti Palosaari 	if (ret)
41194d0eaa4SAntti Palosaari 		goto err;
41294d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0x0c, 0x00);
41394d0eaa4SAntti Palosaari 	if (ret)
41494d0eaa4SAntti Palosaari 		goto err;
41594d0eaa4SAntti Palosaari 
41694d0eaa4SAntti Palosaari 	/* Check if firmware is already running */
41794d0eaa4SAntti Palosaari 	ret = regmap_read(dev->regmap[0], 0xf5, &utmp);
41894d0eaa4SAntti Palosaari 	if (ret)
41994d0eaa4SAntti Palosaari 		goto err;
42094d0eaa4SAntti Palosaari 	if (!(utmp & 0x01))
42194d0eaa4SAntti Palosaari 		goto warm;
42294d0eaa4SAntti Palosaari 
42394d0eaa4SAntti Palosaari 	ret = request_firmware(&firmware, name, &client->dev);
42494d0eaa4SAntti Palosaari 	if (ret) {
42594d0eaa4SAntti Palosaari 		dev_err(&client->dev, "firmware file '%s' not found\n", name);
42694d0eaa4SAntti Palosaari 		goto err;
42794d0eaa4SAntti Palosaari 	}
42894d0eaa4SAntti Palosaari 
42994d0eaa4SAntti Palosaari 	dev_info(&client->dev, "downloading firmware from file '%s'\n", name);
43094d0eaa4SAntti Palosaari 
43194d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[0], 0xf5, 0x03);
43294d0eaa4SAntti Palosaari 	if (ret)
43394d0eaa4SAntti Palosaari 		goto err_release_firmware;
43494d0eaa4SAntti Palosaari 
43594d0eaa4SAntti Palosaari 	for (rem = firmware->size; rem > 0; rem -= (dev->i2c_write_max - 1)) {
43694d0eaa4SAntti Palosaari 		len = min(dev->i2c_write_max - 1, rem);
43794d0eaa4SAntti Palosaari 		ret = regmap_bulk_write(dev->regmap[0], 0xf6,
43894d0eaa4SAntti Palosaari 					&firmware->data[firmware->size - rem],
43994d0eaa4SAntti Palosaari 					len);
44094d0eaa4SAntti Palosaari 		if (ret) {
44194d0eaa4SAntti Palosaari 			dev_err(&client->dev, "firmware download failed %d\n",
44294d0eaa4SAntti Palosaari 				ret);
44394d0eaa4SAntti Palosaari 			goto err_release_firmware;
44494d0eaa4SAntti Palosaari 		}
44594d0eaa4SAntti Palosaari 	}
44694d0eaa4SAntti Palosaari 
44794d0eaa4SAntti Palosaari 	/* Parity check of firmware */
44894d0eaa4SAntti Palosaari 	ret = regmap_read(dev->regmap[0], 0xf8, &utmp);
44994d0eaa4SAntti Palosaari 	if (ret)
45094d0eaa4SAntti Palosaari 		goto err_release_firmware;
45194d0eaa4SAntti Palosaari 	if (utmp & 0x10) {
45294d0eaa4SAntti Palosaari 		ret = -EINVAL;
45394d0eaa4SAntti Palosaari 		dev_err(&client->dev, "firmware did not run\n");
45494d0eaa4SAntti Palosaari 		goto err_release_firmware;
45594d0eaa4SAntti Palosaari 	}
45694d0eaa4SAntti Palosaari 
45794d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[0], 0xf5, 0x00);
45894d0eaa4SAntti Palosaari 	if (ret)
45994d0eaa4SAntti Palosaari 		goto err_release_firmware;
46094d0eaa4SAntti Palosaari 
46194d0eaa4SAntti Palosaari 	release_firmware(firmware);
46294d0eaa4SAntti Palosaari warm:
46394d0eaa4SAntti Palosaari 	/* TS config */
46494d0eaa4SAntti Palosaari 	switch (dev->ts_mode) {
46594d0eaa4SAntti Palosaari 	case SERIAL_TS_MODE:
46694d0eaa4SAntti Palosaari 		utmp = 0x1d;
46794d0eaa4SAntti Palosaari 		break;
46894d0eaa4SAntti Palosaari 	case PARALLEL_TS_MODE:
46994d0eaa4SAntti Palosaari 		utmp = 0x00;
47094d0eaa4SAntti Palosaari 		break;
47194d0eaa4SAntti Palosaari 	default:
47294d0eaa4SAntti Palosaari 		ret = -EINVAL;
47394d0eaa4SAntti Palosaari 		goto err;
47494d0eaa4SAntti Palosaari 	}
47594d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0x08, utmp);
47694d0eaa4SAntti Palosaari 	if (ret)
47794d0eaa4SAntti Palosaari 		goto err;
47894d0eaa4SAntti Palosaari 
47994d0eaa4SAntti Palosaari 	switch (dev->ts_clk) {
48094d0eaa4SAntti Palosaari 	case VARIABLE_TS_CLOCK:
48194d0eaa4SAntti Palosaari 		utmp = 0xe3;
48294d0eaa4SAntti Palosaari 		break;
48394d0eaa4SAntti Palosaari 	case FIXED_TS_CLOCK:
48494d0eaa4SAntti Palosaari 		utmp = 0xe1;
48594d0eaa4SAntti Palosaari 		break;
48694d0eaa4SAntti Palosaari 	default:
48794d0eaa4SAntti Palosaari 		ret = -EINVAL;
48894d0eaa4SAntti Palosaari 		goto err;
48994d0eaa4SAntti Palosaari 	}
49094d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[0], 0xd9, utmp);
49194d0eaa4SAntti Palosaari 	if (ret)
49294d0eaa4SAntti Palosaari 		goto err;
49394d0eaa4SAntti Palosaari 
49494d0eaa4SAntti Palosaari 	dev->active = true;
49594d0eaa4SAntti Palosaari 
49694d0eaa4SAntti Palosaari 	return 0;
49794d0eaa4SAntti Palosaari err_release_firmware:
49894d0eaa4SAntti Palosaari 	release_firmware(firmware);
49994d0eaa4SAntti Palosaari err:
50094d0eaa4SAntti Palosaari 	dev_dbg(&client->dev, "failed=%d\n", ret);
50194d0eaa4SAntti Palosaari 	return ret;
50294d0eaa4SAntti Palosaari }
50394d0eaa4SAntti Palosaari 
mn88472_sleep(struct dvb_frontend * fe)50494d0eaa4SAntti Palosaari static int mn88472_sleep(struct dvb_frontend *fe)
50594d0eaa4SAntti Palosaari {
50694d0eaa4SAntti Palosaari 	struct i2c_client *client = fe->demodulator_priv;
50794d0eaa4SAntti Palosaari 	struct mn88472_dev *dev = i2c_get_clientdata(client);
50894d0eaa4SAntti Palosaari 	int ret;
50994d0eaa4SAntti Palosaari 
51094d0eaa4SAntti Palosaari 	dev_dbg(&client->dev, "\n");
51194d0eaa4SAntti Palosaari 
51294d0eaa4SAntti Palosaari 	/* Power down */
51394d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0x0c, 0x30);
51494d0eaa4SAntti Palosaari 	if (ret)
51594d0eaa4SAntti Palosaari 		goto err;
51694d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0x0b, 0x30);
51794d0eaa4SAntti Palosaari 	if (ret)
51894d0eaa4SAntti Palosaari 		goto err;
51994d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0x05, 0x3e);
52094d0eaa4SAntti Palosaari 	if (ret)
52194d0eaa4SAntti Palosaari 		goto err;
52294d0eaa4SAntti Palosaari 
52394d0eaa4SAntti Palosaari 	return 0;
52494d0eaa4SAntti Palosaari err:
52594d0eaa4SAntti Palosaari 	dev_dbg(&client->dev, "failed=%d\n", ret);
52694d0eaa4SAntti Palosaari 	return ret;
52794d0eaa4SAntti Palosaari }
52894d0eaa4SAntti Palosaari 
529bd336e63SMax Kellermann static const struct dvb_frontend_ops mn88472_ops = {
53094d0eaa4SAntti Palosaari 	.delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A},
53194d0eaa4SAntti Palosaari 	.info = {
53294d0eaa4SAntti Palosaari 		.name = "Panasonic MN88472",
53394d0eaa4SAntti Palosaari 		.symbol_rate_min = 1000000,
53494d0eaa4SAntti Palosaari 		.symbol_rate_max = 7200000,
53594d0eaa4SAntti Palosaari 		.caps =	FE_CAN_FEC_1_2                 |
53694d0eaa4SAntti Palosaari 			FE_CAN_FEC_2_3                 |
53794d0eaa4SAntti Palosaari 			FE_CAN_FEC_3_4                 |
53894d0eaa4SAntti Palosaari 			FE_CAN_FEC_5_6                 |
53994d0eaa4SAntti Palosaari 			FE_CAN_FEC_7_8                 |
54094d0eaa4SAntti Palosaari 			FE_CAN_FEC_AUTO                |
54194d0eaa4SAntti Palosaari 			FE_CAN_QPSK                    |
54294d0eaa4SAntti Palosaari 			FE_CAN_QAM_16                  |
54394d0eaa4SAntti Palosaari 			FE_CAN_QAM_32                  |
54494d0eaa4SAntti Palosaari 			FE_CAN_QAM_64                  |
54594d0eaa4SAntti Palosaari 			FE_CAN_QAM_128                 |
54694d0eaa4SAntti Palosaari 			FE_CAN_QAM_256                 |
54794d0eaa4SAntti Palosaari 			FE_CAN_QAM_AUTO                |
54894d0eaa4SAntti Palosaari 			FE_CAN_TRANSMISSION_MODE_AUTO  |
54994d0eaa4SAntti Palosaari 			FE_CAN_GUARD_INTERVAL_AUTO     |
55094d0eaa4SAntti Palosaari 			FE_CAN_HIERARCHY_AUTO          |
55194d0eaa4SAntti Palosaari 			FE_CAN_MUTE_TS                 |
55294d0eaa4SAntti Palosaari 			FE_CAN_2G_MODULATION           |
55394d0eaa4SAntti Palosaari 			FE_CAN_MULTISTREAM
55494d0eaa4SAntti Palosaari 	},
55594d0eaa4SAntti Palosaari 
55694d0eaa4SAntti Palosaari 	.get_tune_settings = mn88472_get_tune_settings,
55794d0eaa4SAntti Palosaari 
55894d0eaa4SAntti Palosaari 	.init = mn88472_init,
55994d0eaa4SAntti Palosaari 	.sleep = mn88472_sleep,
56094d0eaa4SAntti Palosaari 
56194d0eaa4SAntti Palosaari 	.set_frontend = mn88472_set_frontend,
56294d0eaa4SAntti Palosaari 
56394d0eaa4SAntti Palosaari 	.read_status = mn88472_read_status,
56494d0eaa4SAntti Palosaari };
56594d0eaa4SAntti Palosaari 
mn88472_get_dvb_frontend(struct i2c_client * client)56694d0eaa4SAntti Palosaari static struct dvb_frontend *mn88472_get_dvb_frontend(struct i2c_client *client)
56794d0eaa4SAntti Palosaari {
56894d0eaa4SAntti Palosaari 	struct mn88472_dev *dev = i2c_get_clientdata(client);
56994d0eaa4SAntti Palosaari 
57094d0eaa4SAntti Palosaari 	dev_dbg(&client->dev, "\n");
57194d0eaa4SAntti Palosaari 
57294d0eaa4SAntti Palosaari 	return &dev->fe;
57394d0eaa4SAntti Palosaari }
57494d0eaa4SAntti Palosaari 
mn88472_probe(struct i2c_client * client)575d5f96d7aSUwe Kleine-König static int mn88472_probe(struct i2c_client *client)
57694d0eaa4SAntti Palosaari {
57794d0eaa4SAntti Palosaari 	struct mn88472_config *pdata = client->dev.platform_data;
57894d0eaa4SAntti Palosaari 	struct mn88472_dev *dev;
57961d7c6aaSAntti Palosaari 	struct dtv_frontend_properties *c;
58094d0eaa4SAntti Palosaari 	int ret;
58194d0eaa4SAntti Palosaari 	unsigned int utmp;
58294d0eaa4SAntti Palosaari 	static const struct regmap_config regmap_config = {
58394d0eaa4SAntti Palosaari 		.reg_bits = 8,
58494d0eaa4SAntti Palosaari 		.val_bits = 8,
58594d0eaa4SAntti Palosaari 	};
58694d0eaa4SAntti Palosaari 
58794d0eaa4SAntti Palosaari 	dev_dbg(&client->dev, "\n");
58894d0eaa4SAntti Palosaari 
58994d0eaa4SAntti Palosaari 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
59094d0eaa4SAntti Palosaari 	if (!dev) {
59194d0eaa4SAntti Palosaari 		ret = -ENOMEM;
59294d0eaa4SAntti Palosaari 		goto err;
59394d0eaa4SAntti Palosaari 	}
59494d0eaa4SAntti Palosaari 
59594d0eaa4SAntti Palosaari 	dev->i2c_write_max = pdata->i2c_wr_max ? pdata->i2c_wr_max : ~0;
59694d0eaa4SAntti Palosaari 	dev->clk = pdata->xtal;
59794d0eaa4SAntti Palosaari 	dev->ts_mode = pdata->ts_mode;
59894d0eaa4SAntti Palosaari 	dev->ts_clk = pdata->ts_clock;
59994d0eaa4SAntti Palosaari 	dev->client[0] = client;
60094d0eaa4SAntti Palosaari 	dev->regmap[0] = regmap_init_i2c(dev->client[0], &regmap_config);
60194d0eaa4SAntti Palosaari 	if (IS_ERR(dev->regmap[0])) {
60294d0eaa4SAntti Palosaari 		ret = PTR_ERR(dev->regmap[0]);
60394d0eaa4SAntti Palosaari 		goto err_kfree;
60494d0eaa4SAntti Palosaari 	}
60594d0eaa4SAntti Palosaari 
60694d0eaa4SAntti Palosaari 	/*
60794d0eaa4SAntti Palosaari 	 * Chip has three I2C addresses for different register banks. Used
60894d0eaa4SAntti Palosaari 	 * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients,
60994d0eaa4SAntti Palosaari 	 * 0x1a and 0x1c, in order to get own I2C client for each register bank.
61094d0eaa4SAntti Palosaari 	 *
61194d0eaa4SAntti Palosaari 	 * Also, register bank 2 do not support sequential I/O. Only single
61294d0eaa4SAntti Palosaari 	 * register write or read is allowed to that bank.
61394d0eaa4SAntti Palosaari 	 */
614f0b0710cSWolfram Sang 	dev->client[1] = i2c_new_dummy_device(client->adapter, 0x1a);
615f0b0710cSWolfram Sang 	if (IS_ERR(dev->client[1])) {
616f0b0710cSWolfram Sang 		ret = PTR_ERR(dev->client[1]);
61794d0eaa4SAntti Palosaari 		dev_err(&client->dev, "I2C registration failed\n");
61894d0eaa4SAntti Palosaari 		goto err_regmap_0_regmap_exit;
61994d0eaa4SAntti Palosaari 	}
62094d0eaa4SAntti Palosaari 	dev->regmap[1] = regmap_init_i2c(dev->client[1], &regmap_config);
62194d0eaa4SAntti Palosaari 	if (IS_ERR(dev->regmap[1])) {
62294d0eaa4SAntti Palosaari 		ret = PTR_ERR(dev->regmap[1]);
62394d0eaa4SAntti Palosaari 		goto err_client_1_i2c_unregister_device;
62494d0eaa4SAntti Palosaari 	}
62594d0eaa4SAntti Palosaari 	i2c_set_clientdata(dev->client[1], dev);
62694d0eaa4SAntti Palosaari 
627f0b0710cSWolfram Sang 	dev->client[2] = i2c_new_dummy_device(client->adapter, 0x1c);
628f0b0710cSWolfram Sang 	if (IS_ERR(dev->client[2])) {
629f0b0710cSWolfram Sang 		ret = PTR_ERR(dev->client[2]);
63094d0eaa4SAntti Palosaari 		dev_err(&client->dev, "2nd I2C registration failed\n");
63194d0eaa4SAntti Palosaari 		goto err_regmap_1_regmap_exit;
63294d0eaa4SAntti Palosaari 	}
63394d0eaa4SAntti Palosaari 	dev->regmap[2] = regmap_init_i2c(dev->client[2], &regmap_config);
63494d0eaa4SAntti Palosaari 	if (IS_ERR(dev->regmap[2])) {
63594d0eaa4SAntti Palosaari 		ret = PTR_ERR(dev->regmap[2]);
63694d0eaa4SAntti Palosaari 		goto err_client_2_i2c_unregister_device;
63794d0eaa4SAntti Palosaari 	}
63894d0eaa4SAntti Palosaari 	i2c_set_clientdata(dev->client[2], dev);
63994d0eaa4SAntti Palosaari 
640365fe4e0SAntti Palosaari 	/* Check demod answers with correct chip id */
641365fe4e0SAntti Palosaari 	ret = regmap_read(dev->regmap[2], 0xff, &utmp);
642365fe4e0SAntti Palosaari 	if (ret)
643365fe4e0SAntti Palosaari 		goto err_regmap_2_regmap_exit;
644365fe4e0SAntti Palosaari 
645365fe4e0SAntti Palosaari 	dev_dbg(&client->dev, "chip id=%02x\n", utmp);
646365fe4e0SAntti Palosaari 
647365fe4e0SAntti Palosaari 	if (utmp != 0x02) {
648365fe4e0SAntti Palosaari 		ret = -ENODEV;
649365fe4e0SAntti Palosaari 		goto err_regmap_2_regmap_exit;
650365fe4e0SAntti Palosaari 	}
651365fe4e0SAntti Palosaari 
65294d0eaa4SAntti Palosaari 	/* Sleep because chip is active by default */
65394d0eaa4SAntti Palosaari 	ret = regmap_write(dev->regmap[2], 0x05, 0x3e);
65494d0eaa4SAntti Palosaari 	if (ret)
65594d0eaa4SAntti Palosaari 		goto err_regmap_2_regmap_exit;
65694d0eaa4SAntti Palosaari 
65794d0eaa4SAntti Palosaari 	/* Create dvb frontend */
65894d0eaa4SAntti Palosaari 	memcpy(&dev->fe.ops, &mn88472_ops, sizeof(struct dvb_frontend_ops));
65994d0eaa4SAntti Palosaari 	dev->fe.demodulator_priv = client;
66094d0eaa4SAntti Palosaari 	*pdata->fe = &dev->fe;
66194d0eaa4SAntti Palosaari 	i2c_set_clientdata(client, dev);
66294d0eaa4SAntti Palosaari 
66361d7c6aaSAntti Palosaari 	/* Init stats to indicate which stats are supported */
66461d7c6aaSAntti Palosaari 	c = &dev->fe.dtv_property_cache;
66561d7c6aaSAntti Palosaari 	c->strength.len = 1;
666c635a5e2SAntti Palosaari 	c->cnr.len = 1;
6670fc66c19SAntti Palosaari 	c->block_error.len = 1;
6680fc66c19SAntti Palosaari 	c->block_count.len = 1;
66961d7c6aaSAntti Palosaari 
67094d0eaa4SAntti Palosaari 	/* Setup callbacks */
67194d0eaa4SAntti Palosaari 	pdata->get_dvb_frontend = mn88472_get_dvb_frontend;
67294d0eaa4SAntti Palosaari 
67394d0eaa4SAntti Palosaari 	dev_info(&client->dev, "Panasonic MN88472 successfully identified\n");
67494d0eaa4SAntti Palosaari 
67594d0eaa4SAntti Palosaari 	return 0;
67694d0eaa4SAntti Palosaari err_regmap_2_regmap_exit:
67794d0eaa4SAntti Palosaari 	regmap_exit(dev->regmap[2]);
67894d0eaa4SAntti Palosaari err_client_2_i2c_unregister_device:
67994d0eaa4SAntti Palosaari 	i2c_unregister_device(dev->client[2]);
68094d0eaa4SAntti Palosaari err_regmap_1_regmap_exit:
68194d0eaa4SAntti Palosaari 	regmap_exit(dev->regmap[1]);
68294d0eaa4SAntti Palosaari err_client_1_i2c_unregister_device:
68394d0eaa4SAntti Palosaari 	i2c_unregister_device(dev->client[1]);
68494d0eaa4SAntti Palosaari err_regmap_0_regmap_exit:
68594d0eaa4SAntti Palosaari 	regmap_exit(dev->regmap[0]);
68694d0eaa4SAntti Palosaari err_kfree:
68794d0eaa4SAntti Palosaari 	kfree(dev);
68894d0eaa4SAntti Palosaari err:
68994d0eaa4SAntti Palosaari 	dev_dbg(&client->dev, "failed=%d\n", ret);
69094d0eaa4SAntti Palosaari 	return ret;
69194d0eaa4SAntti Palosaari }
69294d0eaa4SAntti Palosaari 
mn88472_remove(struct i2c_client * client)693ed5c2f5fSUwe Kleine-König static void mn88472_remove(struct i2c_client *client)
69494d0eaa4SAntti Palosaari {
69594d0eaa4SAntti Palosaari 	struct mn88472_dev *dev = i2c_get_clientdata(client);
69694d0eaa4SAntti Palosaari 
69794d0eaa4SAntti Palosaari 	dev_dbg(&client->dev, "\n");
69894d0eaa4SAntti Palosaari 
69994d0eaa4SAntti Palosaari 	regmap_exit(dev->regmap[2]);
70094d0eaa4SAntti Palosaari 	i2c_unregister_device(dev->client[2]);
70194d0eaa4SAntti Palosaari 
70294d0eaa4SAntti Palosaari 	regmap_exit(dev->regmap[1]);
70394d0eaa4SAntti Palosaari 	i2c_unregister_device(dev->client[1]);
70494d0eaa4SAntti Palosaari 
70594d0eaa4SAntti Palosaari 	regmap_exit(dev->regmap[0]);
70694d0eaa4SAntti Palosaari 
70794d0eaa4SAntti Palosaari 	kfree(dev);
70894d0eaa4SAntti Palosaari }
70994d0eaa4SAntti Palosaari 
71094d0eaa4SAntti Palosaari static const struct i2c_device_id mn88472_id_table[] = {
71194d0eaa4SAntti Palosaari 	{"mn88472", 0},
71294d0eaa4SAntti Palosaari 	{}
71394d0eaa4SAntti Palosaari };
71494d0eaa4SAntti Palosaari MODULE_DEVICE_TABLE(i2c, mn88472_id_table);
71594d0eaa4SAntti Palosaari 
71694d0eaa4SAntti Palosaari static struct i2c_driver mn88472_driver = {
71794d0eaa4SAntti Palosaari 	.driver = {
71894d0eaa4SAntti Palosaari 		.name = "mn88472",
71994d0eaa4SAntti Palosaari 		.suppress_bind_attrs = true,
72094d0eaa4SAntti Palosaari 	},
721*aaeb31c0SUwe Kleine-König 	.probe    = mn88472_probe,
72294d0eaa4SAntti Palosaari 	.remove   = mn88472_remove,
72394d0eaa4SAntti Palosaari 	.id_table = mn88472_id_table,
72494d0eaa4SAntti Palosaari };
72594d0eaa4SAntti Palosaari 
72694d0eaa4SAntti Palosaari module_i2c_driver(mn88472_driver);
72794d0eaa4SAntti Palosaari 
72894d0eaa4SAntti Palosaari MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
72994d0eaa4SAntti Palosaari MODULE_DESCRIPTION("Panasonic MN88472 DVB-T/T2/C demodulator driver");
73094d0eaa4SAntti Palosaari MODULE_LICENSE("GPL");
73194d0eaa4SAntti Palosaari MODULE_FIRMWARE(MN88472_FIRMWARE);
732