blob: 091d781918ab823e8a80ee039da7b6aef6fea322 [file] [log] [blame]
/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/ssbi.h>
#include <linux/clk.h>
#include <mach/msm_iomap.h>
#include <mach/gpiomux.h>
#include <mach/board.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
#include <linux/fsm_rfic.h>
#define GENI_OFFSET 0x4000
#define GENI_CFG_REG0_ADDR 0x100
#define GENI_RAM_ADDR 0x200
#define GENI_CLK_CONTROL_ADDR 0x0
#define GENI_FW_REVISION_ADDR 0x8
#define GENI_S_FW_REVISION_ADDR 0xC
#define GENI_FORCE_DEFAULT_REG_ADDR 0x10
#define GENI_OUTPUT_CONTROL_ADDR 0x14
#define GENI_ARB_MISC_CONFIG_ADDR 0x3004
#define GENI_ARB_CHNL_CONFIG_ADDDR 0x3804
/*
* FTR8700, WTR1605 RFIC
*/
#define RFIC_MTR_DEVICE_NUM 5
#define RFIC_DEVICE_NUM 9
#define RFIC_GRFC_REG_NUM 6
#define ANY_BUS 0x0
#define TX1_BUS 0x0
#define TX2_BUS 0x1
#define MISC_BUS 0x2
#define RX_BUS 0x3
#define BUS_BITS 0x3
#define FTR2_HB_NL_SEL 96
#define FTR2_LB_NL_SEL 97
#define FTR1_HB_NL_SEL 98
#define FTR1_LB_NL_SEL 99
#define FTR1_SBI_SEL0 103
#define FTR1_SBI_SEL1 104
#define FTR2_SBI_SEL0 105
#define FTR2_SBI_SEL1 106
#define PDM_1_0_CTL 0x0000
#define PDM_1_1_CTL 0x1000
#define PDM_1_2_CTL 0x2000
#define PDM_2_0_CTL 0x4000
#define PDM_2_1_CTL 0x5000
#define PDM_2_2_CTL 0x6000
#define PDM_OE 1
#define PDM_BYTE 0x80
#define PDM_WORD 0x8000
#define MSM_MAX_GPIO 32
uint8_t rfbid;
void __iomem *grfc_base;
void __iomem *pdm_base;
/*
* Device private information per device node
*/
struct mutex rficlock;
static struct ftr_dev_node_info {
void *grfcctrladdr;
void *grfcmaskaddr;
unsigned int busselect[4];
int maskvalue;
struct device *dev;
struct mutex lock;
} ftr_dev_info[RFIC_DEVICE_NUM];
/*
* Device private information per file
*/
struct ftr_dev_file_info {
int ftrid;
};
int nDev;
/*
* File interface
*/
static int ftr_find_id(int minor);
static int ftr_open(struct inode *inode, struct file *file)
{
struct ftr_dev_file_info *pdfi;
/* private data allocation */
pdfi = kmalloc(sizeof(*pdfi), GFP_KERNEL);
if (pdfi == NULL)
return -ENOMEM;
file->private_data = pdfi;
/* FTR ID */
pdfi->ftrid = ftr_find_id(MINOR(inode->i_rdev));
return 0;
}
static int ftr_release(struct inode *inode, struct file *file)
{
struct ftr_dev_file_info *pdfi;
pdfi = (struct ftr_dev_file_info *) file->private_data;
kfree(file->private_data);
file->private_data = NULL;
return 0;
}
static long ftr_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
unsigned int __user *argp = (unsigned int __user *) arg;
struct ftr_dev_file_info *pdfi =
(struct ftr_dev_file_info *) file->private_data;
struct ftr_dev_node_info *pdev;
if (pdfi->ftrid < 0 || pdfi->ftrid >= RFIC_DEVICE_NUM)
return -EINVAL;
pdev = ftr_dev_info + pdfi->ftrid;
switch (cmd) {
case RFIC_IOCTL_READ_REGISTER:
{
int ret = 0;
unsigned int rficaddr;
u8 value = 0;
if (get_user(rficaddr, argp))
return -EFAULT;
mutex_lock(&pdev->lock);
if (((pdfi->ftrid == 2) || (pdfi->ftrid == 3))
&& (rfbid < RF_TYPE_48)) {
__raw_writel(
pdev->busselect[RFIC_FTR_GET_BUS(rficaddr)],
pdev->grfcctrladdr);
mb();
}
ret = ssbi_read(pdev->dev->parent,
RFIC_FTR_GET_ADDR(rficaddr), &value, 1);
mutex_unlock(&pdev->lock);
if (ret)
return ret;
if (put_user(value, argp))
return -EFAULT;
}
break;
case RFIC_IOCTL_WRITE_REGISTER:
{
int ret;
struct rfic_write_register_param param;
unsigned int rficaddr;
u8 value;
if (copy_from_user(&param, argp, sizeof(param)))
return -EFAULT;
rficaddr = param.rficaddr;
value = (u8) param.value;
mutex_lock(&pdev->lock);
if (((pdfi->ftrid == 2) || (pdfi->ftrid == 3))
&& (rfbid < RF_TYPE_48)) {
__raw_writel(
pdev->busselect[RFIC_FTR_GET_BUS(rficaddr)],
pdev->grfcctrladdr);
mb();
}
ret = ssbi_write(pdev->dev->parent,
RFIC_FTR_GET_ADDR(rficaddr), &value, 1);
mutex_unlock(&pdev->lock);
if (ret)
return ret;
}
break;
case RFIC_IOCTL_WRITE_REGISTER_WITH_MASK:
{
int ret;
struct rfic_write_register_mask_param param;
unsigned int rficaddr;
u8 value;
if (copy_from_user(&param, argp, sizeof(param)))
return -EFAULT;
rficaddr = param.rficaddr;
mutex_lock(&pdev->lock);
if (((pdfi->ftrid == 2) || (pdfi->ftrid == 3))
&& (rfbid < RF_TYPE_48)) {
__raw_writel(
pdev->busselect[RFIC_FTR_GET_BUS(rficaddr)],
pdev->grfcctrladdr);
mb();
}
ret = ssbi_read(pdev->dev->parent,
RFIC_FTR_GET_ADDR(rficaddr), &value, 1);
value &= (u8) ~param.mask;
value |= (u8) (param.value & param.mask);
ret = ssbi_write(pdev->dev->parent,
RFIC_FTR_GET_ADDR(rficaddr), &value, 1);
mutex_unlock(&pdev->lock);
if (ret)
return ret;
}
break;
case RFIC_IOCTL_GPIO_SETTING:
{
struct rfic_gpio_param param;
struct msm_gpiomux_config rf_config[MSM_MAX_GPIO];
struct gpiomux_setting rf_setting[MSM_MAX_GPIO];
struct gpio_alt_config *alt_config;
int gp_size, i;
void *pGP;
if (pdfi->ftrid != 0)
return -EINVAL;
if (copy_from_user(&param, argp, sizeof(param))) {
pr_err("%s: cfu fail for param\n", __func__);
return -EFAULT;
}
if ((param.num < 1) || (param.num > MSM_MAX_GPIO)) {
pr_err("Invalid GPIO count %d\n", param.num);
return -EINVAL;
}
gp_size = sizeof(struct gpio_alt_config) * param.num;
pGP = kmalloc(gp_size, GFP_KERNEL);
if (pGP == NULL)
return -ENOMEM;
if (copy_from_user(pGP, param.pArray, gp_size)) {
pr_err("%s: cfu fail for pGP\n", __func__);
kfree(pGP);
return -EFAULT;
}
alt_config = (struct gpio_alt_config *)pGP;
for (i = 0; i < param.num; i++) {
rf_config[i].gpio = (unsigned)alt_config->gpio;
rf_setting[i].func = alt_config->func;
rf_setting[i].drv = alt_config->drv;
rf_setting[i].pull = alt_config->pull;
rf_setting[i].dir = alt_config->dir;
rf_config[i].settings[GPIOMUX_ACTIVE] =
&rf_setting[i];
rf_config[i].settings[GPIOMUX_SUSPENDED] =
&rf_setting[i];
alt_config++;
}
msm_gpiomux_install(rf_config, param.num);
kfree(pGP);
}
break;
case RFIC_IOCTL_GET_GRFC:
{
struct rfic_grfc_param param;
if (pdfi->ftrid != 0)
return -EINVAL;
if (copy_from_user(&param, argp, sizeof(param)))
return -EFAULT;
if (param.grfcid >= RFIC_GRFC_REG_NUM)
return -EINVAL;
param.maskvalue = __raw_readl(
grfc_base + 0x20 + param.grfcid * 4);
param.ctrlvalue = __raw_readl(
grfc_base + param.grfcid * 4);
if (copy_to_user(argp, &param, sizeof(param)))
return -EFAULT;
}
break;
case RFIC_IOCTL_SET_GRFC:
{
struct rfic_grfc_param param;
if (pdfi->ftrid != 0)
return -EINVAL;
if (copy_from_user(&param, argp, sizeof(param)))
return -EFAULT;
if (param.grfcid >= RFIC_GRFC_REG_NUM)
return -EINVAL;
__raw_writel(param.maskvalue,
grfc_base + 0x20 + param.grfcid * 4);
__raw_writel(param.ctrlvalue,
grfc_base + param.grfcid * 4);
mb();
}
break;
case RFIC_IOCTL_GET_BOARDID:
{
if (pdfi->ftrid != 0)
return -EINVAL;
if (put_user(rfbid, argp))
return -EFAULT;
}
break;
case RFIC_IOCTL_PDM_READ:
{
unsigned int pdmaddr;
u32 value = 0;
if (get_user(pdmaddr, argp))
return -EFAULT;
mutex_lock(&pdev->lock);
if (pdfi->ftrid == 1)
value = __raw_readl(pdm_base + pdmaddr);
mutex_unlock(&pdev->lock);
if (put_user(value, argp))
return -EFAULT;
return 0;
}
break;
case RFIC_IOCTL_PDM_WRITE:
{
struct pdm_write_param param;
void __iomem *pdmaddr;
u8 value;
if (copy_from_user(&param, argp, sizeof(param)))
return -EFAULT;
pdmaddr = pdm_base + param.offset;
value = (u8) param.value;
mutex_lock(&pdev->lock);
if (pdfi->ftrid == 1) {
__raw_writel(value, pdmaddr);
mb();
}
mutex_unlock(&pdev->lock);
return 0;
}
break;
default:
return -EINVAL;
}
return 0;
}
uint8_t rf_interface_id(void)
{
uint8_t tempid = 0;
tempid = gpio_get_value(FTR1_LB_NL_SEL);
rfbid = tempid << 7;
tempid = gpio_get_value(FTR1_HB_NL_SEL);
rfbid |= tempid << 6;
tempid = gpio_get_value(FTR2_LB_NL_SEL);
rfbid |= tempid << 5;
tempid = gpio_get_value(FTR2_HB_NL_SEL);
rfbid |= tempid << 4;
tempid = gpio_get_value(FTR1_SBI_SEL0);
rfbid |= tempid << 3;
tempid = gpio_get_value(FTR1_SBI_SEL1);
rfbid |= tempid << 2;
tempid = gpio_get_value(FTR2_SBI_SEL0);
rfbid |= tempid << 1;
tempid = gpio_get_value(FTR2_SBI_SEL1);
rfbid |= tempid;
return rfbid;
}
static const struct file_operations ftr_fops = {
.owner = THIS_MODULE,
.open = ftr_open,
.release = ftr_release,
.unlocked_ioctl = ftr_ioctl,
};
/* Driver initialization & cleanup */
struct miscdevice ftr_misc_dev[RFIC_DEVICE_NUM] = {
{
.minor = MISC_DYNAMIC_MINOR,
.name = GRFC_DEVICE_NAME,
.fops = &ftr_fops,
},
{
.minor = MISC_DYNAMIC_MINOR,
.name = PDM_DEVICE_NAME,
.fops = &ftr_fops,
},
{
.minor = MISC_DYNAMIC_MINOR,
.name = RFIC_FTR_DEVICE_NAME "0",
.fops = &ftr_fops,
},
{
.minor = MISC_DYNAMIC_MINOR,
.name = RFIC_FTR_DEVICE_NAME "1",
.fops = &ftr_fops,
},
{
.minor = MISC_DYNAMIC_MINOR,
.name = RFIC_WTR_DEVICE_NAME "1-rx",
.fops = &ftr_fops,
},
{
.minor = MISC_DYNAMIC_MINOR,
.name = RFIC_WTR_DEVICE_NAME "1-tx",
.fops = &ftr_fops,
},
{
.minor = MISC_DYNAMIC_MINOR,
.name = RFIC_WTR_DEVICE_NAME "2-tx",
.fops = &ftr_fops,
},
{
.minor = MISC_DYNAMIC_MINOR,
.name = RFIC_WTR_DEVICE_NAME "2-rx",
.fops = &ftr_fops,
},
{
.minor = MISC_DYNAMIC_MINOR,
.name = RFIC_WGR_DEVICE_NAME,
.fops = &ftr_fops,
},
};
struct miscdevice mtr_misc_dev[RFIC_MTR_DEVICE_NUM] = {
{
.minor = MISC_DYNAMIC_MINOR,
.name = GRFC_DEVICE_NAME,
.fops = &ftr_fops,
},
{
.minor = MISC_DYNAMIC_MINOR,
.name = PDM_DEVICE_NAME,
.fops = &ftr_fops,
},
{
.minor = MISC_DYNAMIC_MINOR,
.name = RFIC_MTR_DEVICE_NAME "0",
.fops = &ftr_fops,
},
{
.minor = MISC_DYNAMIC_MINOR,
.name = RFIC_MTR_DEVICE_NAME "1",
.fops = &ftr_fops,
},
{
.minor = MISC_DYNAMIC_MINOR,
.name = RFIC_WGR_DEVICE_NAME,
.fops = &ftr_fops,
},
};
int ftr_find_id(int minor)
{
int i;
for (i = 0; i < RFIC_DEVICE_NUM; ++i)
if (ftr_misc_dev[i].minor == minor)
break;
return i;
}
static ssize_t rfb_id_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return snprintf(buf, sizeof(int), "%d\n", (int)rfbid);
}
static DEVICE_ATTR(rfboard_id, S_IRUGO, rfb_id_show, NULL);
static int ftr_regulator_init(struct platform_device *pdev)
{
int ret;
struct regulator *vreg_ldo18, *vreg_ldo23, *vreg_ldo25;
vreg_ldo23 = regulator_get(&pdev->dev, "vdd-ftr1");
if (IS_ERR(vreg_ldo23)) {
pr_err("%s: vreg get l23-reg failed (%ld)\n",
__func__, PTR_ERR(vreg_ldo23));
return PTR_ERR(vreg_ldo23);
}
ret = regulator_set_optimum_mode(vreg_ldo23, 250000);
if (ret < 0) {
pr_err("%s: unable to set optimum mode for ldo23\n", __func__);
return PTR_ERR(vreg_ldo23);
}
ret = regulator_enable(vreg_ldo23);
if (ret) {
pr_err("%s: unable to enable ldo23 voltage\n", __func__);
return PTR_ERR(vreg_ldo23);
}
vreg_ldo25 = regulator_get(&pdev->dev, "vdd-ftr2");
if (IS_ERR(vreg_ldo25)) {
pr_err("%s: vreg get l25-reg failed (%ld)\n",
__func__, PTR_ERR(vreg_ldo25));
return PTR_ERR(vreg_ldo25);
}
ret = regulator_set_optimum_mode(vreg_ldo25, 250000);
if (ret < 0) {
pr_err("%s: unable to set optimum mode for ldo25\n", __func__);
return PTR_ERR(vreg_ldo25);
}
ret = regulator_enable(vreg_ldo25);
if (ret) {
pr_err("%s: unable to enable ldo25 voltage\n", __func__);
return PTR_ERR(vreg_ldo25);
}
vreg_ldo18 = regulator_get(&pdev->dev, "vdd-switch");
if (IS_ERR(vreg_ldo18)) {
pr_err("%s: vreg get l18-reg failed (%ld)\n",
__func__, PTR_ERR(vreg_ldo18));
return PTR_ERR(vreg_ldo18);
}
ret = regulator_enable(vreg_ldo18);
if (ret) {
pr_err("%s: unable to enable ldo18 voltage\n", __func__);
return PTR_ERR(vreg_ldo18);
}
return 0;
}
static int wtr_regulator_init(struct platform_device *pdev)
{
int ret;
struct regulator *vreg_ldo19;
vreg_ldo19 = regulator_get(&pdev->dev, "vdd-wtr");
if (IS_ERR(vreg_ldo19)) {
pr_err("%s: vreg get l19-reg failed (%ld)\n",
__func__, PTR_ERR(vreg_ldo19));
return PTR_ERR(vreg_ldo19);
}
ret = regulator_enable(vreg_ldo19);
if (ret) {
pr_err("%s: unable to enable ldo19 voltage\n", __func__);
return PTR_ERR(vreg_ldo19);
}
return 0;
}
static int mantaray_regulator_init(struct platform_device *pdev)
{
return 0;
}
static void pdm_enable(void)
{
__raw_writel(PDM_OE, pdm_base + PDM_1_2_CTL);
__raw_writel(PDM_OE, pdm_base + PDM_2_0_CTL);
__raw_writel(PDM_OE, pdm_base + PDM_2_1_CTL);
__raw_writel(PDM_OE, pdm_base + PDM_2_2_CTL);
}
void pdm_mtr_enable(void)
{
__raw_writel(PDM_OE, pdm_base + PDM_1_2_CTL);
__raw_writel(0xb200, pdm_base + PDM_1_2_CTL + 4);
__raw_writel(PDM_OE, pdm_base + PDM_2_0_CTL);
__raw_writel(0xb200, pdm_base + PDM_2_0_CTL + 4);
__raw_writel(PDM_OE, pdm_base + PDM_2_1_CTL);
__raw_writel(0xb2, pdm_base + PDM_2_1_CTL + 4);
__raw_writel(PDM_OE, pdm_base + PDM_2_2_CTL);
__raw_writel(0xb200, pdm_base + PDM_2_2_CTL + 4);
}
static int ftr_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct ftr_dev_node_info *ptr;
struct resource *mem_res;
struct clk *pdm_clk;
int ret;
u8 version = 0;
pr_debug("%s: me = %p, parent = %p\n",
__func__, pdev, pdev->dev.parent);
mutex_lock(&rficlock);
if (nDev >= RFIC_DEVICE_NUM) {
pr_warn("%s: Invalid devices %d\n", __func__, nDev);
mutex_unlock(&rficlock);
return -EINVAL;
}
if (!nDev) {
rfbid = rf_interface_id();
rfbid = rfbid & RF_TYPE_48;
pr_info("%s: RF Board Type 0x%x\n", __func__, rfbid);
switch (rfbid) {
case RF_TYPE_16:
ftr_regulator_init(pdev);
wtr_regulator_init(pdev);
break;
case RF_TYPE_32:
ftr_regulator_init(pdev);
break;
case RF_TYPE_48:
mantaray_regulator_init(pdev);
break;
default:
pr_warn("%s:Regulators may not be turned ON %d\n",
__func__, rfbid);
}
rfbid = rf_interface_id();
pr_info("%s: RF Board Id 0x%x\n", __func__, rfbid);
switch (rfbid) {
case RF_TYPE_33:
fsm9900_gluon_init();
break;
case RF_TYPE_17:
case RF_TYPE_18:
fsm9900_rfic_init();
break;
default:
pr_warn("%s:GPIOs not configured %d\n",
__func__, rfbid);
}
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
grfc_base = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(grfc_base)) {
mutex_unlock(&rficlock);
return PTR_ERR(grfc_base);
}
ret = device_create_file(&pdev->dev, &dev_attr_rfboard_id);
WARN_ON(ret);
} else if ((nDev == 1) && (rfbid > RF_TYPE_48)) {
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pdm_base = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(pdm_base)) {
mutex_unlock(&rficlock);
return PTR_ERR(pdm_base);
}
pdm_clk = clk_get(&pdev->dev, "ahb_clk");
if (IS_ERR(pdm_clk)) {
pdm_clk = NULL;
pr_err("%s: AHB CLK is NULL\n", __func__);
} else {
pr_debug("%s: AHB CLK is 0x%x\n", __func__,
(unsigned int)pdm_clk);
clk_prepare(pdm_clk);
clk_enable(pdm_clk);
}
pdm_clk = clk_get(&pdev->dev, "pdm2_clk");
if (IS_ERR(pdm_clk)) {
pdm_clk = NULL;
pr_err("%s: PDM2 CLK is NULL\n", __func__);
} else {
pr_debug("%s: PDM2 CLK is 0x%x\n", __func__,
(unsigned int)pdm_clk);
clk_prepare(pdm_clk);
clk_enable(pdm_clk);
}
pdm_mtr_enable();
pr_info("%s: MTR PDM Enabled\n", __func__);
} else if ((nDev == 1) && (rfbid > RF_TYPE_16) &&
(rfbid < RF_TYPE_32)) {
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pdm_base = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(pdm_base)) {
mutex_unlock(&rficlock);
return PTR_ERR(pdm_base);
}
pdm_clk = clk_get(&pdev->dev, "ahb_clk");
if (IS_ERR(pdm_clk)) {
pdm_clk = NULL;
pr_err("%s: AHB CLK is NULL\n", __func__);
} else {
clk_prepare(pdm_clk);
clk_enable(pdm_clk);
}
pdm_clk = clk_get(&pdev->dev, "pdm2_clk");
if (IS_ERR(pdm_clk)) {
pdm_clk = NULL;
pr_err("%s: PDM2 CLK is NULL\n", __func__);
} else {
clk_prepare(pdm_clk);
clk_enable(pdm_clk);
}
pdm_enable();
pr_info("%s: PDM Enabled\n", __func__);
}
ptr = ftr_dev_info + nDev;
ptr->dev = &pdev->dev;
if (((rfbid & RF_TYPE_16) || ((rfbid & RF_TYPE_32))) && (nDev == 2)) {
ssbi_write(pdev->dev.parent, 0xff, &version, 1);
ssbi_read(pdev->dev.parent, 0x2, &version, 1);
pr_info("%s: FTR1 Version = %02x\n", __func__, version);
ptr->grfcctrladdr = grfc_base + 0x10; /* grp 4 */
ptr->grfcmaskaddr = grfc_base + 0x30;
__raw_writel(0x00001800, ptr->grfcmaskaddr);
ptr->maskvalue = 0x00001800;
ptr->busselect[TX1_BUS] = 0x00000000;
ptr->busselect[TX2_BUS] = 0x00001000;
ptr->busselect[MISC_BUS] = 0x00000800;
ptr->busselect[RX_BUS] = 0x00001800;
} else if (((rfbid & RF_TYPE_16) || ((rfbid & RF_TYPE_32))) &&
(nDev == 3)) {
ssbi_write(pdev->dev.parent, 0xff, &version, 1);
ssbi_read(pdev->dev.parent, 0x2, &version, 1);
pr_info("%s: FTR2 Version = %02x\n", __func__, version);
ptr->grfcctrladdr = grfc_base + 0x14; /* grp 5*/
ptr->grfcmaskaddr = grfc_base + 0x34;
__raw_writel(0x00000600, ptr->grfcmaskaddr);
ptr->maskvalue = 0x00000600;
ptr->busselect[TX1_BUS] = 0x000000;
ptr->busselect[TX2_BUS] = 0x00000400;
ptr->busselect[MISC_BUS] = 0x00000200;
ptr->busselect[RX_BUS] = 0x00000600;
}
mutex_init(&ptr->lock);
if (rfbid < RF_TYPE_48) {
ret = misc_register(ftr_misc_dev + nDev);
if (ret < 0) {
misc_deregister(ftr_misc_dev + nDev);
mutex_unlock(&rficlock);
return ret;
}
} else {
ret = misc_register(mtr_misc_dev + nDev);
if (ret < 0) {
misc_deregister(mtr_misc_dev + nDev);
mutex_unlock(&rficlock);
return ret;
}
}
nDev++;
pr_info("%s: num_of_ssbi_devices = %d\n", __func__, nDev);
mutex_unlock(&rficlock);
return of_platform_populate(np, NULL, NULL, &pdev->dev);
}
static int ftr_remove(struct platform_device *pdev)
{
int i;
if (rfbid < RF_TYPE_48) {
for (i = 0; i < RFIC_DEVICE_NUM; ++i)
misc_deregister(ftr_misc_dev + i);
} else {
for (i = 0; i < RFIC_MTR_DEVICE_NUM; ++i)
misc_deregister(mtr_misc_dev + i);
}
return 0;
}
static struct of_device_id rfic_match_table[] = {
{ .compatible = "qcom,rfic" },
{}
};
MODULE_DEVICE_TABLE(of, rfic_match_table);
static struct platform_driver ftr_driver = {
.probe = ftr_probe,
.remove = ftr_remove,
.driver = {
.name = "rfic",
.owner = THIS_MODULE,
.of_match_table = rfic_match_table,
},
};
int __init ftr_init(void)
{
int rc;
nDev = 0;
mutex_init(&rficlock);
pr_debug("%s: rfic-fsm9900 driver init\n", __func__);
rc = platform_driver_register(&ftr_driver);
return rc;
}
void __exit ftr_exit(void)
{
pr_debug("%s: rfic-fsm9900 driver exit\n", __func__);
platform_driver_unregister(&ftr_driver);
}
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Qualcomm fsm9900 RFIC driver");
module_init(ftr_init);
module_exit(ftr_exit);