From dd3eba6aac310fb05292ad3baf7477cd12b08b50 Mon Sep 17 00:00:00 2001 From: Santiago Hormazabal Date: Thu, 20 Jul 2023 06:01:05 -0300 Subject: [PATCH] Add a new T31 kernel module for motors. (#913) --- .../configs/t31_ultimate_defconfig | 3 + general/package/Config.in | 1 + general/package/ingenic-motors-t31/Config.in | 8 + .../ingenic-motors-t31/ingenic-motors-t31.mk | 18 + .../package/ingenic-motors-t31/src/Makefile | 36 + .../package/ingenic-motors-t31/src/motor.c | 1098 +++++++++++++++++ .../package/ingenic-motors-t31/src/motor.h | 161 +++ general/package/motors/motors.mk | 2 + 8 files changed, 1327 insertions(+) create mode 100644 general/package/ingenic-motors-t31/Config.in create mode 100644 general/package/ingenic-motors-t31/ingenic-motors-t31.mk create mode 100644 general/package/ingenic-motors-t31/src/Makefile create mode 100644 general/package/ingenic-motors-t31/src/motor.c create mode 100644 general/package/ingenic-motors-t31/src/motor.h diff --git a/br-ext-chip-ingenic/configs/t31_ultimate_defconfig b/br-ext-chip-ingenic/configs/t31_ultimate_defconfig index b28d499c..00cf6c17 100644 --- a/br-ext-chip-ingenic/configs/t31_ultimate_defconfig +++ b/br-ext-chip-ingenic/configs/t31_ultimate_defconfig @@ -108,6 +108,9 @@ BR2_PACKAGE_INGENIC_ATBM603X_SDIO_T31_MMC0=y BR2_PACKAGE_INGENIC_ATBM603X_SDIO_T31_MMC1=y # BR2_PACKAGE_RTL8188EU is not set +# Motors +BR2_PACKAGE_INGENIC_MOTORS_T31=y + # WIREGUARD BR2_PACKAGE_WIREGUARD_LINUX_COMPAT=y BR2_PACKAGE_WIREGUARD_TOOLS=y diff --git a/general/package/Config.in b/general/package/Config.in index ac514377..f88839e7 100644 --- a/general/package/Config.in +++ b/general/package/Config.in @@ -31,6 +31,7 @@ source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3516ev200/Config.in source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3519v101/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-osdrv-hi3536dv100/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/i2c-telemetry/Config.in" +source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-motors-t31/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-atbm603x-sdio-t31/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-opensdk/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/ingenic-osdrv-t20/Config.in" diff --git a/general/package/ingenic-motors-t31/Config.in b/general/package/ingenic-motors-t31/Config.in new file mode 100644 index 00000000..1c2855ab --- /dev/null +++ b/general/package/ingenic-motors-t31/Config.in @@ -0,0 +1,8 @@ +config BR2_PACKAGE_INGENIC_MOTORS_T31 + bool "ingenic-motors-t31" + depends on BR2_LINUX_KERNEL + help + Motor driver for Ingenic T31 using TCU2.2. + +comment "ingenic-motors-t31 needs a Linux kernel to be built" + depends on !BR2_LINUX_KERNEL diff --git a/general/package/ingenic-motors-t31/ingenic-motors-t31.mk b/general/package/ingenic-motors-t31/ingenic-motors-t31.mk new file mode 100644 index 00000000..82169660 --- /dev/null +++ b/general/package/ingenic-motors-t31/ingenic-motors-t31.mk @@ -0,0 +1,18 @@ +################################################################################ +# +# AltoBeam INGENIC_MOTORS_T31 wifi driver +# +################################################################################ + +INGENIC_MOTORS_T31_LICENSE = GPL-2.0 + +define INGENIC_MOTORS_T31_EXTRACT_CMDS + cp -av $(INGENIC_MOTORS_T31_PKGDIR)/src/* $(@D)/ +endef + +INGENIC_MOTORS_T31_MODULE_MAKE_OPTS = \ + KVER=$(LINUX_VERSION_PROBED) \ + KSRC=$(LINUX_DIR) + +$(eval $(kernel-module)) +$(eval $(generic-package)) diff --git a/general/package/ingenic-motors-t31/src/Makefile b/general/package/ingenic-motors-t31/src/Makefile new file mode 100644 index 00000000..e9488b8c --- /dev/null +++ b/general/package/ingenic-motors-t31/src/Makefile @@ -0,0 +1,36 @@ +#CROSS_COMPILE ?= mips-linux-gnu- +#KDIR := ${ISVP_ENV_KERNEL_DIR} + +############################################################################ + +PWD:=$(shell pwd) +INSTALL_DIR := $(PWD)/output + +DEFS = + +MOTORS_NAME := sample_motor + +$(MOTORS_NAME)-objs := motor.o +obj-m := $(MOTORS_NAME).o + + +EXTRA_CFLAGS := $(DEFS) + +all: modules install + +modules: clean + $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KDIR) M=$(shell pwd) modules -j8 + +strip: + $(CROSS_COMPILE)strip $(INSTALL_DIR)/*.ko --strip-unneeded + +install: modules + mkdir -p $(INSTALL_DIR) + chmod 777 $(INSTALL_DIR) + cp *.ko $(INSTALL_DIR) + +clean: + @rm -rf *.o *~ .depend .*.cmd *.mod.c .tmp_versions *.ko *.symvers modules.order + make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) clean + +.PHONY: modules clean diff --git a/general/package/ingenic-motors-t31/src/motor.c b/general/package/ingenic-motors-t31/src/motor.c new file mode 100644 index 00000000..40165f32 --- /dev/null +++ b/general/package/ingenic-motors-t31/src/motor.c @@ -0,0 +1,1098 @@ +/* + * motor.c - Ingenic motor driver + * + * Copyright (C) 2015 Ingenic Semiconductor Co.,Ltd + * http://www.ingenic.com + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SOC_T40 +#include +#else +#include +#endif +#include +#include +#ifdef CONFIG_SOC_T40 +#include +#else +#include +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include "motor.h" +#define JZ_MOTOR_DRIVER_VERSION "H20171204a-16-jul-23-openipc" + +#define HMOTOR2VMOTORRATIO 1 +static unsigned int hmotor2vmotor = 1; +module_param(hmotor2vmotor, int, S_IRUGO); +MODULE_PARM_DESC(hmotor2vmotor, "The value is hmotor's speed / vmotor's"); + + +static unsigned int hmaxstep = 4300; +module_param(hmaxstep, int, S_IRUGO); +MODULE_PARM_DESC(hmaxstep, "The max steps of horizontal motor"); + +static unsigned int vmaxstep = 300; +module_param(vmaxstep, int, S_IRUGO); +MODULE_PARM_DESC(vmaxstep, "The max steps of vertical motor"); + +/* custom definition for GPIOs (so it's generic rather than hardcoded) */ +int hmin = -1; +module_param(hmin, int, S_IRUGO); +MODULE_PARM_DESC(hmin, "Horizontal motor start point GPIO"); + +int hmax = -1; +module_param(hmax, int, S_IRUGO); +MODULE_PARM_DESC(hmax, "Horizontal motor stop point GPIO"); + +int hlevel = 0; +module_param(hlevel, int, S_IRUGO); +MODULE_PARM_DESC(hlevel, "Horizontal motor IRQ style"); + +int hst1 = 49; +module_param(hst1, int, S_IRUGO); +MODULE_PARM_DESC(hst1, "Horizontal motor GPIO for Phase A. Use absolute GPIO index (i.e. GPIOB is 32 + gpio pin, GPIOC is 64 + gpio pin, etc)"); + +int hst2 = 57; +module_param(hst2, int, S_IRUGO); +MODULE_PARM_DESC(hst2, "Horizontal motor GPIO for Phase B. Use absolute GPIO index (i.e. GPIOB is 32 + gpio pin, GPIOC is 64 + gpio pin, etc)"); + +int hst3 = 54; +module_param(hst3, int, S_IRUGO); +MODULE_PARM_DESC(hst3, "Horizontal motor GPIO for Phase C. Use absolute GPIO index (i.e. GPIOB is 32 + gpio pin, GPIOC is 64 + gpio pin, etc)"); + +int hst4 = 51; +module_param(hst4, int, S_IRUGO); +MODULE_PARM_DESC(hst4, "Horizontal motor GPIO for Phase D. Use absolute GPIO index (i.e. GPIOB is 32 + gpio pin, GPIOC is 64 + gpio pin, etc)"); + +int vmin = -1; +module_param(vmin, int, S_IRUGO); +MODULE_PARM_DESC(vmin, "Vertical motor start point GPIO"); + +int vmax = -1; +module_param(vmax, int, S_IRUGO); +MODULE_PARM_DESC(vmax, "Vertical motor stop point GPIO"); + +int vlevel = 0; +module_param(vlevel, int, S_IRUGO); +MODULE_PARM_DESC(vlevel, "Vertical motor IRQ style"); + +int vst1 = 60; +module_param(vst1, int, S_IRUGO); +MODULE_PARM_DESC(vst1, "Vertical motor GPIO for Phase A. Use absolute GPIO index (i.e. GPIOB is 32 + gpio pin, GPIOC is 64 + gpio pin, etc)"); + +int vst2 = 61; +module_param(vst2, int, S_IRUGO); +MODULE_PARM_DESC(vst2, "Vertical motor GPIO for Phase B. Use absolute GPIO index (i.e. GPIOB is 32 + gpio pin, GPIOC is 64 + gpio pin, etc)"); + +int vst3 = 62; +module_param(vst3, int, S_IRUGO); +MODULE_PARM_DESC(vst3, "Vertical motor GPIO for Phase C. Use absolute GPIO index (i.e. GPIOB is 32 + gpio pin, GPIOC is 64 + gpio pin, etc)"); + +int vst4 = 63; +module_param(vst4, int, S_IRUGO); +MODULE_PARM_DESC(vst4, "Vertical motor GPIO for Phase D. Use absolute GPIO index (i.e. GPIOB is 32 + gpio pin, GPIOC is 64 + gpio pin, etc)"); + + +struct motor_platform_data motors_pdata[HAS_MOTOR_CNT] = { + { + .name = "Horizontal motor", + .motor_min_gpio = -1, + .motor_max_gpio = -1, + .motor_gpio_level = -1, + .motor_st1_gpio = -1, + .motor_st2_gpio = -1, + .motor_st3_gpio = -1, + .motor_st4_gpio = -1, + }, + { + .name = "Vertical motor", + .motor_min_gpio = -1, + .motor_max_gpio = -1, + .motor_gpio_level = -1, + .motor_st1_gpio = -1, + .motor_st2_gpio = -1, + .motor_st3_gpio = -1, + .motor_st4_gpio = -1, + }, +}; + +static void motor_set_default(struct motor_device *mdev) +{ + int index = 0; + struct motor_driver *motor = NULL; + mdev->dev_state = MOTOR_OPS_STOP; + for(index = 0; index < HAS_MOTOR_CNT; index++){ + motor = &mdev->motors[index]; + motor->state = MOTOR_OPS_STOP; + if (motor->pdata->motor_st1_gpio) + gpio_direction_output(motor->pdata->motor_st1_gpio, 0); + if (motor->pdata->motor_st2_gpio) + gpio_direction_output(motor->pdata->motor_st2_gpio, 0); + if (motor->pdata->motor_st3_gpio) + gpio_direction_output(motor->pdata->motor_st3_gpio, 0); + if (motor->pdata->motor_st4_gpio) + gpio_direction_output(motor->pdata->motor_st4_gpio, 0); + } + return; +} + +static unsigned char step_8[8] = { + 0x08, + 0x0c, + 0x04, + 0x06, + 0x02, + 0x03, + 0x01, + 0x09 +}; + +static void motor_move_step(struct motor_device *mdev, int index) +{ + struct motor_driver *motor = NULL; + int step = 0; + + motor = &mdev->motors[index]; + if(motor->state != MOTOR_OPS_STOP){ + step = motor->cur_steps % 8; + step = step < 0 ? step + 8 : step; + if (motor->pdata->motor_st1_gpio) + gpio_direction_output(motor->pdata->motor_st1_gpio, step_8[step] & 0x8); + if (motor->pdata->motor_st2_gpio) + gpio_direction_output(motor->pdata->motor_st2_gpio, step_8[step] & 0x4); + if (motor->pdata->motor_st3_gpio) + gpio_direction_output(motor->pdata->motor_st3_gpio, step_8[step] & 0x2); + if (motor->pdata->motor_st4_gpio) + gpio_direction_output(motor->pdata->motor_st4_gpio, step_8[step] & 0x1); + }else{ + if (motor->pdata->motor_st1_gpio) + gpio_direction_output(motor->pdata->motor_st1_gpio, 0); + if (motor->pdata->motor_st2_gpio) + gpio_direction_output(motor->pdata->motor_st2_gpio, 0); + if (motor->pdata->motor_st3_gpio) + gpio_direction_output(motor->pdata->motor_st3_gpio, 0); + if (motor->pdata->motor_st4_gpio) + gpio_direction_output(motor->pdata->motor_st4_gpio, 0); + } + if(motor->state == MOTOR_OPS_RESET){ + motor->total_steps++; + } + + return; +} + +static void move_to_min_pose_ops(struct motor_driver *motor) +{ + // printk("%s min %d\n",motor->pdata->name,__LINE__); + if(motor->state == MOTOR_OPS_RESET){ + /* motor->state = MOTOR_OPS_STOP; */ + /* // complete(&motor->reset_completion); */ + /* motor->move_dir = MOTOR_MOVE_RIGHT_UP; */ + }else if(motor->state == MOTOR_OPS_NORMAL){ + if(motor->move_dir == MOTOR_MOVE_LEFT_DOWN){ + motor->state = MOTOR_OPS_STOP; + } + }else + motor->move_dir = MOTOR_MOVE_RIGHT_UP; + + motor->cur_steps = 0; + //printk("%s min; cur_steps = %d max_steps = %d\n", motor->pdata->name,motor->cur_steps, motor->max_steps); +} + +static void move_to_max_pose_ops(struct motor_driver *motor,int index) +{ + if(motor->state == MOTOR_OPS_RESET){ + motor->state = MOTOR_OPS_STOP; + if(index ==HORIZONTAL_MOTOR) + motor->max_steps=hmaxstep; + else + motor->max_steps=vmaxstep; + complete(&motor->reset_completion); + motor->move_dir = MOTOR_MOVE_LEFT_DOWN; + }else if(motor->state == MOTOR_OPS_NORMAL){ + if(motor->move_dir == MOTOR_MOVE_RIGHT_UP){ + motor->state = MOTOR_OPS_STOP; + } + }else + motor->move_dir = MOTOR_MOVE_LEFT_DOWN; + motor->cur_steps = motor->max_steps; + //printk("%s max; cur_steps = %d max_steps = %d\n", motor->pdata->name,motor->cur_steps, motor->max_steps); +} + + +static char skip_move_mode[4][4] = {{2,0,0,0}, + {3,2,0,0}, + {4,3,2,0}, + {4,3,2,1}}; + +static inline void calc_slow_mode(struct motor_device *mdev, unsigned int steps) +{ + int index = steps / 10; + index = index > 3 ? 3 : index; + mdev->skip_mode = skip_move_mode[index]; +} + +/* return: 1 --> move, 0 --> don't move */ +static inline int whether_move_func(struct motor_device *mdev, unsigned int remainder) +{ + if(remainder == 0) + return 0; + + remainder = remainder / 10; + remainder = remainder > 3 ? 3: remainder; + if(mdev->counter % mdev->skip_mode[remainder] == 0) + return 1; + else + return 0; +} + +static irqreturn_t jz_timer_interrupt(int irq, void *dev_id) +{ + struct motor_device *mdev = dev_id; + struct motor_move *dst = &mdev->dst_move; + struct motor_move *cur = &mdev->cur_move; + struct motor_driver *motors = mdev->motors; + + if(motors[HORIZONTAL_MOTOR].state == MOTOR_OPS_STOP + && motors[VERTICAL_MOTOR].state == MOTOR_OPS_STOP){ + mdev->dev_state = MOTOR_OPS_STOP; + motor_move_step(mdev, HORIZONTAL_MOTOR); + motor_move_step(mdev, VERTICAL_MOTOR); + if(mdev->wait_stop){ + mdev->wait_stop = 0; + complete(&mdev->stop_completion); + } + return IRQ_HANDLED; + } + + if(motors[HORIZONTAL_MOTOR].cur_steps <= 0) + move_to_min_pose_ops(&motors[HORIZONTAL_MOTOR]); + + if(motors[HORIZONTAL_MOTOR].cur_steps >= motors[HORIZONTAL_MOTOR].max_steps) + move_to_max_pose_ops(&motors[HORIZONTAL_MOTOR],HORIZONTAL_MOTOR); + + if(motors[VERTICAL_MOTOR].cur_steps <= 0) + move_to_min_pose_ops(&motors[VERTICAL_MOTOR]); + + if(motors[VERTICAL_MOTOR].cur_steps >= motors[VERTICAL_MOTOR].max_steps) + move_to_max_pose_ops(&motors[VERTICAL_MOTOR],VERTICAL_MOTOR); + + if(mdev->dev_state == MOTOR_OPS_CRUISE){ + mdev->counter++; + motors[HORIZONTAL_MOTOR].cur_steps += motors[HORIZONTAL_MOTOR].move_dir; + if(mdev->counter % hmotor2vmotor == 0) + motors[VERTICAL_MOTOR].cur_steps += motors[VERTICAL_MOTOR].move_dir; + motor_move_step(mdev, HORIZONTAL_MOTOR); + motor_move_step(mdev, VERTICAL_MOTOR); + }else if(mdev->dev_state == MOTOR_OPS_RESET){ + if(motors[HORIZONTAL_MOTOR].state != MOTOR_OPS_STOP){ + motors[HORIZONTAL_MOTOR].cur_steps += motors[HORIZONTAL_MOTOR].move_dir; + motor_move_step(mdev, HORIZONTAL_MOTOR); + cur->one.x++; + } + if(motors[VERTICAL_MOTOR].state != MOTOR_OPS_STOP){ + motors[VERTICAL_MOTOR].cur_steps += motors[VERTICAL_MOTOR].move_dir; + motor_move_step(mdev, VERTICAL_MOTOR); + cur->one.y++; + } + }else{ + mdev->counter++; + + if(cur->one.x < dst->one.x && motors[HORIZONTAL_MOTOR].state != MOTOR_OPS_STOP){ + if(whether_move_func(mdev, dst->one.x - cur->one.x)){ + motors[HORIZONTAL_MOTOR].cur_steps += motors[HORIZONTAL_MOTOR].move_dir; + motor_move_step(mdev, HORIZONTAL_MOTOR); + cur->one.x++; + } + }else{ + motors[HORIZONTAL_MOTOR].state = MOTOR_OPS_STOP; + } + + if(cur->one.y < dst->one.y && motors[VERTICAL_MOTOR].state != MOTOR_OPS_STOP){ + if(mdev->counter % hmotor2vmotor == 0){ + motors[VERTICAL_MOTOR].cur_steps += motors[VERTICAL_MOTOR].move_dir; + cur->one.y++; + motor_move_step(mdev, VERTICAL_MOTOR); + } + }else{ + motors[VERTICAL_MOTOR].state = MOTOR_OPS_STOP; + } + } + return IRQ_HANDLED; +} + +static long motor_ops_move(struct motor_device *mdev, int x, int y) +{ + struct motor_driver *motors = mdev->motors; + unsigned long flags; + int x_dir = MOTOR_MOVE_STOP; + int y_dir = MOTOR_MOVE_STOP; + int x1 = 0; + int y1 = 0; + /* check x value */ + if(x > 0){ + if(motors[HORIZONTAL_MOTOR].cur_steps >= motors[HORIZONTAL_MOTOR].max_steps) + x = 0; + }else{ + if(motors[HORIZONTAL_MOTOR].cur_steps <= 0) + x = 0; + } + /* check y value */ + if(y > 0){ + if(motors[VERTICAL_MOTOR].cur_steps >= motors[VERTICAL_MOTOR].max_steps) + y = 0; + }else{ + if(motors[VERTICAL_MOTOR].cur_steps <= 0) + y = 0; + } + + /*x_dir = x > 0 ? MOTOR_MOVE_RIGHT_UP : (x < 0 ? MOTOR_MOVE_LEFT_DOWN: MOTOR_MOVE_STOP);*/ + /*y_dir = y > 0 ? MOTOR_MOVE_RIGHT_UP : (y < 0 ? MOTOR_MOVE_LEFT_DOWN: MOTOR_MOVE_STOP);*/ + x_dir = x > 0 ? MOTOR_MOVE_RIGHT_UP : MOTOR_MOVE_LEFT_DOWN; + y_dir = y > 0 ? MOTOR_MOVE_RIGHT_UP : MOTOR_MOVE_LEFT_DOWN; + 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); + + calc_slow_mode(mdev, x1); + mdev->counter = 0; + mdev->dev_state = MOTOR_OPS_NORMAL; + mdev->dst_move.one.x = x1; + mdev->dst_move.one.y = y1; + mdev->cur_move.one.x = 0; + mdev->cur_move.one.y = 0; + motors[HORIZONTAL_MOTOR].state = MOTOR_OPS_NORMAL; + motors[HORIZONTAL_MOTOR].move_dir = x_dir; + motors[VERTICAL_MOTOR].state = MOTOR_OPS_NORMAL; + motors[VERTICAL_MOTOR].move_dir = y_dir; + spin_unlock_irqrestore(&mdev->slock, flags); + mutex_unlock(&mdev->dev_mutex); + /* printk("%s%d x=%d y=%d t=%d\n",__func__,__LINE__,mdev->dst_move.one.x,mdev->dst_move.one.y,mdev->dst_move.times); */ + /* printk("x_dir=%d,y_dir=%d\n",x_dir,y_dir); */ +#ifdef CONFIG_SOC_T40 + ingenic_tcu_counter_begin(mdev->tcu); +#else + jz_tcu_enable_counter(mdev->tcu); +#endif + return 0; +} + +static void motor_ops_stop(struct motor_device *mdev) +{ + unsigned long flags; + long ret = 0; + unsigned int remainder = 0; + struct motor_driver *motors = mdev->motors; + struct motor_move *dst = &mdev->dst_move; + struct motor_move *cur = &mdev->cur_move; + + + if(mdev->dev_state == MOTOR_OPS_STOP) + return; + + mutex_lock(&mdev->dev_mutex); + spin_lock_irqsave(&mdev->slock, flags); + + if(mdev->dev_state == MOTOR_OPS_NORMAL){ + remainder = dst->one.x - cur->one.x; + if(remainder > 30){ + dst->one.x = 29; + cur->one.x = 0; + } + remainder = dst->one.y - cur->one.y; + if(remainder > 8){ + dst->one.y = 6; + cur->one.y = 0; + } + } + + if(mdev->dev_state == MOTOR_OPS_CRUISE){ + mdev->dev_state = MOTOR_OPS_NORMAL; + motors[HORIZONTAL_MOTOR].state = MOTOR_OPS_NORMAL; + motors[VERTICAL_MOTOR].state = MOTOR_OPS_NORMAL; + dst->one.x = 0; + cur->one.x = 0; + dst->one.y = 0; + cur->one.y = 0; + } + + mdev->counter = 0; + mdev->wait_stop = 1; + spin_unlock_irqrestore(&mdev->slock, flags); + mutex_unlock(&mdev->dev_mutex); + do{ + ret = wait_for_completion_interruptible_timeout(&mdev->stop_completion, msecs_to_jiffies(15000)); + if(ret == 0){ + ret = -ETIMEDOUT; + break; + } + }while(ret == -ERESTARTSYS); +#ifdef CONFIG_SOC_T40 + ingenic_tcu_counter_stop(mdev->tcu); +#else + jz_tcu_disable_counter(mdev->tcu); +#endif + /*mdev->dev_state = MOTOR_OPS_STOP;*/ + /*motors[HORIZONTAL_MOTOR].state = MOTOR_OPS_STOP;*/ + /*motors[VERTICAL_MOTOR].state = MOTOR_OPS_STOP;*/ + motor_set_default(mdev); + return; +} + +static long motor_ops_goback(struct motor_device *mdev) +{ + struct motor_driver *motors = mdev->motors; + int sx, sy; + int cx, cy; + sx = motors[HORIZONTAL_MOTOR].max_steps >> 1; + sy = motors[VERTICAL_MOTOR].max_steps >> 1; + 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); + return motor_ops_move(mdev, sx-cx, sy-cy); +} + +static long motor_ops_cruise(struct motor_device *mdev) +{ + unsigned long flags; + struct motor_driver *motors = mdev->motors; + motor_ops_goback(mdev); + mutex_lock(&mdev->dev_mutex); + spin_lock_irqsave(&mdev->slock, flags); + mdev->dev_state = MOTOR_OPS_CRUISE; + motors[HORIZONTAL_MOTOR].state = MOTOR_OPS_CRUISE; + motors[VERTICAL_MOTOR].state = MOTOR_OPS_CRUISE; + spin_unlock_irqrestore(&mdev->slock, flags); + mutex_unlock(&mdev->dev_mutex); +#ifdef CONFIG_SOC_T40 + ingenic_tcu_counter_begin(mdev->tcu); +#else + jz_tcu_enable_counter(mdev->tcu); +#endif + return 0; +} + +static void motor_get_message(struct motor_device *mdev, struct motor_message *msg) +{ + struct motor_driver *motors = mdev->motors; + msg->x = motors[HORIZONTAL_MOTOR].cur_steps; + msg->y = motors[VERTICAL_MOTOR].cur_steps; + msg->speed = mdev->tcu_speed; + if(mdev->dev_state == MOTOR_OPS_STOP) + msg->status = MOTOR_IS_STOP; + else + msg->status = MOTOR_IS_RUNNING; + /* This is not standard, return the max_steps of each motor */ + msg->x_max_steps = motors[HORIZONTAL_MOTOR].max_steps; + msg->y_max_steps = motors[VERTICAL_MOTOR].max_steps; + return; +} + +static inline int motor_ops_reset_check_params(struct motor_reset_data *rdata) +{ + if(rdata->x_max_steps == 0 || rdata->y_max_steps == 0){ + return -1; + } + if(rdata->x_max_steps < rdata->x_cur_step || rdata->x_max_steps < rdata->x_cur_step) + return -1; + 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; + printk("%s%d\n",__func__,__LINE__); + + if(mdev == NULL || rdata == NULL){ + printk("ERROR: the parameters of %s is wrong!!\n",__func__); + return -EPERM; + } + + if(motor_ops_reset_check_params(rdata) == 0){ + /* app set max steps and current pos */ + mutex_lock(&mdev->dev_mutex); + spin_lock_irqsave(&mdev->slock, flags); + mdev->motors[HORIZONTAL_MOTOR].max_steps = rdata->x_max_steps; + mdev->motors[HORIZONTAL_MOTOR].cur_steps = rdata->x_cur_step; + mdev->motors[VERTICAL_MOTOR].max_steps = rdata->y_max_steps; + mdev->motors[VERTICAL_MOTOR].cur_steps = rdata->y_cur_step; + spin_unlock_irqrestore(&mdev->slock, flags); + mutex_unlock(&mdev->dev_mutex); + }else{ + /* driver calculate max steps. */ + mutex_lock(&mdev->dev_mutex); + spin_lock_irqsave(&mdev->slock, flags); + for(index = 0; index < HAS_MOTOR_CNT; index++){ + mdev->motors[index].move_dir = MOTOR_MOVE_RIGHT_UP; + mdev->motors[index].state = MOTOR_OPS_RESET; + mdev->motors[index].cur_steps = 0x0; + } + mdev->dst_move.one.x = mdev->motors[HORIZONTAL_MOTOR].max_steps; + mdev->dst_move.one.y = mdev->motors[VERTICAL_MOTOR].max_steps; + mdev->dst_move.times = 1; + mdev->cur_move.one.x = 0; + mdev->cur_move.one.y = 0; + mdev->cur_move.times = 0; + mdev->dev_state = MOTOR_OPS_RESET; + spin_unlock_irqrestore(&mdev->slock, flags); + mutex_unlock(&mdev->dev_mutex); +#ifdef CONFIG_SOC_T40 + ingenic_tcu_counter_begin(mdev->tcu); +#else + jz_tcu_enable_counter(mdev->tcu); +#endif + + for(index = 0; index < HAS_MOTOR_CNT; index++){ + do{ + ret = wait_for_completion_interruptible_timeout(&mdev->motors[index].reset_completion, msecs_to_jiffies(150000)); + if(ret == 0){ + ret = -ETIMEDOUT; + goto exit; + } + }while(ret == -ERESTARTSYS); + } + } + //printk("x_max = %d, y_max = %d\n", mdev->motors[HORIZONTAL_MOTOR].max_steps, + //mdev->motors[VERTICAL_MOTOR].max_steps); + ret = motor_ops_goback(mdev); + /*ret = motor_ops_move(mdev, (mdev->motors[HORIZONTAL_MOTOR].max_steps) >> 1, */ + /*(mdev->motors[VERTICAL_MOTOR].max_steps) >> 1);*/ + + 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.status == MOTOR_IS_RUNNING); + ret = 0; + + /* sync data */ + rdata->x_max_steps = mdev->motors[HORIZONTAL_MOTOR].max_steps; + rdata->x_cur_step = mdev->motors[HORIZONTAL_MOTOR].cur_steps; + rdata->y_max_steps = mdev->motors[VERTICAL_MOTOR].max_steps; + rdata->y_cur_step = mdev->motors[VERTICAL_MOTOR].cur_steps; + +exit: +#ifdef CONFIG_SOC_T40 + ingenic_tcu_counter_stop(mdev->tcu); +#else + jz_tcu_disable_counter(mdev->tcu); +#endif + msleep(10); + motor_set_default(mdev); + return ret; +} + +static int motor_speed(struct motor_device *mdev, int speed) +{ + __asm__("ssnop"); + if ((speed < MOTOR_MIN_SPEED) || (speed > MOTOR_MAX_SPEED)) { + dev_err(mdev->dev, "speed(%d) set error\n", speed); + return -1; + } + __asm__("ssnop"); + + mdev->tcu_speed = speed; +#ifdef CONFIG_SOC_T40 + ingenic_tcu_set_period(mdev->tcu->cib.id,(24000000 / 64 / mdev->tcu_speed)); +#else + jz_tcu_set_period(mdev->tcu, (24000000 / 64 / mdev->tcu_speed)); +#endif + 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->flag){ + ret = -EBUSY; + dev_err(mdev->dev, "Motor driver busy now!\n"); + }else{ + mdev->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->flag = 0; + return 0; +} + +static long motor_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct miscdevice *dev = filp->private_data; + struct motor_device *mdev = container_of(dev, struct motor_device, misc_dev); + long ret = 0; + + if(mdev->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(arg == 0){ + ret = -EPERM; + break; + } + if (copy_from_user(&rdata, (void __user *)arg, + 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 *)arg, &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_steps dst; + if (copy_from_user(&dst, (void __user *)arg, + sizeof(struct motors_steps))) { + dev_err(mdev->dev, "[%s][%d] copy from user error\n", + __func__, __LINE__); + return -EFAULT; + } + ret = motor_ops_move(mdev, dst.x, dst.y); + /*printk("MOTOR_MOVE!!!!!!!!!!!!!!!!!!!\n");*/ + } + break; + case MOTOR_GET_STATUS: + { + struct motor_message msg; + + motor_get_message(mdev, &msg); + if (copy_to_user((void __user *)arg, &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: + { + int speed; + + if (copy_from_user(&speed, (void __user *)arg, sizeof(int))) { + dev_err(mdev->dev, "[%s][%d] copy to user error\n", __func__, __LINE__); + return -EFAULT; + } + + motor_speed(mdev, speed); + } + /*printk("MOTOR_SPEED!!!!!!!!!!!!!!!!!!!!!!!\n");*/ + break; + case MOTOR_GOBACK: + /*printk("MOTOR_GOBACK!!!!!!!!!!!!!!!!!!!!!!!\n");*/ + ret = motor_ops_goback(mdev); + break; + case MOTOR_CRUISE: + /*printk("MOTOR_CRUISE!!!!!!!!!!!!!!!!!!!!!!!\n");*/ + ret = motor_ops_cruise(mdev); + break; + default: + return -EINVAL; + } + + return ret; +} + +static struct file_operations motor_fops = { + .open = motor_open, + .release = motor_release, + .unlocked_ioctl = motor_ioctl, +}; + +static int motor_info_show(struct seq_file *m, void *v) +{ + int len = 0; + struct motor_device *mdev = (struct motor_device *)(m->private); + struct motor_message msg; + int index = 0; + +#ifdef CONFIG_SOC_T40 + seq_printf(m ,"The version of Motor driver is %s. SoC is T40\n",JZ_MOTOR_DRIVER_VERSION); + seq_printf(m ,"Motor driver is %s\n", mdev->flag?"opened":"closed"); + seq_printf(m ,"The max speed is %d and the min speed is %d\n", MOTOR_MAX_SPEED, MOTOR_MIN_SPEED); + motor_get_message(mdev, &msg); + seq_printf(m ,"The status of motor is %s\n", msg.status?"running":"stop"); + seq_printf(m ,"The pos of motor is (%d, %d)\n", msg.x, msg.y); + seq_printf(m ,"The speed of motor is %d\n", msg.speed); + + for(index = 0; index < HAS_MOTOR_CNT; index++){ + seq_printf(m ,"## motor is %s ##\n", mdev->motors[index].pdata->name); + seq_printf(m ,"max steps %d\n", mdev->motors[index].max_steps); + seq_printf(m ,"motor direction %d\n", mdev->motors[index].move_dir); + seq_printf(m ,"motor state %d (normal; cruise; reset)\n", mdev->motors[index].state); + seq_printf(m ,"the irq's counter of max pos is %d\n", mdev->motors[index].max_pos_irq_cnt); + seq_printf(m ,"the irq's counter of min pos is %d\n", mdev->motors[index].min_pos_irq_cnt); + } +#else + len += seq_printf(m ,"The version of Motor driver is %s. SoC is not T40\n",JZ_MOTOR_DRIVER_VERSION); + len += seq_printf(m ,"Motor driver is %s\n", mdev->flag?"opened":"closed"); + len += seq_printf(m ,"The max speed is %d and the min speed is %d\n", MOTOR_MAX_SPEED, MOTOR_MIN_SPEED); + motor_get_message(mdev, &msg); + len += seq_printf(m ,"The status of motor is %s\n", msg.status?"running":"stop"); + len += seq_printf(m ,"The pos of motor is (%d, %d)\n", msg.x, msg.y); + len += seq_printf(m ,"The speed of motor is %d\n", msg.speed); + + for(index = 0; index < HAS_MOTOR_CNT; index++){ + len += seq_printf(m ,"## motor is %s ##\n", mdev->motors[index].pdata->name); + len += seq_printf(m ,"GPIOs: Min %d, Max %d, Level %d, ST1 %d, ST2 %d, ST3 %d, ST4 %d\n", + mdev->motors[index].pdata->motor_min_gpio, + mdev->motors[index].pdata->motor_max_gpio, + mdev->motors[index].pdata->motor_gpio_level, + mdev->motors[index].pdata->motor_st1_gpio, + mdev->motors[index].pdata->motor_st2_gpio, + mdev->motors[index].pdata->motor_st3_gpio, + mdev->motors[index].pdata->motor_st4_gpio); + len += seq_printf(m ,"max steps %d\n", mdev->motors[index].max_steps); + len += seq_printf(m ,"motor direction %d\n", mdev->motors[index].move_dir); + len += seq_printf(m ,"motor state %d (normal; cruise; reset)\n", mdev->motors[index].state); + len += seq_printf(m ,"the irq's counter of max pos is %d\n", mdev->motors[index].max_pos_irq_cnt); + len += seq_printf(m ,"the irq's counter of min pos is %d\n", mdev->motors[index].min_pos_irq_cnt); + } +#endif + + return len; +} + +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 file_operations motor_info_fops ={ + .read = seq_read, + .open = motor_info_open, + .llseek = seq_lseek, + .release = single_release, +}; + +static int motor_probe(struct platform_device *pdev) +{ + int i, ret = 0; + struct motor_device *mdev; + struct motor_driver *motor = NULL; + struct proc_dir_entry *proc; + 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->cell = mfd_get_cell(pdev); + if (!mdev->cell) { + ret = -ENOENT; + dev_err(&pdev->dev, "Failed to get mfd cell for motor_probe!\n"); + goto error_devm_kzalloc; + } + + mdev->dev = &pdev->dev; + +#ifdef CONFIG_SOC_T40 + mdev->tcu = (struct ingenic_tcu_chn *)mdev->cell->platform_data; +#else + mdev->tcu = (struct jz_tcu_chn *)mdev->cell->platform_data; +#endif + mdev->tcu->irq_type = FULL_IRQ_MODE; + mdev->tcu->clk_src = TCU_CLKSRC_EXT; + mdev->tcu_speed = MOTOR_MAX_SPEED; +#ifdef CONFIG_SOC_T40 + mdev->tcu->is_pwm = 0; + mdev->tcu->cib.func = TRACKBALL_FUNC; + mdev->tcu->clk_div = TCU_PRESCALE_64; + ingenic_tcu_config(mdev->tcu); + ingenic_tcu_set_period(mdev->tcu->cib.id,(24000000 / 64 / mdev->tcu_speed)); +// ingenic_tcu_counter_begin(mdev->tcu); +#else + mdev->tcu->prescale = TCU_PRESCALE_64; + jz_tcu_config_chn(mdev->tcu); + jz_tcu_set_period(mdev->tcu, (24000000 / 64 / mdev->tcu_speed)); + jz_tcu_start_counter(mdev->tcu); +#endif + mutex_init(&mdev->dev_mutex); + spin_lock_init(&mdev->slock); + + platform_set_drvdata(pdev, mdev); + + /* copy module parameters to the motors struct */ + motors_pdata[0].motor_min_gpio = hmin; + motors_pdata[0].motor_max_gpio = hmax; + motors_pdata[0].motor_gpio_level = hlevel; + motors_pdata[0].motor_st1_gpio = hst1; + motors_pdata[0].motor_st2_gpio = hst2; + motors_pdata[0].motor_st3_gpio = hst3; + motors_pdata[0].motor_st4_gpio = hst4; + + motors_pdata[1].motor_min_gpio = vmin; + motors_pdata[1].motor_max_gpio = vmax; + motors_pdata[1].motor_gpio_level = vlevel; + motors_pdata[1].motor_st1_gpio = vst1; + motors_pdata[1].motor_st2_gpio = vst2; + motors_pdata[1].motor_st3_gpio = vst3; + motors_pdata[1].motor_st4_gpio = vst4; + + for(i = 0; i < HAS_MOTOR_CNT; i++) { + motor = &(mdev->motors[i]); + motor->pdata = &motors_pdata[i]; + motor->move_dir = MOTOR_MOVE_STOP; + dev_info(&pdev->dev, "'%s' GPIOs: Min %d, Max %d, Level %d, ST1 %d, ST2 %d, ST3 %d, ST4 %d\n", + motor->pdata->name, + motor->pdata->motor_min_gpio, + motor->pdata->motor_max_gpio, + motor->pdata->motor_gpio_level, + motor->pdata->motor_st1_gpio, + motor->pdata->motor_st2_gpio, + motor->pdata->motor_st3_gpio, + motor->pdata->motor_st4_gpio + ); + + init_completion(&motor->reset_completion); + + if (motor->pdata->motor_st1_gpio != -1) { + gpio_request(motor->pdata->motor_st1_gpio, "motor_st1_gpio"); + } + if (motor->pdata->motor_st2_gpio != -1) { + gpio_request(motor->pdata->motor_st2_gpio, "motor_st2_gpio"); + } + if (motor->pdata->motor_st3_gpio != -1) { + gpio_request(motor->pdata->motor_st3_gpio, "motor_st3_gpio"); + } + if (motor->pdata->motor_st4_gpio != -1) { + gpio_request(motor->pdata->motor_st4_gpio, "motor_st4_gpio"); + } + } + + mdev->motors[HORIZONTAL_MOTOR].max_steps = hmaxstep+100; + mdev->motors[VERTICAL_MOTOR].max_steps = vmaxstep+30; + +#ifdef CONFIG_SOC_T40 + ingenic_tcu_channel_to_virq(mdev->tcu); + mdev->run_step_irq = mdev->tcu->virq[0]; +#else + mdev->run_step_irq = platform_get_irq(pdev,0); +#endif + if (mdev->run_step_irq < 0) { + ret = mdev->run_step_irq; + dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); + goto error_get_irq; + } + + ret = request_irq(mdev->run_step_irq, jz_timer_interrupt, 0, + "jz_timer_interrupt", mdev); + if (ret) { + dev_err(&pdev->dev, "Failed to run request_irq() !\n"); + goto error_request_irq; + } + + init_completion(&mdev->stop_completion); + mdev->wait_stop = 0; + 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"); + goto error_misc_register; + } + + /* debug info */ + proc = jz_proc_mkdir("motor"); + if (!proc) { + mdev->proc = NULL; + printk("create motor_info failed!\n"); + } else { + mdev->proc = proc; + } + proc_create_data("motor_info", S_IRUGO, proc, &motor_info_fops, (void *)mdev); + + motor_set_default(mdev); + mdev->flag = 0; + //printk("%s%d\n",__func__,__LINE__); +#ifdef CONFIG_SOC_T40 + ingenic_tcu_counter_begin(mdev->tcu); +#endif + return 0; + +error_misc_register: + free_irq(mdev->run_step_irq, mdev); +error_request_irq: +error_get_irq: + for(i = 0; i < HAS_MOTOR_CNT; i++) { + motor = &(mdev->motors[i]); + if(motor->pdata == NULL) + continue; + + if (motor->pdata->motor_st1_gpio != -1) + gpio_free(motor->pdata->motor_st1_gpio); + + if (motor->pdata->motor_st2_gpio != -1) + gpio_free(motor->pdata->motor_st2_gpio); + + if (motor->pdata->motor_st3_gpio != -1) + gpio_free(motor->pdata->motor_st3_gpio); + + if (motor->pdata->motor_st4_gpio != -1) + gpio_free(motor->pdata->motor_st4_gpio); + motor->pdata = 0; + motor->min_pos_irq = 0; + motor->max_pos_irq = 0; + } + kfree(mdev); +error_devm_kzalloc: + return ret; +} + +static int motor_remove(struct platform_device *pdev) +{ + int i; + struct motor_device *mdev = platform_get_drvdata(pdev); + struct motor_driver *motor = NULL; + +#ifdef CONFIG_SOC_T40 + ingenic_tcu_counter_stop(mdev->tcu); +#else + jz_tcu_disable_counter(mdev->tcu); + jz_tcu_stop_counter(mdev->tcu); +#endif + mutex_destroy(&mdev->dev_mutex); + + free_irq(mdev->run_step_irq, mdev); + for(i = 0; i < HAS_MOTOR_CNT; i++) { + motor = &(mdev->motors[i]); + if(motor->pdata == NULL) + continue; + + if (motor->pdata->motor_st1_gpio != -1) + gpio_free(motor->pdata->motor_st1_gpio); + + if (motor->pdata->motor_st2_gpio != -1) + gpio_free(motor->pdata->motor_st2_gpio); + + if (motor->pdata->motor_st3_gpio != -1) + gpio_free(motor->pdata->motor_st3_gpio); + + if (motor->pdata->motor_st4_gpio != -1) + gpio_free(motor->pdata->motor_st4_gpio); + motor->pdata = 0; + motor->min_pos_irq = 0; + motor->max_pos_irq = 0; + motor->min_pos_irq_cnt = 0; + motor->max_pos_irq_cnt = 0; + } + + if (mdev->proc) + proc_remove(mdev->proc); + misc_deregister(&mdev->misc_dev); + + kfree(mdev); + return 0; +} + +#ifdef CONFIG_SOC_T40 +static struct of_device_id motor_match[]={ + {.compatible = "ingenic,tcu_chn2",}, + {} +}; +#endif + +static struct platform_driver motor_driver = { + .probe = motor_probe, + .remove = motor_remove, + .driver = { + .name = "tcu_chn2", +#ifdef CONFIG_SOC_T40 + .of_match_table = motor_match, +#endif + .owner = THIS_MODULE, + } +}; + +static int __init motor_init(void) +{ + return platform_driver_register(&motor_driver); +} + +static void __exit motor_exit(void) +{ + platform_driver_unregister(&motor_driver); +} + +module_init(motor_init); +module_exit(motor_exit); + +MODULE_LICENSE("GPL"); diff --git a/general/package/ingenic-motors-t31/src/motor.h b/general/package/ingenic-motors-t31/src/motor.h new file mode 100644 index 00000000..0d10af71 --- /dev/null +++ b/general/package/ingenic-motors-t31/src/motor.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2015 Ingenic Semiconductor Co.,Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __MOTOR_H__ +#define __MOTOR_H__ + +#include +#include +#include +#include +#include +/* + * HORIZONTAL is X axis and VERTICAL is Y axis; + * while the Zero point is left-bottom, Origin point + * is cross point of horizontal midpoint and vertical midpoint. + * +*/ + + +/*#define PLATFORM_HAS_HORIZONTAL_MOTOR 1*/ +/*#define PLATFORM_HAS_VERTICAL_MOTOR 1*/ + +enum jz_motor_cnt { + HORIZONTAL_MOTOR, + VERTICAL_MOTOR, + HAS_MOTOR_CNT, +}; + +/* ioctl cmd */ +#define MOTOR_STOP 0x1 +#define MOTOR_RESET 0x2 +#define MOTOR_MOVE 0x3 +#define MOTOR_GET_STATUS 0x4 +#define MOTOR_SPEED 0x5 +#define MOTOR_GOBACK 0x6 +#define MOTOR_CRUISE 0x7 +#define MOTOR_GET_MAXSTEPS 0x8 + +/* motor speed */ +#define MOTOR_MAX_SPEED 900 /**< unit: beats per second */ +#define MOTOR_MIN_SPEED 100 + +enum motor_status { + MOTOR_IS_STOP, + MOTOR_IS_RUNNING, +}; + +struct motor_message { + int x; + int y; + enum motor_status status; + int speed; + unsigned int x_max_steps; + unsigned int y_max_steps; +}; + +struct motors_steps{ + int x; + int y; +}; + +struct motor_reset_data { + unsigned int x_max_steps; + unsigned int y_max_steps; + unsigned int x_cur_step; + unsigned int y_cur_step; +}; + +enum motor_direction { + MOTOR_MOVE_LEFT_DOWN = -1, + MOTOR_MOVE_STOP, + MOTOR_MOVE_RIGHT_UP, +}; + +struct motor_platform_data { + const char name[32]; + int motor_min_gpio; + int motor_max_gpio; + int motor_gpio_level; + + int motor_st1_gpio; + int motor_st2_gpio; + int motor_st3_gpio; + int motor_st4_gpio; +}; + +enum motor_ops_state { + MOTOR_OPS_NORMAL, + MOTOR_OPS_CRUISE, + MOTOR_OPS_RESET, + MOTOR_OPS_STOP, +}; + +struct motor_driver { + struct motor_platform_data *pdata; + int max_pos_irq; + int min_pos_irq; + int max_steps; /* It is right-top point when x is max and y is max.*/ + int cur_steps; /* It is left-bottom point when x is 0 and y is 0.*/ + int total_steps; + char reset_min_pos; + char reset_max_pos; + enum motor_direction move_dir; + enum motor_ops_state state; + struct completion reset_completion; + + struct timer_list min_timer; + struct timer_list max_timer; + /* debug parameters */ + unsigned int max_pos_irq_cnt; + unsigned int min_pos_irq_cnt; +}; + +struct motor_move { + struct motors_steps one; + short times; +}; + +struct motor_device { + struct platform_device *pdev; + const struct mfd_cell *cell; + struct device *dev; + struct miscdevice misc_dev; + struct motor_driver motors[HAS_MOTOR_CNT]; + char *skip_mode; + unsigned int counter; + struct completion stop_completion; + unsigned int wait_stop; +#ifdef CONFIG_SOC_T40 + struct ingenic_tcu_chn *tcu; +#else + struct jz_tcu_chn *tcu; +#endif + int tcu_speed; + + struct mutex dev_mutex; + spinlock_t slock; + + enum motor_ops_state dev_state; + struct motor_message msg; + struct motor_move dst_move; + struct motor_move cur_move; + + int run_step_irq; + int flag; + + /* debug parameters */ + struct proc_dir_entry *proc; +}; + +#endif // __MOTOR_H__ diff --git a/general/package/motors/motors.mk b/general/package/motors/motors.mk index 8cadc9dd..a5b6218d 100644 --- a/general/package/motors/motors.mk +++ b/general/package/motors/motors.mk @@ -21,6 +21,7 @@ define MOTORS_BUILD_CMDS (cd $(@D)/i2c-motor; $(TARGET_CC) -Os -s main.c -o i2c-motor) (cd $(@D)/xm-kmotor; $(TARGET_CC) -Os -s main.c -o xm-kmotor) (cd $(@D)/xm-uart; $(TARGET_CC) -Os -s main.c -o xm-uart) + (cd $(@D)/t31-kmotor; $(TARGET_CC) -Os -s main.c -o t31-kmotor) endef define MOTORS_INSTALL_TARGET_CMDS @@ -28,6 +29,7 @@ define MOTORS_INSTALL_TARGET_CMDS $(INSTALL) -m 0755 -D $(@D)/i2c-motor/i2c-motor $(TARGET_DIR)/usr/bin/i2c-motor $(INSTALL) -m 0755 -D $(@D)/xm-kmotor/xm-kmotor $(TARGET_DIR)/usr/bin/xm-kmotor $(INSTALL) -m 0755 -D $(@D)/xm-uart/xm-uart $(TARGET_DIR)/usr/bin/xm-uart + $(INSTALL) -m 0755 -D $(@D)/t31-kmotor/t31-kmotor $(TARGET_DIR)/usr/bin/t31-kmotor endef $(eval $(generic-package))