From 33b6e91012674a9daa427ce1ce7801184fcd043c Mon Sep 17 00:00:00 2001 From: "Li, Ning" Date: Wed, 29 Feb 2012 14:56:40 +0800 Subject: [PATCH] pwm: add PWM driver on CLV platform BZ: 25800 On Clovertrail platform, Pulse Width Modulator driver needs to be supported to control the LED brightness and etc. This patch adds this driver and changes the interface in LED driver. Change-Id: I6f7595188e4b3f632e2d1551c9f85715aa1d4b04 Signed-off-by: Li, Ning Reviewed-on: http://android.intel.com:8080/37161 Reviewed-by: Yang, Bin Reviewed-by: Du, Alek Tested-by: Wang, Zhifeng Reviewed-by: buildbot Tested-by: buildbot --- arch/x86/include/asm/intel_mid_pwm.h | 25 ++++++ arch/x86/platform/intel-mid/board-blackbay.c | 31 +++++++ arch/x86/platform/intel-mid/board-ctp.c | 31 +++++++ drivers/hwmon/Kconfig | 9 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/intel_mid_pwm.c | 128 +++++++++++++++++++++++++++ drivers/leds/leds-intel-kpd.c | 26 +----- 7 files changed, 227 insertions(+), 24 deletions(-) create mode 100644 arch/x86/include/asm/intel_mid_pwm.h create mode 100644 drivers/hwmon/intel_mid_pwm.c diff --git a/arch/x86/include/asm/intel_mid_pwm.h b/arch/x86/include/asm/intel_mid_pwm.h new file mode 100644 index 0000000..df1141d --- /dev/null +++ b/arch/x86/include/asm/intel_mid_pwm.h @@ -0,0 +1,25 @@ +#ifndef __INTEL_MID_PWM_H__ +#define __INTEL_MID_PWM_H__ + +#define MSIC_REG_PWM0CLKDIV1 0x061 +#define MSIC_REG_PWM0CLKDIV0 0x062 +#define MSIC_REG_PWM0DUTYCYCLE 0x067 + +#define MAX_DUTYCYCLE_PERCENTAGE 100 + +enum { + PWM_LED = 0, + PWM_VIBRATOR, + PWM_LCD_BACKLIGHT, + PWM_NUM, +}; + +struct intel_mid_pwm_platform_data { + int reg_clkdiv0[PWM_NUM]; + int reg_clkdiv1[PWM_NUM]; + int reg_dutycyc[PWM_NUM]; +}; + +int intel_mid_pwm(int id, int value); +#endif + diff --git a/arch/x86/platform/intel-mid/board-blackbay.c b/arch/x86/platform/intel-mid/board-blackbay.c index bbc795a..5e042be 100644 --- a/arch/x86/platform/intel-mid/board-blackbay.c +++ b/arch/x86/platform/intel-mid/board-blackbay.c @@ -71,6 +71,7 @@ #include #include #include +#include #include /* the offset for the mapping of global gpio pin to irq */ @@ -1982,6 +1983,36 @@ out: } rootfs_initcall(hdmi_i2c_workaround); +#ifdef CONFIG_MID_PWM +static int __init intel_mid_pwm_init(void) +{ + int ret, i; + struct ipc_board_info board_info; + static struct intel_mid_pwm_platform_data mid_pwm_pdata; + + for (i = 0; i < PWM_NUM; i++) { + mid_pwm_pdata.reg_clkdiv0[i] = MSIC_REG_PWM0CLKDIV0 + i * 2; + mid_pwm_pdata.reg_clkdiv1[i] = MSIC_REG_PWM0CLKDIV1 + i * 2; + mid_pwm_pdata.reg_dutycyc[i] = MSIC_REG_PWM0DUTYCYCLE + i; + } + + memset(&board_info, 0, sizeof(board_info)); + strncpy(board_info.name, "intel_mid_pwm", 16); + board_info.bus_id = IPC_SCU; + board_info.id = -1; + board_info.platform_data = &mid_pwm_pdata; + + ret = ipc_new_device(&board_info); + if (ret) { + pr_err("failed to create ipc device: intel_mid_pwm\n"); + return -1; + } + + return 0; +} +fs_initcall(intel_mid_pwm_init); +#endif + #ifdef CONFIG_LEDS_INTEL_KPD static int __init intel_kpd_led_init(void) { diff --git a/arch/x86/platform/intel-mid/board-ctp.c b/arch/x86/platform/intel-mid/board-ctp.c index e8dab4b..ba16112 100644 --- a/arch/x86/platform/intel-mid/board-ctp.c +++ b/arch/x86/platform/intel-mid/board-ctp.c @@ -71,6 +71,7 @@ #include #include #include +#include #include /* the offset for the mapping of global gpio pin to irq */ @@ -1711,6 +1712,36 @@ out: } rootfs_initcall(hdmi_i2c_workaround); +#ifdef CONFIG_MID_PWM +static int __init intel_mid_pwm_init(void) +{ + int ret, i; + struct ipc_board_info board_info; + static struct intel_mid_pwm_platform_data mid_pwm_pdata; + + for (i = 0; i < PWM_NUM; i++) { + mid_pwm_pdata.reg_clkdiv0[i] = MSIC_REG_PWM0CLKDIV0 + i * 2; + mid_pwm_pdata.reg_clkdiv1[i] = MSIC_REG_PWM0CLKDIV1 + i * 2; + mid_pwm_pdata.reg_dutycyc[i] = MSIC_REG_PWM0DUTYCYCLE + i; + } + + memset(&board_info, 0, sizeof(board_info)); + strncpy(board_info.name, "intel_mid_pwm", 16); + board_info.bus_id = IPC_SCU; + board_info.id = -1; + board_info.platform_data = &mid_pwm_pdata; + + ret = ipc_new_device(&board_info); + if (ret) { + pr_err("failed to create ipc device: intel_mid_pwm\n"); + return -1; + } + + return 0; +} +fs_initcall(intel_mid_pwm_init); +#endif + #ifdef CONFIG_LEDS_INTEL_KPD static int __init intel_kpd_led_init(void) { diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index c189230..9646bd9 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1440,6 +1440,15 @@ config MSIC_GPADC help Say Y here to enable MSIC GPADC driver on Intel Medfield Platform +config MID_PWM + tristate "MID PWM driver for Intel Medfield platform" + depends on INTEL_SCU_IPC + help + Say Y here to enable MID PWM driver on Intel Medfield Platform. + This driver provides an interface to control the duty cycle of + an output signal. For more information, please refer to the driver + source code. + config SENSORS_MID_CURRENT tristate "Over Current Detection driver for Intel Medfield platform" depends on INTEL_SCU_IPC diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 5140dd0..65ee3ba 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -126,6 +126,7 @@ obj-$(CONFIG_SENSORS_MS5607) += ms5607.o obj-$(CONFIG_SENSORS_L3G4200D_POLL) += l3g4200d_poll.o obj-$(CONFIG_SENSORS_LPS331AP) += lps331ap.o obj-$(CONFIG_MSIC_GPADC) += intel_mid_gpadc.o +obj-$(CONFIG_MID_PWM) += intel_mid_pwm.o obj-$(CONFIG_SENSORS_MID_CURRENT) += intel_mid_ocd.o obj-$(CONFIG_SENSORS_LSM303_MAG) += lsm303dlhc_compass.o diff --git a/drivers/hwmon/intel_mid_pwm.c b/drivers/hwmon/intel_mid_pwm.c new file mode 100644 index 0000000..d6fa943 --- /dev/null +++ b/drivers/hwmon/intel_mid_pwm.c @@ -0,0 +1,128 @@ +/* + * intel_mid_pwm.c - Intel PWM driver + * + * Copyright (C) 2011 Intel Corporation + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include + +struct pwm_info { + int initialized; + int *msic_reg_clkdiv0; + int *msic_reg_clkdiv1; + int *msic_reg_dutycyc; + struct device *dev; + struct mutex lock; +}; + +static struct pwm_info pwm_info; + +int intel_mid_pwm(int id, int value) +{ + int ret; + struct pwm_info *pi = &pwm_info; + int msic_reg_pwmclkdiv0 = *(pi->msic_reg_clkdiv0 + id); + int msic_reg_pwmclkdiv1 = *(pi->msic_reg_clkdiv1 + id); + int msic_reg_pwmdutycyc = *(pi->msic_reg_dutycyc + id); + + if (!pi->initialized) + return -ENODEV; + + if (value < 0 || value > MAX_DUTYCYCLE_PERCENTAGE) { + dev_err(pi->dev, "duty cycle value invalid\n"); + return -EINVAL; + } + + value = (value == 100) ? 99 : value; + + mutex_lock(&pi->lock); + ret = intel_scu_ipc_iowrite8(msic_reg_pwmclkdiv1, 0x00); + if (ret) + dev_err(pi->dev, "set MSIC_REG_PWMCLKDIV1 failed\n"); + + ret = intel_scu_ipc_iowrite8(msic_reg_pwmclkdiv0, 0x03); + if (ret) + dev_err(pi->dev, "set MSIC_REG_PWMCLKDIV0 failed\n"); + + ret = intel_scu_ipc_iowrite8(msic_reg_pwmdutycyc, value); + if (ret) + dev_err(pi->dev, "set MSIC_REG_PWMDUTYCYCLE failed\n"); + + if (value == 0) { + ret = intel_scu_ipc_iowrite8(msic_reg_pwmclkdiv0, 0x00); + if (ret) + dev_err(pi->dev, "set MSIC_REG_PWMCLKDIV0 failed\n"); + } + + mutex_unlock(&pi->lock); + return 0; +} + +static int __devinit intel_mid_pwm_probe(struct ipc_device *ipcdev) +{ + struct pwm_info *pi = &pwm_info; + struct intel_mid_pwm_platform_data *pdata = ipcdev->dev.platform_data; + + mutex_init(&pi->lock); + + pi->dev = &ipcdev->dev; + pi->msic_reg_clkdiv0 = pdata->reg_clkdiv0; + pi->msic_reg_clkdiv1 = pdata->reg_clkdiv1; + pi->msic_reg_dutycyc = pdata->reg_dutycyc; + + pi->initialized = 1; + + return 0; +} + +static int __devexit intel_mid_pwm_remove(struct ipc_device *ipcdev) +{ + return 0; +} + +static struct ipc_driver mid_pwm_driver = { + .driver = { + .name = "intel_mid_pwm", + .owner = THIS_MODULE, + }, + .probe = intel_mid_pwm_probe, + .remove = __devexit_p(intel_mid_pwm_remove), +}; + +static int __init intel_mid_pwm_init(void) +{ + return ipc_driver_register(&mid_pwm_driver); +} + +static void __exit intel_mid_pwm_exit(void) +{ + ipc_driver_unregister(&mid_pwm_driver); +} + +module_init(intel_mid_pwm_init); +module_exit(intel_mid_pwm_exit); + +MODULE_DESCRIPTION("Intel Pulse Width Modulator Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/leds-intel-kpd.c b/drivers/leds/leds-intel-kpd.c index f9817c3..9156199 100644 --- a/drivers/leds/leds-intel-kpd.c +++ b/drivers/leds/leds-intel-kpd.c @@ -28,34 +28,12 @@ #include #include #include - -#define MSIC_REG_PWM0CLKDIV1 0x061 -#define MSIC_REG_PWM0CLKDIV0 0x062 -#define MSIC_REG_PWM0DUTYCYCLE 0x067 +#include static void intel_keypad_led_set(struct led_classdev *led_cdev, enum led_brightness value) { - int ret; - - ret = intel_scu_ipc_iowrite8(MSIC_REG_PWM0CLKDIV1, 0x00); - if (ret) - dev_err(led_cdev->dev, "set MSIC_REG_PWM0CLKDIV1 failed"); - - ret = intel_scu_ipc_iowrite8(MSIC_REG_PWM0CLKDIV0, 0x03); - if (ret) - dev_err(led_cdev->dev, "set MSIC_REG_PWM0CLKDIV0 failed"); - - ret = intel_scu_ipc_iowrite8(MSIC_REG_PWM0DUTYCYCLE, value); - if (ret) - dev_err(led_cdev->dev, "set MSIC_REG_PWM0DUTYCYCLE failed"); - - if (value == 0) { - ret = intel_scu_ipc_iowrite8(MSIC_REG_PWM0CLKDIV0, 0x00); - if (ret) - dev_err(led_cdev->dev, "set MSIC_REG_PWM0CLKDIV0 failed\n"); - } - + intel_mid_pwm(PWM_LED, value); } static struct led_classdev intel_kpd_led = { -- 2.7.4