linux/drivers/media/dvb-frontends/sp887x.c

// SPDX-License-Identifier: GPL-2.0-only
/*
   Driver for the Spase sp887x demodulator
*/

/*
 * This driver needs external firmware. Please use the command
 * "<kerneldir>/scripts/get_dvb_firmware sp887x" to
 * download/extract it, and then copy it to /usr/lib/hotplug/firmware
 * or /lib/firmware (depending on configuration of firmware hotplug).
 */
#define SP887X_DEFAULT_FIRMWARE

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/string.h>
#include <linux/slab.h>

#include <media/dvb_frontend.h>
#include "sp887x.h"


struct sp887x_state {};

static int debug;
#define dprintk(args...)

static int i2c_writebytes (struct sp887x_state* state, u8 *buf, u8 len)
{}

static int sp887x_writereg (struct sp887x_state* state, u16 reg, u16 data)
{}

static int sp887x_readreg (struct sp887x_state* state, u16 reg)
{}

static void sp887x_microcontroller_stop (struct sp887x_state* state)
{}

static void sp887x_microcontroller_start (struct sp887x_state* state)
{}

static void sp887x_setup_agc (struct sp887x_state* state)
{}

#define BLOCKSIZE
#define FW_SIZE
/*
 *  load firmware and setup MPEG interface...
 */
static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw)
{
	struct sp887x_state* state = fe->demodulator_priv;
	u8 buf [BLOCKSIZE + 2];
	int i;
	int fw_size = fw->size;
	const unsigned char *mem = fw->data + 10;

	dprintk("%s\n", __func__);

	/* ignore the first 10 bytes, then we expect 0x4000 bytes of firmware */
	if (fw_size < FW_SIZE + 10)
		return -ENODEV;

	/* soft reset */
	sp887x_writereg(state, 0xf1a, 0x000);

	sp887x_microcontroller_stop (state);

	printk ("%s: firmware upload... ", __func__);

	/* setup write pointer to -1 (end of memory) */
	/* bit 0x8000 in address is set to enable 13bit mode */
	sp887x_writereg(state, 0x8f08, 0x1fff);

	/* dummy write (wrap around to start of memory) */
	sp887x_writereg(state, 0x8f0a, 0x0000);

	for (i = 0; i < FW_SIZE; i += BLOCKSIZE) {
		int c = BLOCKSIZE;
		int err;

		if (c > FW_SIZE - i)
			c = FW_SIZE - i;

		/* bit 0x8000 in address is set to enable 13bit mode */
		/* bit 0x4000 enables multibyte read/write transfers */
		/* write register is 0xf0a */
		buf[0] = 0xcf;
		buf[1] = 0x0a;

		memcpy(&buf[2], mem + i, c);

		if ((err = i2c_writebytes (state, buf, c+2)) < 0) {
			printk ("failed.\n");
			printk ("%s: i2c error (err == %i)\n", __func__, err);
			return err;
		}
	}

	/* don't write RS bytes between packets */
	sp887x_writereg(state, 0xc13, 0x001);

	/* suppress clock if (!data_valid) */
	sp887x_writereg(state, 0xc14, 0x000);

	/* setup MPEG interface... */
	sp887x_writereg(state, 0xc1a, 0x872);
	sp887x_writereg(state, 0xc1b, 0x001);
	sp887x_writereg(state, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */
	sp887x_writereg(state, 0xc1a, 0x871);

	/* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */
	sp887x_writereg(state, 0x301, 0x002);

	sp887x_setup_agc(state);

	/* bit 0x010: enable data valid signal */
	sp887x_writereg(state, 0xd00, 0x010);
	sp887x_writereg(state, 0x0d1, 0x000);
	return 0;
};

static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05)
{}

/*
 *  estimates division of two 24bit numbers,
 *  derived from the ves1820/stv0299 driver code
 */
static void divide (int n, int d, int *quotient_i, int *quotient_f)
{}

static void sp887x_correct_offsets (struct sp887x_state* state,
				    struct dtv_frontend_properties *p,
				    int actual_freq)
{}

static int sp887x_setup_frontend_parameters(struct dvb_frontend *fe)
{}

static int sp887x_read_status(struct dvb_frontend *fe, enum fe_status *status)
{}

static int sp887x_read_ber(struct dvb_frontend* fe, u32* ber)
{}

static int sp887x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
{}

static int sp887x_read_snr(struct dvb_frontend* fe, u16* snr)
{}

static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
{}

static int sp887x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
{}

static int sp887x_sleep(struct dvb_frontend* fe)
{}

static int sp887x_init(struct dvb_frontend* fe)
{}

static int sp887x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{}

static void sp887x_release(struct dvb_frontend* fe)
{}

static const struct dvb_frontend_ops sp887x_ops;

struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
				   struct i2c_adapter* i2c)
{}

static const struct dvb_frontend_ops sp887x_ops =;

module_param(debug, int, 0644);
MODULE_PARM_DESC();

MODULE_DESCRIPTION();
MODULE_LICENSE();

EXPORT_SYMBOL_GPL();