

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <asm/current.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/err.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <asm-generic/ioctl.h>

#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/wait.h>

#include "stm32f4xx.h"
#include "stm32f4xx_hal_gpio.h"
#include "stm32_hal_legacy.h"
#include "stm32f4xx_hal_i2c.h"
#include "driver.h"


#define  I2C_MAJOR  MAJOR_I2C
//static int minor = 0;
//static dev_t devno;
//static struct cdev *i2c_cdev = NULL;
//static int count = 3;
//static int ret=0;
#define DEVNAME "i2c"
#define NUM_OF_DEVICES	3

static uint8_t i2c_rcv_buf[100];
static uint8_t i2c_rcv_size;

static DECLARE_WAIT_QUEUE_HEAD(wq_1);
static DECLARE_WAIT_QUEUE_HEAD(wq_2);
static DECLARE_WAIT_QUEUE_HEAD(wq_3);
static int ev_press_1 = 0, ev_press_2 = 0, ev_press_3 = 0;


struct i2c_device {
	dev_t devno;
	struct cdev cdev;
	char name[16];
	IRQn_Type	Event_IRQn;
	IRQn_Type	Err_IRQn;
} i2c_dev[NUM_OF_DEVICES];

static int i2c_open(struct inode *inode, struct file *filep);
static int i2c_close(struct inode *inode, struct file *filep);
static ssize_t i2c_read(struct file *filep, char __user *buf, size_t size, loff_t *offset);
static ssize_t i2c_write(struct file *filep, const char __user *buf, size_t size, loff_t *offset);
static int i2c_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);

static struct file_operations i2c_ops = 
{
	.owner = THIS_MODULE,
	.open = i2c_open,
	.release = i2c_close,
	.ioctl = i2c_ioctl,
	.read = i2c_read,
	.write = i2c_write,
	
};

static int i2c_open(struct inode *inode, struct file *filep)
{
	int imajor,iminor;
	I2C_HandleTypeDef hi2c;
	imajor = MAJOR(inode->i_rdev);
	iminor = MINOR(inode->i_rdev);

	if(imajor != I2C_MAJOR)
	{
		printk("Error: %s %d i2c major fail! %d\n",__FILE__,__LINE__,imajor);
		return -1;
	}
	switch(iminor)
	{
	case 0:
		HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
		HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
		hi2c.Instance = I2C1;
		//printk("i2c1 open\n");
		break;
	case 1:
		HAL_NVIC_EnableIRQ(I2C2_EV_IRQn);
		HAL_NVIC_EnableIRQ(I2C2_ER_IRQn);
		hi2c.Instance = I2C2;
		//printk("i2c2 open\n");
		break;
	case 2:
		HAL_NVIC_EnableIRQ(I2C3_EV_IRQn);
		HAL_NVIC_EnableIRQ(I2C3_ER_IRQn);
		hi2c.Instance = I2C3;
		//printk("i2c3 open\n");
		break;
	default:
		printk("Error:%s %d Invalid minor %d",__FILE__,__LINE__,iminor);
		return -1;
	}

	
	__HAL_I2C_DISABLE(&hi2c);	//clear all flags.
	hi2c.State = HAL_I2C_STATE_READY;
	__HAL_I2C_ENABLE(&hi2c);
	//HAL_I2C_EnableListen_IT(&hi2c);
	//printk("Open SR1 %#x, SR2: %#x\n", hi2c.Instance->SR1, hi2c.Instance->SR2);
	return 0;
}

static int i2c_close(struct inode *inode, struct file *filep)
{
	return 0;
}

irqreturn_t i2cErrIRQHandler(int irqno, void *dev_id)
{
	I2C_HandleTypeDef hi2c; 
	switch(irqno)
	{
	case I2C1_ER_IRQn:
		hi2c.Instance = I2C1;
		printk("i2c1 Error, restart...\n");
		break;
	case I2C2_ER_IRQn:
		hi2c.Instance = I2C2;
		printk("i2c2 Error, restart...\n");
		break;
	case I2C3_ER_IRQn:
		hi2c.Instance = I2C3;
		printk("i2c3 Error, restart...\n");
		break;
	default: 
		printk("Unknow irqno! %#x\n", irqno);
		return IRQ_HANDLED;
	}

	printk("SR1: %#x, SR2: %#x\n", hi2c.Instance->SR1, hi2c.Instance->SR2);

	//restart i2c
	hi2c.State	= HAL_I2C_STATE_READY;
	__HAL_I2C_DISABLE(&hi2c);
	__HAL_I2C_ENABLE(&hi2c);
	
	return IRQ_HANDLED;
}

