dect
/
linux-2.6
Archived
13
0
Fork 0
This repository has been archived on 2022-02-17. You can view files and clone it, but cannot push or open issues or pull requests.
linux-2.6/drivers/dect/coa/radio_u2785.c

262 lines
6.7 KiB
C

/*
* radio_u2785 - ATMEL U2785 RF IC radio operations
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*/
//#define DEBUG
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/dect.h>
#include <net/dect/dect.h>
#include <net/dect/transceiver.h>
#include "com_on_air.h"
#define u2785_debug(dev, fmt, args...) \
dev_dbg(dev->dev, "u2785: " fmt, ## args)
/* Intermediate frequencies */
#define RADIO_U2785_FREQ_IF1 110592 /* kHz */
#define RADIO_U2785_FREQ_IF2 112320 /* kHz */
/*
* RC (Reference Divider)
*/
#define RADIO_U2785_RC_SHIFT 22
#define RADIO_U2785_RC_12 (0x1 << RADIO_U2785_RC_SHIFT)
#define RADIO_U2785_RC_16 (0x2 << RADIO_U2785_RC_SHIFT)
#define RADIO_U2785_RC_24 (0x3 << RADIO_U2785_RC_SHIFT)
/*
* SC (Swallow Counter) 0-31
*/
#define RADIO_U2785_SC_SHIFT 17
#define RADIO_U2785_SC_MAX 31
#define RADIO_U2785_SC_MASK (0x1F << RADIO_U2785_SC_SHIFT)
/*
* MC (Main Divider)
*/
#define RADIO_U2785_MC_SHIFT 15
#define RADIO_U2785_MC_MIN 31
#define RADIO_U2785_MC_MAX 34
#define RADIO_U2785_MC_31 (0x0 << RADIO_U2785_MC_SHIFT)
#define RADIO_U2785_MC_32 (0x1 << RADIO_U2785_MC_SHIFT)
#define RADIO_U2785_MC_33 (0x2 << RADIO_U2785_MC_SHIFT)
#define RADIO_U2785_MC_34 (0x3 << RADIO_U2785_MC_SHIFT)
/*
* PS (Phase Settings)
*/
/* Phase of GF_DATA */
#define RADIO_U2785_PS_GF (0x1 << 14)
/* Phase of MCC Internal Connection */
#define RADIO_U2785_PS_MCC (0x1 << 13)
/* Phase of Charge Pump */
#define RADIO_U2785_PS_CP (0x1 << 12)
/*
* Current-Saving Power-up/down Settings
*/
/* Gaussian Filter */
#define RADIO_U2785_GF (0x1 << 11)
/* Modulation Compensation Circuit */
#define RADIO_U2785_MCC (0x1 << 10)
/* Frequency Doubler */
#define RADIO_U2785_FD (0x1 << 8)
/* OP1 + OP2 (Op Amps) */
#define RADIO_U2785_OP (0x1 << 7)
/*
* Current Gain Settings (in percent)
*/
#define RADIO_U2785_CGS_60 0x0
#define RADIO_U2785_CGS_70 0x1
#define RADIO_U2785_CGS_80 0x2
#define RADIO_U2785_CGS_90 0x3
#define RADIO_U2785_CGS_100 0x4
#define RADIO_U2785_CGS_110 0x5
#define RADIO_U2785_CGS_120 0x6
#define RADIO_U2785_CGS_130 0x7
/* GFCS (Gaussian-Filter Current Settings) */
#define RADIO_U2785_GFCS_SHIFT 7
/* CPCS (Charge-Pump Current Settings) */
#define RADIO_U2785_CPCS_SHIFT 1
/* MCCS (Modulation-Compensation Current Settings) */
#define RADIO_U2785_MCCS_SHIFT 4
/*
* Pretune DAC Voltage
*/
#define RADIO_U2785_DAC_SHIFT 4
#define RADIO_U2785_DAC_300mV (0x0 << RADIO_U2785_DAC_SHIFT)
#define RADIO_U2785_DAC_600mV (0x1 << RADIO_U2785_DAC_SHIFT)
#define RADIO_U2785_DAC_900mV (0x2 << RADIO_U2785_DAC_SHIFT)
#define RADIO_U2785_DAC_1200mV (0x3 << RADIO_U2785_DAC_SHIFT)
#define RADIO_U2785_DAC_1400mV (0x4 << RADIO_U2785_DAC_SHIFT)
#define RADIO_U2785_DAC_1700mV (0x5 << RADIO_U2785_DAC_SHIFT)
#define RADIO_U2785_DAC_2000mV (0x6 << RADIO_U2785_DAC_SHIFT)
#define RADIO_U2785_DAC_2300mV (0x7 << RADIO_U2785_DAC_SHIFT)
/*
* Address bit
*/
#define RADIO_U2785_ADDRESS_BIT 0x1
static void u2785_write_config(const struct coa_device *dev, u16 offset,
u32 init1, u32 init2)
{
u8 init[5] = {
/* first word: 24 bits */
[0] = init1 >> 16,
[1] = init1 >> 8,
[2] = init1 | RADIO_U2785_ADDRESS_BIT,
/* second word: 9 bits */
[3] = init2 >> 1,
[4] = 0,
};
sc1442x_rfdesc_write(dev, offset, init, sizeof(init));
}
static void u2785_rx_init(const struct coa_device *dev, u16 offset)
{
u32 init1 = 0, init2 = 0;
init1 |= RADIO_U2785_RC_12;
init1 |= RADIO_U2785_MC_32;
init1 |= 10 << RADIO_U2785_SC_SHIFT;
init1 |= RADIO_U2785_CGS_100 << RADIO_U2785_CPCS_SHIFT;
init2 |= RADIO_U2785_FD;
init2 |= RADIO_U2785_CGS_100 << RADIO_U2785_MCCS_SHIFT;
u2785_write_config(dev, offset, init1, init2);
}
static void u2785_tx_init(const struct coa_device *dev, u16 offset)
{
u32 init1 = 0, init2 = 0;
init1 |= RADIO_U2785_RC_12;
init1 |= RADIO_U2785_MC_34;
init1 |= 7 << RADIO_U2785_SC_SHIFT;
init1 |= RADIO_U2785_GF;
init1 |= RADIO_U2785_MCC;
init1 |= RADIO_U2785_CGS_120 << RADIO_U2785_GFCS_SHIFT;
init1 |= RADIO_U2785_DAC_1400mV;
init1 |= RADIO_U2785_CGS_60 << RADIO_U2785_CPCS_SHIFT;
init2 |= RADIO_U2785_FD;
init2 |= RADIO_U2785_CGS_130 << RADIO_U2785_MCCS_SHIFT;
u2785_write_config(dev, offset, init1, init2);
}
static void u2785_write_carrier(const struct coa_device *dev, u16 offset,
u32 init1)
{
u8 init[3] = {
/* first word: 24 bits */
[0] = init1 >> 16,
[1] = init1 >> 8,
[2] = init1 | RADIO_U2785_ADDRESS_BIT,
};
sc1442x_rfdesc_write(dev, offset, init, sizeof(init));
}
static void u2785_set_carrier(const struct coa_device *dev, u16 offset,
enum dect_slot_states mode, u8 carrier)
{
const struct coa_freq_map_entry *fe = &dev->freq_map.carrier[carrier];
u32 init1 = 0;
init1 |= RADIO_U2785_RC_12;
switch (mode) {
case DECT_SLOT_SCANNING:
case DECT_SLOT_RX:
init1 |= (fe->rx.divisor - RADIO_U2785_MC_MIN) <<
RADIO_U2785_MC_SHIFT;
init1 |= fe->rx.swcnt << RADIO_U2785_SC_SHIFT;
init1 |= RADIO_U2785_CGS_100 << RADIO_U2785_CPCS_SHIFT;
break;
case DECT_SLOT_TX:
init1 |= (fe->tx.divisor - RADIO_U2785_MC_MIN) <<
RADIO_U2785_MC_SHIFT;
init1 |= fe->tx.swcnt << RADIO_U2785_SC_SHIFT;
init1 |= RADIO_U2785_GF;
init1 |= RADIO_U2785_MCC;
init1 |= RADIO_U2785_CGS_120 << RADIO_U2785_GFCS_SHIFT;
init1 |= RADIO_U2785_DAC_1400mV;
init1 |= RADIO_U2785_CGS_60 << RADIO_U2785_CPCS_SHIFT;
break;
default:
return;
}
u2785_write_carrier(dev, offset, init1);
}
static int u2785_map_freq(u32 frequency, u8 *s_mc, u8 *s_sc)
{
frequency /= DECT_CARRIER_WIDTH;
*s_mc = frequency / 32;
if (*s_mc < RADIO_U2785_MC_MIN || *s_mc > RADIO_U2785_MC_MAX)
return false;
*s_sc = frequency % 32;
return true;
}
static u64 u2785_map_band(struct coa_device *dev, const struct dect_band *band)
{
struct coa_freq_map_entry *fe;
u64 carriers = 0;
u32 frequency;
u8 carrier;
for (carrier = 0; carrier < band->carriers; carrier++) {
frequency = band->frequency[carrier];
fe = &dev->freq_map.carrier[carrier];
if (!u2785_map_freq(frequency - RADIO_U2785_FREQ_IF1,
&fe->rx.divisor, &fe->rx.swcnt))
continue;
if (!u2785_map_freq(frequency,
&fe->tx.divisor, &fe->tx.swcnt))
continue;
carriers |= 1 << carrier;
u2785_debug(dev, "carrier %u (%u.%03uMHz) => "
"rx: div: %u sw: %u tx: div: %u sw: %u\n",
carrier, frequency / 1000, frequency % 1000,
fe->rx.divisor, fe->rx.swcnt,
fe->tx.divisor, fe->tx.swcnt);
}
return carriers;
}
const struct coa_radio_ops coa_u2785_radio_ops = {
.type = "U2785B",
.rx_init = u2785_rx_init,
.tx_init = u2785_tx_init,
.set_carrier = u2785_set_carrier,
.map_band = u2785_map_band,
};
EXPORT_SYMBOL_GPL(coa_u2785_radio_ops);