#include <linux/init.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/delay.h>
#include <mach/dma.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
#include <mach/ldo.h>
#include <mach/adi_hal_internal.h>
#include <mach/regs_ana.h>
//add by zhangbing for intr.
#define __USE_EXTERNAL_INTR__
#ifdef __USE_EXTERNAL_INTR__
//add for irq mode
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/sched.h>
#endif
/*
* This supports acccess to SPI devices using normal userspace I/O calls.
* Note that while traditional UNIX/POSIX I/O semantics are half duplex,
* and often mask message boundaries, full SPI support requires full duplex
* transfers. There are several kinds of of internal message boundaries to
* handle chipselect management and other protocol options.
*
* SPI has a character major number assigned. We allocate minor numbers
* dynamically using a bitmask. You must use hotplug tools, such as udev
* (or mdev with busybox) to create and destroy the /dev/mxdspidevB.C device
* nodes, since there is no fixed association of minor numbers with any
* particular SPI bus or device.
*/
//#define SPIDEV_MAJOR 153 /* assigned */
int SPIDEV_MAJOR = 153; /* assigned */
#define N_SPI_MINORS 32 /* ... up to 256 */
static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG];
extern struct spi_device *sprd_spi_cmmb_device_register(int master_bus_num, struct spi_board_info *chip);
extern void sprd_spi_tmod(struct spi_device *spi, u32 transfer_mod);
/* Bit masks for spi_device.mode management. Note that incorrect
* settings for CS_HIGH and 3WIRE can cause *lots* of trouble for other
* devices on a shared bus: CS_HIGH, because this device will be
* active when it shouldn't be; 3WIRE, because when active it won't
* behave as it should.
*
* REVISIT should changing those two modes be privileged?
*/
#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP)
struct mxdspidev_data {
dev_t devt;
spinlock_t spi_lock;
struct spi_device *spi;
struct list_head device_entry;
//add by zhangbing.
#ifdef __USE_EXTERNAL_INTR__
/*add for irq mode*/
unsigned long irq_flag; /* irq flag */
unsigned char irq_enable;
wait_queue_head_t iowait; /* use for user space polling */
#endif
/* buffer is NULL unless this device is open (users > 0) */
struct mutex buf_lock;
unsigned users;
u8 *buffer;
};
static LIST_HEAD(device_list);
static DEFINE_MUTEX(device_list_lock);
static unsigned bufsiz = (64*1024);
module_param(bufsiz, uint, S_IRUGO);
MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
extern int sprd_3rdparty_gpio_cmmb_power;
extern int sprd_3rdparty_gpio_cmmb_reset;
extern int sprd_3rdparty_gpio_cmmb_irq;
static int spi_cs_gpio;
int comip_mxd0251_power(int onoff)
{
if (onoff) {
//gpio_direction_output(sprd_3rdparty_gpio_cmmb_power, 1);
/*
LDO_VOLT_LEVEL2 1.8mv
LDO_VOLT_LEVEL3 1.2mv */
LDO_SetVoltLevel(LDO_LDO_SIM3,LDO_VOLT_LEVEL3);
LDO_TurnOffLDO(LDO_LDO_SIM3);// add by duanxufang;
printk("maxscend:dxf,LDO_TurnOffLDO power-on 1");
LDO_SetVoltLevel(LDO_LDO_RF1,LDO_VOLT_LEVEL2);
LDO_TurnOnLDO(LDO_LDO_RF1);
LDO_SetVoltLevel(LDO_LDO_SIM3,LDO_VOLT_LEVEL3);
LDO_TurnOffLDO(LDO_LDO_SIM3);// add by duanxufang;
printk("maxscend:dxf,LDO_TurnOffLDO power-on 2");
msleep(20);
gpio_direction_output(spi_cs_gpio, 1);
ANA_REG_OR(ANA_MIXED_CTRL, BIT_6);//REF1_OUT
msleep(20);
gpio_direction_output(sprd_3rdparty_gpio_cmmb_reset, 1);
msleep(20);
gpio_direction_output(sprd_3rdparty_gpio_cmmb_reset, 0);
msleep(100);
gpio_direction_output(sprd_3rdparty_gpio_cmmb_reset, 1);
msleep(10);
}
else
{
ANA_REG_AND(ANA_MIXED_CTRL, ~BIT_6);
gpio_direction_output(sprd_3rdparty_gpio_cmmb_reset, 0);
gpio_direction_output(spi_cs_gpio, 0);
//gpio_direction_output(sprd_3rdparty_gpio_cmmb_power, 0);
LDO_TurnOffLDO(LDO_LDO_RF1);
LDO_SetVoltLevel(LDO_LDO_SIM3,LDO_VOLT_LEVEL3);
LDO_TurnOffLDO(LDO_LDO_SIM3);// add by duanxufang;
printk("maxscend:dxf,LDO_TurnOffLDO power off");
//gpio_direction_input(mxd0251_gpio_int);
msleep(10);
}
return 0;
}
/*-------------------------------------------------------------------------*/
/*
* We can't use the standard synchronous wrappers for file I/O; we
* need to protect against async removal of the underlying spi_device.
*/
static void mxdspidev_complete(void *arg)
{
complete(arg);
}
static ssize_t
mxdspidev_sync(struct mxdspidev_data *mxdspidev, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);
int status;
message->complete = mxdspidev_complete;
message->context = &done;
spin_lock_irq(&mxdspidev->spi_lock);
if (mxdspidev->spi == NULL)
status = -ESHUTDOWN;
else
status = spi_async(mxdspidev-&