/**
 ** @brief  This function handles I2C event interrupt request.
 ** @param  
 ** @retval 
 **/
irqreturn_t i2cEvIRQHandler(int irqno, void *dev_id)
{
	I2C_HandleTypeDef hi2c; 
	uint32_t sr2itflags;   
	uint32_t sr1itflags;   
	uint32_t itsources;    
	uint32_t CurrentMode;  
	wait_queue_head_t *pwq = NULL;
	int *pev_press = NULL;

//	memcpy(h12c, &I2cHandle, sizeof(I2C_HandleTypeDef));

	switch(irqno)
	{
	case I2C1_EV_IRQn:
		hi2c.Instance = I2C1;
		pwq = &wq_1;
		pev_press = &ev_press_1;
		break;
	case I2C2_EV_IRQn:
		hi2c.Instance = I2C2;
		pwq = &wq_2;
		pev_press = &ev_press_2;
		break;
	case I2C3_EV_IRQn:
		hi2c.Instance = I2C3;
		pwq = &wq_3;
		pev_press = &ev_press_3;
		break;
	default: 
		return IRQ_HANDLED;
	}

	hi2c.Mode	= HAL_I2C_MODE_SLAVE;
	sr2itflags	= READ_REG(hi2c.Instance->SR2);
	sr1itflags  = READ_REG(hi2c.Instance->SR1);
	itsources   = READ_REG(hi2c.Instance->CR2);
	CurrentMode = hi2c.Mode;
   
    //printk("SR1: %#x, SR2: %#x, CR2: %#x\n", sr1itflags, sr2itflags, itsources);
	/* Slave mode selected */
	/* ADDR set --------------------------------------------------------------*/
	if(((sr1itflags & I2C_FLAG_ADDR) != RESET) && ((itsources & I2C_IT_EVT) != RESET))
	{
		i2c_rcv_size = 0;
		/* Clear ADDR flag */
		__HAL_I2C_CLEAR_ADDRFLAG(&hi2c);
	}
	else if(((sr1itflags & I2C_FLAG_RXNE) != RESET))
	{
		i2c_rcv_buf[i2c_rcv_size++] = hi2c.Instance->DR;
	}
	/* STOPF set --------------------------------------------------------------*/
	else if(((sr1itflags & I2C_FLAG_STOPF) != RESET) && ((itsources & I2C_IT_EVT) != RESET))
	{
		/* Clear STOPF flag */
		__HAL_I2C_CLEAR_STOPFLAG(&hi2c);
		if(i2c_rcv_size > 0)
		{
			*pev_press	= 1;
			wake_up_interruptible(pwq);		
		}
		//printk("irqno: %#x\n", irqno);

	}
	else
	{
		//clear all flags
		//printk("---> Unknow irq\n");
		hi2c.State	= HAL_I2C_STATE_READY;
		//__HAL_I2C_DISABLE(&hi2c);
		//__HAL_I2C_ENABLE(&hi2c);
	}


	return IRQ_HANDLED;
}

