s921_module.c 4.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
/*
 * Driver for Sharp s921 driver
 *
 * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
 *
 * All rights reserved.
 *
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
#include "s921_module.h"
#include "s921_core.h"

static  unsigned int debug = 0;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"s921 debugging (default off)");

#define dprintk(fmt, args...) if (debug) do {\
			printk("s921 debug: " fmt, ##args); } while (0)

struct s921_state
{
        struct dvb_frontend frontend;
        fe_modulation_t current_modulation;
        __u32 snr;
        __u32 current_frequency;
	__u8 addr;
	struct s921_isdb_t dev;
	struct i2c_adapter *i2c;
};

static int s921_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
	struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
	struct s921_isdb_t_transmission_mode_params params;
	struct s921_isdb_t_tune_params tune_params;

	tune_params.frequency = param->frequency;
	s921_isdb_cmd(&state->dev, ISDB_T_CMD_SET_PARAM, &params);
	s921_isdb_cmd(&state->dev, ISDB_T_CMD_TUNE, &tune_params);
	mdelay(100);
	return 0;
}

static int s921_init(struct dvb_frontend *fe) {
	printk("s921 init\n");
        return 0;
}

static int s921_sleep(struct dvb_frontend *fe) {
	printk("s921 sleep\n");
	return 0;
}

static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
	struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
	unsigned int ret;
	mdelay(5);
	s921_isdb_cmd(&state->dev, ISDB_T_CMD_GET_STATUS, &ret);
	*status = 0;

	printk("status: %02x\n", ret);
	if (ret == 1) {
		*status |= FE_HAS_CARRIER;
		*status |= FE_HAS_VITERBI;
		*status |= FE_HAS_LOCK;
		*status |= FE_HAS_SYNC;
		*status |= FE_HAS_SIGNAL;
	}

	return 0;
}

static int s921_read_ber(struct dvb_frontend *fe, __u32 *ber)
{
	dprintk("read ber\n");
	return 0;
}

static int s921_read_snr(struct dvb_frontend *fe, __u16 *snr)
{
	dprintk("read snr\n");
	return 0;
}

static int s921_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
{
	dprintk("read ucblocks\n");
	return 0;
}

static void s921_release(struct dvb_frontend *fe)
{
	struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
	kfree(state);
}

static struct dvb_frontend_ops demod_s921={
	.info = {
		.name			= "SHARP S921",
		.type			= FE_OFDM,
		.frequency_min		= 473143000,
		.frequency_max		= 767143000,
		.frequency_stepsize	=   6000000,
		.frequency_tolerance	= 0,
		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
			FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
			FE_CAN_FEC_AUTO |
			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
			FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
			FE_CAN_MUTE_TS
	},
	.init = s921_init,
	.sleep = s921_sleep,
	.set_frontend = s921_set_parameters,
	.read_snr = s921_read_snr,
	.read_ber = s921_read_ber,
	.read_status = s921_read_status,
	.read_ucblocks = s921_read_ucblocks,
	.release = s921_release,
};

static int s921_write(void *dev, u8 reg, u8 val) {
	struct s921_state *state = dev;
	char buf[2]={reg,val};
        int err;
	struct i2c_msg i2cmsgs = {
		.addr = state->addr,
		.flags = 0,
		.len = 2,
		.buf = buf
	};

	if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
		printk("%s i2c_transfer error %d\n", __FUNCTION__, err);
                if (err < 0)
                        return err;
                else
                        return -EREMOTEIO;
        }

	return 0;
}

static int s921_read(void *dev, u8 reg) {
	struct s921_state *state = dev;
	u8 b1;
	int ret;
	struct i2c_msg msg[2] = { { .addr = state->addr,
				    .flags = 0,
				    .buf = &reg, .len = 1 },
				  { .addr = state->addr,
				    .flags = I2C_M_RD,
				    .buf = &b1, .len = 1 } };

	ret = i2c_transfer(state->i2c, msg, 2);
	if (ret != 2)
		return ret;
	return b1;
}

struct dvb_frontend* s921_attach(const struct s921_config *config,
					   struct i2c_adapter *i2c)
{

	struct s921_state *state;
	state = kzalloc(sizeof(struct s921_state), GFP_KERNEL);
	memset(state, 0x0, sizeof(struct s921_state));

	state->addr = config->i2c_address;
	state->i2c = i2c;
	state->dev.i2c_write = &s921_write;
	state->dev.i2c_read = &s921_read;
	state->dev.priv_dev = state;

	s921_isdb_cmd(&state->dev, ISDB_T_CMD_INIT, NULL);

	memcpy(&state->frontend.ops, &demod_s921, sizeof(struct dvb_frontend_ops));
	state->frontend.demodulator_priv = state;
	return &state->frontend;
}

EXPORT_SYMBOL_GPL(s921_attach);
MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>");
MODULE_DESCRIPTION("Sharp S921 ISDB-T 1Seg");
MODULE_LICENSE("GPL");