123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 |
- /*
- * File : drv_pwm.c
- * This file is part of GK710X BSP for RT-Thread distribution.
- *
- * Copyright (c) 2017 GOKE Microelectronics Co., Ltd.
- * All rights reserved
- *
- * 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; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Visit http://www.goke.com to get contact with Goke.
- *
- * Change Logs:
- * Date Author Notes
- */
- #include <rtdevice.h>
- //#include "gpio.h"
- #include "drv_pwm.h"
- #include <rtdef.h>
- #include <rtthread.h>
- #include <rtdevice.h>
- #include <drivers/watchdog.h>
- #include "gtypes.h"
- #include "gd_pwm.h"
- #include "platform.h"
- #define GK_TEST_PWM
- static struct gk_pwm_obj *pwm_drv = NULL;
- static struct pwm_driver pwm_drv_table;
- static rt_err_t pwm_get_status(rt_uint32_t *status)
- {
- rt_uint32_t channel_enable;
- struct gk_pwm_obj *pwm_obj = (struct gk_pwm_obj *)pwm_drv;
- if(status == NULL || pwm_obj->id >= PWM_MAX_CHANNEL)
- {
- rt_kprintf("PWM: > max channel \n");
- return RT_ERROR;
- }
- if (GD_OK != GD_PWM_Get_Status(pwm_obj->id, &channel_enable))
- {
- rt_kprintf("get pwm status failed!\n");
- return RT_ERROR;
- }
- *status = channel_enable;
- return RT_EOK;
- }
- static rt_err_t pwm_enable(struct gk_pwm_obj *pwm_obj)
- {
- rt_uint32_t ret = RT_EOK;
- if (pwm_obj->id >= PWM_MAX_CHANNEL)
- {
- rt_kprintf("PWM: > max channel \n");
- return RT_ERROR;
- }
- ret = GD_PwmOnOff(pwm_obj->id, GTRUE);
- if (ret != GD_OK)
- {
- rt_kprintf("enable pwm device failed!\n");
- return RT_ERROR;
- }
- return RT_EOK;
- }
- static rt_err_t pwm_disable(struct gk_pwm_obj *pwm_obj)
- {
- rt_uint32_t ret = RT_EOK;
- if (pwm_obj->id >= PWM_MAX_CHANNEL)
- {
- rt_kprintf("PWM: > max channel \n");
- return RT_ERROR;
- }
- ret = GD_PwmOnOff(pwm_obj->id, GFALSE);
- if (ret != GD_OK)
- {
- rt_kprintf("disable pwm device failed!\n");
- return RT_ERROR;
- }
- return ret;
- }
- static int pwm_get_duty_cycle_ns(struct pwm_device *pwm)
- {
- struct gk_pwm_obj *pwm_obj = (struct gk_pwm_obj *)pwm_drv;
- rt_uint32_t freq, duty;
- if (pwm_obj->id >= PWM_MAX_CHANNEL)
- {
- rt_kprintf("PWM: > max channel \n");
- return -1;
- }
- if (GD_PWM_Get_Param(pwm_obj->id, &freq, &duty))
- {
- rt_kprintf("GD_PWM_Get_Param error.\n");
- return -1;
- }
- rt_kprintf("get duty: %lu%%, freq: %lu\n", duty, freq);
- return 0;
- }
- static int pwm_set_duty_cycle_ns(struct pwm_device *pwm)
- {
- struct gk_pwm_obj *pwm_obj = (struct gk_pwm_obj *)pwm_drv;
- rt_uint32_t range, duty, freq;
- GERR ret = 0;
- if(pwm_obj->id >= PWM_MAX_CHANNEL)
- {
- rt_kprintf("PWM: > max channel \n");
- return -1;
- }
- freq = pwm->freq;
- range = pwm->range;
- duty = pwm->duty;
- //param mode The PWM mode: 0 - Normal Speed Mode; 1 - Sync Speed Mode.
- ret = GD_PWM_Set_Mode(pwm_obj->id, 0);
- if(ret != GD_OK)
- {
- rt_kprintf("Set pwm mode 0 failed!\n");
- return -1;
- }
- ret = GD_PWM_Set_Param(pwm_obj->id, freq, range, duty);
- if (GD_PWM_NO_ERR != ret)
- {
- if (GD_PWM_ERR_NOT_SUPPORTED_CHANNEL == ret)
- {
- rt_kprintf("PWM Set_Param:set[%d %d %d]error *not support channel.\n",
- (int)freq, (int)range, (int)duty);
- }
- else if(GD_PWM_ERR_NOT_SUPPORTED_FREQUENCY == ret)
- {
- rt_kprintf("PWM Set_Param:set[%d %d %d]error *not support Freq.\n",
- (int)freq, (int)range, (int)duty);
- }
- else if(GD_PWM_ERR_NOT_SUPPORTED_RANGE == ret)
- {
- rt_kprintf("PWM Set_Param:set[%d %d %d]error *not support Range.\n",
- (int)freq, (int)range, (int)duty);
- }
- else if(GD_PWM_ERR_WRONG_DUTY_CONFIGURATION == ret)
- {
- rt_kprintf("PWM Set_Param:set[%d %d %d]error *wrong duty.\n",
- (int)freq, (int)range, (int)duty);
- }
- else if(GD_PWM_ERR_RANGE_EXCEED_LIMIT == ret)
- {
- rt_kprintf("PWM Set_Param:set[%d %d %d]error *exceed Range limit.\n",
- (int)freq, (int)range, (int)duty);
- }
- return -1;
- }
- return 0;
- }
- static int pwm_get_vsync_mode_param(rt_uint16_t *speed)
- {
- struct gk_pwm_obj *pwm_obj = (struct gk_pwm_obj *)pwm_drv;
- GERR ret = GD_OK;
- if (pwm_obj->id >= PWM_MAX_CHANNEL)
- {
- rt_kprintf("PWM: > max channel \n");
- return -1;
- }
- ret = GD_PWM_Get_Speed(pwm_obj->id, speed);
- if(ret != GD_OK)
- {
- rt_kprintf("Get pwm speed failed!\n");
- return -1;
- }
- rt_kprintf("get speed: %u\n", *speed);
- return 0;
- }
- static int pwm_set_vsync_mode_param(struct pwm_param_vsync_mode *param)
- {
- struct gk_pwm_obj *pwm_obj = (struct gk_pwm_obj *)pwm_drv;
- GERR ret = GD_OK;
- if(pwm_obj->id >= PWM_MAX_CHANNEL)
- {
- rt_kprintf("PWM: > max channel \n");
- return -1;
- }
- //param mode The PWM mode: 0 - Normal Speed Mode; 1 - Sync Speed Mode.
- ret = GD_PWM_Set_Mode(pwm_obj->id, 1);
- if(ret != GD_OK)
- {
- rt_kprintf("Set pwm mode 1 failed!\n");
- return -1;
- }
- ret = GD_PWM_Set_Speed(pwm_obj->id, param->speed);
- if(ret != GD_OK)
- {
- rt_kprintf("Set pwm speed failed!\n");
- return -1;
- }
- ret = GD_PWM_Cycle(pwm_obj->id, param->highLevelCnt, param->lowLevelCnt);
- if(ret != GD_OK)
- {
- rt_kprintf("Set pwm cycle failed!\n");
- return -1;
- }
- return 0;
- }
- static int pwm_set_clock_divider(int ratio)
- {
- struct gk_pwm_obj *pwm_obj = (struct gk_pwm_obj *)pwm_drv;
- rt_uint32_t range, duty, freq;
- GERR ret = 0;
- if (pwm_obj->id >= PWM_MAX_CHANNEL)
- {
- rt_kprintf("PWM: > max channel \n");
- return -1;
- }
- if ((ratio != 1) && (ratio != 2) && (ratio != 3))
- {
- rt_kprintf("pwm_set_clock_divider:%d wrong param.\n", ratio);
- return -1;
- }
- if (GD_OK != GD_PWM_Set_Clock_Divider(pwm_obj->id, ratio))
- {
- rt_kprintf("gadi_pwm_set_clock_divider:%d set error.\n", ratio);
- return -1;
- }
- return 0;
- }
- static int pwm_set_active_channel(int id)
- {
- GERR ret = 0;
- if (id >= PWM_MAX_CHANNEL)
- {
- rt_kprintf("PWM: > max channel \n");
- return -1;
- }
- if (pwm_drv_table.pwm[id].gpio_id == 0xff)
- {
- rt_kprintf("channel not open \n");
- return -1;
- }
- pwm_drv->id = id;
- return 0;
- }
- static rt_err_t pwm_start(struct gk_pwm_obj *pwm_obj)
- {
- rt_uint32_t pwmStatus = 0;
- rt_uint32_t ret = GD_OK;
- ret = pwm_get_status(&pwmStatus);
- if(ret != RT_EOK)
- {
- return ret;
- }
- if(pwmStatus)
- {
- ret = pwm_disable(pwm_obj);
- if(ret != RT_EOK)
- {
- return ret;
- }
- }
- return pwm_enable(pwm_obj);
- }
- static rt_err_t gk_pwm_open(rt_device_t dev, rt_uint16_t oflag)
- {
- rt_err_t ret = RT_EOK;
- int index;
- for (index=0; index<PWM_MAX_CHANNEL; index++)
- {
- if ((pwm_drv_table.pwm[index].id != 0xff) && (pwm_drv_table.pwm[index].gpio_id != 0xff))
- {
- rt_kprintf("pwm_drv_table.pwm[%d] id= %d, gpio_id = %d\n",
- index,
- pwm_drv_table.pwm[index].id,
- pwm_drv_table.pwm[index].gpio_id);
- ret = GD_PWM_Open(pwm_drv_table.pwm[index].id, pwm_drv_table.pwm[index].gpio_id);
- if(ret != GD_OK)
- {
- rt_kprintf("open pwm device %d channel failed!\n", pwm_drv_table.pwm[index].id);
- continue;
- }
- }
- }
- if (pwm_drv_table.pwm[0].gpio_id != 0xff)
- {
- pwm_drv->id = pwm_drv_table.pwm[0].id;
- }
- return ret;
- }
- static rt_err_t gk_pwm_close(rt_device_t dev)
- {
- struct gk_pwm_obj *pwm_obj = (struct gk_pwm_obj *)pwm_drv;
- if(pwm_obj->id >= PWM_MAX_CHANNEL)
- {
- rt_kprintf("PWM: > max channel \n");
- return RT_ERROR;
- }
- GD_PWM_Close(pwm_obj->id);
- return RT_EOK;
- }
- static rt_err_t gk_pwm_ioctl(rt_device_t dev, int cmd, void *arg)
- {
- int ratio, ret = 0;
- rt_uint16_t *speed = NULL;
- struct pwm_device *pwm = NULL;
- struct pwm_param_vsync_mode *vsync_param = NULL;
- struct gk_pwm_obj *pwm_obj = (struct gk_pwm_obj *)pwm_drv;
- switch (cmd)
- {
- case ENABLE_PWM:
- pwm_start(pwm_obj);
- break;
- case DISABLE_PWM:
- pwm_disable(pwm_obj);
- break;
- case SET_PWM_DUTY_CYCLE:
- pwm = (struct pwm_device *)arg;
- pwm_set_duty_cycle_ns(pwm);
- break;
- case GET_PWM_DUTY_CYCLE:
- pwm = (struct pwm_device *)arg;
- pwm_get_duty_cycle_ns(pwm);
- break;
- case SET_PWM_VSYNC_MODE:
- vsync_param = (struct pwm_param_vsync_mode *)arg;
- pwm_set_vsync_mode_param(vsync_param);
- break;
- case GET_PWM_VSYNC_MODE:
- speed = (rt_uint16_t *)arg;
- pwm_get_vsync_mode_param(speed);
- break;
- case SET_PWM_CLOCK_DIV:
- ratio = *((int*)arg);
- pwm_set_clock_divider(ratio);
- break;
- case SET_PWM_ACT_CHANNEL:
- ratio = *((int*)arg);
- pwm_set_active_channel(ratio);
- break;
- default:
- break;
- }
- return ret;
- }
- static rt_err_t gk_pwm_init(rt_device_t dev)
- {
- rt_err_t ret = RT_EOK;
- ret = (rt_err_t)GD_PWM_Init();
- return ret;
- }
- int gk_pwm_probe(void *priv_data)
- {
- rt_device_t pwm_dev;
- int index;
- for (index=0; index < PWM_MAX_CHANNEL; index++)
- {
- pwm_drv_table.pwm[index].id = 0xff;
- pwm_drv_table.pwm[index].gpio_id = 0xff;
- }
- for (index=0; index < PWM_MAX_CHANNEL; index++)
- {
- if (((struct pwm_driver *)priv_data)->pwm[index].gpio_id > 0)
- {
- pwm_drv_table.pwm[index].id = ((struct pwm_driver *)priv_data)->pwm[index].id;
- pwm_drv_table.pwm[index].gpio_id = ((struct pwm_driver *)priv_data)->pwm[index].gpio_id;
- }
- }
- pwm_drv = rt_malloc(sizeof(struct gk_pwm_obj));
- if (pwm_drv == RT_NULL)
- {
- rt_kprintf("ERROR: %s pwm_drv malloc failed\n", __func__);
- }
- rt_memset(pwm_drv, 0, sizeof(struct gk_pwm_obj));
- pwm_dev = rt_malloc(sizeof(struct rt_device));
- if (pwm_dev == RT_NULL)
- {
- rt_kprintf("ERROR: %s rt_device malloc failed\n", __func__);
- }
- rt_memset(pwm_dev, 0, sizeof(struct rt_device));
- pwm_dev->user_data = &pwm_drv_table;
- pwm_dev->open = gk_pwm_open;
- pwm_dev->close = gk_pwm_close;
- pwm_dev->control = gk_pwm_ioctl;
- pwm_dev->init = gk_pwm_init;
- pwm_dev->type = RT_Device_Class_Miscellaneous;
- rt_device_register(pwm_dev, "pwm", RT_DEVICE_FLAG_RDWR);
- return 0;
- }
- int gk_pwm_exit(void *priv_data) { return 0; }
- struct gk_platform_driver pwm_driver_ops = {
- .name = "pwm", .probe = gk_pwm_probe, .remove = gk_pwm_exit,
- };
- void rt_hw_pwm_init(void)
- {
- gk_platform_driver_init(&pwm_driver_ops);
- }
- #ifdef GK_TEST_PWM
- int gk_pwm_test(void)
- {
- rt_device_t pwm_dev;
- struct pwm_device pwm;
- pwm.duty = 50;
- pwm.range = 100;
- pwm.freq = 1000;
- pwm_dev = rt_device_find("pwm");
- if (!pwm_dev)
- {
- rt_kprintf("cann't find the pwm dev\n");
- }
- pwm_dev->init(pwm_dev);
- pwm_dev->open(pwm_dev, 0);
- pwm_dev->control(pwm_dev, SET_PWM_DUTY_CYCLE, &pwm);
- pwm_dev->control(pwm_dev, ENABLE_PWM, NULL);
- return 0;
- }
- #endif
- #ifdef RT_USING_FINSH
- #include <finsh.h>
- #ifdef GK_TEST_PWM
- FINSH_FUNCTION_EXPORT(gk_pwm_test, gk_pwm_test);
- #endif
- #endif
|