static int i2c_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg)
{
	uint32_t			pclk1 = 0;
	I2C_HandleTypeDef	I2CxHandle;
	i2c_arg_t			i2c_arg;
	int					imajor,iminor;
	HAL_StatusTypeDef	retSta;
	IRQn_Type			I2CxEvIRQn;
	wait_queue_head_t *pwq = NULL;
	int *pev_press = NULL;
	int 			retval = 0;

	imajor = MAJOR(inode->i_rdev);
	iminor = MINOR(inode->i_rdev);

	if(imajor != I2C_MAJOR)
	{
		printk("Error: %s %d i2c major fail! %d\n",__FILE__,__LINE__,imajor);
		return -EFAULT;
	}
	
	

	if(iminor == 0)
	{
		I2CxHandle.Instance = I2C1;
		I2CxEvIRQn	=	I2C1_EV_IRQn;
		pwq = &wq_1;
		pev_press = &ev_press_1;
	}
	else if(iminor == 1)
	{
		I2CxHandle.Instance = I2C2;
		I2CxEvIRQn	=	I2C2_EV_IRQn;
		pwq = &wq_2;
		pev_press = &ev_press_2;
	}
	else if(iminor == 2)
	{
		I2CxHandle.Instance = I2C3;
		I2CxEvIRQn	=	I2C3_EV_IRQn;
		pwq = &wq_3;
		pev_press = &ev_press_3;
	}
	else
	{
		printk(KERN_ERR"Invalid minor\n");
		return -EFAULT;
	} 

	switch(cmd)
	{
	case SET_I2C_SPEED:
		if ( copy_from_user(&i2c_arg, (void*)arg, 11) != 0)
		{
			printk("---> copy form user space fail!\n");
			return -EFAULT;
		}
		/* Get PCLK1 frequency */
		pclk1 = HAL_RCC_GetPCLK1Freq();
		__HAL_I2C_DISABLE(&I2CxHandle);

		if(i2c_arg.ClockSpeed <= 100000)
			I2CxHandle.Instance->CCR = I2C_SPEED_STANDARD(pclk1, i2c_arg.ClockSpeed) & 0x7fff;
		else
			I2CxHandle.Instance->CCR = I2C_SPEED_FAST(pclk1, i2c_arg.ClockSpeed, I2C_DUTYCYCLE_16_9) | 0x8000;

		__HAL_I2C_ENABLE(&I2CxHandle);
		break;
	
	case GET_I2C_SPEED:
		pclk1 = HAL_RCC_GetPCLK1Freq();
		if(I2CxHandle.Instance->CCR & 0x8000)	//fast mode
			i2c_arg.ClockSpeed = pclk1/((I2CxHandle.Instance->CCR & I2C_CCR_CCR)*25);
		else	//slow mode
			i2c_arg.ClockSpeed = pclk1/((I2CxHandle.Instance->CCR & I2C_CCR_CCR)<<1);

		if(copy_to_user((void*)arg, &i2c_arg, 11))
			return -EFAULT;
		break;
	
	case SET_I2C_ADDR:	//8bit
		__HAL_I2C_DISABLE(&I2CxHandle);
		if ( copy_from_user(&i2c_arg, (void*)arg, 11) != 0)
		{
			printk("---> copy form user space fail!\n");
			return -EFAULT;
		}
		/* Configure I2Cx: Own Address1 and addressing mode */
		I2CxHandle.Instance->OAR1 = (I2C_ADDRESSINGMODE_7BIT | i2c_arg.OwnAddress1)&0xff;
		
		__HAL_I2C_ENABLE(&I2CxHandle);
//		printk("OAR1: %#x\n", I2CxHandle.Instance->OAR1);
		break;

	case GET_I2C_ADDR:	//8bit
		i2c_arg.OwnAddress1	= I2CxHandle.Instance->OAR1 & 0x0ff;
		if(copy_to_user((void*)arg, &i2c_arg, 11))
			return -EFAULT;
		break;

	case I2C_MASTER_TRANSFER:
		__HAL_I2C_DISABLE_IT(&I2CxHandle, I2C_IT_EVT | I2C_IT_ERR);
		if ( copy_from_user(&i2c_arg, (void*)arg, sizeof(i2c_arg_t)) != 0)
		{
			printk("---> copy form user space fail!\n");
			return -EFAULT;
		}
		I2CxHandle.State = HAL_I2C_STATE_READY;
		I2CxHandle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
		retSta = HAL_I2C_Master_Transmit(&I2CxHandle, (uint16_t)i2c_arg.DevAddress, i2c_arg.Buf, i2c_arg.WriteLen, 100);	//timeout 1s
		if(retSta != HAL_OK)
		{
			retval = -1;
			//printk(KERN_ERR"I2C master tansfer error, Addr %#x, minor = %d, Err = %#x\n", i2c_arg.DevAddress, iminor, retSta);
		}

		__HAL_I2C_ENABLE_IT(&I2CxHandle, I2C_IT_EVT | I2C_IT_ERR);
		break;

	case I2C_MASTER_RECEIVE:
		__HAL_I2C_DISABLE_IT(&I2CxHandle, I2C_IT_EVT | I2C_IT_ERR);
		if ( copy_from_user(&i2c_arg, (void*)arg, 11) != 0)
		{
			printk("---> copy form user space fail!\n");
			return -EFAULT;
		}
		I2CxHandle.State = HAL_I2C_STATE_READY;
		I2CxHandle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
		//printk("CR1 %#x, CR2 %#x, SR1 %#x, SR2 %#x\n", );
		retSta = HAL_I2C_Master_Receive(&I2CxHandle, (uint16_t) i2c_arg.DevAddress, i2c_arg.Buf, i2c_arg.ReadLen, 100);	//timeout 1s
		if(retSta != HAL_OK)
		{
			//printk(KERN_ERR"I2C master recevice error, Addr %#x, retSta %d!\n", i2c_arg.DevAddress, retSta);
			retval = -1;
		}
		if(copy_to_user((void*)arg, &i2c_arg, 11+i2c_arg.ReadLen))
			return -EFAULT;
		
		__HAL_I2C_ENABLE_IT(&I2CxHandle, I2C_IT_EVT | I2C_IT_ERR);
		break;
	
	case I2C_SLAVE_RECEIVE_IT:
		I2CxHandle.State = HAL_I2C_STATE_READY;
		HAL_I2C_EnableListen_IT(&I2CxHandle);
		if(0 == wait_event_interruptible_timeout(*pwq, *pev_press, 3*HZ))	//3s
		{
			i2c_arg.ReadLen	= 0;
		}
		else
		{
			*pev_press = 0;
			memcpy(i2c_arg.Buf, i2c_rcv_buf, i2c_rcv_size);	
			i2c_arg.ReadLen	= i2c_rcv_size;
		}
		
		//printk("SR1: %#x, SR2: %#x, CR1: %#x, CR2: %#x\n", I2CxHandle.Instance->SR1, 
		//	I2CxHandle.Instance->SR2, I2CxHandle.Instance->CR1, I2CxHandle.Instance->CR2);

		if(copy_to_user((void*)arg, &i2c_arg, 11+i2c_arg.ReadLen))
			return -EFAULT;
		break;
	case I2C_MASTER_TRANSFER_RECEIVE:
		__HAL_I2C_DISABLE_IT(&I2CxHandle, I2C_IT_EVT | I2C_IT_ERR);
		if ( copy_from_user(&i2c_arg, (void*)arg, sizeof(i2c_arg_t)) != 0)
		{
			printk("---> copy form user space fail!\n");
			return -EFAULT;
		}
		I2CxHandle.State = HAL_I2C_STATE_READY;
		I2CxHandle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
		retSta = HAL_I2C_Master_Transmit_Receive(&I2CxHandle, (uint16_t)i2c_arg.DevAddress,i2c_arg.Buf, i2c_arg.WriteLen, i2c_arg.Buf, i2c_arg.ReadLen, 100);	
		if(retSta != HAL_OK)
		{
			retval = -1;
		}
		if(copy_to_user((void*)arg, &i2c_arg, 11+i2c_arg.ReadLen))
			return -EFAULT;
		
		__HAL_I2C_ENABLE_IT(&I2CxHandle, I2C_IT_EVT | I2C_IT_ERR);
		break;
	default:
		printk("---> Invalid action\n");
		return -1;
		break;

	}	

	return retval;
}

