luckfox-pico-sdk/sysdrv/drv_ko/motor/motor_24byj48.c
luckfox-eng29 8f34c2760d project:build.sh: Added fastboot support; custom modifications to U-Boot and kernel implemented using patches.
project:cfg:BoardConfig_IPC: Added fastboot BoardConfig file and firmware post-scripts, distinguishing between
the BoardConfigs for Luckfox Pico Pro and Luckfox Pico Max. project:app: Added fastboot_client and rk_smart_door
for quick boot applications; updated rkipc app to adapt to the latest media library. media:samples: Added more
usage examples. media:rockit: Fixed bugs; removed support for retrieving data frames from VPSS. media:isp:
Updated rkaiq library and related tools to support connection to RKISP_Tuner. sysdrv:Makefile: Added support for
compiling drv_ko on Luckfox Pico Ultra W using Ubuntu; added support for custom root filesystem.
sysdrv:tools:board: Updated Buildroot optional mirror sources, updated some software versions, and stored device
tree files and configuration files that undergo multiple modifications for U-Boot and kernel separately.
sysdrv:source:mcu: Used RISC-V MCU SDK with RT-Thread system, mainly for initializing camera AE during quick
boot. sysdrv:source:uboot: Added support for fastboot; added high baud rate DDR bin for serial firmware upgrades.
sysdrv:source:kernel: Upgraded to version 5.10.160; increased NPU frequency for RV1106G3; added support for
fastboot.

Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
2024-10-14 09:47:04 +08:00

