blob: a462d882bc6e7801889b1884d1481a4d508bdb0c [file] [log] [blame]
/***************************************************************************
* Copyright (c) 2014 Amlogic, Inc. All rights reserved.
*
* This source code is subject to the terms and conditions defined in the
* file 'LICENSE' which is part of this source code package.
*
* Description:
*
***************************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/of.h>
#include "../aml_ci.h"
#include "aml_cimax.h"
#include "aml_cimax_spi.h"
#include "aml_cimax_usb.h"
#define MODUDLE_NAME "aml_cimax"
MODULE_PARM_DESC(cimax_debug, "enable verbose debug messages");
static int aml_cimax_debug = 1;
module_param_named(cimax_debug, aml_cimax_debug, int, 0644);
//static struct switch_dev slot_state = {
// .name = "ci_slot",
//};
#define pr_dbg(fmt...)\
do {\
if (aml_cimax_debug)\
pr_info("AML_CIMAX: " fmt);\
} while (0)
#define pr_error(fmt...) pr_err("AML_CIMAX: " fmt)
static int aml_cimax_slot_reset(struct aml_ci *ci, int slot)
{
int ret = 0;
struct aml_cimax *cimax = ci->data;
pr_dbg("cimax: slot(%d) reset\n", slot);
if (cimax->ops.slot_reset)
ret = cimax->ops.slot_reset(cimax, slot);
return ret;
}
static int aml_cimax_slot_shutdown(struct aml_ci *ci, int slot)
{
pr_dbg("slot(%d) shutdown\n", slot);
return 0;
}
static int aml_cimax_slot_ts_enable(struct aml_ci *ci, int slot)
{
pr_dbg("slot(%d) ts control\n", slot);
return 0;
}
static int aml_cimax_slot_status(struct aml_ci *ci, int slot, int open)
{
int ret = 0;
struct aml_cimax *cimax = ci->data;
/*pr_dbg("cimax: slot(%d) poll\n", slot);*/
if (cimax->ops.slot_status)
ret = cimax->ops.slot_status(cimax, slot);
return ret;
}
#define DEF_FUNC_WRAPPER3(_pre, _fn, _S, _P1, _P2, _P3) \
static int _pre##_fn(_S s, _P1 p1, _P2 p2, _P3 p3)\
{\
struct aml_cimax *cimax = s->data;\
/*pr_dbg("%s\n", #_fn);*/\
if (cimax->ops._fn)\
return cimax->ops._fn(cimax, p1, p2, p3);\
return 0;\
}
/*DEF_FUNC_WRAPPER3(aml_cimax_, read_reg, struct aml_ci*, int, u8*, int)*/
/*DEF_FUNC_WRAPPER3(aml_cimax_, write_reg, struct aml_ci*, int, u8*, int)*/
DEF_FUNC_WRAPPER3(aml_cimax_, read_cis, struct aml_ci*, int, u8*, int)
DEF_FUNC_WRAPPER3(aml_cimax_, read_lpdu, struct aml_ci*, int, u8*, int)
DEF_FUNC_WRAPPER3(aml_cimax_, write_lpdu, struct aml_ci*, int, u8*, int)
static int aml_cimax_write_cor(struct aml_ci *ci, int slot, int addr, u8 *buf)
{
struct aml_cimax *cimax = ci->data;
pr_dbg("write_cor\n");
if (cimax->ops.write_cor)
return cimax->ops.write_cor(cimax, slot, addr, buf);
return 0;
}
static int aml_cimax_negotiate(struct aml_ci *ci, int slot, int size)
{
struct aml_cimax *cimax = ci->data;
pr_dbg("negotiate\n");
if (cimax->ops.negotiate)
return cimax->ops.negotiate(cimax, slot, size);
return 0;
}
static int aml_cimax_read_cam_status(struct aml_ci *ci, int slot)
{
struct aml_cimax *cimax = ci->data;
if (cimax->ops.read_cam_status)
return cimax->ops.read_cam_status(cimax, slot);
return 0;
}
static int aml_cimax_cam_reset(struct aml_ci *ci, int slot)
{
struct aml_cimax *cimax = ci->data;
if (cimax->ops.cam_reset)
return cimax->ops.cam_reset(cimax, slot);
return 0;
}
static int aml_cimax_get_capbility(struct aml_ci *ci, int slot)
{
return 0;
}
int aml_cimax_camchanged(struct aml_cimax *cimax, int slot, int plugin)
{
struct aml_ci *ci = cimax->ci;
if (plugin) {
dvb_ca_en50221_cimax_camchange_irq(&ci->en50221_cimax,
slot, DVB_CA_EN50221_CAMCHANGE_INSERTED);
} else {
dvb_ca_en50221_cimax_camchange_irq(&ci->en50221_cimax,
slot, DVB_CA_EN50221_CAMCHANGE_REMOVED);
}
return 0;
}
static int aml_cimax_start(struct aml_cimax *cimax)
{
int ret = 0;
if (cimax->ops.start)
ret = cimax->ops.start(cimax);
return ret;
}
static int aml_cimax_stop(struct aml_cimax *cimax)
{
int ret = 0;
if (cimax->ops.stop)
ret = cimax->ops.stop(cimax);
return ret;
}
static int aml_cimax_get_config_from_dts(struct aml_cimax *cimax)
{
struct device_node *child = NULL;
struct platform_device *pdev = cimax->pdev;
struct device_node *np = pdev->dev.of_node;
unsigned int val;
int ret = 0;
pr_dbg("get cimax dts\n");
child = of_get_child_by_name(np, "cimax");
if (child == NULL) {
pr_error("failed to get cimax\n");
return -1;
}
ret = of_property_read_u32(child, "io_type", &val);
if (ret)
cimax->io_type = IO_TYPE_SPI;
else
cimax->io_type = val;
return 0;
}
int aml_cimax_init(struct platform_device *pdev, struct aml_ci *ci)
{
struct aml_cimax *cimax = NULL;
int ret = 0;
cimax = kzalloc(sizeof(struct aml_cimax), GFP_KERNEL);
if (!cimax) {
pr_error("Out of memory!, exiting ..\n");
return -ENOMEM;
}
cimax->pdev = pdev;
cimax->ci = ci;
aml_cimax_get_config_from_dts(cimax);
if (cimax->io_type == IO_TYPE_SPI) {
//ret = aml_cimax_spi_init(pdev, cimax);
}
else {
ret = aml_cimax_usb_init(pdev, cimax);
}
if (ret != 0) {
kfree(cimax);
cimax = NULL;
return -EIO;
}
ret = aml_cimax_start(cimax);
if (ret != 0)
return ret;
ci->data = cimax;
ci->ci_read_cis = aml_cimax_read_cis;
ci->ci_write_cor = aml_cimax_write_cor;
ci->ci_negotiate = aml_cimax_negotiate;
ci->ci_read_lpdu = aml_cimax_read_lpdu;
ci->ci_write_lpdu = aml_cimax_write_lpdu;
ci->ci_read_cam_status = aml_cimax_read_cam_status;
ci->ci_cam_reset = aml_cimax_cam_reset;
ci->ci_get_capbility = aml_cimax_get_capbility;
ci->ci_slot_reset = aml_cimax_slot_reset;
ci->ci_slot_shutdown = aml_cimax_slot_shutdown;
ci->ci_slot_ts_enable = aml_cimax_slot_ts_enable;
ci->ci_poll_slot_status = aml_cimax_slot_status;
return 0;
}
EXPORT_SYMBOL(aml_cimax_init);
int aml_cimax_exit(struct aml_ci *ci)
{
struct aml_cimax *cimax = ci->data;
ci->ci_read_cis = NULL;
ci->ci_write_cor = NULL;
ci->ci_negotiate = NULL;
ci->ci_read_lpdu = NULL;
ci->ci_write_lpdu = NULL;
ci->ci_read_cam_status = NULL;
ci->ci_cam_reset = NULL;
ci->ci_get_capbility = NULL;
ci->ci_slot_reset = NULL;
ci->ci_slot_shutdown = NULL;
ci->ci_slot_ts_enable = NULL;
ci->ci_poll_slot_status = NULL;
aml_cimax_stop(cimax);
if (cimax->io_type == IO_TYPE_SPI) {
//aml_cimax_spi_exit(cimax);
}
else {
aml_cimax_usb_exit(cimax);
}
kfree(cimax);
ci->data = NULL;
return 0;
}
EXPORT_SYMBOL(aml_cimax_exit);
int aml_cimax_slot_state_changed(struct aml_cimax *cimax, int slot, int state)
{
//if (slot == 0)
// switch_set_state(&slot_state, state);
return 0;
}
EXPORT_SYMBOL(aml_cimax_slot_state_changed);
#if 0
static int __init aml_cimax_mod_init(void)
{
pr_dbg("Amlogic DVB CIMAX Init\n");
//switch_dev_register(&slot_state);
//switch_set_state(&slot_state, 0);
return 0;
}
static void __exit aml_cimax_mod_exit(void)
{
pr_dbg("Amlogic DVB CIMAX Exit\n");
//switch_dev_unregister(&slot_state);
}
module_init(aml_cimax_mod_init);
module_exit(aml_cimax_mod_exit);
MODULE_LICENSE("GPL");
#endif