static ssize_t i2c_read(struct file *filep, char __user *buf, size_t size, loff_t *offset)
{
	return 0;
}

static ssize_t i2c_write(struct file *filep, const char __user *buf, size_t size, loff_t *offset)
{
	return 0;
}

void i2c_hw_init(void)
{
	I2C_HandleTypeDef I2cHandle;
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	//enable periph clock	
	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();
	__HAL_RCC_GPIOC_CLK_ENABLE();
	__HAL_RCC_GPIOH_CLK_ENABLE();
	__HAL_RCC_I2C1_CLK_ENABLE();
	__HAL_RCC_I2C2_CLK_ENABLE();
	__HAL_RCC_I2C3_CLK_ENABLE();

	//config gpio
	GPIO_InitStruct.Mode	= GPIO_MODE_AF_OD;
	GPIO_InitStruct.Pull    = GPIO_PULLUP;
	GPIO_InitStruct.Speed   = GPIO_SPEED_FAST;
	
	//I2C1
	GPIO_InitStruct.Pin		= GPIO_PIN_6 | GPIO_PIN_7;	//SCL | SDA
	GPIO_InitStruct.Alternate	= GPIO_AF4_I2C1;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	//I2C2
	GPIO_InitStruct.Pin		= GPIO_PIN_4 | GPIO_PIN_5;	//SCL | SDA
	GPIO_InitStruct.Alternate	= GPIO_AF4_I2C2;
	HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);

	//I2C3
	GPIO_InitStruct.Alternate	= GPIO_AF4_I2C3;
	GPIO_InitStruct.Pin		= GPIO_PIN_8;	//SCL
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	GPIO_InitStruct.Pin		= GPIO_PIN_9;	//SDA
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
	
	//config I2C controller
	I2cHandle.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;
	I2cHandle.Init.ClockSpeed      = 100000;
	I2cHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
	I2cHandle.Init.DutyCycle       = I2C_DUTYCYCLE_16_9;
	I2cHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
	I2cHandle.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLE;
	I2cHandle.Init.OwnAddress1     = 0x22;	//default address
	I2cHandle.Init.OwnAddress2     = 0xFE;
	I2cHandle.State				   = HAL_I2C_STATE_READY;

	I2cHandle.Instance             = I2C1;
	if(HAL_I2C_Init(&I2cHandle) != HAL_OK)
	{
		printk(KERN_ERR"I2C1 hw init error!\n");
	}
	HAL_NVIC_SetPriority(I2C1_EV_IRQn, 2, 0);
	HAL_NVIC_SetPriority(I2C1_ER_IRQn, 15, 0);
	//HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
	//HAL_I2C_EnableListen_IT(&I2cHandle);

	I2cHandle.Instance             = I2C2;
	if(HAL_I2C_Init(&I2cHandle) != HAL_OK)
	{
		printk(KERN_ERR"I2C1 hw init error!\n");
	}
	HAL_NVIC_SetPriority(I2C2_EV_IRQn, 2, 0);
	HAL_NVIC_SetPriority(I2C2_ER_IRQn, 15, 0);
	//HAL_NVIC_EnableIRQ(I2C2_EV_IRQn);
	//HAL_I2C_EnableListen_IT(&I2cHandle);
	
	I2cHandle.Instance             = I2C3;
	if(HAL_I2C_Init(&I2cHandle) != HAL_OK)
	{
		printk(KERN_ERR"I2C1 hw init error!\n");
	}
	HAL_NVIC_SetPriority(I2C3_EV_IRQn, 2, 0);
	HAL_NVIC_SetPriority(I2C3_ER_IRQn, 15, 0);
	//HAL_NVIC_EnableIRQ(I2C3_EV_IRQn);
	//HAL_I2C_EnableListen_IT(&I2cHandle);

}




