/*
 * This work is part of the White Rabbit project
 *
 * Copyright (C) 2012 CERN (www.cern.ch)
 * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
 *
 * Released according to the GNU GPL, version 2 or any later version.
 */
/* SFP Detection / managenent functions */

#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <errno.h>

#include "dev/syscon.h"
#include "dev/bb_i2c.h"
#include "dev/gpio.h"
#include "sfp.h"
#include "storage.h"

/* Calibration data (from EEPROM if available) */
int64_t sfp_alpha = 1235332333756144; /* def values if could not read EEPROM */
int32_t sfp_deltaTx = 0;
int32_t sfp_deltaRx = 0;
int32_t sfp_in_db = 0;

char sfp_pn[SFP_PN_LEN];

static int sfp_present(void)
{
	return !gen_gpio_in(&pin_sysc_sfp_det);
}

static int sfp_read_part_id(char *part_id)
{
	int i;
	uint8_t data, sum;

	bb_i2c_init( &dev_i2c_sfp );

	bb_i2c_start( &dev_i2c_sfp );
	bb_i2c_put_byte(&dev_i2c_sfp, 0xA0);
	bb_i2c_put_byte(&dev_i2c_sfp, 0x00);
	bb_i2c_repeat_start(&dev_i2c_sfp);
	bb_i2c_put_byte(&dev_i2c_sfp, 0xA1);
	bb_i2c_get_byte(&dev_i2c_sfp, &data, 1);
	bb_i2c_stop(&dev_i2c_sfp);

	sum = data;

	bb_i2c_start( &dev_i2c_sfp );
	bb_i2c_put_byte(&dev_i2c_sfp, 0xA1);
	for (i = 1; i < 63; ++i) {
		bb_i2c_get_byte(&dev_i2c_sfp, &data, 0);
		sum = (uint8_t) ((uint16_t) sum + data) & 0xff;
		if (i >= 40 && i <= 55)	//Part Number
			part_id[i - 40] = data;
	}
	bb_i2c_get_byte(&dev_i2c_sfp, &data, 1);	//final word, checksum
	bb_i2c_stop(&dev_i2c_sfp);

	if (sum == data)
		return 0;

	return -1;
}

int sfp_match(int force)
{
	struct s_sfpinfo sfp;

	sfp_pn[0] = '\0';
	if (!force && !sfp_present()) {
		return -ENODEV;
	}
	if (sfp_read_part_id(sfp_pn)) {
		return -EIO;
	}

	strncpy(sfp.pn, sfp_pn, SFP_PN_LEN);
	if (storage_match_sfp(&sfp) == 0) {
		sfp_in_db = SFP_NOT_MATCHED;
		return -ENXIO;
	}
	sfp_deltaTx = sfp.dTx;
	sfp_deltaRx = sfp.dRx;
	sfp_alpha = sfp.alpha;
	sfp_in_db = SFP_MATCHED;
	return 0;
}