1239 lines
33 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/clk.h>
#include <linux/pwm.h>
#include <linux/file.h>
#include <linux/list.h>
#include <linux/gpio.h>
#include <linux/time.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/kthread.h>
#include <linux/mempolicy.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/sched_clock.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/dev_printk.h>
#include "motor_24byj48.h"
#define TIMER_LOAD_COUNT0 0x00
#define TIMER_LOAD_COUNT1 0x04
#define TIMER_CONTROL_REG3288 0x10
#define TIMER_CONTROL_REG3399 0x1c
#define TIMER_INT_STATUS 0x18
#define TIMER_DISABLE 0x0
#define TIMER_ENABLE 0x1
#define TIMER_MODE_FREE_RUNNING (0 << 1)
#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1)
#define TIMER_INT_UNMASK (1 << 2)
struct rk_timer {
void __iomem *base;
void __iomem *ctrl;
struct clk *timer_clk;
struct clk *pclk;
u32 freq;
bool skipped;
};
enum motor_status {
MOTOR_IS_STOP,
MOTOR_IS_RUNNING,
};
struct motor_reset_data {
unsigned int x_max_steps;
unsigned int y_max_steps;
unsigned int reset_x;
unsigned int reset_y;
unsigned int x_cur_steps;
unsigned int y_cur_steps;
};
enum motor_cnt {
HORIZONTAL_MOTOR,
VERTICAL_MOTOR,
HAS_MOTOR_CNT,
};
struct motor_device_attribute {
char motor_direction;
int max_steps;
int input_move_steps;
int real_move_steps;
int cur_steps;
int motor_speed;
int reset_point;
ktime_t m_kt;
unsigned int timer_count;
int motor_gpio[MAX_GPIO_NUM];
enum motor_status motor_current_status;
};
struct motor_message {
int x_cur_steps;
int y_cur_steps;
enum motor_status x_cur_status;
enum motor_status y_cur_status;
int x_cur_speed;
int y_cur_speed;
};
struct motors_input_steps {
int input_x_steps;
int input_y_steps;
};
struct motors_input_speed {
int input_x_speed;
int input_y_speed;
};
struct motors_init_data {
struct motor_reset_data motor_data;
struct motors_input_speed motor_speed;
};
struct motor_device {
struct proc_dir_entry *proc;
struct miscdevice misc_dev;
struct device *dev;
struct mutex dev_mutex;
spinlock_t slock;
int motor_open_flag;
struct rk_timer rk_timer;
struct motor_device_attribute motors[HAS_MOTOR_CNT];
};
static inline void rk_timer_disable(struct rk_timer *timer)
{
writel_relaxed(TIMER_DISABLE, timer->ctrl);
}
static inline void rk_timer_enable(struct rk_timer *timer, u32 flags)
{
writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags, timer->ctrl);
}
static void rk_timer_update_counter(unsigned long cycles, struct rk_timer *timer)
{
writel_relaxed(cycles, timer->base + TIMER_LOAD_COUNT0);
writel_relaxed(0, timer->base + TIMER_LOAD_COUNT1);
}
static void rk_timer_interrupt_clear(struct rk_timer *timer)
{
writel_relaxed(1, timer->base + TIMER_INT_STATUS);
}
static inline int rk_timer_set_next_event(unsigned long cycles, struct rk_timer *timer)
{
rk_timer_disable(timer);
rk_timer_update_counter(cycles, timer);
rk_timer_enable(timer, TIMER_MODE_USER_DEFINED_COUNT | TIMER_INT_UNMASK);
return 0;
}
static __maybe_unused int rk_timer_set_periodic(unsigned long cycles, struct rk_timer *timer)
{
rk_timer_disable(timer);
rk_timer_update_counter(cycles, timer);
rk_timer_enable(timer, TIMER_MODE_FREE_RUNNING);
return 0;
}
void motor_off(struct motor_device_attribute motor)
{
gpio_set_value(motor.motor_gpio[0], 0);
gpio_set_value(motor.motor_gpio[1], 0);
gpio_set_value(motor.motor_gpio[2], 0);
gpio_set_value(motor.motor_gpio[3], 0);
}
static int meter_turn(struct motor_device_attribute motor)
{
switch (motor.timer_count) {
case 0:
gpio_set_value(motor.motor_gpio[0], 1);
gpio_set_value(motor.motor_gpio[1], 0);
gpio_set_value(motor.motor_gpio[2], 0);
gpio_set_value(motor.motor_gpio[3], 0);
break;
case 1:
gpio_set_value(motor.motor_gpio[0], 1);
gpio_set_value(motor.motor_gpio[1], 1);
gpio_set_value(motor.motor_gpio[2], 0);
gpio_set_value(motor.motor_gpio[3], 0);
break;
case 2:
gpio_set_value(motor.motor_gpio[0], 0);
gpio_set_value(motor.motor_gpio[1], 1);
gpio_set_value(motor.motor_gpio[2], 0);
gpio_set_value(motor.motor_gpio[3], 0);
break;
case 3:
gpio_set_value(motor.motor_gpio[0], 0);
gpio_set_value(motor.motor_gpio[1], 1);
gpio_set_value(motor.motor_gpio[2], 1);
gpio_set_value(motor.motor_gpio[3], 0);
break;
case 4:
gpio_set_value(motor.motor_gpio[0], 0);
gpio_set_value(motor.motor_gpio[1], 0);
gpio_set_value(motor.motor_gpio[2], 1);
gpio_set_value(motor.motor_gpio[3], 0);
break;
case 5:
gpio_set_value(motor.motor_gpio[0], 0);
gpio_set_value(motor.motor_gpio[1], 0);
gpio_set_value(motor.motor_gpio[2], 1);
gpio_set_value(motor.motor_gpio[3], 1);
break;
case 6:
gpio_set_value(motor.motor_gpio[0], 0);
gpio_set_value(motor.motor_gpio[1], 0);
gpio_set_value(motor.motor_gpio[2], 0);
gpio_set_value(motor.motor_gpio[3], 1);
break;
case 7:
gpio_set_value(motor.motor_gpio[0], 1);
gpio_set_value(motor.motor_gpio[1], 0);
gpio_set_value(motor.motor_gpio[2], 0);
gpio_set_value(motor.motor_gpio[3], 1);
break;
}
return 0;
}
static void motor_turn_by_id(struct motor_device *mdev, int motor_id)
{
unsigned long flags;
if (mdev->motors[motor_id].motor_direction == 'R') {
mdev->motors[motor_id].timer_count++;
if (mdev->motors[motor_id].timer_count > 7)
mdev->motors[motor_id].timer_count = 0;
} else {
if (mdev->motors[motor_id].timer_count == 0)
mdev->motors[motor_id].timer_count = 8;
mdev->motors[motor_id].timer_count--;
}
meter_turn(mdev->motors[motor_id]);
mdev->motors[motor_id].real_move_steps++;
mdev->motors[motor_id].input_move_steps--;
if (mdev->motors[motor_id].input_move_steps == 0) {
mutex_lock(&mdev->dev_mutex);
spin_lock_irqsave(&mdev->slock, flags);
mdev->motors[motor_id].motor_current_status = MOTOR_IS_STOP;
if (mdev->motors[motor_id].motor_direction == 'R')
mdev->motors[motor_id].cur_steps = mdev->motors[motor_id].cur_steps +
mdev->motors[motor_id].real_move_steps;
else if (mdev->motors[motor_id].motor_direction == 'L')
mdev->motors[motor_id].cur_steps = mdev->motors[motor_id].cur_steps -
mdev->motors[motor_id].real_move_steps;
mdev->motors[motor_id].input_move_steps = 0;
mdev->motors[motor_id].real_move_steps = 0;
spin_unlock_irqrestore(&mdev->slock, flags);
mutex_unlock(&mdev->dev_mutex);
printk("the motor %d steps after stop%d\n", motor_id, mdev->motors[HORIZONTAL_MOTOR].cur_steps);
motor_off(mdev->motors[motor_id]);
}
}
#define SECOND_IN_NS 1000000000u
static inline uint32_t ns_to_rktimer_cycles(uint32_t freq, uint32_t ns)
{
return ns / (SECOND_IN_NS / freq);
}
static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
{
struct motor_device *mdev = dev_id;
int next_event = 0;
rk_timer_interrupt_clear(&mdev->rk_timer);
if (mdev->motors[HORIZONTAL_MOTOR].input_move_steps != 0) {
next_event = 1;
motor_turn_by_id(mdev, HORIZONTAL_MOTOR);
}
if (mdev->motors[VERTICAL_MOTOR].input_move_steps !=0) {
next_event = 1;
motor_turn_by_id(mdev, VERTICAL_MOTOR);
}
if (next_event) {
rk_timer_set_next_event(ns_to_rktimer_cycles(mdev->rk_timer.freq, MOTOR_MAX_SPEED), &mdev->rk_timer);
}
return IRQ_HANDLED;
}
static void rk_timer_deinit(struct motor_device *mdev)
{
struct rk_timer *timer = &mdev->rk_timer;
rk_timer_interrupt_clear(timer);
rk_timer_disable(timer);
clk_disable_unprepare(timer->timer_clk);
clk_disable_unprepare(timer->pclk);
iounmap(timer->base);
};
static struct rk_timer *rk_timer_init(struct platform_device *pdev, struct motor_device *mdev)
{
struct rk_timer *timer = &mdev->rk_timer;
struct device_node *np = pdev->dev.of_node;
int ret, irq;
timer->base = of_iomap(np, 0);
if (!timer->base) {
dev_err(mdev->dev, "Failed to get base address\n");
return NULL;
}
timer->ctrl = timer->base + TIMER_CONTROL_REG3288; //TODO: check 3399/3288
timer->pclk = of_clk_get_by_name(np, "pclk");
if (IS_ERR(timer->pclk)) {
dev_err(mdev->dev, "Failed to get pclk\n");
goto out_unmap;
}
if (clk_prepare_enable(timer->pclk)) {
dev_err(mdev->dev, "Failed to enable pclk\n");
goto out_unmap;
}
timer->timer_clk = of_clk_get_by_name(np, "timer");
if (IS_ERR(timer->timer_clk)) {
dev_err(mdev->dev, "Failed to get timer clock\n");
goto out_timer_clk;
}
if (clk_prepare_enable(timer->timer_clk)) {
dev_err(mdev->dev, "Failed to enable timer clock\n");
goto out_timer_clk;
}
timer->freq = clk_get_rate(timer->timer_clk);
dev_info(mdev->dev, "Timer clk is %d\n", timer->freq);
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
dev_err(mdev->dev, "Failed to map interrupts for\n");
goto out_irq;
}
rk_timer_interrupt_clear(timer);
rk_timer_disable(timer);
ret = devm_request_irq(mdev->dev, irq, rk_timer_interrupt,
IRQF_TIMER, dev_name(mdev->dev), mdev);
if (ret) {
dev_err(mdev->dev, "Failed to initialize: %d\n", ret);
goto out_irq;
}
return timer;
out_irq:
clk_disable_unprepare(timer->timer_clk);
out_timer_clk:
clk_disable_unprepare(timer->pclk);
out_unmap:
iounmap(timer->base);
return NULL;
}
static void motor_set_default(struct motor_device *mdev)
{
int index = 0;
struct motor_device_attribute *motor = NULL;
for (index = 0; index < HAS_MOTOR_CNT; index++) {
motor = &mdev->motors[index];
motor->motor_direction = 'R';
motor->cur_steps = 0;
motor->input_move_steps = 0;
motor->real_move_steps = 0;
motor->timer_count = 0;
motor->motor_speed = MOTOR_MIN_SPEED;
motor->motor_current_status = MOTOR_IS_STOP;
motor->reset_point = motor->max_steps >> 1;
}
}
static long motor_ops_move(struct motor_device *mdev, int x, int y)
{
struct motor_device_attribute *motors = mdev->motors;
unsigned long flags;
char x_dir = 'R';
char y_dir = 'R';
int x1 = 0;
int y1 = 0;
if (mdev->motors[HORIZONTAL_MOTOR].motor_current_status
== MOTOR_IS_RUNNING)
return -1;
if (mdev->motors[VERTICAL_MOTOR].motor_current_status
== MOTOR_IS_RUNNING)
return -1;
/* check x value */
if (x > 0) {
if (motors[HORIZONTAL_MOTOR].cur_steps + x >
motors[HORIZONTAL_MOTOR].max_steps)
x = motors[HORIZONTAL_MOTOR].max_steps -
motors[HORIZONTAL_MOTOR].cur_steps;
} else {
if (motors[HORIZONTAL_MOTOR].cur_steps <= 0)
x = 0;
else
if (-x > motors[HORIZONTAL_MOTOR].cur_steps + 1)
x = -motors[HORIZONTAL_MOTOR].cur_steps;
}
/* check y value */
if (y > 0) {
if (motors[VERTICAL_MOTOR].cur_steps + y >
motors[VERTICAL_MOTOR].max_steps)
y = motors[VERTICAL_MOTOR].max_steps -
motors[VERTICAL_MOTOR].cur_steps;
} else {
if (motors[VERTICAL_MOTOR].cur_steps <= 0)
y = 0;
else
if (-y > motors[VERTICAL_MOTOR].cur_steps + 1)
y = -motors[VERTICAL_MOTOR].cur_steps;
}
x_dir = x > 0 ? 'R' : 'L';
y_dir = y > 0 ? 'R' : 'L';
x1 = x < 0 ? 0 - x : x;
y1 = y < 0 ? 0 - y : y;
if (x1 + y1 == 0)
return 0;
mutex_lock(&mdev->dev_mutex);
spin_lock_irqsave(&mdev->slock, flags);
if (x1 > 0) {
mdev->motors[HORIZONTAL_MOTOR].motor_current_status =
MOTOR_IS_RUNNING;
mdev->motors[HORIZONTAL_MOTOR].input_move_steps = x1;
mdev->motors[HORIZONTAL_MOTOR].real_move_steps = 0;
mdev->motors[HORIZONTAL_MOTOR].motor_direction = x_dir;
}
if (y1 > 0) {
mdev->motors[VERTICAL_MOTOR].motor_current_status =
MOTOR_IS_RUNNING;
mdev->motors[VERTICAL_MOTOR].input_move_steps = y1;
mdev->motors[VERTICAL_MOTOR].real_move_steps = 0;
mdev->motors[VERTICAL_MOTOR].motor_direction = y_dir;
}
spin_unlock_irqrestore(&mdev->slock, flags);
mutex_unlock(&mdev->dev_mutex);
rk_timer_set_next_event(ns_to_rktimer_cycles(mdev->rk_timer.freq, MOTOR_MAX_SPEED), &mdev->rk_timer);
return 0;
}
static void motor_ops_stop(struct motor_device *mdev)
{
unsigned long flags;
int index;
struct motor_device_attribute *motors = mdev->motors;
if (mdev->motors[HORIZONTAL_MOTOR].motor_current_status ==
MOTOR_IS_STOP &&
mdev->motors[VERTICAL_MOTOR].motor_current_status ==
MOTOR_IS_STOP)
return;
if (mdev->motors[HORIZONTAL_MOTOR].motor_current_status !=
MOTOR_IS_STOP) {
motor_off(mdev->motors[HORIZONTAL_MOTOR]);
}
if (mdev->motors[VERTICAL_MOTOR].motor_current_status !=
MOTOR_IS_STOP) {
motor_off(mdev->motors[VERTICAL_MOTOR]);
}
mutex_lock(&mdev->dev_mutex);
spin_lock_irqsave(&mdev->slock, flags);
for (index = 0; index < HAS_MOTOR_CNT; index++) {
motors[index].motor_current_status = MOTOR_IS_STOP;
if (mdev->motors[index].motor_direction == 'R')
mdev->motors[index].cur_steps = mdev->motors[index].cur_steps +
motors[index].real_move_steps;
else if (mdev->motors[index].motor_direction == 'L')
mdev->motors[index].cur_steps = mdev->motors[index].cur_steps -
motors[index].real_move_steps;
motors[index].input_move_steps = 0;
motors[index].real_move_steps = 0;
}
spin_unlock_irqrestore(&mdev->slock, flags);
mutex_unlock(&mdev->dev_mutex);
}
static int motor_speed(struct motor_device *mdev, struct motors_input_speed speed)
{
if ((speed.input_x_speed <= MOTOR_MIN_SPEED) &&
(speed.input_x_speed >= MOTOR_MAX_SPEED)) {
mdev->motors[HORIZONTAL_MOTOR].motor_speed = speed.input_x_speed;
}
if ((speed.input_y_speed <= MOTOR_MIN_SPEED) &&
(speed.input_y_speed >= MOTOR_MAX_SPEED)) {
mdev->motors[VERTICAL_MOTOR].motor_speed = speed.input_y_speed;
}
return 0;
}
static long motor_ops_goback(struct motor_device *mdev)
{
struct motor_device_attribute *motors = mdev->motors;
int sx, sy;
int cx, cy;
printk("%s enter\n", __func__);
if (mdev->motors[HORIZONTAL_MOTOR].motor_current_status ==
MOTOR_IS_RUNNING)
return -1;
sx = motors[HORIZONTAL_MOTOR].reset_point;
sy = motors[VERTICAL_MOTOR].reset_point;
cx = motors[HORIZONTAL_MOTOR].cur_steps;
cy = motors[VERTICAL_MOTOR].cur_steps;
printk("sx=%d, sy=%d, cx=%d, cy=%d\n", sx, sy, cx, cy);
motor_ops_move(mdev, sx-cx, sy-cy);
return 0;
}
static void motor_get_message(struct motor_device *mdev, struct motor_message *msg)
{
struct motor_device_attribute *motors = mdev->motors;
msg->x_cur_steps = motors[HORIZONTAL_MOTOR].cur_steps;
msg->y_cur_steps = motors[VERTICAL_MOTOR].cur_steps;
msg->x_cur_speed = motors[HORIZONTAL_MOTOR].motor_speed;
msg->y_cur_speed = motors[VERTICAL_MOTOR].motor_speed;
msg->x_cur_status = motors[HORIZONTAL_MOTOR].motor_current_status;
msg->y_cur_status = motors[VERTICAL_MOTOR].motor_current_status;
}
static int motor_set_message(struct motor_device *mdev, struct motors_init_data msg)
{
struct motor_device_attribute *motors = mdev->motors;
printk("%s enter\n", __func__);
if (mdev->motors[HORIZONTAL_MOTOR].motor_current_status == MOTOR_IS_RUNNING ||
mdev->motors[VERTICAL_MOTOR].motor_current_status == MOTOR_IS_RUNNING)
return -1;
if (msg.motor_data.x_max_steps < mdev->motors[HORIZONTAL_MOTOR].cur_steps ||
msg.motor_data.y_max_steps < mdev->motors[VERTICAL_MOTOR].cur_steps)
return -1;
if (msg.motor_data.reset_x < 0 || msg.motor_data.reset_x > msg.motor_data.x_max_steps ||
msg.motor_data.reset_y < 0 || msg.motor_data.reset_y > msg.motor_data.y_max_steps)
return -1;
if (msg.motor_speed.input_x_speed > MOTOR_MIN_SPEED || msg.motor_speed.input_x_speed < MOTOR_MAX_SPEED ||
msg.motor_speed.input_y_speed > MOTOR_MIN_SPEED || msg.motor_speed.input_y_speed < MOTOR_MAX_SPEED)
return -1;
motors[HORIZONTAL_MOTOR].max_steps = msg.motor_data.x_max_steps;
motors[HORIZONTAL_MOTOR].motor_speed = msg.motor_speed.input_x_speed;
motors[HORIZONTAL_MOTOR].reset_point = msg.motor_data.reset_x;
motors[VERTICAL_MOTOR].max_steps = msg.motor_data.y_max_steps;
motors[VERTICAL_MOTOR].motor_speed = msg.motor_speed.input_y_speed;
motors[VERTICAL_MOTOR].reset_point = msg.motor_data.reset_y;
return 0;
}
static int motor_set_calibrated_message(struct motor_device *mdev, struct motor_reset_data msg) {
struct motor_device_attribute *motors = mdev->motors;
if (msg.x_cur_steps > mdev->motors[HORIZONTAL_MOTOR].max_steps ||
msg.y_cur_steps > mdev->motors[VERTICAL_MOTOR].max_steps)
return -1;
motors[HORIZONTAL_MOTOR].cur_steps = msg.x_cur_steps;
motors[VERTICAL_MOTOR].cur_steps = msg.y_cur_steps;
return 0;
}
static long motor_ops_reset(struct motor_device *mdev, struct motor_reset_data *rdata)
{
unsigned long flags;
int index = 0;
long ret = 0;
int times = 0;
struct motor_message msg;
struct motor_device_attribute *motor = NULL;
if (mdev == NULL || rdata == NULL) {
printk("ERROR: the parameters of %s is wrong!!\n", __func__);
return -EPERM;
}
if (rdata->x_max_steps <= 0 || rdata->y_max_steps <= 0)
return -1;
if (rdata->reset_x < 0 || rdata->reset_x > rdata->x_max_steps ||
rdata->reset_y < 0 || rdata->reset_y > rdata->y_max_steps)
return -1;
mutex_lock(&mdev->dev_mutex);
spin_lock_irqsave(&mdev->slock, flags);
for (index = 0; index < HAS_MOTOR_CNT; index++) {
motor = &mdev->motors[index];
motor->motor_speed = MOTOR_MAX_SPEED;
motor->motor_current_status = MOTOR_IS_STOP;
}
mdev->motors[HORIZONTAL_MOTOR].max_steps = rdata->x_max_steps;
mdev->motors[VERTICAL_MOTOR].max_steps = rdata->y_max_steps;
mdev->motors[HORIZONTAL_MOTOR].cur_steps = rdata->x_max_steps;
mdev->motors[VERTICAL_MOTOR].cur_steps = rdata->y_max_steps;
spin_unlock_irqrestore(&mdev->slock, flags);
mutex_unlock(&mdev->dev_mutex);
ret = motor_ops_move(mdev, -(rdata->x_max_steps + 1), -(rdata->y_max_steps + 1));
do {
msleep(15);
motor_get_message(mdev, &msg);
times++;
if (times > 1000) {
printk("ERROR:wait motor timeout %s%d\n", __func__, __LINE__);
ret = -ETIMEDOUT;
goto exit;
}
} while (msg.x_cur_status == MOTOR_IS_RUNNING || msg.y_cur_status == MOTOR_IS_RUNNING);
mutex_lock(&mdev->dev_mutex);
spin_lock_irqsave(&mdev->slock, flags);
mdev->motors[HORIZONTAL_MOTOR].cur_steps = 0;
mdev->motors[VERTICAL_MOTOR].cur_steps = 0;
mdev->motors[HORIZONTAL_MOTOR].reset_point = rdata->reset_x;
mdev->motors[VERTICAL_MOTOR].reset_point = rdata->reset_y;
spin_unlock_irqrestore(&mdev->slock, flags);
mutex_unlock(&mdev->dev_mutex);
ret = motor_ops_goback(mdev);
do {
msleep(10);
motor_get_message(mdev, &msg);
times++;
if (times > 1000) {
printk("ERROR:wait motor timeout %s%d\n", __func__, __LINE__);
ret = -ETIMEDOUT;
goto exit;
}
} while (msg.x_cur_status == MOTOR_IS_RUNNING || msg.y_cur_status == MOTOR_IS_RUNNING);
/* sync data */
rdata->x_max_steps = mdev->motors[HORIZONTAL_MOTOR].max_steps;
rdata->y_max_steps = mdev->motors[VERTICAL_MOTOR].max_steps;
for (index = 0; index < HAS_MOTOR_CNT; index++) {
motor = &mdev->motors[index];
motor->motor_direction = 'R';
motor->input_move_steps = 0;
motor->real_move_steps = 0;
motor->timer_count = 0;
motor->motor_speed = MOTOR_MIN_SPEED;
}
exit:
msleep(10);
return 0;
}
static int motor_open(struct inode *inode, struct file *file)
{
struct miscdevice *dev = file->private_data;
struct motor_device *mdev = container_of(dev, struct motor_device, misc_dev);
int ret = 0;
if (mdev->motor_open_flag) {
ret = -EBUSY;
dev_err(mdev->dev, "Motor driver busy now!\n");
} else {
printk("open motor is success!\n");
mdev->motor_open_flag = 1;
}
return ret;
}
static int motor_release(struct inode *inode, struct file *file)
{
struct miscdevice *dev = file->private_data;
struct motor_device *mdev = container_of(dev, struct motor_device, misc_dev);
motor_ops_stop(mdev);
mdev->motor_open_flag = 0;
printk("release motor is success!\n");
return 0;
}
static long motor_ioctl(struct file *file, unsigned int cmd, unsigned long value)
{
struct miscdevice *dev = file->private_data;
struct motor_device *mdev = container_of(dev, struct motor_device, misc_dev);
long ret = 0;
if (mdev->motor_open_flag == 0) {
printk("Please Open /dev/motor Firstly\n");
return -EPERM;
}
switch (cmd) {
case MOTOR_STOP: {
motor_ops_stop(mdev);
//printk("MOTOR_STOP!!!!!!!!!!!!!!!!!!!\n");
break;
}
case MOTOR_RESET: {
struct motor_reset_data rdata;
if (value == 0) {
ret = -EPERM;
break;
}
if (copy_from_user(&rdata, (void __user *)value,
sizeof(rdata))) {
dev_err(mdev->dev, "[%s][%d] copy from user error\n",
__func__, __LINE__);
return -EFAULT;
}
ret = motor_ops_reset(mdev, &rdata);
if (!ret) {
if (copy_to_user((void __user *)value, &rdata,
sizeof(rdata))) {
dev_err(mdev->dev, "[%s][%d] copy to user error\n",
__func__, __LINE__);
return -EFAULT;
}
}
/*printk("MOTOR_RESET!!!!!!!!!!!!!!!!!!!\n");*/
break;
}
case MOTOR_MOVE: {
struct motors_input_steps dst;
if (copy_from_user(&dst, (void __user *)value,
sizeof(struct motors_input_steps))) {
dev_err(mdev->dev, "[%s][%d] copy from user error\n",
__func__, __LINE__);
return -EFAULT;
}
motor_ops_move(mdev, dst.input_x_steps, dst.input_y_steps);
//printk("MOTOR_MOVE!!!!!!!!!!!!!!!!!!!\n");
break;
}
case MOTOR_GET_STATUS: {
struct motor_message msg;
motor_get_message(mdev, &msg);
if (copy_to_user((void __user *)value, &msg,
sizeof(struct motor_message))) {
dev_err(mdev->dev, "[%s][%d] copy to user error\n",
__func__, __LINE__);
return -EFAULT;
}
/*printk("MOTOR_GET_STATUS!!!!!!!!!!!!!!!!!!\n");*/
break;
}
case MOTOR_SPEED:{
struct motors_input_speed speed;
if (copy_from_user(&speed, (void __user *)value, sizeof(struct motors_input_speed))) {
dev_err(mdev->dev, "[%s][%d] copy to user error\n", __func__, __LINE__);
return -EFAULT;
}
ret = motor_speed(mdev, speed);
if (ret) {
printk("set motor_speed fail\n");
ret = -1;
}
break;
//printk("MOTOR_SPEED!!!!!!!!!!!!!!!!!!!!!!!\n");
}
case MOTOR_GOBACK: {
motor_ops_stop(mdev);
ret = motor_ops_goback(mdev);
//printk("MOTOR_GOBACK!!!!!!!!!!!!!!!!!!!!!!!\n");
break;
}
case MOTOR_CRUISE: {
//printk("MOTOR_CRUISE!!!!!!!!!!!!!!!!!!!!!!!\n");
break;
}
case MOTOR_SET_STATUS: {
struct motors_init_data data;
if (copy_from_user(&data, (void __user *)value,
sizeof(struct motors_init_data))) {
dev_err(mdev->dev, "[%s][%d] copy from user error\n",
__func__, __LINE__);
return -EFAULT;
}
printk("set data:max_x:%d, max_y:%d, x_speed:%d, y_speed:%d,x_reset:%d, y_reset:%d\n",
data.motor_data.x_max_steps, data.motor_data.y_max_steps, data.motor_speed.input_x_speed,
data.motor_speed.input_y_speed, data.motor_data.reset_x, data.motor_data.reset_y);
ret = motor_set_message(mdev, data);
if (ret) {
printk("motor_set_message fail\n");
ret = -1;
}
/*printk("MOTOR_SET_STATUS!!!!!!!!!!!!!!!!!!\n");*/
break;
}
case MOTOR_RESET_NOTCALI: {
struct motor_reset_data data;
if (copy_from_user(&data, (void __user *)value,
sizeof(struct motor_reset_data))) {
dev_err(mdev->dev, "[%s][%d] copy from user error\n",
__func__, __LINE__);
return -EFAULT;
}
printk("saved location x is %d, y is %d \n", data.x_cur_steps, data.y_cur_steps);
ret = motor_set_calibrated_message(mdev,data);
if (ret) {
dev_err(mdev->dev,"motor_set_calibrated_messgae fail\n");
ret = -1;
}
break;
}
default:
return -EINVAL;
}
return ret;
}
static struct file_operations motor_fops = {
.owner = THIS_MODULE,
.open = motor_open,
.release = motor_release,
.unlocked_ioctl = motor_ioctl,
};
static int motor_info_show(struct seq_file *m, void *v)
{
printk("%s enter!\n", __func__);
return 0;
}
static int motor_info_open(struct inode *inode, struct file *file)
{
return single_open_size(file, motor_info_show, PDE_DATA(inode), 1024);
}
static const struct proc_ops motor_info_fops = {
.proc_read = seq_read,
.proc_open = motor_info_open,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
static int motor_request_gpio(struct platform_device *pdev, struct motor_device *mdev)
{
int ret;
int GPIO_ID_A = -1;
int GPIO_ID_B = -1;
int GPIO_ID_C = -1;
int GPIO_ID_D = -1;
int GPIO_ID_E = -1;
int GPIO_ID_F = -1;
int GPIO_ID_G = -1;
int GPIO_ID_H = -1;
GPIO_ID_A = of_get_named_gpio(pdev->dev.of_node, "motorA-gpios", 0);
if (GPIO_ID_A < 0) {
printk("get gpioA named is error!\n");
return -1;
}
GPIO_ID_B = of_get_named_gpio(pdev->dev.of_node, "motorB-gpios", 0);
if (GPIO_ID_B < 0) {
printk("get gpioB named is error!\n");
return -1;
}
GPIO_ID_C = of_get_named_gpio(pdev->dev.of_node, "motorC-gpios", 0);
if (GPIO_ID_C < 0) {
printk("get gpioC named is error!\n");
return -1;
}
GPIO_ID_D = of_get_named_gpio(pdev->dev.of_node, "motorD-gpios", 0);
if (GPIO_ID_D < 0) {
printk("get gpioD named is error!\n");
return -1;
}
GPIO_ID_E = of_get_named_gpio(pdev->dev.of_node, "motorE-gpios", 0);
if (GPIO_ID_E < 0) {
printk("get gpioA named is error!\n");
return -1;
}
GPIO_ID_F = of_get_named_gpio(pdev->dev.of_node, "motorF-gpios", 0);
if (GPIO_ID_F < 0) {
printk("get gpioB named is error!\n");
return -1;
}
GPIO_ID_G = of_get_named_gpio(pdev->dev.of_node, "motorG-gpios", 0);
if (GPIO_ID_G < 0) {
printk("get gpioC named is error!\n");
return -1;
}
GPIO_ID_H = of_get_named_gpio(pdev->dev.of_node, "motorH-gpios", 0);
if (GPIO_ID_H < 0) {
printk("get gpioD named is error!\n");
return -1;
}
ret = gpio_request(GPIO_ID_A, "motor_A_GPIO");
if (ret != 0) {
printk("motor gpio request is error!\n");
return -1;
}
ret = gpio_request(GPIO_ID_B, "motor_B_GPIO");
if (ret != 0) {
printk("motor gpio request is error!\n");
gpio_free(GPIO_ID_A);
GPIO_ID_A = -1;
return -1;
}
ret = gpio_request(GPIO_ID_C, "motor_C_GPIO");
if (ret != 0) {
printk("motor gpio request is error!\n");
gpio_free(GPIO_ID_A);
gpio_free(GPIO_ID_B);
GPIO_ID_A = -1;
GPIO_ID_B = -1;
return -1;
}
ret = gpio_request(GPIO_ID_D, "motor_D_GPIO");
if (ret != 0) {
printk("motor gpio request is error!\n");
gpio_free(GPIO_ID_A);
gpio_free(GPIO_ID_B);
gpio_free(GPIO_ID_C);
GPIO_ID_A = -1;
GPIO_ID_B = -1;
GPIO_ID_C = -1;
return -1;
}
ret = gpio_request(GPIO_ID_E, "motor_E_GPIO");
if (ret != 0) {
printk("motor gpio request is error!\n");
gpio_free(GPIO_ID_A);
gpio_free(GPIO_ID_B);
gpio_free(GPIO_ID_C);
gpio_free(GPIO_ID_D);
GPIO_ID_A = -1;
GPIO_ID_B = -1;
GPIO_ID_C = -1;
GPIO_ID_D = -1;
return -1;
}
ret = gpio_request(GPIO_ID_F, "motor_F_GPIO");
if (ret != 0) {
printk("motor gpio request is error!\n");
gpio_free(GPIO_ID_A);
gpio_free(GPIO_ID_B);
gpio_free(GPIO_ID_C);
gpio_free(GPIO_ID_D);
gpio_free(GPIO_ID_E);
GPIO_ID_A = -1;
GPIO_ID_B = -1;
GPIO_ID_C = -1;
GPIO_ID_D = -1;
GPIO_ID_E = -1;
return -1;
}
ret = gpio_request(GPIO_ID_G, "motor_G_GPIO");
if (ret != 0) {
printk("motor gpio request is error!\n");
gpio_free(GPIO_ID_A);
gpio_free(GPIO_ID_B);
gpio_free(GPIO_ID_C);
gpio_free(GPIO_ID_D);
gpio_free(GPIO_ID_E);
gpio_free(GPIO_ID_F);
GPIO_ID_A = -1;
GPIO_ID_B = -1;
GPIO_ID_C = -1;
GPIO_ID_D = -1;
GPIO_ID_E = -1;
GPIO_ID_F = -1;
return -1;
}
ret = gpio_request(GPIO_ID_H, "motor_H_GPIO");
if (ret != 0) {
printk("motor gpio request is error!\n");
gpio_free(GPIO_ID_A);
gpio_free(GPIO_ID_B);
gpio_free(GPIO_ID_C);
gpio_free(GPIO_ID_D);
gpio_free(GPIO_ID_E);
gpio_free(GPIO_ID_F);
gpio_free(GPIO_ID_G);
GPIO_ID_A = -1;
GPIO_ID_B = -1;
GPIO_ID_C = -1;
GPIO_ID_D = -1;
GPIO_ID_E = -1;
GPIO_ID_F = -1;
GPIO_ID_G = -1;
return -1;
}
ret = gpio_direction_output(GPIO_ID_A, 0);
if (ret) {
printk("motor gpioA set direction fail%d\n", ret);
goto free_gpio;
}
ret = gpio_direction_output(GPIO_ID_B, 0);
if (ret) {
printk("motor gpioB set direction fail%d\n", ret);
goto free_gpio;
}
ret = gpio_direction_output(GPIO_ID_C, 0);
if (ret) {
printk("motor gpioC set direction fail%d\n", ret);
goto free_gpio;
}
ret = gpio_direction_output(GPIO_ID_D, 0);
if (ret) {
printk("motor gpioD set direction fail%d\n", ret);
goto free_gpio;
}
ret = gpio_direction_output(GPIO_ID_E, 0);
if (ret) {
printk("motor gpioE set direction fail%d\n", ret);
goto free_gpio;
}
ret = gpio_direction_output(GPIO_ID_F, 0);
if (ret) {
printk("motor gpioF set direction fail%d\n", ret);
goto free_gpio;
}
ret = gpio_direction_output(GPIO_ID_G, 0);
if (ret) {
printk("motor gpioG set direction fail%d\n", ret);
goto free_gpio;
}
ret = gpio_direction_output(GPIO_ID_H, 0);
if (ret) {
printk("motor gpioH set direction fail%d\n", ret);
goto free_gpio;
}
mdev->motors[HORIZONTAL_MOTOR].motor_gpio[0] = GPIO_ID_A;
mdev->motors[HORIZONTAL_MOTOR].motor_gpio[1] = GPIO_ID_B;
mdev->motors[HORIZONTAL_MOTOR].motor_gpio[2] = GPIO_ID_C;
mdev->motors[HORIZONTAL_MOTOR].motor_gpio[3] = GPIO_ID_D;
mdev->motors[VERTICAL_MOTOR].motor_gpio[0] = GPIO_ID_E;
mdev->motors[VERTICAL_MOTOR].motor_gpio[1] = GPIO_ID_F;
mdev->motors[VERTICAL_MOTOR].motor_gpio[2] = GPIO_ID_G;
mdev->motors[VERTICAL_MOTOR].motor_gpio[3] = GPIO_ID_H;
return 0;
free_gpio:
if (GPIO_ID_A != -1)
gpio_free(GPIO_ID_A);
if (GPIO_ID_B != -1)
gpio_free(GPIO_ID_B);
if (GPIO_ID_C != -1)
gpio_free(GPIO_ID_C);
if (GPIO_ID_D != -1)
gpio_free(GPIO_ID_D);
if (GPIO_ID_E != -1)
gpio_free(GPIO_ID_E);
if (GPIO_ID_F != -1)
gpio_free(GPIO_ID_F);
if (GPIO_ID_G != -1)
gpio_free(GPIO_ID_G);
if (GPIO_ID_H != -1)
gpio_free(GPIO_ID_H);
return -1;
}
static void motor_release_gpio(struct motor_device *mdev)
{
int i = 0, index = 0;
struct motor_device_attribute *motor = NULL;
int GPIO_ID_A = mdev->motors[HORIZONTAL_MOTOR].motor_gpio[0];
int GPIO_ID_B = mdev->motors[HORIZONTAL_MOTOR].motor_gpio[1];
int GPIO_ID_C = mdev->motors[HORIZONTAL_MOTOR].motor_gpio[2];
int GPIO_ID_D = mdev->motors[HORIZONTAL_MOTOR].motor_gpio[3];
int GPIO_ID_E = mdev->motors[VERTICAL_MOTOR].motor_gpio[0];
int GPIO_ID_F = mdev->motors[VERTICAL_MOTOR].motor_gpio[1];
int GPIO_ID_G = mdev->motors[VERTICAL_MOTOR].motor_gpio[2];
int GPIO_ID_H = mdev->motors[VERTICAL_MOTOR].motor_gpio[3];
if (GPIO_ID_A != -1)
gpio_free(GPIO_ID_A);
if (GPIO_ID_B != -1)
gpio_free(GPIO_ID_B);
if (GPIO_ID_C != -1)
gpio_free(GPIO_ID_C);
if (GPIO_ID_D != -1)
gpio_free(GPIO_ID_D);
if (GPIO_ID_E != -1)
gpio_free(GPIO_ID_E);
if (GPIO_ID_F != -1)
gpio_free(GPIO_ID_F);
if (GPIO_ID_G != -1)
gpio_free(GPIO_ID_G);
if (GPIO_ID_H != -1)
gpio_free(GPIO_ID_H);
for (index = 0; index < HAS_MOTOR_CNT; index++) {
motor = &mdev->motors[index];
for (i = 0; i < MAX_GPIO_NUM; i++)
motor->motor_gpio[i] = -1;
}
}
static int motor_probe(struct platform_device *pdev)
{
int i = 0, index = 0;
struct motor_device_attribute *motor = NULL;
struct motor_device *mdev;
struct proc_dir_entry *proc = NULL;
struct proc_dir_entry *motor_info = NULL;
int ret = 0;
printk("%s enter\n", __func__);
mdev = devm_kzalloc(&pdev->dev, sizeof(struct motor_device), GFP_KERNEL);
if (!mdev) {
ret = -ENOENT;
dev_err(&pdev->dev, "kzalloc motor device memery error\n");
goto error_devm_kzalloc;
}
mdev->dev = &pdev->dev;
mutex_init(&mdev->dev_mutex);
spin_lock_init(&mdev->slock);
platform_set_drvdata(pdev, mdev);
mdev->misc_dev.minor = MISC_DYNAMIC_MINOR;
mdev->misc_dev.name = "motor";
mdev->misc_dev.fops = &motor_fops;
ret = misc_register(&mdev->misc_dev);
if (ret < 0) {
ret = -ENOENT;
dev_err(&pdev->dev, "misc_register failed\n");
}
proc = proc_mkdir("motor", NULL);
if (!proc) {
mdev->proc = NULL;
printk("create motor dir failed!\n");
ret = -1;
goto proc_mkdir_fail;
} else {
mdev->proc = proc;
}
motor_info = proc_create_data("motor_info", S_IRUGO, proc, &motor_info_fops, (void *)mdev);
if (!motor_info)
printk("create motor_info failed!\n");
motor_set_default(mdev);
mdev->motors[HORIZONTAL_MOTOR].max_steps = HORIZONTAL_MAX_STEPS;
mdev->motors[VERTICAL_MOTOR].max_steps = VERTICAL_MAX_STEPS;
for (index = 0; index < HAS_MOTOR_CNT; index++) {
motor = &mdev->motors[index];
for (i = 0; i < MAX_GPIO_NUM; i++)
motor->motor_gpio[i] = -1;
}
mdev->motor_open_flag = 0;
ret = motor_request_gpio(pdev, mdev);
if (ret) {
printk("motor_request_gpio fail\n");
ret = -1;
goto motor_request_gpio_fail;
}
if (rk_timer_init(pdev, mdev) == NULL) {
printk("init timer fail\n");
ret = -1;
goto motor_timer_init_fail;
}
printk("%s leave\n", __func__);
return 0;
motor_timer_init_fail:
motor_release_gpio(mdev);
motor_request_gpio_fail:
if (mdev->proc)
proc_remove(mdev->proc);
proc_mkdir_fail:
mutex_destroy(&mdev->dev_mutex);
misc_deregister(&mdev->misc_dev);
kfree(mdev);
error_devm_kzalloc:
return ret;
}
static int motor_remove(struct platform_device *pdev)
{
struct motor_device *mdev = platform_get_drvdata(pdev);
rk_timer_deinit(mdev);
mutex_destroy(&mdev->dev_mutex);
motor_release_gpio(mdev);
if (mdev->proc)
proc_remove(mdev->proc);
misc_deregister(&mdev->misc_dev);
kfree(mdev);
return 0;
}
struct of_device_id of_match_table[] = {
{ .compatible = "motor",},
{},
};
static struct platform_driver motor_platform_driver = {
.probe = motor_probe,
.remove = motor_remove,
.driver = {
.name = "motor",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_match_table),
}
};
static int __init motor_init(void)
{
int ret;
ret = platform_driver_register(&motor_platform_driver);
return ret;
}
static void __exit motor_exit(void)
{
platform_driver_unregister(&motor_platform_driver);
}
module_init(motor_init);
module_exit(motor_exit);
MODULE_LICENSE("GPL");