static int __init i2c_init(void)
{
	int ret;
	int i;

	for (i = 0; i < NUM_OF_DEVICES; i++)
	{
		printk("i2c%d module start...\n", i+1);
	    i2c_dev[i].devno = MKDEV(MAJOR_I2C, i);
		sprintf(i2c_dev[i].name, "%s%d", DEVNAME, i+1);
		register_chrdev_region(i2c_dev[i].devno, 1, i2c_dev[i].name);
		     
		cdev_add(&i2c_dev[i].cdev, i2c_dev[i].devno, 1);
		cdev_init(&i2c_dev[i].cdev, &i2c_ops);
	}
	
	i2c_hw_init();	

	i2c_dev[0].Event_IRQn	= I2C1_EV_IRQn;
	i2c_dev[1].Event_IRQn	= I2C2_EV_IRQn;
	i2c_dev[2].Event_IRQn	= I2C3_EV_IRQn;
	i2c_dev[0].Err_IRQn	= I2C1_ER_IRQn;
	i2c_dev[1].Err_IRQn	= I2C2_ER_IRQn;
	i2c_dev[2].Err_IRQn	= I2C3_ER_IRQn;

	
	for(i=0; i<NUM_OF_DEVICES; i++)
	{
		ret = request_irq(i2c_dev[i].Event_IRQn, i2cEvIRQHandler, IRQF_SHARED, i2c_dev[i].name, &i2c_dev[i].devno);
		if(ret) {
			printk("request_irq() event fialed! %d\n", ret);
			goto ERR_STEP1;
		}

		ret = request_irq(i2c_dev[i].Err_IRQn, i2cErrIRQHandler, IRQF_SHARED, i2c_dev[i].name, &i2c_dev[i].devno);
		if(ret) {
			printk("request_irq() error fialed! %d\n", ret);
			goto ERR_STEP1;
		}
	
	}
	return 0;

ERR_STEP1:
	for(i=0;i<NUM_OF_DEVICES;i++)
		unregister_chrdev_region(i2c_dev[i].devno,1);
//ERR_STEP:
	for(i=0;i<NUM_OF_DEVICES;i++)
		cdev_del(&i2c_dev[i].cdev);
	return ret;
}

static void __exit i2c_exit(void)
{
	int i;
	for(i=0;i<NUM_OF_DEVICES;i++)
	{
		unregister_chrdev_region(i2c_dev[i].devno, 1);
		cdev_del(&i2c_dev[i].cdev);
	}
}

module_init(i2c_init);
module_exit(i2c_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jimbo");
MODULE_DESCRIPTION("this is i2c module");



