Home | History | Annotate | Line # | Download | only in i2c
      1 /*	$NetBSD: zl10353.c,v 1.5 2017/06/01 02:45:10 chs Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2011 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jukka Ruohonen.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  *
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     30  * SUCH DAMAGE.
     31  */
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: zl10353.c,v 1.5 2017/06/01 02:45:10 chs Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/kmem.h>
     37 #include <sys/module.h>
     38 
     39 #include <dev/dtv/dtvif.h>
     40 
     41 #include <dev/i2c/i2cvar.h>
     42 #include <dev/i2c/zl10353reg.h>
     43 #include <dev/i2c/zl10353var.h>
     44 
     45 /*
     46  * Zarlink ZL10353 demodulator (now known as Intel CE623x).
     47  *
     48  * An incomplete datasheet:
     49  *
     50  *	Intel Corporation: CE6230 - COFDM demodulator with
     51  *	USB interface for PC-TV. Data Sheet, Revision 1.1.
     52  *	March 29, 2007.
     53  */
     54 
     55 static int	zl10353_probe(struct zl10353 *);
     56 static int	zl10353_read(struct zl10353 *, uint8_t, uint8_t *);
     57 static int	zl10353_write(struct zl10353 *, uint8_t, uint8_t);
     58 static int	zl10353_reset(struct zl10353 *, bool);
     59 static int	zl10353_set_agc(struct zl10353 *,
     60 			const struct dvb_frontend_parameters *);
     61 static int	zl10353_set_bw(struct zl10353 *, fe_bandwidth_t);
     62 static int	zl10353_set_rate(struct zl10353 *);
     63 static int	zl10353_set_freq(struct zl10353 *);
     64 static int	zl10353_set_tps(struct zl10353 *,
     65 			const struct dvb_frontend_parameters *);
     66 static int	zl10353_get_guard(fe_guard_interval_t, uint16_t *);
     67 static int	zl10353_get_mode(fe_transmit_mode_t, uint16_t *);
     68 static int	zl10353_get_fec(fe_code_rate_t, bool, uint16_t *);
     69 static int	zl10353_get_modulation(fe_modulation_t, uint16_t *);
     70 static int	zl10353_get_hier(fe_hierarchy_t, uint16_t *);
     71 
     72 struct zl10353 *
     73 zl10353_open(device_t parent, i2c_tag_t i2c, i2c_addr_t addr)
     74 {
     75 	struct zl10353 *zl;
     76 
     77 	zl = kmem_zalloc(sizeof(*zl), KM_SLEEP);
     78 	zl->zl_i2c = i2c;
     79 	zl->zl_i2c_addr = addr;
     80 	zl->zl_parent = parent;
     81 
     82 	zl->zl_freq = ZL10353_DEFAULT_INPUT_FREQ;
     83 	zl->zl_clock = ZL10353_DEFAULT_CLOCK_MHZ;
     84 
     85 	if (zl10353_reset(zl, true) != 0) {
     86 		zl10353_close(zl);
     87 		return NULL;
     88 	}
     89 
     90 	if (zl10353_probe(zl) != 0) {
     91 		zl10353_close(zl);
     92 		return NULL;
     93 	}
     94 
     95 	return zl;
     96 }
     97 
     98 void
     99 zl10353_close(struct zl10353 *zl)
    100 {
    101 	kmem_free(zl, sizeof(*zl));
    102 }
    103 
    104 static int
    105 zl10353_probe(struct zl10353 *zl)
    106 {
    107 	uint8_t val;
    108 	int rv;
    109 
    110 	if ((rv = zl10353_read(zl, ZL10353_REG_ID, &val)) != 0)
    111 		return rv;
    112 
    113 	switch (val) {
    114 
    115 	case ZL10353_ID_CE6230:
    116 		zl->zl_name = "Intel CE6230";
    117 		break;
    118 
    119 	case ZL10353_ID_CE6231:
    120 		zl->zl_name = "Intel CE6231";
    121 		break;
    122 
    123 	case ZL10353_ID_ZL10353:
    124 		zl->zl_name = "Zarlink ZL10353";
    125 		break;
    126 
    127 	default:
    128 		aprint_error_dev(zl->zl_parent, "unknown chip 0x%02x\n", val);
    129 		return ENOTSUP;
    130 	}
    131 
    132 	aprint_verbose_dev(zl->zl_parent, "found %s at i2c "
    133 	    "addr 0x%02x\n",  zl->zl_name, zl->zl_i2c_addr);
    134 
    135 	return 0;
    136 }
    137 
    138 static int
    139 zl10353_read(struct zl10353 *zl, uint8_t reg, uint8_t *valp)
    140 {
    141 	static const i2c_op_t op = I2C_OP_READ;
    142 	int rv;
    143 
    144 	if ((rv = iic_acquire_bus(zl->zl_i2c, 0)) != 0)
    145 		return rv;
    146 
    147 	rv = iic_exec(zl->zl_i2c, op, zl->zl_i2c_addr, &reg, 1, valp, 1, 0);
    148 	iic_release_bus(zl->zl_i2c, 0);
    149 
    150 	return rv;
    151 }
    152 
    153 static int
    154 zl10353_write(struct zl10353 *zl, uint8_t reg, uint8_t val)
    155 {
    156 	static const i2c_op_t op = I2C_OP_WRITE;
    157 	const uint8_t cmd[2] = { reg, val };
    158 	int rv;
    159 
    160 	if ((rv = iic_acquire_bus(zl->zl_i2c, 0)) != 0)
    161 		return rv;
    162 
    163 	rv = iic_exec(zl->zl_i2c, op, zl->zl_i2c_addr, cmd, 2, NULL, 0, 0);
    164 	iic_release_bus(zl->zl_i2c, 0);
    165 
    166 	return rv;
    167 }
    168 
    169 static int
    170 zl10353_reset(struct zl10353 *zl, bool hard)
    171 {
    172 	size_t i = 0, len = 5;
    173 	int rv;
    174 
    175 	static const struct {
    176 		uint8_t		reg;
    177 		uint8_t		val;
    178 	} reset[] = {
    179 		{ 0x50, 0x03 },	/* Hard */
    180 		{ 0x03, 0x44 },
    181 		{ 0x44, 0x46 },
    182 		{ 0x46, 0x15 },
    183 		{ 0x15, 0x0f },
    184 		{ 0x55, 0x80 },	/* Soft */
    185 		{ 0xea, 0x01 },
    186 		{ 0xea, 0x00 },
    187 	};
    188 
    189 	if (hard != true) {
    190 		len = __arraycount(reset);
    191 		i = 5;
    192 	}
    193 
    194 	while (i < len) {
    195 
    196 		if ((rv = zl10353_write(zl, reset[i].reg, reset[i].val)) != 0)
    197 			return rv;
    198 		else {
    199 			delay(100);
    200 		}
    201 
    202 		i++;
    203 
    204 	}
    205 
    206 	return 0;
    207 }
    208 
    209 void
    210 zl10353_get_devinfo(struct dvb_frontend_info *fi)
    211 {
    212 
    213 	fi->type = FE_OFDM;
    214 
    215 	fi->frequency_min = 174000000;
    216 	fi->frequency_max = 862000000;
    217 
    218 	fi->frequency_tolerance = 0;
    219 	fi->frequency_stepsize = 166667;
    220 
    221 	fi->caps |= FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
    222 		    FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_QPSK |
    223 	            FE_CAN_QAM_16  | FE_CAN_QAM_64  | FE_CAN_RECOVER |
    224 		    FE_CAN_MUTE_TS;
    225 
    226 	fi->caps |= FE_CAN_FEC_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
    227 		    FE_CAN_QAM_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
    228 		    FE_CAN_HIERARCHY_AUTO;
    229 }
    230 
    231 int
    232 zl10353_set_params(struct zl10353 *zl,const struct dvb_frontend_parameters *fp)
    233 {
    234 	int rv;
    235 
    236 	/* 1. Soft reset. */
    237 	if ((rv = zl10353_reset(zl, false)) != 0)
    238 		return rv;
    239 
    240 	/* 2. Set AGC. */
    241 	if ((rv = zl10353_set_agc(zl, fp)) != 0)
    242 		return rv;
    243 
    244 	/* 3. Set bandwidth. */
    245 	if ((rv = zl10353_set_bw(zl, fp->u.ofdm.bandwidth)) != 0)
    246 		return rv;
    247 
    248 	/* 4. Set nominal rate. */
    249 	if ((rv = zl10353_set_rate(zl)) != 0)
    250 		return rv;
    251 
    252 	/* 5. Set input frequency. */
    253 	if ((rv = zl10353_set_freq(zl)) != 0)
    254 		return rv;
    255 
    256 	/* 6. Set TPS parameters. */
    257 	if ((rv = zl10353_set_tps(zl, fp)) != 0)
    258 		return rv;
    259 
    260 	return 0;
    261 }
    262 
    263 int
    264 zl10353_set_fsm(struct zl10353 *zl)
    265 {
    266 	return zl10353_write(zl, ZL10353_REG_FSM, ZL10353_FSM_START);
    267 }
    268 
    269 int
    270 zl10353_set_gate(void *aux, bool enable)
    271 {
    272 	uint8_t val = ZL10353_GATE_DISABLE;
    273 
    274 	if (enable != false)
    275 		val = ZL10353_GATE_ENABLE;
    276 
    277 	return zl10353_write(aux, ZL10353_REG_GATE, val);
    278 }
    279 
    280 static int
    281 zl10353_set_agc(struct zl10353 *zl, const struct dvb_frontend_parameters *fp)
    282 {
    283 	const struct dvb_ofdm_parameters *ofdm = &fp->u.ofdm;
    284 	uint8_t val = ZL10353_AGC_TARGET_DEFAULT;
    285 	int rv;
    286 
    287 	if ((rv = zl10353_write(zl, ZL10353_REG_AGC_TARGET, val)) != 0)
    288 		return rv;
    289 	else {
    290 		val = 0;
    291 	}
    292 
    293 	if (ofdm->guard_interval != GUARD_INTERVAL_AUTO)
    294 		val |= ZL10353_AGC_CTRL_GUARD_NONAUTO;
    295 
    296 	if (ofdm->transmission_mode != TRANSMISSION_MODE_AUTO)
    297 		val |= ZL10353_AGC_CTRL_MODE_NONAUTO;
    298 
    299 	return zl10353_write(zl, ZL10353_REG_AGC_CTRL, val);
    300 }
    301 
    302 static int
    303 zl10353_set_bw(struct zl10353 *zl, fe_bandwidth_t bw)
    304 {
    305 	uint8_t val[3];
    306 	int rv;
    307 
    308 	switch (bw) {
    309 
    310 	case BANDWIDTH_6_MHZ:
    311 		val[0] = ZL10353_BW_1_6_MHZ;
    312 		val[1] = ZL10353_BW_2_6_MHZ;
    313 		val[2] = ZL10353_BW_3_6_MHZ;
    314 		zl->zl_bw = 6;
    315 		break;
    316 
    317 	case BANDWIDTH_7_MHZ:
    318 		val[0] = ZL10353_BW_1_7_MHZ;
    319 		val[1] = ZL10353_BW_2_7_MHZ;
    320 		val[2] = ZL10353_BW_3_7_MHZ;
    321 		zl->zl_bw = 7;
    322 		break;
    323 
    324 	case BANDWIDTH_8_MHZ:
    325 		val[0] = ZL10353_BW_1_8_MHZ;
    326 		val[1] = ZL10353_BW_2_8_MHZ;
    327 		val[2] = ZL10353_BW_3_8_MHZ;
    328 		zl->zl_bw = 8;
    329 		break;
    330 
    331 	default:
    332 		zl->zl_bw = 0;
    333 		return EINVAL;
    334 	}
    335 
    336 	if ((rv = zl10353_write(zl, ZL10353_REG_BW_1, val[0])) != 0)
    337 		return rv;
    338 
    339 	if ((rv = zl10353_write(zl, ZL10353_REG_BW_2, val[1])) != 0)
    340 		return rv;
    341 
    342 	if ((rv = zl10353_write(zl, ZL10353_REG_BW_3, val[2])) != 0)
    343 		return rv;
    344 
    345 	return 0;
    346 }
    347 
    348 static int
    349 zl10353_set_rate(struct zl10353 *zl)
    350 {
    351 	static const uint64_t c = 1497965625;
    352 	uint64_t val;
    353 	int rv;
    354 
    355 	KASSERT(zl->zl_bw >= 6 && zl->zl_bw <= 8);
    356 	KASSERT(zl->zl_clock > 0 && zl->zl_freq > 0);
    357 
    358 	val = zl->zl_bw * c;
    359 	val += zl->zl_clock >> 1;
    360 	val /= zl->zl_clock;
    361 	val = val & 0xffff;
    362 
    363 	if ((rv = zl10353_write(zl, ZL10353_REG_RATE_1, val >> 8)) != 0)
    364 		return rv;
    365 
    366 	return zl10353_write(zl, ZL10353_REG_RATE_2, val & 0xff);
    367 }
    368 
    369 static int
    370 zl10353_set_freq(struct zl10353 *zl)
    371 {
    372 	const uint16_t val = zl->zl_freq;
    373 	int rv;
    374 
    375 	if ((rv = zl10353_write(zl, ZL10353_REG_FREQ_1, val >> 8)) != 0)
    376 		return rv;
    377 
    378 	return zl10353_write(zl, ZL10353_REG_FREQ_2, val & 0xff);
    379 }
    380 
    381 static int
    382 zl10353_set_tps(struct zl10353 *zl, const struct dvb_frontend_parameters *fp)
    383 {
    384 	const struct dvb_ofdm_parameters *ofdm = &fp->u.ofdm;
    385 	uint16_t val = 0;
    386 	int rv;
    387 
    388 	if ((rv = zl10353_get_guard(ofdm->guard_interval, &val)) != 0)
    389 		goto fail;
    390 
    391 	if ((rv = zl10353_get_mode(ofdm->transmission_mode, &val)) != 0)
    392 		goto fail;
    393 
    394 	if ((rv = zl10353_get_fec(ofdm->code_rate_HP, true, &val)) != 0)
    395 		goto fail;
    396 
    397 	if ((rv = zl10353_get_fec(ofdm->code_rate_LP, false, &val)) != 0)
    398 		goto fail;
    399 
    400 	if ((rv = zl10353_get_modulation(ofdm->constellation, &val)) != 0)
    401 		goto fail;
    402 
    403 	if ((rv = zl10353_get_hier(ofdm->hierarchy_information, &val)) != 0)
    404 		goto fail;
    405 
    406 	if ((rv = zl10353_write(zl, ZL10353_REG_TPS_1, val >> 8)) != 0)
    407 		goto fail;
    408 
    409 	if ((rv = zl10353_write(zl, ZL10353_REG_TPS_2, val & 0xff)) != 0)
    410 		goto fail;
    411 
    412 	return 0;
    413 
    414 fail:
    415 	aprint_error_dev(zl->zl_parent, "failed to set "
    416 	    "tps for %s (err %d)\n", zl->zl_name, rv);
    417 
    418 	return rv;
    419 }
    420 
    421 static int
    422 zl10353_get_guard(fe_guard_interval_t fg, uint16_t *valp)
    423 {
    424 
    425 	switch (fg) {
    426 
    427 	case GUARD_INTERVAL_1_4:
    428 		*valp |= ZL10353_TPS_GUARD_1_4;
    429 		break;
    430 
    431 	case GUARD_INTERVAL_1_8:
    432 		*valp |= ZL10353_TPS_GUARD_1_8;
    433 		break;
    434 
    435 	case GUARD_INTERVAL_1_16:
    436 		*valp |= ZL10353_TPS_GUARD_1_16;
    437 		break;
    438 
    439 	case GUARD_INTERVAL_1_32:
    440 		*valp |= ZL10353_TPS_GUARD_1_32;
    441 		break;
    442 
    443 	case GUARD_INTERVAL_AUTO:
    444 		*valp |= ZL10353_TPS_GUARD_AUTO;
    445 		break;
    446 
    447 	default:
    448 		return EINVAL;
    449 	}
    450 
    451 	return 0;
    452 }
    453 
    454 static int
    455 zl10353_get_mode(fe_transmit_mode_t fm, uint16_t *valp)
    456 {
    457 
    458 	switch (fm) {
    459 
    460 	case TRANSMISSION_MODE_2K:
    461 		*valp |= ZL10353_TPS_MODE_2K;
    462 		break;
    463 
    464 	case TRANSMISSION_MODE_8K:
    465 		*valp |= ZL10353_TPS_MODE_8K;
    466 		break;
    467 
    468 	case TRANSMISSION_MODE_AUTO:
    469 		*valp |= ZL10353_TPS_MODE_AUTO;
    470 		break;
    471 
    472 	default:
    473 		return EINVAL;
    474 	}
    475 
    476 	return 0;
    477 }
    478 
    479 static int
    480 zl10353_get_fec(fe_code_rate_t fc, bool hp, uint16_t *valp)
    481 {
    482 	uint16_t hpval = 0, lpval = 0;
    483 
    484 	switch (fc) {
    485 
    486 	case FEC_1_2:
    487 		hpval = ZL10353_TPS_HP_FEC_1_2;
    488 		lpval = ZL10353_TPS_LP_FEC_1_2;
    489 		break;
    490 
    491 	case FEC_2_3:
    492 		hpval = ZL10353_TPS_HP_FEC_2_3;
    493 		lpval = ZL10353_TPS_LP_FEC_2_3;
    494 		break;
    495 
    496 	case FEC_3_4:
    497 		hpval = ZL10353_TPS_HP_FEC_3_4;
    498 		lpval = ZL10353_TPS_LP_FEC_3_4;
    499 		break;
    500 
    501 	case FEC_5_6:
    502 		hpval = ZL10353_TPS_HP_FEC_5_6;
    503 		lpval = ZL10353_TPS_LP_FEC_5_6;
    504 		break;
    505 
    506 	case FEC_7_8:
    507 		hpval = ZL10353_TPS_HP_FEC_7_8;
    508 		lpval = ZL10353_TPS_LP_FEC_7_8;
    509 		break;
    510 
    511 	case FEC_AUTO:
    512 		hpval = ZL10353_TPS_HP_FEC_AUTO;
    513 		lpval = ZL10353_TPS_LP_FEC_AUTO;
    514 		break;
    515 
    516 	case FEC_NONE:
    517 		return EOPNOTSUPP;
    518 
    519 	default:
    520 		return EINVAL;
    521 	}
    522 
    523 	*valp |= (hp != false) ? hpval : lpval;
    524 
    525 	return 0;
    526 }
    527 
    528 static int
    529 zl10353_get_modulation(fe_modulation_t fm, uint16_t *valp)
    530 {
    531 
    532 	switch (fm) {
    533 
    534 	case QPSK:
    535 		*valp |= ZL10353_TPS_MODULATION_QPSK;
    536 		break;
    537 
    538 	case QAM_16:
    539 		*valp |= ZL10353_TPS_MODULATION_QAM_16;
    540 		break;
    541 
    542 	case QAM_64:
    543 		*valp |= ZL10353_TPS_MODULATION_QAM_64;
    544 		break;
    545 
    546 	case QAM_AUTO:
    547 		*valp |= ZL10353_TPS_MODULATION_QAM_AUTO;
    548 		break;
    549 
    550 	default:
    551 		return EINVAL;
    552 	}
    553 
    554 	return 0;
    555 }
    556 
    557 static int
    558 zl10353_get_hier(fe_hierarchy_t fh, uint16_t *valp)
    559 {
    560 
    561 	switch (fh) {
    562 
    563 	case HIERARCHY_1:
    564 		*valp |= ZL10353_TPS_HIERARCHY_1;
    565 		break;
    566 
    567 	case HIERARCHY_2:
    568 		*valp |= ZL10353_TPS_HIERARCHY_2;
    569 		break;
    570 
    571 	case HIERARCHY_4:
    572 		*valp |= ZL10353_TPS_HIERARCHY_4;
    573 		break;
    574 
    575 	case HIERARCHY_NONE:
    576 		*valp |= ZL10353_TPS_HIERARCHY_NONE;
    577 		break;
    578 
    579 	case HIERARCHY_AUTO:
    580 		*valp |= ZL10353_TPS_HIERARCHY_AUTO;
    581 		break;
    582 
    583 	default:
    584 		return EINVAL;
    585 	}
    586 
    587 	return 0;
    588 }
    589 
    590 fe_status_t
    591 zl10353_get_status(struct zl10353 *zl)
    592 {
    593 	const uint8_t lock = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC;
    594 	fe_status_t fs = 0;
    595 	uint8_t val;
    596 
    597 	if (zl10353_read(zl, ZL10353_REG_STATUS_LOCK, &val) == 0) {
    598 
    599 		if ((val & ZL10353_STATUS_LOCK_ON) != 0)
    600 			fs |= FE_HAS_LOCK;
    601 
    602 		if ((val & ZL10353_STATUS_LOCK_CARRIER) != 0)
    603 			fs |= FE_HAS_CARRIER;
    604 
    605 		if ((val & ZL10353_STATUS_LOCK_VITERBI) != 0)
    606 			fs |= FE_HAS_VITERBI;
    607 	}
    608 
    609 	if (zl10353_read(zl, ZL10353_REG_STATUS_SYNC, &val) == 0) {
    610 
    611 		if ((val & ZL10353_STATUS_SYNC_ON) != 0)
    612 			fs |= FE_HAS_SYNC;
    613 	}
    614 
    615 	if (zl10353_read(zl, ZL10353_REG_STATUS_SIGNAL, &val) == 0) {
    616 
    617 		if ((val & ZL10353_STATUS_SIGNAL_ON) != 0)
    618 			fs |= FE_HAS_SIGNAL;
    619 	}
    620 
    621 	return ((fs & lock) != lock) ? fs & ~FE_HAS_LOCK : fs;
    622 };
    623 
    624 uint16_t
    625 zl10353_get_signal_strength(struct zl10353 *zl)
    626 {
    627 	uint8_t val1, val2;
    628 
    629 	if (zl10353_read(zl, ZL10353_REG_SIGSTR_1, &val1) != 0)
    630 		return 0;
    631 
    632 	if (zl10353_read(zl, ZL10353_REG_SIGSTR_2, &val2) != 0)
    633 		return 0;
    634 
    635 	return val1 << 10 | val2 << 2 | 0x03;
    636 }
    637 
    638 uint16_t
    639 zl10353_get_snr(struct zl10353 *zl)
    640 {
    641 	uint8_t val;
    642 
    643 	if (zl10353_read(zl, ZL10353_REG_SNR, &val) != 0)
    644 		return 0;
    645 
    646 	return (val << 8) | val;
    647 }
    648 
    649 MODULE(MODULE_CLASS_DRIVER, zl10353, "i2cexec");
    650 
    651 static int
    652 zl10353_modcmd(modcmd_t cmd, void *aux)
    653 {
    654 
    655 	if (cmd != MODULE_CMD_INIT && cmd != MODULE_CMD_FINI)
    656 		return ENOTTY;
    657 
    658 	return 0;
    659 }
    660