420 lines
9.1 KiB
C
420 lines
9.1 KiB
C
/* isp/piris.c
|
|
*
|
|
* Copyright (c) 2006 Hisilicon Co., Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program;
|
|
*
|
|
* History:
|
|
* 23-march-2011 create this file
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/miscdevice.h>
|
|
#include <linux/fcntl.h>
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/hrtimer.h>
|
|
|
|
#include <asm/uaccess.h>
|
|
#include <asm/system.h>
|
|
#include <asm/io.h>
|
|
|
|
#include "piris.h"
|
|
#include "piris_ext.h"
|
|
|
|
|
|
#define PIRISI_ADRESS_BASE 0x20210000 // Piris use GPIO13
|
|
|
|
void __iomem* reg_pirisI_base_va = 0;
|
|
|
|
#define HI_IO_PIRISI_ADDRESS(x) (reg_pirisI_base_va + ((x)-(PIRISI_ADRESS_BASE)))
|
|
|
|
#define PIRIS_CFG_REG HI_IO_PIRISI_ADDRESS(PIRISI_ADRESS_BASE + 0x007C)
|
|
#define PIRIS_CTRL_REG HI_IO_PIRISI_ADDRESS(PIRISI_ADRESS_BASE + 0x0400)
|
|
|
|
#define PIRIS_WRITE_REG(Addr, Value) ((*(volatile unsigned int *)(Addr)) = (Value))
|
|
#define PIRIS_READ_REG(Addr) (*(volatile unsigned int *)(Addr))
|
|
|
|
|
|
#define MAX(a, b) (a > b? a : b)
|
|
#define MIN(a, b) (a < b? a : b)
|
|
#define MAX_MOTOR_PAHSE 4
|
|
#define MAX_STEPS 92
|
|
#define PIRIS_PPS 100
|
|
|
|
static const unsigned char motor_phase_tbl[MAX_MOTOR_PAHSE] = { 0x0, 0x1, 0x2, 0x3};
|
|
|
|
typedef struct hiPIRIS_DEV
|
|
{
|
|
int src_pos;
|
|
int dest_pos;
|
|
unsigned int pps;
|
|
int phase;
|
|
const unsigned char* phase_tbl;
|
|
struct semaphore sem;
|
|
struct timer_list timer;
|
|
} PIRIS_DEV;
|
|
|
|
static PIRIS_DEV* p_piris_dev;
|
|
|
|
DECLARE_COMPLETION(piris_comp);
|
|
|
|
|
|
int piris_gpio_update(int* pPirisPos)
|
|
{
|
|
p_piris_dev->dest_pos = *pPirisPos;
|
|
|
|
p_piris_dev->pps = PIRIS_PPS;
|
|
p_piris_dev->pps = MAX(MIN(p_piris_dev->pps, HZ), 1);
|
|
p_piris_dev->timer.expires = jiffies + HZ / p_piris_dev->pps;
|
|
|
|
/* whether piris timer already at the kerbel timer pending list */
|
|
if (p_piris_dev->timer.entry.next != NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
add_timer(&p_piris_dev->timer);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* first go to the full open iris step, set the full open as origin */
|
|
int piris_origin_set(PIRIS_DATA_S* pstPirisData)
|
|
{
|
|
int piris_pos;
|
|
|
|
piris_pos = pstPirisData->CurPos;
|
|
|
|
piris_gpio_update(&piris_pos);
|
|
|
|
// wait for piris origin done
|
|
init_completion(&piris_comp);
|
|
wait_for_completion(&piris_comp);
|
|
|
|
if (pstPirisData->ZeroIsMax == 1)
|
|
{
|
|
p_piris_dev->src_pos = 0;
|
|
p_piris_dev->dest_pos = 0;
|
|
}
|
|
else
|
|
{
|
|
p_piris_dev->src_pos = pstPirisData->TotalStep - 1;
|
|
p_piris_dev->dest_pos = pstPirisData->TotalStep - 1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
/* go to the full close iris step */
|
|
int piris_close_set(PIRIS_DATA_S* pstPirisData)
|
|
{
|
|
int piris_pos;
|
|
|
|
piris_pos = pstPirisData->CurPos;
|
|
|
|
piris_gpio_update(&piris_pos);
|
|
|
|
// wait for piris origin done
|
|
init_completion(&piris_comp);
|
|
wait_for_completion(&piris_comp);
|
|
|
|
if (pstPirisData->ZeroIsMax == 1)
|
|
{
|
|
p_piris_dev->src_pos = pstPirisData->TotalStep - 1;
|
|
p_piris_dev->dest_pos = pstPirisData->TotalStep - 1;
|
|
}
|
|
else
|
|
{
|
|
p_piris_dev->src_pos = 0;
|
|
p_piris_dev->dest_pos = 0;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
/* file operation */
|
|
|
|
int piris_open(struct inode* inode, struct file* file)
|
|
{
|
|
file->private_data = p_piris_dev;
|
|
|
|
return 0 ;
|
|
|
|
}
|
|
|
|
int piris_close(struct inode* inode, struct file* file)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#if 0
|
|
static int PIRIS_DRV_Disable(void)
|
|
{
|
|
PIRIS_WRITE_REG(PIRIS_CTRL_REG, 0x1F);
|
|
PIRIS_WRITE_REG(PIRIS_CFG_REG, 0x10);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int PIRIS_DRV_Write(unsigned char bits)
|
|
{
|
|
switch (bits)
|
|
{
|
|
case 0:
|
|
PIRIS_WRITE_REG(PIRIS_CTRL_REG, 0x1F);
|
|
PIRIS_WRITE_REG(PIRIS_CFG_REG , 0x15);
|
|
break;
|
|
|
|
case 1:
|
|
PIRIS_WRITE_REG(PIRIS_CTRL_REG, 0x1F);
|
|
PIRIS_WRITE_REG(PIRIS_CFG_REG , 0x16);
|
|
break;
|
|
|
|
case 2:
|
|
PIRIS_WRITE_REG(PIRIS_CTRL_REG, 0x1F);
|
|
PIRIS_WRITE_REG(PIRIS_CFG_REG , 0x1A);
|
|
break;
|
|
|
|
case 3:
|
|
PIRIS_WRITE_REG(PIRIS_CTRL_REG, 0x1F);
|
|
PIRIS_WRITE_REG(PIRIS_CFG_REG , 0x19);
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static long piris_ioctl(struct file* file, unsigned int cmd, unsigned long arg)
|
|
{
|
|
int __user* pPirisPos;
|
|
PIRIS_DATA_S __user* argp;
|
|
PIRIS_STATUS_E __user* pPirisStatus;
|
|
PIRIS_DEV* pstPirisDev = (PIRIS_DEV*) file->private_data;
|
|
|
|
int err = 0;
|
|
|
|
if (_IOC_TYPE(cmd) != PIRIS_IOC_MAGIC)
|
|
{
|
|
return -ENOTTY;
|
|
}
|
|
if (_IOC_NR(cmd) > PIRIS_IOC_MAXNR)
|
|
{
|
|
return -ENOTTY;
|
|
}
|
|
|
|
if (_IOC_DIR(cmd) & _IOC_READ)
|
|
{
|
|
err = !access_ok(VERIFY_WRITE, (void __user*)arg, _IOC_SIZE(cmd));
|
|
}
|
|
else if (_IOC_DIR(cmd) & _IOC_WRITE)
|
|
{
|
|
err = !access_ok(VERIFY_READ, (void __user*)arg, _IOC_SIZE(cmd));
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
return -EFAULT;
|
|
}
|
|
|
|
// lock pstPirisDev
|
|
if (down_interruptible(&pstPirisDev->sem))
|
|
{
|
|
return -ERESTARTSYS;
|
|
}
|
|
|
|
switch (cmd)
|
|
{
|
|
case PIRIS_SET_ACT_ARGS:
|
|
pPirisPos = (int __user*)arg;
|
|
piris_gpio_update(pPirisPos);
|
|
break;
|
|
|
|
case PIRIS_SET_ORGIN:
|
|
argp = (PIRIS_DATA_S __user*)arg;
|
|
piris_origin_set(argp);
|
|
break;
|
|
|
|
case PIRIS_SET_CLOSE:
|
|
argp = (PIRIS_DATA_S __user*)arg;
|
|
piris_close_set(argp);
|
|
break;
|
|
|
|
case PIRIS_GET_STATUS:
|
|
pPirisStatus = (PIRIS_STATUS_E __user*)arg;
|
|
|
|
if (pstPirisDev->dest_pos != pstPirisDev->src_pos)
|
|
{
|
|
*pPirisStatus = PIRIS_BUSY;
|
|
}
|
|
else
|
|
{
|
|
*pPirisStatus = PIRIS_IDLE;
|
|
//PIRIS_DRV_Disable();
|
|
}
|
|
break;
|
|
|
|
default: /* redundant, as cmd was checked against MAXNR */
|
|
break;
|
|
}
|
|
|
|
// unlock pstPirisDev
|
|
up(&pstPirisDev->sem);
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
|
|
static struct file_operations piris_fops =
|
|
{
|
|
.owner = THIS_MODULE,
|
|
.unlocked_ioctl = piris_ioctl ,
|
|
.open = piris_open ,
|
|
.release = piris_close ,
|
|
};
|
|
|
|
static struct miscdevice gstPirisDev =
|
|
{
|
|
.minor = MISC_DYNAMIC_MINOR,
|
|
.name = "piris" ,
|
|
.fops = &piris_fops,
|
|
};
|
|
|
|
void piris_timer_cb(unsigned long arg)
|
|
{
|
|
int sign = 1;
|
|
unsigned char bits;
|
|
|
|
PIRIS_DEV* pstPirisDev = (PIRIS_DEV*)arg;
|
|
|
|
if (pstPirisDev->src_pos == pstPirisDev->dest_pos)
|
|
{
|
|
return ;
|
|
}
|
|
|
|
sign = (pstPirisDev->dest_pos - pstPirisDev->src_pos < 0) ? -1 : 1;
|
|
pstPirisDev->src_pos += sign;
|
|
|
|
// close iris: 0->1->2->3->0; open iris: 3->2->1->0->3
|
|
pstPirisDev->phase = (pstPirisDev->phase + MAX_MOTOR_PAHSE + sign) % MAX_MOTOR_PAHSE;
|
|
bits = pstPirisDev->phase_tbl[pstPirisDev->phase];
|
|
|
|
PIRIS_DRV_Write(bits);
|
|
|
|
if (pstPirisDev->dest_pos == pstPirisDev->src_pos)
|
|
{
|
|
complete(&piris_comp);
|
|
}
|
|
|
|
pstPirisDev->timer.expires = jiffies + HZ / pstPirisDev->pps;
|
|
add_timer(&pstPirisDev->timer);
|
|
|
|
//printk("%s, pos :%d @ pps:%d\n", __FUNCTION__, pstPirisDev->src_pos, pstPirisDev->pps);
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
static int hi_piris_isp_register(void)
|
|
{
|
|
ISP_PIRIS_CALLBACK_S stPirisCb = {0};
|
|
|
|
stPirisCb.pfn_piris_gpio_update = (HI_S32 (*)(HI_S32))piris_gpio_update;
|
|
if (CKFN_ISP_RegisterPirisCallBack())
|
|
{
|
|
CALL_ISP_RegisterPirisCallBack(0, &stPirisCb);
|
|
}
|
|
else
|
|
{
|
|
printk("register piris_gpio_write_callback to isp failed, hi_piris init is failed!\n");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* module init and exit */
|
|
static int __init piris_init(void)
|
|
{
|
|
int ret;
|
|
|
|
p_piris_dev = kmalloc(sizeof(PIRIS_DEV), GFP_KERNEL);
|
|
|
|
if (!p_piris_dev)
|
|
{
|
|
return -1;
|
|
}
|
|
memset(p_piris_dev, 0x0, sizeof(PIRIS_DEV));
|
|
|
|
sema_init(&p_piris_dev->sem, 1);
|
|
init_completion(&piris_comp);
|
|
|
|
// init timer
|
|
init_timer(&p_piris_dev->timer);
|
|
p_piris_dev->timer.function = piris_timer_cb;
|
|
p_piris_dev->timer.data = (unsigned long)p_piris_dev;
|
|
p_piris_dev->timer.expires = jiffies + HZ; /* one second */
|
|
|
|
p_piris_dev->phase_tbl = motor_phase_tbl;
|
|
|
|
reg_pirisI_base_va = ioremap_nocache(PIRISI_ADRESS_BASE, 0x10000);
|
|
ret = misc_register(&gstPirisDev);
|
|
|
|
hi_piris_isp_register();
|
|
|
|
if (ret != 0)
|
|
{
|
|
printk("register piris device failed with %#x!\n", ret);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __exit piris_exit(void)
|
|
{
|
|
del_timer(&p_piris_dev->timer);
|
|
kfree(p_piris_dev);
|
|
|
|
misc_deregister(&gstPirisDev);
|
|
|
|
}
|
|
|
|
|
|
module_init(piris_init);
|
|
module_exit(piris_exit);
|
|
|
|
MODULE_DESCRIPTION("piris driver");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("hisilicon");
|
|
|