From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Hi. I'm trying to push DA9053 PMIC driver to mainline kernel. Please help me to review these patches. Many Thanks.
Ying-Chun Liu (PaulLiu) (11): PMIC: Add DA9053 headers from Dialog PMIC: Add GPIO Driver for Dialog DA9052 PMIC: Add ADC Driver for Dialog DA9052 PMIC: Add TSI/misc input Driver for Dialog DA9052 PMIC: Add LED Driver for Dialog DA9052 PMIC: Add MFD Driver for Dialog DA9052 PMIC: Add BATTERY Driver for Dialog DA9052 PMIC: Add REGULATOR Driver for Dialog DA9052 PMIC: Add RTC Driver for Dialog DA9052 PMIC: Add Video Backlight Driver for Dialog DA9052 PMIC: Add Watchdog Driver for Dialog DA9052
drivers/gpio/Kconfig | 7 + drivers/gpio/Makefile | 1 + drivers/gpio/da9052-gpio.c | 731 +++++++++++ drivers/hwmon/Kconfig | 10 + drivers/hwmon/Makefile | 1 + drivers/hwmon/da9052-adc.c | 644 ++++++++++ drivers/input/misc/Kconfig | 10 + drivers/input/misc/Makefile | 1 + drivers/input/misc/da9052_onkey.c | 133 ++ drivers/input/touchscreen/Kconfig | 7 + drivers/input/touchscreen/Makefile | 2 + drivers/input/touchscreen/da9052_tsi.c | 1446 ++++++++++++++++++++++ drivers/input/touchscreen/da9052_tsi_calibrate.c | 107 ++ drivers/input/touchscreen/da9052_tsi_filter.c | 489 ++++++++ drivers/leds/Kconfig | 10 + drivers/leds/Makefile | 1 + drivers/leds/leds-da9052.c | 308 +++++ drivers/mfd/Kconfig | 37 + drivers/mfd/Makefile | 2 + drivers/mfd/da9052-core.c | 536 ++++++++ drivers/mfd/da9052-i2c.c | 378 ++++++ drivers/mfd/da9052-spi.c | 402 ++++++ drivers/power/Kconfig | 7 + drivers/power/Makefile | 1 + drivers/power/da9052-battery.c | 847 +++++++++++++ drivers/regulator/Kconfig | 7 + drivers/regulator/Makefile | 2 + drivers/regulator/da9052-regulator.c | 490 ++++++++ drivers/rtc/Kconfig | 7 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-da9052.c | 694 +++++++++++ drivers/video/backlight/Kconfig | 6 + drivers/video/backlight/Makefile | 2 +- drivers/video/backlight/da9052_bl.c | 461 +++++++ drivers/watchdog/Kconfig | 5 + drivers/watchdog/Makefile | 1 + drivers/watchdog/da9052_wdt.c | 542 ++++++++ include/linux/mfd/da9052/adc.h | 66 + include/linux/mfd/da9052/bat.h | 264 ++++ include/linux/mfd/da9052/bl.h | 289 +++++ include/linux/mfd/da9052/da9052.h | 209 ++++ include/linux/mfd/da9052/eh.h | 77 ++ include/linux/mfd/da9052/gpio.h | 253 ++++ include/linux/mfd/da9052/led.h | 39 + include/linux/mfd/da9052/pm.h | 81 ++ include/linux/mfd/da9052/reg.h | 929 ++++++++++++++ include/linux/mfd/da9052/rtc.h | 322 +++++ include/linux/mfd/da9052/tsi.h | 427 +++++++ include/linux/mfd/da9052/tsi_calibrate.h | 47 + include/linux/mfd/da9052/tsi_cfg.h | 132 ++ include/linux/mfd/da9052/tsi_filter.h | 58 + include/linux/mfd/da9052/wdt.h | 83 ++ include/linux/regulator/da9052-regulator.h | 15 + 53 files changed, 11626 insertions(+), 1 deletions(-) create mode 100644 drivers/gpio/da9052-gpio.c create mode 100644 drivers/hwmon/da9052-adc.c create mode 100644 drivers/input/misc/da9052_onkey.c create mode 100644 drivers/input/touchscreen/da9052_tsi.c create mode 100644 drivers/input/touchscreen/da9052_tsi_calibrate.c create mode 100644 drivers/input/touchscreen/da9052_tsi_filter.c create mode 100644 drivers/leds/leds-da9052.c create mode 100644 drivers/mfd/da9052-core.c create mode 100644 drivers/mfd/da9052-i2c.c create mode 100644 drivers/mfd/da9052-spi.c create mode 100644 drivers/power/da9052-battery.c create mode 100644 drivers/regulator/da9052-regulator.c create mode 100644 drivers/rtc/rtc-da9052.c create mode 100644 drivers/video/backlight/da9052_bl.c create mode 100644 drivers/watchdog/da9052_wdt.c create mode 100644 include/linux/mfd/da9052/adc.h create mode 100644 include/linux/mfd/da9052/bat.h create mode 100644 include/linux/mfd/da9052/bl.h create mode 100644 include/linux/mfd/da9052/da9052.h create mode 100644 include/linux/mfd/da9052/eh.h create mode 100644 include/linux/mfd/da9052/gpio.h create mode 100644 include/linux/mfd/da9052/led.h create mode 100644 include/linux/mfd/da9052/pm.h create mode 100644 include/linux/mfd/da9052/reg.h create mode 100644 include/linux/mfd/da9052/rtc.h create mode 100644 include/linux/mfd/da9052/tsi.h create mode 100644 include/linux/mfd/da9052/tsi_calibrate.h create mode 100644 include/linux/mfd/da9052/tsi_cfg.h create mode 100644 include/linux/mfd/da9052/tsi_filter.h create mode 100644 include/linux/mfd/da9052/wdt.h create mode 100644 include/linux/regulator/da9052-regulator.h
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9053 headers source code.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org --- include/linux/mfd/da9052/adc.h | 66 +++ include/linux/mfd/da9052/bat.h | 264 +++++++++ include/linux/mfd/da9052/bl.h | 289 ++++++++++ include/linux/mfd/da9052/da9052.h | 209 +++++++ include/linux/mfd/da9052/eh.h | 77 +++ include/linux/mfd/da9052/gpio.h | 253 ++++++++ include/linux/mfd/da9052/led.h | 39 ++ include/linux/mfd/da9052/pm.h | 81 +++ include/linux/mfd/da9052/reg.h | 929 ++++++++++++++++++++++++++++++ include/linux/mfd/da9052/rtc.h | 322 +++++++++++ include/linux/mfd/da9052/tsi.h | 427 ++++++++++++++ include/linux/mfd/da9052/tsi_calibrate.h | 47 ++ include/linux/mfd/da9052/tsi_cfg.h | 132 +++++ include/linux/mfd/da9052/tsi_filter.h | 58 ++ include/linux/mfd/da9052/wdt.h | 83 +++ 15 files changed, 3276 insertions(+), 0 deletions(-) create mode 100644 include/linux/mfd/da9052/adc.h create mode 100644 include/linux/mfd/da9052/bat.h create mode 100644 include/linux/mfd/da9052/bl.h create mode 100644 include/linux/mfd/da9052/da9052.h create mode 100644 include/linux/mfd/da9052/eh.h create mode 100644 include/linux/mfd/da9052/gpio.h create mode 100644 include/linux/mfd/da9052/led.h create mode 100644 include/linux/mfd/da9052/pm.h create mode 100644 include/linux/mfd/da9052/reg.h create mode 100644 include/linux/mfd/da9052/rtc.h create mode 100644 include/linux/mfd/da9052/tsi.h create mode 100644 include/linux/mfd/da9052/tsi_calibrate.h create mode 100644 include/linux/mfd/da9052/tsi_cfg.h create mode 100644 include/linux/mfd/da9052/tsi_filter.h create mode 100644 include/linux/mfd/da9052/wdt.h
diff --git a/include/linux/mfd/da9052/adc.h b/include/linux/mfd/da9052/adc.h new file mode 100644 index 0000000..49c7d18 --- /dev/null +++ b/include/linux/mfd/da9052/adc.h @@ -0,0 +1,66 @@ +/* + * da9052 ADC module declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_ADC_H +#define __LINUX_MFD_DA9052_ADC_H + +#include "gpio.h" + +#define DA9052_ADC_DEVICE_NAME "da9052_adc" + +/* Channel Definations */ +#define DA9052_ADC_VDDOUT 0 +#define DA9052_ADC_ICH 1 +#define DA9052_ADC_TBAT 2 +#define DA9052_ADC_VBAT 3 +#define DA9052_ADC_ADCIN4 4 +#define DA9052_ADC_ADCIN5 5 +#define DA9052_ADC_ADCIN6 6 +#define DA9052_ADC_TSI 7 +#define DA9052_ADC_TJUNC 8 +#define DA9052_ADC_VBBAT 9 + +#if (DA9052_GPIO_PIN_0 == DA9052_GPIO_CONFIG_ADC) +#define DA9052_ADC_CONF_ADC4 1 +#else +#define DA9052_ADC_CONF_ADC4 0 +#endif +#if (DA9052_GPIO_PIN_1 == DA9052_GPIO_CONFIG_ADC) +#define DA9052_ADC_CONF_ADC5 1 +#else +#define DA9052_ADC_CONF_ADC5 0 +#endif +#if (DA9052_GPIO_PIN_2 == DA9052_GPIO_CONFIG_ADC) +#define DA9052_ADC_CONF_ADC6 1 +#else +#define DA9052_ADC_CONF_ADC6 0 +#endif + +/* Maximum retry count to check manual conversion over */ +#define DA9052_ADC_MAX_MANCONV_RETRY_COUNT 8 + +struct da9052_adc_priv { + struct da9052 *da9052; + struct device *hwmon_dev; + struct mutex manconv_lock; +}; + +#endif /* __LINUX_MFD_DA9052_ADC_H */ diff --git a/include/linux/mfd/da9052/bat.h b/include/linux/mfd/da9052/bat.h new file mode 100644 index 0000000..4643c45 --- /dev/null +++ b/include/linux/mfd/da9052/bat.h @@ -0,0 +1,264 @@ +/* + * da9052 BAT module declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_BAT_H +#define __LINUX_MFD_DA9052_BAT_H + +#include <linux/power_supply.h> + +/* STATIC CONFIGURATION */ +#define DA9052_LOOK_UP_TABLE_SIZE 68 +#define DA9052_NO_OF_LOOKUP_TABLE 3 +#define DA9052_FILTER_SIZE 4 +#define DA9052_NUMBER_OF_STORE_CURENT_READING 4 +#define DA9052_BAT_FILTER_HYS 0 + + +static const u16 temperature_lookup_ref + [DA9052_NO_OF_LOOKUP_TABLE] = {10, 25, 40}; +static u32 const vbat_vs_capacity_look_up[DA9052_NO_OF_LOOKUP_TABLE] + [DA9052_LOOK_UP_TABLE_SIZE][2] = { + /* For temperature 10 degree celisus*/ + { + {4082, 100}, {4036, 98}, + {4020, 96}, {4008, 95}, + {3997, 93}, {3983, 91}, + {3964, 90}, {3943, 88}, + {3926, 87}, {3912, 85}, + {3900, 84}, {3890, 82}, + {3881, 80}, {3873, 79}, + {3865, 77}, {3857, 76}, + {3848, 74}, {3839, 73}, + {3829, 71}, {3820, 70}, + {3811, 68}, {3802, 67}, + {3794, 65}, {3785, 64}, + {3778, 62}, {3770, 61}, + {3763, 59}, {3756, 58}, + {3750, 56}, {3744, 55}, + {3738, 53}, {3732, 52}, + {3727, 50}, {3722, 49}, + {3717, 47}, {3712, 46}, + {3708, 44}, {3703, 43}, + {3700, 41}, {3696, 40}, + {3693, 38}, {3691, 37}, + {3688, 35}, {3686, 34}, + {3683, 32}, {3681, 31}, + {3678, 29}, {3675, 28}, + {3672, 26}, {3669, 25}, + {3665, 23}, {3661, 22}, + {3656, 21}, {3651, 19}, + {3645, 18}, {3639, 16}, + {3631, 15}, {3622, 13}, + {3611, 12}, {3600, 10}, + {3587, 9}, {3572, 7}, + {3548, 6}, {3503, 5}, + {3420, 3}, {3268, 2}, + {2992, 1}, {2746, 0} + }, + /* For temperature 25 degree celisus */ + { + {4102, 100}, {4065, 98}, + {4048, 96}, {4034, 95}, + {4021, 93}, {4011, 92}, + {4001, 90}, {3986, 88}, + {3968, 87}, {3952, 85}, + {3938, 84}, {3926, 82}, + {3916, 81}, {3908, 79}, + {3900, 77}, {3892, 76}, + {3883, 74}, {3874, 73}, + {3864, 71}, {3855, 70}, + {3846, 68}, {3836, 67}, + {3827, 65}, {3819, 64}, + {3810, 62}, {3801, 61}, + {3793, 59}, {3786, 58}, + {3778, 56}, {3772, 55}, + {3765, 53}, {3759, 52}, + {3754, 50}, {3748, 49}, + {3743, 47}, {3738, 46}, + {3733, 44}, {3728, 43}, + {3724, 41}, {3720, 40}, + {3716, 38}, {3712, 37}, + {3709, 35}, {3706, 34}, + {3703, 33}, {3701, 31}, + {3698, 30}, {3696, 28}, + {3693, 27}, {3690, 25}, + {3687, 24}, {3683, 22}, + {3680, 21}, {3675, 19}, + {3671, 18}, {3666, 17}, + {3660, 15}, {3654, 14}, + {3647, 12}, {3639, 11}, + {3630, 9}, {3621, 8}, + {3613, 6}, {3606, 5}, + {3597, 4}, {3582, 2}, + {3546, 1}, {2747, 0} + }, + /* For temperature 40 degree celisus*/ + { + {4114, 100}, {4081, 98}, + {4065, 96}, {4050, 95}, + {4036, 93}, {4024, 92}, + {4013, 90}, {4002, 88}, + {3990, 87}, {3976, 85}, + {3962, 84}, {3950, 82}, + {3939, 81}, {3930, 79}, + {3921, 77}, {3912, 76}, + {3902, 74}, {3893, 73}, + {3883, 71}, {3874, 70}, + {3865, 68}, {3856, 67}, + {3847, 65}, {3838, 64}, + {3829, 62}, {3820, 61}, + {3812, 59}, {3803, 58}, + {3795, 56}, {3787, 55}, + {3780, 53}, {3773, 52}, + {3767, 50}, {3761, 49}, + {3756, 47}, {3751, 46}, + {3746, 44}, {3741, 43}, + {3736, 41}, {3732, 40}, + {3728, 38}, {3724, 37}, + {3720, 35}, {3716, 34}, + {3713, 33}, {3710, 31}, + {3707, 30}, {3704, 28}, + {3701, 27}, {3698, 25}, + {3695, 24}, {3691, 22}, + {3686, 21}, {3681, 19}, + {3676, 18}, {3671, 17}, + {3666, 15}, {3661, 14}, + {3655, 12}, {3648, 11}, + {3640, 9}, {3632, 8}, + {3622, 6}, {3616, 5}, + {3611, 4}, {3604, 2}, + {3594, 1}, {2747, 0} + } +}; + +enum charger_type_enum { + DA9052_NOCHARGER = 1, + DA9052_USB_HUB, + DA9052_USB_CHARGER, + DA9052_WALL_CHARGER +}; + +struct da9052_bat_event_registration { + u8 da9052_event_tbat:1; +}; + +struct da9052_bat_hysteresis { + u16 bat_volt_arr[3]; + u16 array_hys_batvoltage[2]; + u16 upper_limit; + u16 lower_limit; + u8 index; + u8 hys_flag; +}; + +struct da9052_charger_device { + struct da9052 *da9052; + struct workqueue_struct *monitor_wqueue; + struct delayed_work monitor_work; + struct power_supply psy; + struct da9052_eh_nb tbat_eh_data; + u8 cal_capacity; + u8 charger_type; + u8 health; + u8 status; + u8 illegal; + u16 technology; + u16 chg_current; + u16 bat_voltage; + u16 bat_capacity_limit_low; + u16 bat_capacity_full; + u16 bat_capacity_limit_high; + u16 bat_volt_cutoff; + u16 bat_with_no_resistor; + u16 bat_temp; + u8 hys_flag; + u16 charger_voltage_drop; + u16 bat_target_voltage; + u16 chg_end_current; + u16 hysteresis_window_size; + u16 chg_hysteresis_const; + u16 hysteresis_reading_interval; + u16 hysteresis_no_of_reading; + u16 vbat_first_valid_detect_iteration; +}; + + +static inline u8 bat_temp_reg_to_C(u16 value) { return (55 - value); } +static inline u8 bat_mV_to_reg(u16 value) { return (((value-4100)/100)<<4); } +static inline u8 bat_drop_mV_to_reg(u16 value) + { return (((value-100)/100)<<6); } +static inline u16 bat_reg_to_mV(u8 value) { return ((value*100) + 4100); } +static inline u16 bat_drop_reg_to_mV(u8 value) { return ((value*100)+100); } +static inline u8 vch_thr_mV_to_reg(u16 value) { return ((value-3700)/100); } +static inline u8 precharge_mA_to_reg(u8 value) { return ((value/20)<<6); } +static inline u8 vddout_mon_mV_to_reg(u16 value) + { return (((value-2500)*128)/1000); } +static inline u16 vddout_reg_to_mV(u8 value) + { return ((value*1000)/128)+2500; } +static inline u16 volt_reg_to_mV(u16 value) + { return ((value*1000)/512)+2500; } +static inline u8 ichg_mA_to_reg(u16 value) { return (value/4); } +static inline u16 ichg_reg_to_mA(u8 value) { return ((value*3900)/1000); } +static inline u8 iset_mA_to_reg(u16 iset_value) + {\ + if ((70 <= iset_value) && (iset_value <= 120)) \ + return (iset_value-70)/10; \ + else if ((400 <= iset_value) && (iset_value <= 700)) \ + return ((iset_value-400)/50)+6; \ + else if ((900 <= iset_value) && (iset_value <= 1300)) \ + return ((iset_value-900)/200)+13; else return 0; + } + +#define DA9052_BAT_DEBUG 0 + +#define DA9052_BAT_PROFILE 0 +#define SUCCESS 0 +#define FAILURE 1 + +#define TRUE 1 +#define FALSE 0 + +#define set_bits(value, mask) (value | mask) +#define clear_bits(value, mask) (value & ~(mask)) + +#undef DA9052_DEBUG +#if DA9052_BAT_DEBUG +#define DA9052_DEBUG(fmt, args...) printk(KERN_CRIT "" fmt, ##args) +#else +#define DA9052_DEBUG(fmt, args...) +#endif + + +/* SSC Read or Write Error */ +#define DA9052_SSC_FAIL 150 + +/* To enable debug output for your module, set this to 1 */ +#define DA9052_SSC_DEBUG 0 + +#undef DA9052_DEBUG +#if DA9052_SSC_DEBUG +#define DA9052_DEBUG(fmt, args...) printk(KERN_CRIT "" fmt, ##args) +#else +#define DA9052_DEBUG(fmt, args...) +#endif + + +#endif /* __LINUX_MFD_DA9052_BAT_H */ diff --git a/include/linux/mfd/da9052/bl.h b/include/linux/mfd/da9052/bl.h new file mode 100644 index 0000000..9217eb9 --- /dev/null +++ b/include/linux/mfd/da9052/bl.h @@ -0,0 +1,289 @@ +/* + * da9052 Backlight module declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_BL_H +#define __LINUX_MFD_DA9052_BL_H + +/* + * enum da9052_bl_current_value - Enum for current values of LED + * DA9052_BL_CURRENT_50_0UA: represents 50.0 uA current value + */ +enum da9052_bl_current_value { +/* Current Value for LEDMIN, LED1_CONF, LED2_CONF, LED3_CONF Registers */ + DA9052_BL_CURRENT_50_0UA = 0, + DA9052_BL_CURRENT_51_2UA, + DA9052_BL_CURRENT_52_5UA, + DA9052_BL_CURRENT_53_7UA, + DA9052_BL_CURRENT_55_1UA, + DA9052_BL_CURRENT_56_4UA, + DA9052_BL_CURRENT_57_8UA, + DA9052_BL_CURRENT_59_3UA, + DA9052_BL_CURRENT_60_7UA, + DA9052_BL_CURRENT_62_2UA, + DA9052_BL_CURRENT_63_8UA, + DA9052_BL_CURRENT_65_3UA, + DA9052_BL_CURRENT_67_0UA, + DA9052_BL_CURRENT_68_6UA, + DA9052_BL_CURRENT_70_3UA, + DA9052_BL_CURRENT_72_0UA, + DA9052_BL_CURRENT_73_8UA, + DA9052_BL_CURRENT_75_7UA, + DA9052_BL_CURRENT_77_5UA, + DA9052_BL_CURRENT_79_4UA, + DA9052_BL_CURRENT_81_4UA, + DA9052_BL_CURRENT_83_4UA, + DA9052_BL_CURRENT_85_5UA, + DA9052_BL_CURRENT_87_6UA, + DA9052_BL_CURRENT_89_8UA, + DA9052_BL_CURRENT_92_0UA, + DA9052_BL_CURRENT_94_2UA, + DA9052_BL_CURRENT_96_6UA, + DA9052_BL_CURRENT_99_0UA, + DA9052_BL_CURRENT_101_4UA, + DA9052_BL_CURRENT_103_9UA, + DA9052_BL_CURRENT_106_5UA, + DA9052_BL_CURRENT_109_1UA, + DA9052_BL_CURRENT_111_8UA, + DA9052_BL_CURRENT_114_6UA, + DA9052_BL_CURRENT_117_4UA, + DA9052_BL_CURRENT_120_6UA, + DA9052_BL_CURRENT_123_3UA, + DA9052_BL_CURRENT_126_3UA, + DA9052_BL_CURRENT_129_4UA, + DA9052_BL_CURRENT_132_6UA, + DA9052_BL_CURRENT_135_9UA, + DA9052_BL_CURRENT_139_3UA, + DA9052_BL_CURRENT_142_7UA, + DA9052_BL_CURRENT_146_2UA, + DA9052_BL_CURRENT_149_9UA, + DA9052_BL_CURRENT_153_6UA, + DA9052_BL_CURRENT_157_4UA, + DA9052_BL_CURRENT_161_2UA, + DA9052_BL_CURRENT_165_2UA, + DA9052_BL_CURRENT_169_3UA, + DA9052_BL_CURRENT_173_5UA, + DA9052_BL_CURRENT_177_8UA, + DA9052_BL_CURRENT_182_2UA, + DA9052_BL_CURRENT_186_7UA, + DA9052_BL_CURRENT_191_3UA, + DA9052_BL_CURRENT_196_0UA, + DA9052_BL_CURRENT_200_9UA, + DA9052_BL_CURRENT_205_8UA, + DA9052_BL_CURRENT_210_9UA, + DA9052_BL_CURRENT_216_1UA, + DA9052_BL_CURRENT_221_4UA, + DA9052_BL_CURRENT_226_9UA, + DA9052_BL_CURRENT_232_5UA, + DA9052_BL_CURRENT_238_3UA, + DA9052_BL_CURRENT_244_2UA, + DA9052_BL_CURRENT_250_2UA, + DA9052_BL_CURRENT_256_4UA, + DA9052_BL_CURRENT_262_7UA, + DA9052_BL_CURRENT_269_2UA, + DA9052_BL_CURRENT_275_8UA, + DA9052_BL_CURRENT_282_7UA, + DA9052_BL_CURRENT_289_6UA, + DA9052_BL_CURRENT_296_8UA, + DA9052_BL_CURRENT_304_1UA, + DA9052_BL_CURRENT_311_6UA, + DA9052_BL_CURRENT_319_3UA, + DA9052_BL_CURRENT_327_2UA, + DA9052_BL_CURRENT_335_3UA, + DA9052_BL_CURRENT_343_6UA, + DA9052_BL_CURRENT_352_1UA, + DA9052_BL_CURRENT_360_8UA, + DA9052_BL_CURRENT_369_7UA, + DA9052_BL_CURRENT_378_8UA, + DA9052_BL_CURRENT_388_2UA, + DA9052_BL_CURRENT_397_8UA, + DA9052_BL_CURRENT_407_6UA, + DA9052_BL_CURRENT_417_7UA, + DA9052_BL_CURRENT_428_0UA, + DA9052_BL_CURRENT_438_6UA, + DA9052_BL_CURRENT_449_4UA, + DA9052_BL_CURRENT_460_5UA, + DA9052_BL_CURRENT_471_9UA, + DA9052_BL_CURRENT_483_5UA, + DA9052_BL_CURRENT_495_5UA, + DA9052_BL_CURRENT_507_7UA, + DA9052_BL_CURRENT_520_3UA, + DA9052_BL_CURRENT_533_1UA, + DA9052_BL_CURRENT_546_3UA, + DA9052_BL_CURRENT_559_8UA, + DA9052_BL_CURRENT_573_6UA, + DA9052_BL_CURRENT_587_8UA, + DA9052_BL_CURRENT_602_3UA, + DA9052_BL_CURRENT_617_2UA, + DA9052_BL_CURRENT_632_4UA, + DA9052_BL_CURRENT_648_0UA, + DA9052_BL_CURRENT_664_0UA, + DA9052_BL_CURRENT_680_4UA, + DA9052_BL_CURRENT_697_2UA, + DA9052_BL_CURRENT_714_5UA, + DA9052_BL_CURRENT_732_1UA, + DA9052_BL_CURRENT_750_2UA, + DA9052_BL_CURRENT_768_7UA, + DA9052_BL_CURRENT_787_7UA, + DA9052_BL_CURRENT_807_2UA, + DA9052_BL_CURRENT_827_1UA, + DA9052_BL_CURRENT_847_6UA, + DA9052_BL_CURRENT_868_5UA, + DA9052_BL_CURRENT_889_9UA, + DA9052_BL_CURRENT_911_9UA, + DA9052_BL_CURRENT_934_4UA, + DA9052_BL_CURRENT_957_5UA, + DA9052_BL_CURRENT_981_2UA, + DA9052_BL_CURRENT_1005_4UA, + DA9052_BL_CURRENT_1030_3UA, + DA9052_BL_CURRENT_1055_7UA, + DA9052_BL_CURRENT_1081_8UA, + DA9052_BL_CURRENT_1108_5UA, + DA9052_BL_CURRENT_1135_9UA, + DA9052_BL_CURRENT_1163_9UA, + DA9052_BL_CURRENT_1192_7UA, + DA9052_BL_CURRENT_1222_2UA, + DA9052_BL_CURRENT_1252_3UA, + DA9052_BL_CURRENT_1283_3UA, + DA9052_BL_CURRENT_1315_0UA, + DA9052_BL_CURRENT_1347_5UA, + DA9052_BL_CURRENT_1380_7UA, + DA9052_BL_CURRENT_1414_8UA, + DA9052_BL_CURRENT_1449_8UA, + DA9052_BL_CURRENT_1485_6UA, + DA9052_BL_CURRENT_1522_3UA, + DA9052_BL_CURRENT_1559_9UA, + DA9052_BL_CURRENT_1598_4UA, + DA9052_BL_CURRENT_1637_9UA, + DA9052_BL_CURRENT_1678_4UA, + DA9052_BL_CURRENT_1719_8UA, + DA9052_BL_CURRENT_1762_3UA, + DA9052_BL_CURRENT_1805_8UA, + DA9052_BL_CURRENT_1850_4UA, + DA9052_BL_CURRENT_1896_1UA, + DA9052_BL_CURRENT_1943_0UA, + DA9052_BL_CURRENT_1991_0UA, + DA9052_BL_CURRENT_2040_2UA, + DA9052_BL_CURRENT_2090_5UA, + DA9052_BL_CURRENT_2142_2UA, + DA9052_BL_CURRENT_2195_1UA, + DA9052_BL_CURRENT_2249_3UA, + DA9052_BL_CURRENT_2304_9UA, + DA9052_BL_CURRENT_2361_8UA, + DA9052_BL_CURRENT_2420_1UA, + DA9052_BL_CURRENT_2479_9UA, + DA9052_BL_CURRENT_2541_2UA, + DA9052_BL_CURRENT_2604_0UA, + DA9052_BL_CURRENT_2668_3UA, + DA9052_BL_CURRENT_2734_2UA, + DA9052_BL_CURRENT_2801_7UA, + DA9052_BL_CURRENT_2870_9UA, + DA9052_BL_CURRENT_2941_8UA, + DA9052_BL_CURRENT_3014_5UA, + DA9052_BL_CURRENT_3089_0UA, + DA9052_BL_CURRENT_3165_3UA, + DA9052_BL_CURRENT_3243_4UA, + DA9052_BL_CURRENT_3323_5UA, + DA9052_BL_CURRENT_3405_6UA, + DA9052_BL_CURRENT_3489_8UA, + DA9052_BL_CURRENT_3576_0UA, + DA9052_BL_CURRENT_3664_3UA, + DA9052_BL_CURRENT_3754_8UA, + DA9052_BL_CURRENT_3847_5UA, + DA9052_BL_CURRENT_3942_6UA, + DA9052_BL_CURRENT_4040_0UA, + DA9052_BL_CURRENT_4139_7UA, + DA9052_BL_CURRENT_4242_0UA, + DA9052_BL_CURRENT_4346_8UA, + DA9052_BL_CURRENT_4454_1UA, + DA9052_BL_CURRENT_4564_2UA, + DA9052_BL_CURRENT_4676_9UA, + DA9052_BL_CURRENT_4792_4UA, + DA9052_BL_CURRENT_4910_8UA, + DA9052_BL_CURRENT_5032_1UA, + DA9052_BL_CURRENT_5156_4UA, + DA9052_BL_CURRENT_5283_7UA, + DA9052_BL_CURRENT_5414_3UA, + DA9052_BL_CURRENT_5548_0UA, + DA9052_BL_CURRENT_5685_0UA, + DA9052_BL_CURRENT_5825_5UA, + DA9052_BL_CURRENT_5969_3UA, + DA9052_BL_CURRENT_6116_8UA, + DA9052_BL_CURRENT_6267_9UA, + DA9052_BL_CURRENT_6422_7UA, + DA9052_BL_CURRENT_6581_3UA, + DA9052_BL_CURRENT_6743_9UA, + DA9052_BL_CURRENT_6910_5UA, + DA9052_BL_CURRENT_7081_2UA, + DA9052_BL_CURRENT_7256_1UA, + DA9052_BL_CURRENT_7435_3UA, + DA9052_BL_CURRENT_7618_9UA, + DA9052_BL_CURRENT_7807_1UA, + DA9052_BL_CURRENT_8000_0UA, + DA9052_BL_CURRENT_8197_6UA, + DA9052_BL_CURRENT_8400_0UA, + DA9052_BL_CURRENT_8607_5UA, + DA9052_BL_CURRENT_8820_1UA, + DA9052_BL_CURRENT_9038_0UA, + DA9052_BL_CURRENT_9261_2UA, + DA9052_BL_CURRENT_9490_0UA, + DA9052_BL_CURRENT_9724_4UA, + DA9052_BL_CURRENT_9964_6UA, + DA9052_BL_CURRENT_10210_7UA, + DA9052_BL_CURRENT_10462_9UA, + DA9052_BL_CURRENT_10721_4UA, + DA9052_BL_CURRENT_10986_4UA, + DA9052_BL_CURRENT_11257_5UA, + DA9052_BL_CURRENT_11535_6UA, + DA9052_BL_CURRENT_11820_5UA, + DA9052_BL_CURRENT_12112_5UA, + DA9052_BL_CURRENT_12411_7UA, + DA9052_BL_CURRENT_12718_2UA, + DA9052_BL_CURRENT_13032_4UA, + DA9052_BL_CURRENT_13354_3UA, + DA9052_BL_CURRENT_13684_1UA, + DA9052_BL_CURRENT_14022_1UA, + DA9052_BL_CURRENT_14368_5UA, + DA9052_BL_CURRENT_14723_4UA, + DA9052_BL_CURRENT_15087_1UA, + DA9052_BL_CURRENT_15459_7UA, + DA9052_BL_CURRENT_15841_6UA, + DA9052_BL_CURRENT_16232_9UA, + DA9052_BL_CURRENT_16633_8UA, + DA9052_BL_CURRENT_17044_7UA, + DA9052_BL_CURRENT_17465_7UA, + DA9052_BL_CURRENT_17897_1UA, + DA9052_BL_CURRENT_18339_1UA, + DA9052_BL_CURRENT_18792_1UA, + DA9052_BL_CURRENT_19256_3UA, + DA9052_BL_CURRENT_19731_9UA, + DA9052_BL_CURRENT_20219_3UA, + DA9052_BL_CURRENT_20718_7UA, + DA9052_BL_CURRENT_21230_5UA, + DA9052_BL_CURRENT_21754_8UA, + DA9052_BL_CURRENT_22292_2UA, + DA9052_BL_CURRENT_22842_8UA, + DA9052_BL_CURRENT_23407_0UA, + DA9052_BL_CURRENT_23985_2UA, + DA9052_BL_CURRENT_24577_6UA, + DA9052_BL_CURRENT_25000_0UA, +}; + +#endif /* __LINUX_MFD_DA9052_BL_H */ diff --git a/include/linux/mfd/da9052/da9052.h b/include/linux/mfd/da9052/da9052.h new file mode 100644 index 0000000..88d34ca --- /dev/null +++ b/include/linux/mfd/da9052/da9052.h @@ -0,0 +1,209 @@ +/* + * da9052 declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_DA9052_H +#define __LINUX_MFD_DA9052_DA9052_H + +#include <linux/slab.h> +#include <linux/mfd/core.h> + +#include <linux/mfd/da9052/eh.h> +#include <linux/mfd/da9052/reg.h> +#include <linux/mfd/da9052/led.h> + + +#define SPI 1 +#define I2C 2 + +#define DA9052_SSC_DEVICE_NAME "da9052_ssc" +#define DA9052_EH_DEVICE_NAME "da9052_eh" + +#define DA9052_IRQ S3C_EINT(9) + +/* Module specific error codes */ +#define INVALID_REGISTER 2 +#define INVALID_READ 3 +#define INVALID_PAGE 4 + +/* Defines for Volatile and Non Volatile register types */ +#define VOLATILE 0 +#define NON_VOLATILE 1 + +/* Defines for cache state */ +#define VALID 0 +#define INVALID 1 + +/* Total number of registers in DA9057 */ +#define DA9052_REG_CNT DA9052_PAGE1_REG_END + +/* Maximum number of registers that can be read/written by a singe request */ +#define MAX_READ_WRITE_CNT 16 + + +#define DA9052_SSC_SPI_DEVICE_NAME "da9052_ssc_spi" +#define PAGE_0_START 1 +#define PAGE_0_END 127 +#define PAGE_1_START 128 +#define PAGE_1_END 255 +#define ACTIVE_PAGE_0 0 +#define ACTIVE_PAGE_1 1 +#define PAGECON_0 0 +#define PAGECON_128 128 +#define RW_POL 1 + +#define DA9052_SSC_I2C_DEVICE_NAME "da9052_ssc_i2c" +#define DA9052_I2C_ADDR 0x90 +#define DA9052_SSC_I2C_PAGE_WRITE_MODE 0 +#define DA9052_SSC_I2C_REPEAT_WRITE_MODE 1 +#define DA9052_SSC_I2C_WRITE_MODE DA9052_SSC_I2C_REPEAT_WRITE_MODE + +struct da9052_ssc_msg { + unsigned char data; + unsigned char addr; +}; + +struct ssc_cache_entry { + unsigned char val; + unsigned char type:4; + unsigned char status:4; +}; + +struct da9052_eh_nb { + struct list_head nb_list; + unsigned char eve_type; + void (*call_back)(struct da9052_eh_nb *, unsigned int); +}; + +struct da9052_regulator_init_data { + struct regulator_init_data *init_data; + int id; + +}; + +struct da9052_regulator_platform_data { + struct regulator_init_data *regulators; +}; + +struct da9052_tsi_platform_data { + u32 pen_up_interval; + u16 tsi_delay_bit_shift; + u16 tsi_skip_bit_shift; + u16 num_gpio_tsi_register; + u16 tsi_supply_voltage; + u16 tsi_ref_source; + u16 max_tsi_delay; + u16 max_tsi_skip_slot; +}; + + +struct da9052 { + struct mutex ssc_lock; + struct mutex eve_nb_lock; + struct mutex manconv_lock; + struct work_struct eh_isr_work; + struct ssc_cache_entry ssc_cache[DA9052_REG_CNT]; + int (*read) (struct da9052 *da9052, struct da9052_ssc_msg *sscmsg); + int (*write) (struct da9052 *da9052, struct da9052_ssc_msg *sscmsg); + int (*read_many) (struct da9052 *da9052, + struct da9052_ssc_msg *sscmsg, int cnt); + int (*write_many)(struct da9052 *da9052, + struct da9052_ssc_msg *sscmsg, int cnt); + int (*register_event_notifier)(struct da9052 *da9052, + struct da9052_eh_nb *nb); + int (*unregister_event_notifier)(struct da9052 *da9052, + struct da9052_eh_nb *nb); + int num_regulators; + int connecting_device; + int irq; + struct spi_device *spi_dev; + unsigned int spi_active_page; + unsigned char rw_pol; + unsigned char *spi_rx_buf; + unsigned char *spi_tx_buf; + + struct i2c_client *i2c_client; + struct device *dev; + struct i2c_adapter *adapter; + unsigned char slave_addr; +}; + + +struct da9052_platform_data { + int (*init)(struct da9052 *da9052); + int irq_high; + int irq_base; + int gpio_base; + int num_regulators; + struct da9052 *da9052; + struct regulator_init_data *regulators; + struct da9052_leds_platform_data *led_data; + struct da9052_tsi_platform_data *tsi_data; +}; + +struct da9052_ssc_ops { + int (*write)(struct da9052 *da9052, struct da9052_ssc_msg *msg); + int (*read)(struct da9052 *da9052, struct da9052_ssc_msg *msg); + int (*write_many)(struct da9052 *da9052, + struct da9052_ssc_msg *sscmsg, int msg_no); + int (*read_many)(struct da9052 *da9052, + struct da9052_ssc_msg *sscmsg, int msg_no); + int (*device_register)(struct da9052 *da9052); + void (*device_unregister)(void); +}; + +int da9052_ssc_write(struct da9052 *da9052, + struct da9052_ssc_msg *sscmsg); +int da9052_ssc_read(struct da9052 *da9052, + struct da9052_ssc_msg *sscmsg); +int da9052_ssc_write_many(struct da9052 *da9052, + struct da9052_ssc_msg *sscmsg, int cnt); +int da9052_ssc_read_many(struct da9052 *da9052, + struct da9052_ssc_msg *sscmsg, int cnt); + +int da9052_spi_write(struct da9052 *da9052, + struct da9052_ssc_msg *msg); +int da9052_spi_read(struct da9052 *da9052, + struct da9052_ssc_msg *msg); + +int da9052_spi_write_many(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg, + int msg_no); +int da9052_spi_read_many(struct da9052 *da9052, + struct da9052_ssc_msg *sscmsg, + int msg_no); + +void da9052_ssc_exit(struct da9052 *da9052); +int da9052_ssc_init(struct da9052 *da9052); + +/* I2C specific Functions */ +int da9052_i2c_write(struct da9052 *da9052, struct da9052_ssc_msg *msg); +int da9052_i2c_read(struct da9052 *da9052, struct da9052_ssc_msg *msg); +int da9052_i2c_write_many(struct da9052 *da9052, + struct da9052_ssc_msg *sscmsg, int msg_no); +int da9052_i2c_read_many(struct da9052 *da9052, + struct da9052_ssc_msg *sscmsg, int msg_no); + +void da9052_lock(struct da9052 *da9052); +void da9052_unlock(struct da9052 *da9052); +int eh_register_nb(struct da9052 *da9052, struct da9052_eh_nb *nb); +int eh_unregister_nb(struct da9052 *da9052, struct da9052_eh_nb *nb); +int da9052_manual_read(struct da9052 *da9052, + unsigned char channel); +#endif /* __LINUX_MFD_DA9052_DA9052_H */ diff --git a/include/linux/mfd/da9052/eh.h b/include/linux/mfd/da9052/eh.h new file mode 100644 index 0000000..c46df5d --- /dev/null +++ b/include/linux/mfd/da9052/eh.h @@ -0,0 +1,77 @@ +/* + * da9052 Event Handler module declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_EH_H +#define __LINUX_MFD_DA9052_EH_H + +#define DA9052_EVE_REGISTERS 4 +#define DA9052_EVE_REGISTER_SIZE 8 + +/* Define for all possible events */ +#define DCIN_DET_EVE 0 +#define VBUS_DET_EVE 1 +#define DCIN_REM_EVE 2 +#define VBUS_REM_EVE 3 +#define VDD_LOW_EVE 4 +#define ALARM_EVE 5 +#define SEQ_RDY_EVE 6 +#define COMP_1V2 7 +#define ONKEY_EVE 8 +#define ID_FLOAT_EVE 9 +#define ID_GND_EVE 10 +#define CHG_END_EVE 11 +#define TBAT_EVE 12 +#define ADC_EOM_EVE 13 +#define PEN_DOWN_EVE 14 +#define TSI_READY_EVE 15 +#define GPI0_EVE 16 +#define GPI1_EVE 17 +#define GPI2_EVE 18 +#define GPI3_EVE 19 +#define GPI4_EVE 20 +#define GPI5_EVE 21 +#define GPI6_EVE 22 +#define GPI7_EVE 23 +#define GPI8_EVE 24 +#define GPI9_EVE 25 +#define GPI10_EVE 26 +#define GPI11_EVE 27 +#define GPI12_EVE 28 +#define GPI13_EVE 29 +#define GPI14_EVE 30 +#define GPI15_EVE 31 + +/* Total number of events */ +#define EVE_CNT (GPI15_EVE+1) + +/* Error code for register/unregister functions */ +#define INVALID_NB 2 +#define INVALID_EVE 3 + +/* State for EH thread */ +#define ACTIVE 0 +#define INACTIVE 1 + +/* Status of nIRQ line */ +#define IRQ_HIGH 0 +#define IRQ_LOW 1 + +#endif /* __LINUX_MFD_DA9052_EH_H */ diff --git a/include/linux/mfd/da9052/gpio.h b/include/linux/mfd/da9052/gpio.h new file mode 100644 index 0000000..68a24ad --- /dev/null +++ b/include/linux/mfd/da9052/gpio.h @@ -0,0 +1,253 @@ +/* + * da9052 GPIO module declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_GPIO_H +#define __LINUX_MFD_DA9052_GPIO_H + +#include <linux/gpio.h> +#define DA9052_GPIO_DEVICE_NAME "da9052_gpio" + +#define DA9052_GPIO_INVALID_TYPE 1 +#define DA9052_GPIO_INVALID_MODE 2 +#define DA9052_GPIO_INVALID_PORTNUMBER 3 +#define DA9052_GPIO_INVALID_FUNCTION 4 + +#define DA9052_GPIO_CONFIG_ADC 1 +#define DA9052_GPIO_CONFIG_TSI 2 +#define DA9052_GPIO_CONFIG_PM 3 +#define DA9052_GPIO_CONFIG_ACC_ID_DET 4 +#define DA9052_GPIO_CONFIG_GP_FB1 5 +#define DA9052_GPIO_CONFIG_VDD_FAULT 6 +#define DA9052_GPIO_CONFIG_I2C 7 +#define DA9052_GPIO_CONFIG 8 + +/* Currently used defines for GPIO PINs */ +#define DA9052_GPIO_PIN_0 DA9052_GPIO_CONFIG_ADC +#define DA9052_GPIO_PIN_1 DA9052_GPIO_CONFIG_ADC +#define DA9052_GPIO_PIN_2 DA9052_GPIO_CONFIG_ADC + +#define DA9052_GPIO_PIN_3 DA9052_GPIO_CONFIG_TSI +#define DA9052_GPIO_PIN_4 DA9052_GPIO_CONFIG_TSI +#define DA9052_GPIO_PIN_5 DA9052_GPIO_CONFIG_TSI +#define DA9052_GPIO_PIN_6 DA9052_GPIO_CONFIG_TSI +#define DA9052_GPIO_PIN_7 DA9052_GPIO_CONFIG_TSI + +#define DA9052_GPIO_PIN_8 DA9052_GPIO_CONFIG +#define DA9052_GPIO_PIN_9 DA9052_GPIO_CONFIG +#define DA9052_GPIO_PIN_10 DA9052_GPIO_CONFIG +#define DA9052_GPIO_PIN_11 DA9052_GPIO_CONFIG + +#define DA9052_GPIO_PIN_12 DA9052_GPIO_CONFIG +#define DA9052_GPIO_PIN_13 DA9052_GPIO_CONFIG + +#define DA9052_GPIO_PIN_14 DA9052_GPIO_CONFIG +#define DA9052_GPIO_PIN_15 DA9052_GPIO_CONFIG + +enum ip_op_type { + ALTERNATE_FUNCTIONALITY = 0, + INPUT, + OUTPUT_OPENDRAIN, + OUTPUT_PUSHPULL +}; + +enum ip_type { + ACTIVE_LOW = 0, + ACTIVE_HIGH +}; + +enum op_type { + SUPPLY_VDD_IO1 = 0, + SUPPLY_VDD_IO2 +}; + + +enum op_mode { + OUTPUT_LOWLEVEL = 0, + OUTPUT_HIGHLEVEL +}; + + +enum ip_mode { + DEBOUNCING_OFF = 0, + DEBOUNCING_ON +}; + +/*DEFAULT CONFIG FOR GPIO 0*/ +#if (DA9052_GPIO_PIN_0 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO0_FUNCTION INPUT +#define DEFAULT_GPIO0_TYPE ACTIVE_LOW +#define DEFAULT_GPIO0_MODE DEBOUNCING_ON +#endif + +/*DEFAULT CONFIG FOR GPIO 1*/ +#if (DA9052_GPIO_PIN_1 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO1_FUNCTION INPUT +#define DEFAULT_GPIO1_TYPE ACTIVE_LOW +#define DEFAULT_GPIO1_MODE DEBOUNCING_ON +#endif + +/*DEFAULT CONFIG FOR GPIO 2*/ +#if (DA9052_GPIO_PIN_2 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO2_FUNCTION INPUT +#define DEFAULT_GPIO2_TYPE ACTIVE_LOW +#define DEFAULT_GPIO2_MODE DEBOUNCING_ON +#endif + +/*DEFAULT CONFIG FOR GPIO 3*/ +#if (DA9052_GPIO_PIN_3 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO3_FUNCTION INPUT +#define DEFAULT_GPIO3_TYPE ACTIVE_LOW +#define DEFAULT_GPIO3_MODE DEBOUNCING_ON +#endif + +/*DEFAULT CONFIG FOR GPIO 4*/ +#if (DA9052_GPIO_PIN_4 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO4_FUNCTION OUTPUT_PUSHPULL +#define DEFAULT_GPIO4_TYPE SUPPLY_VDD_IO1 +#define DEFAULT_GPIO4_MODE OUTPUT_LOWLEVEL +#endif +/*DEFAULT CONFIG FOR GPIO 5*/ +#if (DA9052_GPIO_PIN_5 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO5_FUNCTION OUTPUT_PUSHPULL +#define DEFAULT_GPIO5_TYPE SUPPLY_VDD_IO1 +#define DEFAULT_GPIO5_MODE OUTPUT_LOWLEVEL +#endif + +/*DEFAULT CONFIG FOR GPIO 6*/ +#if (DA9052_GPIO_PIN_6 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO6_FUNCTION OUTPUT_PUSHPULL +#define DEFAULT_GPIO6_TYPE SUPPLY_VDD_IO1 +#define DEFAULT_GPIO6_MODE OUTPUT_LOWLEVEL +#endif + +/*DEFAULT CONFIG FOR GPIO 7*/ +#if (DA9052_GPIO_PIN_7 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO7_FUNCTION OUTPUT_PUSHPULL +#define DEFAULT_GPIO7_TYPE SUPPLY_VDD_IO1 +#define DEFAULT_GPIO7_MODE OUTPUT_LOWLEVEL +#endif + +/*DEFAULT CONFIG FOR GPIO 8*/ +#if (DA9052_GPIO_PIN_8 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO8_FUNCTION INPUT +#define DEFAULT_GPIO8_TYPE ACTIVE_LOW +#define DEFAULT_GPIO8_MODE DEBOUNCING_ON +#endif + +/*DEFAULT CONFIG FOR GPIO 9*/ +#if (DA9052_GPIO_PIN_9 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO9_FUNCTION INPUT +#define DEFAULT_GPIO9_TYPE ACTIVE_LOW +#define DEFAULT_GPIO9_MODE DEBOUNCING_ON +#endif + +#if (DA9052_GPIO_PIN_10 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO10_FUNCTION OUTPUT_PUSHPULL +#define DEFAULT_GPIO10_TYPE SUPPLY_VDD_IO2 +#define DEFAULT_GPIO10_MODE OUTPUT_HIGHLEVEL +#endif + +/*DEFAULT CONFIG FOR GPIO 11 - for RTC blinking LED */ +#if (DA9052_GPIO_PIN_11 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO11_FUNCTION OUTPUT_PUSHPULL +#define DEFAULT_GPIO11_TYPE SUPPLY_VDD_IO2 +#define DEFAULT_GPIO11_MODE OUTPUT_HIGHLEVEL +#endif + +/*DEFAULT CONFIG FOR GPIO 12*/ +#if (DA9052_GPIO_PIN_12 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO12_FUNCTION OUTPUT_PUSHPULL +#define DEFAULT_GPIO12_TYPE SUPPLY_VDD_IO1 +#define DEFAULT_GPIO12_MODE OUTPUT_LOWLEVEL +#endif +/*DEFAULT CONFIG FOR GPIO 13*/ +#if (DA9052_GPIO_PIN_13 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO13_FUNCTION OUTPUT_PUSHPULL +#define DEFAULT_GPIO13_TYPE SUPPLY_VDD_IO1 +#define DEFAULT_GPIO13_MODE OUTPUT_LOWLEVEL +#endif + +/*DEFAULT CONFIG FOR GPIO 14 - for LED4 */ +#if (DA9052_GPIO_PIN_14 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO14_FUNCTION OUTPUT_OPENDRAIN +#define DEFAULT_GPIO14_TYPE SUPPLY_VDD_IO1 +#define DEFAULT_GPIO14_MODE OUTPUT_HIGHLEVEL +#endif + +/*DEFAULT CONFIG FOR GPIO 15 - for LED5 */ +#if (DA9052_GPIO_PIN_15 == DA9052_GPIO_CONFIG) +#define DEFAULT_GPIO15_FUNCTION OUTPUT_OPENDRAIN +#define DEFAULT_GPIO15_TYPE SUPPLY_VDD_IO1 +#define DEFAULT_GPIO15_MODE OUTPUT_HIGHLEVEL +#endif + +#define DA9052_GPIO_MAX_PORTNUMBER 16 +#define DA9052_GPIO_MAX_PORTS_PER_REGISTER 8 +#define DA9052_GPIO_SHIFT_COUNT(no) ((no)%8) +#define DA9052_GPIO_EVEN_PORT_FUNCTIONALITY 0x03 +#define DA9052_GPIO_ODD_PORT_FUNCTIONALITY 0x30 +#define DA9052_GPIO_MASK_UPPER_NIBBLE 0xF0 +#define DA9052_GPIO_MASK_LOWER_NIBBLE 0x0F +#define DA9052_GPIO_NIBBLE_SHIFT 4 +#define DA9052_GPIO_EVEN_PORT_WRITE_MODE (1 << 3) +#define DA9052_GPIO_ODD_PORT_WRITE_MODE (1 << 7) + + +struct da9052_gpio_read_write { + u8 port_number:4; + u8 read_write_value:1; +} ; + +struct da9052_gpio_multiple_read { + u8 signal_value[16]; +}; + +struct da9052_gpi_config { + enum ip_type type; + enum ip_mode mode; +}; + +struct da9052_gpo_config { + enum op_type type; + enum op_mode mode; +} ; + +union da9052_gpio_config { + struct da9052_gpi_config input; + struct da9052_gpo_config output; +}; + +struct da9052_gpio { + union da9052_gpio_config gpio_config; + enum ip_op_type gpio_function; + u8 port_number:4; +}; + +struct da9052_gpio_chip { + struct da9052_gpio gpio; + struct da9052_gpio_read_write read_write; + struct da9052 *da9052; + /* For testing*/ + struct da9052_eh_nb eh_data; + struct gpio_chip gp; +}; + +#endif /* __LINUX_MFD_DA9052_GPIO_H */ diff --git a/include/linux/mfd/da9052/led.h b/include/linux/mfd/da9052/led.h new file mode 100644 index 0000000..b4145cd --- /dev/null +++ b/include/linux/mfd/da9052/led.h @@ -0,0 +1,39 @@ +/* + * da9052 LED module declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_LED_H +#define __LINUX_MFD_DA9052_LED_H + +struct da9052_led_platform_data { +#define DA9052_LED_4 4 +#define DA9052_LED_5 5 +#define DA9052_LED_MAX 2 + int id; + const char *name; + const char *default_trigger; +}; + +struct da9052_leds_platform_data { + int num_leds; + struct da9052_led_platform_data *led; +}; + +#endif /* __LINUX_MFD_DA9052_LED_H */ diff --git a/include/linux/mfd/da9052/pm.h b/include/linux/mfd/da9052/pm.h new file mode 100644 index 0000000..95487fd --- /dev/null +++ b/include/linux/mfd/da9052/pm.h @@ -0,0 +1,81 @@ +/* + * da9052 Power Management module declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_PM_H +#define __LINUX_MFD_DA9052_PM_H + +/* PM Device name and static Major number macros */ +#define DRIVER_NAME "da9052-regulator" + +/* PM Device Macros */ +#define DA9052_LDO1 0 +#define DA9052_LDO2 1 +#define DA9052_LDO3 2 +#define DA9052_LDO4 3 +#define DA9052_LDO5 4 +#define DA9052_LDO6 5 +#define DA9052_LDO7 6 +#define DA9052_LDO8 7 +#define DA9052_LDO9 8 +#define DA9052_LDO10 9 +#define DA9052_BUCK_CORE 10 +#define DA9052_BUCK_PRO 11 +#define DA9052_BUCK_MEM 12 +#define DA9052_BUCK_PERI 13 + +/* PM Device Error Codes */ + +/* Buck Config Validation Macros */ +#define DA9052_BUCK_CORE_PRO_VOLT_UPPER 2075 +#define DA9052_BUCK_CORE_PRO_VOLT_LOWER 500 +#define DA9052_BUCK_CORE_PRO_STEP 25 +#define DA9052_BUCK_MEM_VOLT_UPPER 2500 +#define DA9052_BUCK_MEM_VOLT_LOWER 925 +#define DA9052_BUCK_MEM_STEP 25 +#if defined(CONFIG_PMIC_DA9052) +#define DA9052_BUCK_PERI_VOLT_UPPER 3600 +#define DA9052_BUCK_PERI_VOLT_LOWER 1800 +#define DA9052_BUCK_PERI_STEP_BELOW_3000 50 +#define DA9052_BUCK_PERI_STEP_ABOVE_3000 100000 +#define DA9052_BUCK_PERI_VALUES_UPTO_3000 24 +#define DA9052_BUCK_PERI_VALUES_3000 3000000 +#elif defined(CONFIG_PMIC_DA9053AA) || (CONFIG_PMIC_DA9053Bx) +#define DA9052_BUCK_PERI_VOLT_UPPER 2500 +#define DA9052_BUCK_PERI_VOLT_LOWER 925 +#define DA9052_BUCK_PERI_STEP 25 +#endif +#define DA9052_LDO1_VOLT_UPPER 1800 +#define DA9052_LDO1_VOLT_LOWER 600 +#define DA9052_LDO1_VOLT_STEP 50 +#define DA9052_LDO2_VOLT_UPPER 1800 +#define DA9052_LDO2_VOLT_LOWER 600 +#define DA9052_LDO2_VOLT_STEP 25 +#define DA9052_LDO34_VOLT_UPPER 3300 +#define DA9052_LDO34_VOLT_LOWER 1725 +#define DA9052_LDO34_VOLT_STEP 25 +#define DA9052_LDO567810_VOLT_UPPER 3600 +#define DA9052_LDO567810_VOLT_LOWER 1200 +#define DA9052_LDO567810_VOLT_STEP 50 +#define DA9052_LDO9_VOLT_STEP 50 +#define DA9052_LDO9_VOLT_LOWER 1250 +#define DA9052_LDO9_VOLT_UPPER 3650 + +#endif /* __LINUX_MFD_DA9052_PM_H */ diff --git a/include/linux/mfd/da9052/reg.h b/include/linux/mfd/da9052/reg.h new file mode 100644 index 0000000..ba6ad63 --- /dev/null +++ b/include/linux/mfd/da9052/reg.h @@ -0,0 +1,929 @@ +/* + * da9052 register declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_REG_H +#define __LINUX_MFD_DA9052_REG_H + +#define DA9052_PAGECON0_REG 0 +#define DA9052_STATUSA_REG 1 +#define DA9052_STATUSB_REG 2 +#define DA9052_STATUSC_REG 3 +#define DA9052_STATUSD_REG 4 +#define DA9052_EVENTA_REG 5 +#define DA9052_EVENTB_REG 6 +#define DA9052_EVENTC_REG 7 +#define DA9052_EVENTD_REG 8 +#define DA9052_FAULTLOG_REG 9 +#define DA9052_IRQMASKA_REG 10 +#define DA9052_IRQMASKB_REG 11 +#define DA9052_IRQMASKC_REG 12 +#define DA9052_IRQMASKD_REG 13 +#define DA9052_CONTROLA_REG 14 +#define DA9052_CONTROLB_REG 15 +#define DA9052_CONTROLC_REG 16 +#define DA9052_CONTROLD_REG 17 +#define DA9052_PDDIS_REG 18 +#define DA9052_INTERFACE_REG 19 +#define DA9052_RESET_REG 20 +#define DA9052_GPIO0001_REG 21 +#define DA9052_GPIO0203_REG 22 +#define DA9052_GPIO0405_REG 23 +#define DA9052_GPIO0607_REG 24 +#define DA9052_GPIO0809_REG 25 +#define DA9052_GPIO1011_REG 26 +#define DA9052_GPIO1213_REG 27 +#define DA9052_GPIO1415_REG 28 +#define DA9052_ID01_REG 29 +#define DA9052_ID23_REG 30 +#define DA9052_ID45_REG 31 +#define DA9052_ID67_REG 32 +#define DA9052_ID89_REG 33 +#define DA9052_ID1011_REG 34 +#define DA9052_ID1213_REG 35 +#define DA9052_ID1415_REG 36 +#define DA9052_ID1617_REG 37 +#define DA9052_ID1819_REG 38 +#define DA9052_ID2021_REG 39 +#define DA9052_SEQSTATUS_REG 40 +#define DA9052_SEQA_REG 41 +#define DA9052_SEQB_REG 42 +#define DA9052_SEQTIMER_REG 43 +#define DA9052_BUCKA_REG 44 +#define DA9052_BUCKB_REG 45 +#define DA9052_BUCKCORE_REG 46 +#define DA9052_BUCKPRO_REG 47 +#define DA9052_BUCKMEM_REG 48 +#define DA9052_BUCKPERI_REG 49 +#define DA9052_LDO1_REG 50 +#define DA9052_LDO2_REG 51 +#define DA9052_LDO3_REG 52 +#define DA9052_LDO4_REG 53 +#define DA9052_LDO5_REG 54 +#define DA9052_LDO6_REG 55 +#define DA9052_LDO7_REG 56 +#define DA9052_LDO8_REG 57 +#define DA9052_LDO9_REG 58 +#define DA9052_LDO10_REG 59 +#define DA9052_SUPPLY_REG 60 +#define DA9052_PULLDOWN_REG 61 +#define DA9052_CHGBUCK_REG 62 +#define DA9052_WAITCONT_REG 63 +#define DA9052_ISET_REG 64 +#define DA9052_BATCHG_REG 65 +#define DA9052_CHGCONT_REG 66 +#define DA9052_INPUTCONT_REG 67 +#define DA9052_CHGTIME_REG 68 +#define DA9052_BBATCONT_REG 69 +#define DA9052_BOOST_REG 70 +#define DA9052_LEDCONT_REG 71 +#define DA9052_LEDMIN123_REG 72 +#define DA9052_LED1CONF_REG 73 +#define DA9052_LED2CONF_REG 74 +#define DA9052_LED3CONF_REG 75 +#define DA9052_LED1CONT_REG 76 +#define DA9052_LED2CONT_REG 77 +#define DA9052_LED3CONT_REG 78 +#define DA9052_LED4CONT_REG 79 +#define DA9052_LED5CONT_REG 80 +#define DA9052_ADCMAN_REG 81 +#define DA9052_ADCCONT_REG 82 +#define DA9052_ADCRESL_REG 83 +#define DA9052_ADCRESH_REG 84 +#define DA9052_VDDRES_REG 85 +#define DA9052_VDDMON_REG 86 +#define DA9052_ICHGAV_REG 87 +#define DA9052_ICHGTHD_REG 88 +#define DA9052_ICHGEND_REG 89 +#define DA9052_TBATRES_REG 90 +#define DA9052_TBATHIGHP_REG 91 +#define DA9052_TBATHIGHIN_REG 92 +#define DA9052_TBATLOW_REG 93 +#define DA9052_TOFFSET_REG 94 +#define DA9052_ADCIN4RES_REG 95 +#define DA9052_AUTO4HIGH_REG 96 +#define DA9052_AUTO4LOW_REG 97 +#define DA9052_ADCIN5RES_REG 98 +#define DA9052_AUTO5HIGH_REG 99 +#define DA9052_AUTO5LOW_REG 100 +#define DA9052_ADCIN6RES_REG 101 +#define DA9052_AUTO6HIGH_REG 102 +#define DA9052_AUTO6LOW_REG 103 +#define DA9052_TJUNCRES_REG 104 +#define DA9052_TSICONTA_REG 105 +#define DA9052_TSICONTB_REG 106 +#define DA9052_TSIXMSB_REG 107 +#define DA9052_TSIYMSB_REG 108 +#define DA9052_TSILSB_REG 109 +#define DA9052_TSIZMSB_REG 110 +#define DA9052_COUNTS_REG 111 +#define DA9052_COUNTMI_REG 112 +#define DA9052_COUNTH_REG 113 +#define DA9052_COUNTD_REG 114 +#define DA9052_COUNTMO_REG 115 +#define DA9052_COUNTY_REG 116 +#define DA9052_ALARMMI_REG 117 +#define DA9052_ALARMH_REG 118 +#define DA9052_ALARMD_REG 119 +#define DA9052_ALARMMO_REG 120 +#define DA9052_ALARMY_REG 121 +#define DA9052_SECONDA_REG 122 +#define DA9052_SECONDB_REG 123 +#define DA9052_SECONDC_REG 124 +#define DA9052_SECONDD_REG 125 +#define DA9052_PAGECON128_REG 128 +#define DA9052_CHIPID_REG 129 +#define DA9052_CONFIGID_REG 130 +#define DA9052_OTPCONT_REG 131 +#define DA9052_OSCTRIM_REG 132 +#define DA9052_GPID0_REG 133 +#define DA9052_GPID1_REG 134 +#define DA9052_GPID2_REG 135 +#define DA9052_GPID3_REG 136 +#define DA9052_GPID4_REG 137 +#define DA9052_GPID5_REG 138 +#define DA9052_GPID6_REG 139 +#define DA9052_GPID7_REG 140 +#define DA9052_GPID8_REG 141 +#define DA9052_GPID9_REG 142 + +#define DA9052_PAGE0_REG_START (DA9052_STATUSA_REG) +#define DA9052_PAGE0_REG_END (DA9052_SECONDD_REG) + +#define DA9052_PAGE1_REG_START (DA9052_CHIPID_REG) +#define DA9052_PAGE1_REG_END (DA9052_GPID9_REG) + +/* PAGE CONFIGURATION */ + +/* Reg Page Configuration */ +#define DA9052_PAGECON0_REGPAGE (1<<7) + +/* PAGE CONFIGURATION 128 REGISTER */ +#define DA9052_PAGECON128_REGPAGE (1<<7) + +/* SYSTEM REGISTER */ + +/* STATUS REGISTER A */ +#define DA9052_STATUSA_VDATDET (1<<7) +#define DA9052_STATUSA_VBUSSEL (1<<6) +#define DA9052_STATUSA_DCINSEL (1<<5) +#define DA9052_STATUSA_VBUSDET (1<<4) +#define DA9052_STATUSA_DCINDET (1<<3) +#define DA9052_STATUSA_IDGND (1<<2) +#define DA9052_STATUSA_IDFLOAT (1<<1) +#define DA9052_STATUSA_NONKEY (1<<0) + + +/* STATUS REGISTER B */ +#define DA9052_STATUSB_COMPDET (1<<7) +#define DA9052_STATUSB_SEQUENCING (1<<6) +#define DA9052_STATUSB_GPFB2 (1<<5) +#define DA9052_STATUSB_CHGTO (1<<4) +#define DA9052_STATUSB_CHGEND (1<<3) +#define DA9052_STATUSB_CHGLIM (1<<2) +#define DA9052_STATUSB_CHGPRE (1<<1) +#define DA9052_STATUSB_CHGATT (1<<0) + + +/* STATUS REGISTER C */ +#define DA9052_STATUSC_GPI7 (1<<7) +#define DA9052_STATUSC_GPI6 (1<<6) +#define DA9052_STATUSC_GPI5 (1<<5) +#define DA9052_STATUSC_GPI4 (1<<4) +#define DA9052_STATUSC_GPI3 (1<<3) +#define DA9052_STATUSC_GPI2 (1<<2) +#define DA9052_STATUSC_GPI1 (1<<1) +#define DA9052_STATUSC_GPI0 (1<<0) + + +/* STATUS REGISTER D */ +#define DA9052_STATUSD_GPI15 (1<<7) +#define DA9052_STATUSD_GPI14 (1<<6) +#define DA9052_STATUSD_GPI13 (1<<5) +#define DA9052_STATUSD_GPI12 (1<<4) +#define DA9052_STATUSD_GPI11 (1<<3) +#define DA9052_STATUSD_GPI10 (1<<2) +#define DA9052_STATUSD_GPI9 (1<<1) +#define DA9052_STATUSD_GPI8 (1<<0) + + +/* EVENT REGISTER A */ +#define DA9052_EVENTA_ECOMP1V2 (1<<7) +#define DA9052_EVENTA_ESEQRDY (1<<6) +#define DA9052_EVENTA_EALRAM (1<<5) +#define DA9052_EVENTA_EVDDLOW (1<<4) +#define DA9052_EVENTA_EVBUSREM (1<<3) +#define DA9052_EVENTA_EDCINREM (1<<2) +#define DA9052_EVENTA_EVBUSDET (1<<1) +#define DA9052_EVENTA_EDCINDET (1<<0) + +/* EVENT REGISTER B */ +#define DA9052_EVENTB_ETSIREADY (1<<7) +#define DA9052_EVENTB_EPENDOWN (1<<6) +#define DA9052_EVENTB_EADCEOM (1<<5) +#define DA9052_EVENTB_ETBAT (1<<4) +#define DA9052_EVENTB_ECHGEND (1<<3) +#define DA9052_EVENTB_EIDGND (1<<2) +#define DA9052_EVENTB_EIDFLOAT (1<<1) +#define DA9052_EVENTB_ENONKEY (1<<0) + +/* EVENT REGISTER C */ +#define DA9052_EVENTC_EGPI7 (1<<7) +#define DA9052_EVENTC_EGPI6 (1<<6) +#define DA9052_EVENTC_EGPI5 (1<<5) +#define DA9052_EVENTC_EGPI4 (1<<4) +#define DA9052_EVENTC_EGPI3 (1<<3) +#define DA9052_EVENTC_EGPI2 (1<<2) +#define DA9052_EVENTC_EGPI1 (1<<1) +#define DA9052_EVENTC_EGPI0 (1<<0) + +/* EVENT REGISTER D */ +#define DA9052_EVENTC_EGPI15 (1<<7) +#define DA9052_EVENTC_EGPI14 (1<<6) +#define DA9052_EVENTC_EGPI13 (1<<5) +#define DA9052_EVENTC_EGPI12 (1<<4) +#define DA9052_EVENTC_EGPI11 (1<<3) +#define DA9052_EVENTC_EGPI10 (1<<2) +#define DA9052_EVENTC_EGPI9 (1<<1) +#define DA9052_EVENTC_EGPI8 (1<<0) + + +/* FAULT LOG REGISTER */ +#define DA9052_FAULTLOG_WAITSET (1<<7) +#define DA9052_FAULTLOG_NSDSET (1<<6) +#define DA9052_FAULTLOG_KEYSHUT (1<<5) +#define DA9052_FAULTLOG_TEMPOVER (1<<3) +#define DA9052_FAULTLOG_VDDSTART (1<<2) +#define DA9052_FAULTLOG_VDDFAULT (1<<1) +#define DA9052_FAULTLOG_TWDERROR (1<<0) + +/* IRQ_MASK REGISTER A */ +#define DA9052_IRQMASKA_MCOMP1V2 (1<<7) +#define DA9052_IRQMASKA_MSEQRDY (1<<6) +#define DA9052_IRQMASKA_MALRAM (1<<5) +#define DA9052_IRQMASKA_MVDDLOW (1<<4) +#define DA9052_IRQMASKA_MVBUSREM (1<<3) +#define DA9052_IRQMASKA_MDCINREM (1<<2) +#define DA9052_IRQMASKA_MVBUSVLD (1<<1) +#define DA9052_IRQMASKA_MDCINVLD (1<<0) + +/* IRQ_MASK REGISTER B */ +#define DA9052_IRQMASKB_MTSIREADY (1<<7) +#define DA9052_IRQMASKB_MPENDOWN (1<<6) +#define DA9052_IRQMASKB_MADCEOM (1<<5) +#define DA9052_IRQMASKB_MTBAT (1<<4) +#define DA9052_IRQMASKB_MCHGEND (1<<3) +#define DA9052_IRQMASKB_MIDGND (1<<2) +#define DA9052_IRQMASKB_MIDFLOAT (1<<1) +#define DA9052_IRQMASKB_MNONKEY (1<<0) + +/* IRQ_MASK REGISTER C */ +#define DA9052_IRQMASKC_MGPI7 (1<<7) +#define DA9052_IRQMASKC_MGPI6 (1<<6) +#define DA9052_IRQMASKC_MGPI5 (1<<5) +#define DA9052_IRQMASKC_MGPI4 (1<<4) +#define DA9052_IRQMASKC_MGPI3 (1<<3) +#define DA9052_IRQMASKC_MGPI2 (1<<2) +#define DA9052_IRQMASKC_MGPI1 (1<<1) +#define DA9052_IRQMASKC_MGPI0 (1<<0) + +/* IRQ_MASK REGISTER D */ +#define DA9052_IRQMASKD_MGPI15 (1<<7) +#define DA9052_IRQMASKD_MGPI14 (1<<6) +#define DA9052_IRQMASKD_MGPI13 (1<<5) +#define DA9052_IRQMASKD_MGPI12 (1<<4) +#define DA9052_IRQMASKD_MGPI11 (1<<3) +#define DA9052_IRQMASKD_MGPI10 (1<<2) +#define DA9052_IRQMASKD_MGPI9 (1<<1) +#define DA9052_IRQMASKD_MGPI8 (1<<0) + +/* CONTROL REGISTER A */ +#define DA9052_CONTROLA_GPIV (1<<7) +#define DA9052_CONTROLA_PMOTYPE (1<<5) +#define DA9052_CONTROLA_PMOV (1<<4) +#define DA9052_CONTROLA_PMIV (1<<3) +#define DA9052_CONTROLA_PMIFV (1<<3) +#define DA9052_CONTROLA_PWR1EN (1<<2) +#define DA9052_CONTROLA_PWREN (1<<1) +#define DA9052_CONTROLA_SYSEN (1<<0) + +/* CONTROL REGISTER B */ +#define DA9052_CONTROLB_SHUTDOWN (1<<7) +#define DA9052_CONTROLB_DEEPSLEEP (1<<6) +#define DA9052_CONTROLB_WRITEMODE (1<<5) +#define DA9052_CONTROLB_BBATEN (1<<4) +#define DA9052_CONTROLB_OTPREADEN (1<<3) +#define DA9052_CONTROLB_AUTOBOOT (1<<2) +#define DA9052_CONTROLB_ACTDIODE (1<<1) +#define DA9052_CONTROLB_BUCKMERGE (1<<0) + +/* CONTROL REGISTER C */ +#define DA9052_CONTROLC_BLINKDUR (1<<7) +#define DA9052_CONTROLC_BLINKFRQ (3<<5) +#define DA9052_CONTROLC_DEBOUNCING (7<<2) +#define DA9052_CONTROLC_PMFB2PIN (1<<1) +#define DA9052_CONTROLC_PMFB1PIN (1<<0) + +/* CONTROL REGISTER D */ +#define DA9052_CONTROLD_WATCHDOG (1<<7) +#define DA9052_CONTROLD_ACCDETEN (1<<6) +#define DA9052_CONTROLD_GPI1415SD (1<<5) +#define DA9052_CONTROLD_NONKEYSD (1<<4) +#define DA9052_CONTROLD_KEEPACTEN (1<<3) +#define DA9052_CONTROLD_TWDSCALE (7<<0) + +/* POWER DOWN DISABLE REGISTER */ +#define DA9052_PDDIS_PMCONTPD (1<<7) +#define DA9052_PDDIS_OUT32KPD (1<<6) +#define DA9052_PDDIS_CHGBBATPD (1<<5) +#define DA9052_PDDIS_CHGPD (1<<4) +#define DA9052_PDDIS_HS2WIREPD (1<<3) +#define DA9052_PDDIS_PMIFPD (1<<2) +#define DA9052_PDDIS_GPADCPD (1<<1) +#define DA9052_PDDIS_GPIOPD (1<<0) + +/* CONTROL REGISTER D */ +#define DA9052_INTERFACE_IFBASEADDR (7<<5) +#define DA9052_INTERFACE_NCSPOL (1<<4) +#define DA9052_INTERFACE_RWPOL (1<<3) +#define DA9052_INTERFACE_CPHA (1<<2) +#define DA9052_INTERFACE_CPOL (1<<1) +#define DA9052_INTERFACE_IFTYPE (1<<0) + +/* CONTROL REGISTER D */ +#define DA9052_RESET_RESETEVENT (3<<6) +#define DA9052_RESET_RESETTIMER (63<<0) + +/* GPIO REGISTERS */ + +/* GPIO control register for PIN 0 and 1 */ +#define DA9052_GPIO0001_GPIO1MODE (1<<7) +#define DA9052_GPIO0001_GPIO1TYPE (1<<6) +#define DA9052_GPIO0001_GPIO1PIN (3<<4) +#define DA9052_GPIO0001_GPIO0MODE (1<<3) +#define DA9052_GPIO0001_GPIO0TYPE (1<<2) +#define DA9052_GPIO0001_GPIO0PIN (3<<0) + +/* GPIO control register for PIN 2 and 3 */ +#define DA9052_GPIO0203_GPIO3MODE (1<<7) +#define DA9052_GPIO0203_GPIO3TYPE (1<<6) +#define DA9052_GPIO0203_GPIO3PIN (3<<4) +#define DA9052_GPIO0203_GPIO2MODE (1<<3) +#define DA9052_GPIO0203_GPIO2TYPE (1<<2) +#define DA9052_GPIO0203_GPIO2PIN (3<<0) + +/* GPIO control register for PIN 4 and 5 */ +#define DA9052_GPIO0405_GPIO5MODE (1<<7) +#define DA9052_GPIO0405_GPIO5TYPE (1<<6) +#define DA9052_GPIO0405_GPIO5PIN (3<<4) +#define DA9052_GPIO0405_GPIO4MODE (1<<3) +#define DA9052_GPIO0405_GPIO4TYPE (1<<2) +#define DA9052_GPIO0405_GPIO4PIN (3<<0) + +/* GPIO control register for PIN 6 and 7 */ +#define DA9052_GPIO0607_GPIO7MODE (1<<7) +#define DA9052_GPIO0607_GPIO7TYPE (1<<6) +#define DA9052_GPIO0607_GPIO7PIN (3<<4) +#define DA9052_GPIO0607_GPIO6MODE (1<<3) +#define DA9052_GPIO0607_GPIO6TYPE (1<<2) +#define DA9052_GPIO0607_GPIO6PIN (3<<0) + +/* GPIO control register for PIN 8 and 9 */ +#define DA9052_GPIO0809_GPIO9MODE (1<<7) +#define DA9052_GPIO0809_GPIO9TYPE (1<<6) +#define DA9052_GPIO0809_GPIO9PIN (3<<4) +#define DA9052_GPIO0809_GPIO8MODE (1<<3) +#define DA9052_GPIO0809_GPIO8TYPE (1<<2) +#define DA9052_GPIO0809_GPIO8PIN (3<<0) + +/* GPIO control register for PIN 10 and 11 */ +#define DA9052_GPIO1011_GPIO11MODE (1<<7) +#define DA9052_GPIO1011_GPIO11TYPE (1<<6) +#define DA9052_GPIO1011_GPIO11PIN (3<<4) +#define DA9052_GPIO1011_GPIO10MODE (1<<3) +#define DA9052_GPIO1011_GPIO10TYPE (1<<2) +#define DA9052_GPIO1011_GPIO10PIN (3<<0) + +/* GPIO control register for PIN 12 and 13 */ +#define DA9052_GPIO1213_GPIO13MODE (1<<7) +#define DA9052_GPIO1213_GPIO13TYPE (1<<6) +#define DA9052_GPIO1213_GPIO13PIN (3<<4) +#define DA9052_GPIO1213_GPIO12MODE (1<<3) +#define DA9052_GPIO1213_GPIO12TYPE (1<<2) +#define DA9052_GPIO1213_GPIO12PIN (3<<0) + +/* GPIO control register for PIN 14 and 15 */ +#define DA9052_GPIO1415_GPIO15MODE (1<<7) +#define DA9052_GPIO1415_GPIO15TYPE (1<<6) +#define DA9052_GPIO1415_GPIO15PIN (3<<4) +#define DA9052_GPIO1415_GPIO14MODE (1<<3) +#define DA9052_GPIO1415_GPIO14TYPE (1<<2) +#define DA9052_GPIO1415_GPIO14PIN (3<<0) + +/*POWER SEQUENCER REGISTER*/ + +/* SEQ control register for ID 0 and 1 */ +#define DA9052_ID01_LDO1STEP (15<<4) +#define DA9052_ID01_SYSPRE (1<<2) +#define DA9052_ID01_DEFSUPPLY (1<<1) +#define DA9052_ID01_nRESMODE (1<<0) + +/* SEQ control register for ID 2 and 3 */ +#define DA9052_ID23_LDO3STEP (15<<4) +#define DA9052_ID23_LDO2STEP (15<<0) + +/* SEQ control register for ID 4 and 5 */ +#define DA9052_ID45_LDO5STEP (15<<4) +#define DA9052_ID45_LDO4STEP (15<<0) + +/* SEQ control register for ID 6 and 7 */ +#define DA9052_ID67_LDO7STEP (15<<4) +#define DA9052_ID67_LDO6STEP (15<<0) + +/* SEQ control register for ID 8 and 9 */ +#define DA9052_ID89_LDO9STEP (15<<4) +#define DA9052_ID89_LDO8STEP (15<<0) + +/* SEQ control register for ID 10 and 11 */ +#define DA9052_ID1011_PDDISSTEP (15<<4) +#define DA9052_ID1011_LDO10STEP (15<<0) + +/* SEQ control register for ID 12 and 13 */ +#define DA9052_ID1213_VMEMSWSTEP (15<<4) +#define DA9052_ID1213_VPERISWSTEP (15<<0) + +/* SEQ control register for ID 14 and 15 */ +#define DA9052_ID1415_BUCKPROSTEP (15<<4) +#define DA9052_ID1415_BUCKCORESTEP (15<<0) + +/* SEQ control register for ID 16 and 17 */ +#define DA9052_ID1617_BUCKPERISTEP (15<<4) +#define DA9052_ID1617_BUCKMEMSTEP (15<<0) + +/* SEQ control register for ID 18 and 19 */ +#define DA9052_ID1819_GPRISE2STEP (15<<4) +#define DA9052_ID1819_GPRISE1STEP (15<<0) + +/* SEQ control register for ID 20 and 21 */ +#define DA9052_ID2021_GPFALL2STEP (15<<4) +#define DA9052_ID2021_GPFALL1STEP (15<<0) + +/* Power SEQ Status register */ +#define DA9052_SEQSTATUS_SEQPOINTER (15<<4) +#define DA9052_SEQSTATUS_WAITSTEP (15<<0) + +/* Power SEQ A register */ +#define DA9052_SEQA_POWEREND (15<<4) +#define DA9052_SEQA_SYSTEMEND (15<<0) + +/* Power SEQ B register */ +#define DA9052_SEQB_PARTDOWN (15<<4) +#define DA9052_SEQB_MAXCOUNT (15<<0) + +/* Power SEQ TIMER register */ +#define DA9052_SEQTIMER_SEQDUMMY (15<<4) +#define DA9052_SEQTIMER_SEQTIME (15<<0) + +/*POWER SUPPLY CONTROL REGISTER*/ + +/* BUCK REGISTER A */ +#define DA9052_BUCKA_BPROILIM (3<<6) +#define DA9052_BUCKA_BPROMODE (3<<4) +#define DA9052_BUCKA_BCOREILIM (3<<2) +#define DA9052_BUCKA_BCOREMODE (3<<0) + +/* BUCK REGISTER B */ +#define DA9052_BUCKB_BERIILIM (3<<6) +#define DA9052_BUCKB_BPERIMODE (3<<4) +#define DA9052_BUCKB_BMEMILIM (3<<2) +#define DA9052_BUCKB_BMEMMODE (3<<0) + +/* BUCKCORE REGISTER */ +#define DA9052_BUCKCORE_BCORECONF (1<<7) +#define DA9052_BUCKCORE_BCOREEN (1<<6) +#define DA9052_BUCKCORE_VBCORE (63<<0) + +/* BUCKPRO REGISTER */ +#define DA9052_BUCKPRO_BPROCONF (1<<7) +#define DA9052_BUCKPRO_BPROEN (1<<6) +#define DA9052_BUCKPRO_VBPRO (63<<0) + +/* BUCKMEM REGISTER */ +#define DA9052_BUCKMEM_BMEMCONF (1<<7) +#define DA9052_BUCKMEM_BMEMEN (1<<6) +#define DA9052_BUCKMEM_VBMEM (63<<0) + +/* BUCKPERI REGISTER */ +#define DA9052_BUCKPERI_BPERICONF (1<<7) +#define DA9052_BUCKPERI_BPERIEN (1<<6) +#if defined(CONFIG_PMIC_DA9052) +#define DA9052_BUCKPERI_BPERIHS (1<<5) +#define DA9052_BUCKPERI_VBPERI (31<<0) +#elif defined(CONFIG_PMIC_DA9053AA) || (CONFIG_PMIC_DA9053Bx) +#define DA9052_BUCKPERI_VBPERI (63<<0) +#endif + +/* LDO1 REGISTER */ +#define DA9052_LDO1_LDO1CONF (1<<7) +#define DA9052_LDO1_LDO1EN (1<<6) +#define DA9052_LDO1_VLDO1 (31<<0) + +/* LDO2 REGISTER */ +#define DA9052_LDO2_LDO2CONF (1<<7) +#define DA9052_LDO2_LDO2EN (1<<6) +#define DA9052_LDO2_VLDO2 (63<<0) + +/* LDO3 REGISTER */ +#define DA9052_LDO3_LDO3CONF (1<<7) +#define DA9052_LDO3_LDO3EN (1<<6) +#define DA9052_LDO3_VLDO3 (63<<0) + +/* LDO4 REGISTER */ +#define DA9052_LDO4_LDO4CONF (1<<7) +#define DA9052_LDO4_LDO4EN (1<<6) +#define DA9052_LDO4_VLDO4 (63<<0) + +/* LDO5 REGISTER */ +#define DA9052_LDO5_LDO5CONF (1<<7) +#define DA9052_LDO5_LDO5EN (1<<6) +#define DA9052_LDO5_VLDO5 (63<<0) + +/* LDO6 REGISTER */ +#define DA9052_LDO6_LDO6CONF (1<<7) +#define DA9052_LDO6_LDO6EN (1<<6) +#define DA9052_LDO6_VLDO6 (63<<0) + +/* LDO7 REGISTER */ +#define DA9052_LDO7_LDO7CONF (1<<7) +#define DA9052_LDO7_LDO7EN (1<<6) +#define DA9052_LDO7_VLDO7 (63<<0) + +/* LDO8 REGISTER */ +#define DA9052_LDO8_LDO8CONF (1<<7) +#define DA9052_LDO8_LDO8EN (1<<6) +#define DA9052_LDO8_VLDO8 (63<<0) + +/* LDO9 REGISTER */ +#define DA9052_LDO9_LDO9CONF (1<<7) +#define DA9052_LDO9_LDO9EN (1<<6) +#define DA9052_LDO9_VLDO9 (63<<0) + +/* LDO10 REGISTER */ +#define DA9052_LDO10_LDO10CONF (1<<7) +#define DA9052_LDO10_LDO10EN (1<<6) +#define DA9052_LDO10_VLDO10 (63<<0) + +/* SUPPLY REGISTER */ +#define DA9052_SUPPLY_VLOCK (1<<7) +#define DA9052_SUPPLY_VMEMSWEN (1<<6) +#define DA9052_SUPPLY_VPERISWEN (1<<5) +#define DA9052_SUPPLY_VLDO3GO (1<<4) +#define DA9052_SUPPLY_VLDO2GO (1<<3) +#define DA9052_SUPPLY_VBMEMGO (1<<2) +#define DA9052_SUPPLY_VBPROGO (1<<1) +#define DA9052_SUPPLY_VBCOREGO (1<<0) + +/* PULLDOWN REGISTER */ +#define DA9052_PULLDOWN_LDO5PDDIS (1<<5) +#define DA9052_PULLDOWN_LDO2PDDIS (1<<4) +#define DA9052_PULLDOWN_LDO1PDDIS (1<<3) +#define DA9052_PULLDOWN_MEMPDDIS (1<<2) +#define DA9052_PULLDOWN_PROPDDIS (1<<1) +#define DA9052_PULLDOWN_COREPDDIS (1<<0) + +/* BAT CHARGER REGISTER */ + +/* CHARGER BUCK REGISTER */ +#define DA9052_CHGBUCK_CHGTEMP (1<<7) +#define DA9052_CHGBUCK_CHGUSBILIM (1<<6) +#define DA9052_CHGBUCK_CHGBUCKLP (1<<5) +#define DA9052_CHGBUCK_CHGBUCKEN (1<<4) +#define DA9052_CHGBUCK_ISETBUCK (15<<0) + +/* WAIT COUNTER REGISTER */ +#define DA9052_WAITCONT_WAITDIR (1<<7) +#define DA9052_WAITCONT_RTCCLOCK (1<<6) +#define DA9052_WAITCONT_WAITMODE (1<<5) +#define DA9052_WAITCONT_EN32KOUT (1<<4) +#define DA9052_WAITCONT_DELAYTIME (15<<0) + +/* ISET CONTROL REGISTER */ +#define DA9052_ISET_ISETDCIN (15<<4) +#define DA9052_ISET_ISETVBUS (15<<0) + +/* BATTERY CHARGER CONTROL REGISTER */ +#define DA9052_BATCHG_ICHGPRE (3<<6) +#define DA9052_BATCHG_ICHGBAT (63<<0) + +/* CHARGER COUNTER REGISTER */ +#define DA9052_CHGCONT_VCHGBAT (31<<3) +#define DA9052_CHGCONT_TCTR (7<<0) + +/* INPUT CONTROL REGISTER */ +#define DA9052_INPUTCONT_TCTRMODE (1<<7) +#define DA9052_INPUTCONT_ICHGLOW (1<<5) +#define DA9052_INPUTCONT_VBUSSUSP (1<<4) +#define DA9052_INPUTCONT_DCINSUSP (1<<3) +#define DA9052_INPUTCONT_VCHGTHR (7<<0) + +/* CHARGING TIME REGISTER */ +#define DA9052_CHGTIME_CHGTIME (255<<0) + +/* BACKUP BATTERY CONTROL REGISTER */ +#define DA9052_BBATCONT_BCHARGERISET (15<<4) +#define DA9052_BBATCONT_BCHARGERVSET (15<<0) + +/* LED REGISTERS */ + +/* LED BOOST REGISTER */ +#define DA9052_BOOST_EBFAULT (1<<7) +#define DA9052_BOOST_MBFAULT (1<<6) +#define DA9052_BOOST_BOOSTFRQ (1<<5) +#define DA9052_BOOST_BOOSTILIM (1<<4) +#define DA9052_BOOST_LED3INEN (1<<3) +#define DA9052_BOOST_LED2INEN (1<<2) +#define DA9052_BOOST_LED1INEN (1<<1) +#define DA9052_BOOST_BOOSTEN (1<<0) + +/* LED COUNT REGISTER */ +#if defined(CONFIG_PMIC_DA9053Bx) +#define DA9052_LEDCONT_SELLEDMODE (1<<7) +#endif +#define DA9052_LEDCONT_LED3ICONT (1<<6) +#define DA9052_LEDCONT_LED3RAMP (1<<5) +#define DA9052_LEDCONT_LED3EN (1<<4) +#define DA9052_LEDCONT_LED2RAMP (1<<3) +#define DA9052_LEDCONT_LED2EN (1<<2) +#define DA9052_LEDCONT_LED1RAMP (1<<1) +#define DA9052_LEDCONT_LED1EN (1<<0) + +/* LEDMIN123 REGISTER */ +#define DA9052_LEDMIN123_LEDMINCURRENT (255<<0) + +/* LED1CONF REGISTER */ +#define DA9052_LED1CONF_LED1CURRENT (255<<0) + +/* LED2CONF REGISTER */ +#define DA9052_LED2CONF_LED2CURRENT (255<<0) + +/* LED3CONF REGISTER */ +#define DA9052_LED3CONF_LED3CURRENT (255<<0) + +/* LED1 COUNT REGISTER */ +#define DA9052_LED1CONT_LED1DIM (1<<7) +#define DA9052_LED1CONT_LED1PWM (127<<0) + +/* LED2 COUNT REGISTER */ +#define DA9052_LED2CONT_LED2DIM (1<<7) +#define DA9052_LED2CONT_LED2PWM (127<<0) + +/* LED3 COUNT REGISTER */ +#define DA9052_LED3CONT_LED3DIM (1<<7) +#define DA9052_LED3CONT_LED3PWM (127<<0) + +/* LED4 COUNT REGISTER */ +#define DA9052_LED4CONT_LED4DIM (1<<7) +#define DA9052_LED4CONT_LED4PWM (127<<0) + +/* LED5 COUNT REGISTER */ +#define DA9052_LED5CONT_LED5DIM (1<<7) +#define DA9052_LED5CONT_LED5PWM (127<<0) + +/* ADC REGISTERS */ + +/* ADC MAN registers */ +#define DA9052_ADCMAN_MANCONV (1<<4) +#define DA9052_ADCMAN_MUXSEL (15<<0) + +/* ADC COUNT regsisters */ +#define DA9052_ADCCONT_COMP1V2EN (1<<7) +#define DA9052_ADCCONT_ADCMODE (1<<6) +#define DA9052_ADCCONT_TBATISRCEN (1<<5) +#define DA9052_ADCCONT_AD4ISRCEN (1<<4) +#define DA9052_ADCCONT_AUTOAD6EN (1<<3) +#define DA9052_ADCCONT_AUTOAD5EN (1<<2) +#define DA9052_ADCCONT_AUTOAD4EN (1<<1) +#define DA9052_ADCCONT_AUTOVDDEN (1<<0) + +/* ADC 10 BIT MANUAL CONVERSION RESULT LOW register */ +#define DA9052_ADCRESL_ADCRESLSB (3<<0) + +/* ADC 10 BIT MANUAL CONVERSION RESULT HIGH register */ +#define DA9052_ADCRESH_ADCRESMSB (255<<0) + +/* VDD RES regsister*/ +#define DA9052_VDDRES_VDDOUTRES (255<<0) + +/* VDD MON regsister*/ +#define DA9052_VDDMON_VDDOUTMON (255<<0) + +/* ICHG_AV regsister*/ +#define DA9052_ICHGAV_ICHGAV (255<<0) + +/* ICHG_THD regsister*/ +#define DA9052_ICHGTHD_ICHGTHD (255<<0) + +/* ICHG_END regsister*/ +#define DA9052_ICHGEND_ICHGEND (255<<0) + +/* TBAT_RES regsister*/ +#define DA9052_TBATRES_TBATRES (255<<0) + +/* TBAT_HIGHP regsister*/ +#define DA9052_TBATHIGHP_TBATHIGHP (255<<0) + +/* TBAT_HIGHN regsister*/ +#define DA9052_TBATHIGHN_TBATHIGHN (255<<0) + +/* TBAT_LOW regsister*/ +#define DA9052_TBATLOW_TBATLOW (255<<0) + +/* T_OFFSET regsister*/ +#define DA9052_TOFFSET_TOFFSET (255<<0) + +/* ADCIN4_RES regsister*/ +#define DA9052_ADCIN4RES_ADCIN4RES (255<<0) + +/* ADCIN4_HIGH regsister*/ +#define DA9052_AUTO4HIGH_AUTO4HIGH (255<<0) + +/* ADCIN4_LOW regsister*/ +#define DA9052_AUTO4LOW_AUTO4LOW (255<<0) + +/* ADCIN5_RES regsister*/ +#define DA9052_ADCIN5RES_ADCIN5RES (255<<0) + +/* ADCIN5_HIGH regsister*/ +#define DA9052_AUTO5HIGH_AUTOHIGH (255<<0) + +/* ADCIN5_LOW regsister*/ +#define DA9052_AUTO5LOW_AUTO5LOW (255<<0) + +/* ADCIN6_RES regsister*/ +#define DA9052_ADCIN6RES_ADCIN6RES (255<<0) + +/* ADCIN6_HIGH regsister*/ +#define DA9052_AUTO6HIGH_AUTO6HIGH (255<<0) + +/* ADCIN6_LOW regsister*/ +#define DA9052_AUTO6LOW_AUTO6LOW (255<<0) + +/* TJUNC_RES regsister*/ +#define DA9052_TJUNCRES_TJUNCRES (255<<0) + +/* TSI REGISTER */ + +/* TSI Control Register A */ +#define DA9052_TSICONTA_TSIDELAY (3<<6) +#define DA9052_TSICONTA_TSISKIP (7<<3) +#define DA9052_TSICONTA_TSIMODE (1<<2) +#define DA9052_TSICONTA_PENDETEN (1<<1) +#define DA9052_TSICONTA_AUTOTSIEN (1<<0) + +/* TSI Control Register B */ +#define DA9052_TSICONTB_ADCREF (1<<7) +#define DA9052_TSICONTB_TSIMAN (1<<6) +#define DA9052_TSICONTB_TSIMUX (3<<4) +#define DA9052_TSICONTB_TSISEL3 (1<<3) +#define DA9052_TSICONTB_TSISEL2 (1<<2) +#define DA9052_TSICONTB_TSISEL1 (1<<1) +#define DA9052_TSICONTB_TSISEL0 (1<<0) + +/* TSI X Co-ordinate MSB Result register */ +#define DA9052_TSIXMSB_TSIXM (255<<0) + +/* TSI Y Co-ordinate MSB Result register */ +#define DA9052_TSIYMSB_TSIYM (255<<0) + +/* TSI Co-ordinate LSB Result register */ +#define DA9052_TSILSB_PENDOWN (1<<6) +#define DA9052_TSILSB_TSIZL (3<<4) +#define DA9052_TSILSB_TSIYL (3<<2) +#define DA9052_TSILSB_TSIXL (3<<0) + +/* TSI Z Measurement MSB Result register */ +#define DA9052_TSIZMSB_TSIZM (255<<0) + +/* RTC REGISTER */ + +/* RTC TIMER SECONDS REGISTER */ +#define DA9052_COUNTS_MONITOR (1<<6) +#define DA9052_COUNTS_COUNTSEC (63<<0) + +/* RTC TIMER MINUTES REGISTER */ +#define DA9052_COUNTMI_COUNTMIN (63<<0) + +/* RTC TIMER HOUR REGISTER */ +#define DA9052_COUNTH_COUNTHOUR (31<<0) + +/* RTC TIMER DAYS REGISTER */ +#define DA9052_COUNTD_COUNTDAY (31<<0) + +/* RTC TIMER MONTHS REGISTER */ +#define DA9052_COUNTMO_COUNTMONTH (15<<0) + +/* RTC TIMER YEARS REGISTER */ +#define DA9052_COUNTY_COUNTYEAR (63<<0) + +/* RTC ALARM MINUTES REGISTER */ +#define DA9052_ALARMMI_TICKTYPE (1<<7) +#define DA9052_ALARMMI_ALARMTYPE (1<<6) +#define DA9052_ALARMMI_ALARMMIN (63<<0) + +/* RTC ALARM HOURS REGISTER */ +#define DA9052_ALARMH_ALARMHOUR (31<<0) + +/* RTC ALARM DAYS REGISTER */ +#define DA9052_ALARMD_ALARMDAY (31<<0) + +/* RTC ALARM MONTHS REGISTER */ +#define DA9052_ALARMMO_ALARMMONTH (15<<0) + +/* RTC ALARM YEARS REGISTER */ +#define DA9052_ALARMY_TICKON (1<<7) +#define DA9052_ALARMY_ALARMON (1<<6) +#define DA9052_ALARMY_ALARMYEAR (63<<0) + +/* RTC SECONDS REGISTER A*/ +#define DA9052_SECONDA_SECONDSA (255<<0) + +/* RTC SECONDS REGISTER B*/ +#define DA9052_SECONDB_SECONDSB (255<<0) + +/* RTC SECONDS REGISTER C*/ +#define DA9052_SECONDC_SECONDSC (255<<0) + +/* RTC SECONDS REGISTER D*/ +#define DA9052_SECONDD_SECONDSD (255<<0) + +/* OTP REGISTER */ + +/* CHIP IDENTIFICATION REGISTER */ +#define DA9052_CHIPID_MRC (15<<4) +#define DA9052_CHIPID_TRC (15<<0) + +/* CONFIGURATION IDENTIFICATION REGISTER */ +#define DA9052_CONFIGID_CUSTOMERID (31<<3) +#define DA9052_CONFIGID_CONFID (7<<0) + +/* OTP CONTROL REGISTER */ +#define DA9052_OTPCONT_GPWRITEDIS (1<<7) +#define DA9052_OTPCONT_OTPCONFLOCK (1<<6) +#define DA9052_OTPCONT_OTPGPLOCK (1<<5) +#define DA9052_OTPCONT_OTPCONFG (1<<3) +#define DA9052_OTPCONT_OTPGP (1<<2) +#define DA9052_OTPCONT_OTPRP (1<<1) +#define DA9052_OTPCONT_OTPTRANSFER (1<<0) + +/* RTC OSCILLATOR TRIM REGISTER */ +#define DA9052_OSCTRIM_TRIM32K (255<<0) + +/* GP ID REGISTER 0 */ +#define DA9052_GPID0_GP0 (255<<0) + +/* GP ID REGISTER 1 */ +#define DA9052_GPID1_GP1 (255<<0) + +/* GP ID REGISTER 2 */ +#define DA9052_GPID2_GP2 (255<<0) + +/* GP ID REGISTER 3 */ +#define DA9052_GPID3_GP3 (255<<0) + +/* GP ID REGISTER 4 */ +#define DA9052_GPID4_GP4 (255<<0) + +/* GP ID REGISTER 5 */ +#define DA9052_GPID5_GP5 (255<<0) + +/* GP ID REGISTER 6 */ +#define DA9052_GPID6_GP6 (255<<0) + +/* GP ID REGISTER 7 */ +#define DA9052_GPID7_GP7 (255<<0) + +/* GP ID REGISTER 8 */ +#define DA9052_GPID8_GP8 (255<<0) + +/* GP ID REGISTER 9 */ +#define DA9052_GPID9_GP9 (255<<0) + +#endif +/* __LINUX_MFD_DA9052_REG_H */ diff --git a/include/linux/mfd/da9052/rtc.h b/include/linux/mfd/da9052/rtc.h new file mode 100644 index 0000000..2057e9e --- /dev/null +++ b/include/linux/mfd/da9052/rtc.h @@ -0,0 +1,322 @@ +/* + * da9052 RTC module declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_RTC_H +#define __LINUX_MFD_DA9052_RTC_H + +#define DA9052_RTC_DEVICE_NAME "da9052_rtc" + +/* Limit values */ +#define DA9052_RTC_SECONDS_LIMIT 59 +#define DA9052_RTC_MINUTES_LIMIT 59 +#define DA9052_RTC_HOURS_LIMIT 23 +#define DA9052_RTC_DAYS_LIMIT 31 +#define DA9052_RTC_MONTHS_LIMIT 12 +#define DA9052_RTC_YEARS_LIMIT 63 + +/* Months */ +#define FEBRUARY 2 +#define APRIL 4 +#define JUNE 6 +#define SEPTEMBER 9 +#define NOVEMBER 11 + +/* BYTE shifts */ +#define DA9052_RTC_FOURTH_BYTE 24 +#define DA9052_RTC_THIRD_BYTE 16 +#define DA9052_RTC_SECOND_BYTE 8 +#define DA9052_RTC_FIRST_BYTE 0 + +/* Oscillator trim values */ +#define DA9052_RTC_OSC_FRQ_0_0ppm 0 +#define DA9052_RTC_OSC_FRQ_1_9ppm 1 +#define DA9052_RTC_OSC_FRQ_3_8ppm 2 +#define DA9052_RTC_OSC_FRQ_5_7ppm 3 +#define DA9052_RTC_OSC_FRQ_7_6ppm 4 +#define DA9052_RTC_OSC_FRQ_9_5ppm 5 +#define DA9052_RTC_OSC_FRQ_11_4ppm 6 +#define DA9052_RTC_OSC_FRQ_13_3ppm 7 +#define DA9052_RTC_OSC_FRQ_15_2ppm 8 +#define DA9052_RTC_OSC_FRQ_17_1ppm 9 +#define DA9052_RTC_OSC_FRQ_19_0ppm 10 +#define DA9052_RTC_OSC_FRQ_20_9ppm 11 +#define DA9052_RTC_OSC_FRQ_22_8ppm 12 +#define DA9052_RTC_OSC_FRQ_24_7ppm 13 +#define DA9052_RTC_OSC_FRQ_26_7ppm 14 +#define DA9052_RTC_OSC_FRQ_28_6ppm 15 +#define DA9052_RTC_OSC_FRQ_30_5ppm 16 +#define DA9052_RTC_OSC_FRQ_32_4ppm 17 +#define DA9052_RTC_OSC_FRQ_34_3ppm 18 +#define DA9052_RTC_OSC_FRQ_36_2ppm 19 +#define DA9052_RTC_OSC_FRQ_38_1ppm 20 +#define DA9052_RTC_OSC_FRQ_40_0ppm 21 +#define DA9052_RTC_OSC_FRQ_41_9ppm 22 +#define DA9052_RTC_OSC_FRQ_43_8ppm 23 +#define DA9052_RTC_OSC_FRQ_45_7ppm 24 +#define DA9052_RTC_OSC_FRQ_47_6ppm 25 +#define DA9052_RTC_OSC_FRQ_49_5ppm 26 +#define DA9052_RTC_OSC_FRQ_51_4ppm 27 +#define DA9052_RTC_OSC_FRQ_53_4ppm 28 +#define DA9052_RTC_OSC_FRQ_55_3ppm 29 +#define DA9052_RTC_OSC_FRQ_57_2ppm 30 +#define DA9052_RTC_OSC_FRQ_59_1ppm 31 +#define DA9052_RTC_OSC_FRQ_61_0ppm 32 +#define DA9052_RTC_OSC_FRQ_62_9ppm 33 +#define DA9052_RTC_OSC_FRQ_64_8ppm 34 +#define DA9052_RTC_OSC_FRQ_66_7ppm 35 +#define DA9052_RTC_OSC_FRQ_68_6ppm 36 +#define DA9052_RTC_OSC_FRQ_70_5ppm 37 +#define DA9052_RTC_OSC_FRQ_72_4ppm 38 +#define DA9052_RTC_OSC_FRQ_74_3ppm 39 +#define DA9052_RTC_OSC_FRQ_76_2ppm 40 +#define DA9052_RTC_OSC_FRQ_78_2ppm 41 +#define DA9052_RTC_OSC_FRQ_80_1ppm 42 +#define DA9052_RTC_OSC_FRQ_82_0ppm 43 +#define DA9052_RTC_OSC_FRQ_83_9ppm 44 +#define DA9052_RTC_OSC_FRQ_85_8ppm 45 +#define DA9052_RTC_OSC_FRQ_87_7ppm 46 +#define DA9052_RTC_OSC_FRQ_89_6ppm 47 +#define DA9052_RTC_OSC_FRQ_91_5ppm 48 +#define DA9052_RTC_OSC_FRQ_93_4ppm 49 +#define DA9052_RTC_OSC_FRQ_95_3ppm 50 +#define DA9052_RTC_OSC_FRQ_97_2ppm 51 +#define DA9052_RTC_OSC_FRQ_99_1ppm 52 +#define DA9052_RTC_OSC_FRQ_101_0ppm 53 +#define DA9052_RTC_OSC_FRQ_102_9ppm 54 +#define DA9052_RTC_OSC_FRQ_104_9ppm 55 +#define DA9052_RTC_OSC_FRQ_106_8ppm 56 +#define DA9052_RTC_OSC_FRQ_108_7ppm 57 +#define DA9052_RTC_OSC_FRQ_110_6ppm 58 +#define DA9052_RTC_OSC_FRQ_112_5ppm 59 +#define DA9052_RTC_OSC_FRQ_114_4ppm 60 +#define DA9052_RTC_OSC_FRQ_116_3ppm 61 +#define DA9052_RTC_OSC_FRQ_118_2ppm 62 +#define DA9052_RTC_OSC_FRQ_120_1ppm 63 +#define DA9052_RTC_OSC_FRQ_122_0ppm 64 +#define DA9052_RTC_OSC_FRQ_123_9ppm 65 +#define DA9052_RTC_OSC_FRQ_125_8ppm 66 +#define DA9052_RTC_OSC_FRQ_127_7ppm 67 +#define DA9052_RTC_OSC_FRQ_129_6ppm 68 +#define DA9052_RTC_OSC_FRQ_131_6ppm 69 +#define DA9052_RTC_OSC_FRQ_133_5ppm 70 +#define DA9052_RTC_OSC_FRQ_135_4ppm 71 +#define DA9052_RTC_OSC_FRQ_137_3ppm 72 +#define DA9052_RTC_OSC_FRQ_139_2ppm 73 +#define DA9052_RTC_OSC_FRQ_141_1ppm 74 +#define DA9052_RTC_OSC_FRQ_143_0ppm 75 +#define DA9052_RTC_OSC_FRQ_144_9ppm 76 +#define DA9052_RTC_OSC_FRQ_146_8ppm 77 +#define DA9052_RTC_OSC_FRQ_148_7ppm 78 +#define DA9052_RTC_OSC_FRQ_150_6ppm 79 +#define DA9052_RTC_OSC_FRQ_152_5ppm 80 +#define DA9052_RTC_OSC_FRQ_154_4ppm 81 +#define DA9052_RTC_OSC_FRQ_156_4ppm 82 +#define DA9052_RTC_OSC_FRQ_158_3ppm 83 +#define DA9052_RTC_OSC_FRQ_160_2ppm 84 +#define DA9052_RTC_OSC_FRQ_162_1ppm 85 +#define DA9052_RTC_OSC_FRQ_164_0ppm 86 +#define DA9052_RTC_OSC_FRQ_165_9ppm 87 +#define DA9052_RTC_OSC_FRQ_167_8ppm 88 +#define DA9052_RTC_OSC_FRQ_169_7ppm 89 +#define DA9052_RTC_OSC_FRQ_171_6ppm 90 +#define DA9052_RTC_OSC_FRQ_173_5ppm 91 +#define DA9052_RTC_OSC_FRQ_175_4ppm 92 +#define DA9052_RTC_OSC_FRQ_177_3ppm 93 +#define DA9052_RTC_OSC_FRQ_179_2ppm 94 +#define DA9052_RTC_OSC_FRQ_181_1ppm 95 +#define DA9052_RTC_OSC_FRQ_183_1ppm 96 +#define DA9052_RTC_OSC_FRQ_185_0ppm 97 +#define DA9052_RTC_OSC_FRQ_186_9ppm 98 +#define DA9052_RTC_OSC_FRQ_188_8ppm 99 +#define DA9052_RTC_OSC_FRQ_190_7ppm 100 +#define DA9052_RTC_OSC_FRQ_192_6ppm 101 +#define DA9052_RTC_OSC_FRQ_194_5ppm 102 +#define DA9052_RTC_OSC_FRQ_196_4ppm 103 +#define DA9052_RTC_OSC_FRQ_198_3ppm 104 +#define DA9052_RTC_OSC_FRQ_200_2ppm 105 +#define DA9052_RTC_OSC_FRQ_202_1ppm 106 +#define DA9052_RTC_OSC_FRQ_204_0ppm 107 +#define DA9052_RTC_OSC_FRQ_205_9ppm 108 +#define DA9052_RTC_OSC_FRQ_207_9ppm 109 +#define DA9052_RTC_OSC_FRQ_209_8ppm 110 +#define DA9052_RTC_OSC_FRQ_211_7ppm 111 +#define DA9052_RTC_OSC_FRQ_213_6ppm 112 +#define DA9052_RTC_OSC_FRQ_215_5ppm 113 +#define DA9052_RTC_OSC_FRQ_217_4ppm 114 +#define DA9052_RTC_OSC_FRQ_219_3ppm 115 +#define DA9052_RTC_OSC_FRQ_221_2ppm 116 +#define DA9052_RTC_OSC_FRQ_223_1ppm 117 +#define DA9052_RTC_OSC_FRQ_225_0ppm 118 +#define DA9052_RTC_OSC_FRQ_226_9ppm 119 +#define DA9052_RTC_OSC_FRQ_228_8ppm 120 +#define DA9052_RTC_OSC_FRQ_230_7ppm 121 +#define DA9052_RTC_OSC_FRQ_232_6ppm 122 +#define DA9052_RTC_OSC_FRQ_234_6ppm 123 +#define DA9052_RTC_OSC_FRQ_236_5ppm 124 +#define DA9052_RTC_OSC_FRQ_238_4ppm 125 +#define DA9052_RTC_OSC_FRQ_240_3ppm 126 +#define DA9052_RTC_OSC_FRQ_242_2ppm 127 +#define DA9052_RTC_OSC_FRQ_MINUS_244_1ppm 128 +#define DA9052_RTC_OSC_FRQ_MINUS_242_2ppm 129 +#define DA9052_RTC_OSC_FRQ_MINUS_240_3ppm 130 +#define DA9052_RTC_OSC_FRQ_MINUS_238_4ppm 131 +#define DA9052_RTC_OSC_FRQ_MINUS_236_5ppm 132 +#define DA9052_RTC_OSC_FRQ_MINUS_234_6ppm 133 +#define DA9052_RTC_OSC_FRQ_MINUS_232_6ppm 134 +#define DA9052_RTC_OSC_FRQ_MINUS_230_7ppm 135 +#define DA9052_RTC_OSC_FRQ_MINUS_228_8ppm 136 +#define DA9052_RTC_OSC_FRQ_MINUS_226_9ppm 137 +#define DA9052_RTC_OSC_FRQ_MINUS_225_0ppm 138 +#define DA9052_RTC_OSC_FRQ_MINUS_223_1ppm 139 +#define DA9052_RTC_OSC_FRQ_MINUS_221_2ppm 140 +#define DA9052_RTC_OSC_FRQ_MINUS_219_3ppm 141 +#define DA9052_RTC_OSC_FRQ_MINUS_217_4ppm 142 +#define DA9052_RTC_OSC_FRQ_MINUS_215_5ppm 143 +#define DA9052_RTC_OSC_FRQ_MINUS_213_6ppm 144 +#define DA9052_RTC_OSC_FRQ_MINUS_211_7ppm 145 +#define DA9052_RTC_OSC_FRQ_MINUS_209_8ppm 146 +#define DA9052_RTC_OSC_FRQ_MINUS_207_9ppm 147 +#define DA9052_RTC_OSC_FRQ_MINUS_205_9ppm 148 +#define DA9052_RTC_OSC_FRQ_MINUS_204_0ppm 149 +#define DA9052_RTC_OSC_FRQ_MINUS_202_1ppm 150 +#define DA9052_RTC_OSC_FRQ_MINUS_200_2ppm 151 +#define DA9052_RTC_OSC_FRQ_MINUS_198_3ppm 152 +#define DA9052_RTC_OSC_FRQ_MINUS_196_4ppm 153 +#define DA9052_RTC_OSC_FRQ_MINUS_194_5ppm 154 +#define DA9052_RTC_OSC_FRQ_MINUS_192_6ppm 155 +#define DA9052_RTC_OSC_FRQ_MINUS_190_7ppm 156 +#define DA9052_RTC_OSC_FRQ_MINUS_188_8ppm 157 +#define DA9052_RTC_OSC_FRQ_MINUS_186_9ppm 158 +#define DA9052_RTC_OSC_FRQ_MINUS_185_0ppm 159 +#define DA9052_RTC_OSC_FRQ_MINUS_183_1ppm 160 +#define DA9052_RTC_OSC_FRQ_MINUS_181_1ppm 161 +#define DA9052_RTC_OSC_FRQ_MINUS_179_2ppm 162 +#define DA9052_RTC_OSC_FRQ_MINUS_177_3ppm 163 +#define DA9052_RTC_OSC_FRQ_MINUS_175_4ppm 164 +#define DA9052_RTC_OSC_FRQ_MINUS_173_5ppm 165 +#define DA9052_RTC_OSC_FRQ_MINUS_171_6ppm 166 +#define DA9052_RTC_OSC_FRQ_MINUS_169_7ppm 167 +#define DA9052_RTC_OSC_FRQ_MINUS_167_8ppm 168 +#define DA9052_RTC_OSC_FRQ_MINUS_165_9ppm 169 +#define DA9052_RTC_OSC_FRQ_MINUS_164_0ppm 170 +#define DA9052_RTC_OSC_FRQ_MINUS_162_1ppm 171 +#define DA9052_RTC_OSC_FRQ_MINUS_160_2ppm 172 +#define DA9052_RTC_OSC_FRQ_MINUS_158_3ppm 173 +#define DA9052_RTC_OSC_FRQ_MINUS_156_4ppm 174 +#define DA9052_RTC_OSC_FRQ_MINUS_154_4ppm 175 +#define DA9052_RTC_OSC_FRQ_MINUS_152_5ppm 176 +#define DA9052_RTC_OSC_FRQ_MINUS_150_6ppm 177 +#define DA9052_RTC_OSC_FRQ_MINUS_148_7ppm 178 +#define DA9052_RTC_OSC_FRQ_MINUS_146_8ppm 179 +#define DA9052_RTC_OSC_FRQ_MINUS_144_9ppm 180 +#define DA9052_RTC_OSC_FRQ_MINUS_143_0ppm 181 +#define DA9052_RTC_OSC_FRQ_MINUS_141_1ppm 182 +#define DA9052_RTC_OSC_FRQ_MINUS_139_2ppm 183 +#define DA9052_RTC_OSC_FRQ_MINUS_137_3ppm 184 +#define DA9052_RTC_OSC_FRQ_MINUS_135_4ppm 185 +#define DA9052_RTC_OSC_FRQ_MINUS_133_5ppm 186 +#define DA9052_RTC_OSC_FRQ_MINUS_131_6ppm 187 +#define DA9052_RTC_OSC_FRQ_MINUS_129_6ppm 188 +#define DA9052_RTC_OSC_FRQ_MINUS_127_7ppm 189 +#define DA9052_RTC_OSC_FRQ_MINUS_125_8ppm 190 +#define DA9052_RTC_OSC_FRQ_MINUS_123_9ppm 191 +#define DA9052_RTC_OSC_FRQ_MINUS_122_0ppm 192 +#define DA9052_RTC_OSC_FRQ_MINUS_120_1ppm 193 +#define DA9052_RTC_OSC_FRQ_MINUS_118_2ppm 194 +#define DA9052_RTC_OSC_FRQ_MINUS_116_3ppm 195 +#define DA9052_RTC_OSC_FRQ_MINUS_114_4ppm 196 +#define DA9052_RTC_OSC_FRQ_MINUS_112_5ppm 197 +#define DA9052_RTC_OSC_FRQ_MINUS_110_6ppm 198 +#define DA9052_RTC_OSC_FRQ_MINUS_108_7ppm 199 +#define DA9052_RTC_OSC_FRQ_MINUS_106_8ppm 200 +#define DA9052_RTC_OSC_FRQ_MINUS_104_9ppm 201 +#define DA9052_RTC_OSC_FRQ_MINUS_102_9ppm 202 +#define DA9052_RTC_OSC_FRQ_MINUS_101_0ppm 203 +#define DA9052_RTC_OSC_FRQ_MINUS_99_1ppm 204 +#define DA9052_RTC_OSC_FRQ_MINUS_97_2ppm 205 +#define DA9052_RTC_OSC_FRQ_MINUS_95_3ppm 206 +#define DA9052_RTC_OSC_FRQ_MINUS_93_4ppm 207 +#define DA9052_RTC_OSC_FRQ_MINUS_91_5ppm 208 +#define DA9052_RTC_OSC_FRQ_MINUS_89_6ppm 209 +#define DA9052_RTC_OSC_FRQ_MINUS_87_7ppm 210 +#define DA9052_RTC_OSC_FRQ_MINUS_85_8ppm 211 +#define DA9052_RTC_OSC_FRQ_MINUS_83_9ppm 212 +#define DA9052_RTC_OSC_FRQ_MINUS_82_0ppm 213 +#define DA9052_RTC_OSC_FRQ_MINUS_80_1ppm 214 +#define DA9052_RTC_OSC_FRQ_MINUS_78_2ppm 215 +#define DA9052_RTC_OSC_FRQ_MINUS_76_2ppm 216 +#define DA9052_RTC_OSC_FRQ_MINUS_74_3ppm 217 +#define DA9052_RTC_OSC_FRQ_MINUS_72_4ppm 218 +#define DA9052_RTC_OSC_FRQ_MINUS_70_5ppm 219 +#define DA9052_RTC_OSC_FRQ_MINUS_68_6ppm 220 +#define DA9052_RTC_OSC_FRQ_MINUS_66_7ppm 221 +#define DA9052_RTC_OSC_FRQ_MINUS_64_8ppm 222 +#define DA9052_RTC_OSC_FRQ_MINUS_62_9ppm 223 +#define DA9052_RTC_OSC_FRQ_MINUS_61_0ppm 224 +#define DA9052_RTC_OSC_FRQ_MINUS_59_1ppm 225 +#define DA9052_RTC_OSC_FRQ_MINUS_57_2ppm 226 +#define DA9052_RTC_OSC_FRQ_MINUS_55_3ppm 227 +#define DA9052_RTC_OSC_FRQ_MINUS_53_4ppm 228 +#define DA9052_RTC_OSC_FRQ_MINUS_51_4ppm 229 +#define DA9052_RTC_OSC_FRQ_MINUS_49_5ppm 230 +#define DA9052_RTC_OSC_FRQ_MINUS_47_6ppm 231 +#define DA9052_RTC_OSC_FRQ_MINUS_45_7ppm 232 +#define DA9052_RTC_OSC_FRQ_MINUS_43_8ppm 233 +#define DA9052_RTC_OSC_FRQ_MINUS_41_9ppm 234 +#define DA9052_RTC_OSC_FRQ_MINUS_40_0ppm 235 +#define DA9052_RTC_OSC_FRQ_MINUS_38_1ppm 236 +#define DA9052_RTC_OSC_FRQ_MINUS_36_2ppm 237 +#define DA9052_RTC_OSC_FRQ_MINUS_34_3ppm 238 +#define DA9052_RTC_OSC_FRQ_MINUS_32_4ppm 239 +#define DA9052_RTC_OSC_FRQ_MINUS_30_5ppm 240 +#define DA9052_RTC_OSC_FRQ_MINUS_28_6ppm 241 +#define DA9052_RTC_OSC_FRQ_MINUS_26_7ppm 242 +#define DA9052_RTC_OSC_FRQ_MINUS_24_7ppm 243 +#define DA9052_RTC_OSC_FRQ_MINUS_22_8ppm 244 +#define DA9052_RTC_OSC_FRQ_MINUS_20_9ppm 245 +#define DA9052_RTC_OSC_FRQ_MINUS_19_0ppm 246 +#define DA9052_RTC_OSC_FRQ_MINUS_17_1ppm 247 +#define DA9052_RTC_OSC_FRQ_MINUS_15_2ppm 248 +#define DA9052_RTC_OSC_FRQ_MINUS_13_3ppm 249 +#define DA9052_RTC_OSC_FRQ_MINUS_11_4ppm 250 +#define DA9052_RTC_OSC_FRQ_MINUS_9_5ppm 251 +#define DA9052_RTC_OSC_FRQ_MINUS_7_6ppm 252 +#define DA9052_RTC_OSC_FRQ_MINUS_5_7ppm 253 +#define DA9052_RTC_OSC_FRQ_MINUS_3_8ppm 254 +#define DA9052_RTC_OSC_FRQ_MINUS_1_9ppm 255 + +/* RTC error codes */ +#define DA9052_RTC_INVALID_SECONDS 3 +#define DA9052_RTC_INVALID_MINUTES 4 +#define DA9052_RTC_INVALID_HOURS 5 +#define DA9052_RTC_INVALID_DAYS 6 +#define DA9052_RTC_INVALID_MONTHS 7 +#define DA9052_RTC_INVALID_YEARS 8 +#define DA9052_RTC_INVALID_EVENT 9 +#define DA9052_RTC_INVALID_IOCTL 10 +#define DA9052_RTC_INVALID_SETTING 11 +#define DA9052_RTC_EVENT_ALREADY_REGISTERED 12 +#define DA9052_RTC_EVENT_UNREGISTERED 13 +#define DA9052_RTC_EVENT_REGISTRATION_FAILED 14 +#define DA9052_RTC_EVENT_UNREGISTRATION_FAILED 15 + +#endif +/* __LINUX_MFD_DA9052_RTC_H */ diff --git a/include/linux/mfd/da9052/tsi.h b/include/linux/mfd/da9052/tsi.h new file mode 100644 index 0000000..a677bbc --- /dev/null +++ b/include/linux/mfd/da9052/tsi.h @@ -0,0 +1,427 @@ +/* + * da9052 TSI module declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_TSI_H +#define __LINUX_MFD_DA9052_TSI_H + +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/tsi_filter.h> +#include <linux/mfd/da9052/tsi_calibrate.h> +#include <linux/mfd/da9052/pm.h> + +#define DA9052_TSI_DEVICE_NAME "da9052-tsi" +#define DA9052_TSI_INPUT_DEV DA9052_TSI_DEVICE_NAME + +#define TSI_VERSION 0x0101 +#define DA9052_VENDOR_ID 0x15B6 +#define DA9052_PRODUCT_ID 0x9052 + +#define TSI_INPUT_DEVICE_OFF 0 +#define NUM_INPUT_DEVS 1 + +#define DA9052_DISPLAY_X_MAX 0x3FF +#define DA9052_DISPLAY_Y_MAX 0x3FF +#define DA9052_TOUCH_PRESSURE_MAX 0x3FF + +#define DA9052_TCA_AUTO_TSI_ENABLE (1<<0) +#define DA9052_TCA_PEN_DET_ENABLE (1<<1) +#define DA9052_TCA_TSI_XP_MODE_ENABLE (1<<2) + +#define DA9052_TCA_TSI_DELAY_0SLOTS (0<<6) +#define DA9052_TCA_TSI_DELAY_2SLOTS (2<<6) +#define DA9052_TCA_TSI_DELAY_4SLOTS (3<<6) + +#define DA9052_TCA_TSI_SEL_XPLUS (1<<0) +#define DA9052_TCA_TSI_SEL_XMINUS (1<<1) +#define DA9052_TCA_TSI_SEL_YPLUS (1<<2) +#define DA9052_TCA_TSI_SEL_YMINUS (1<<3) + +#define DA9052_TCA_TSI_MUX_XPLUS_ROUTED_ADCIN7 (0<<4) +#define DA9052_TCA_TSI_MUX_YPLUS_ROUTED_ADCIN7 (1<<4) +#define DA9052_TCA_TSI_MUX_XMINUS_ROUTED_ADCIN7 (2<<4) +#define DA9052_TCA_TSI_MUX_YMINUS_ROUTED_ADCIN7 (3<<4) + +#define DA9052_TCA_TSI_MAN_ENABLE (1<<6) +#define DA9052_TCA_TSI_SET_TSIREF (0<<7) +#define DA9052_TCA_TSI_SET_XY_REF (1<<7) + +#define DA9052_EVETN_B_E_PEN_DOWN (1<<6) +#define DA9052_EVENT_B_E_TSI_READY (1<<7) + +#define DA9052_IRQMASK_B_PENDOWN_MASK (1<<6) +#define DA9052_IRQMASK_B_TSI_READY_MASK (1<<7) + +#define X_LSB_SHIFT (0) +#define Y_LSB_SHIFT (2) +#define Z_LSB_SHIFT (4) +#define PEN_DET_SHIFT (6) +#define X_MSB_SHIFT (2) +#define Y_MSB_SHIFT (2) +#define Z_MSB_SHIFT (2) +#define X_LSB_MASK (11 << X_LSB_SHIFT) +#define Y_LSB_MASK (11 << Y_LSB_SHIFT) +#define Z_LSB_MASK (11 << Z_LSB_SHIFT) +#define PEN_DET_MASK (11 << PEN_DET_SHIFT) + +#define TSI_FIFO_SIZE 16 + +#define INVALID_LDO9_VOLT_VALUE 17 + +#define set_bits(value, mask) (value | mask) +#define clear_bits(value, mask) (value & ~(mask)) + +#define SUCCESS 0 +#define FAILURE 1 + +#define SET 1 +#define RESET 0 +#define CLEAR 0 + +#define ENABLE 1 +#define DISABLE 0 + +#define TRUE 1 +#define FALSE 0 + +#define incr_with_wrap_reg_fifo(x) \ + if (++x >= TSI_REG_DATA_BUF_SIZE) \ + x = 0 + +#define incr_with_wrap(x) \ + if (++x >= TSI_FIFO_SIZE) \ + x = 0 + +#undef DA9052_DEBUG +#if DA9052_TSI_DEBUG +#define DA9052_DEBUG(fmt, args...) printk(KERN_CRIT "" fmt, ##args) +#else +#define DA9052_DEBUG(fmt, args...) +#endif + +enum ADC_MODE { + + ECONOMY_MODE = 0, + FAST_MODE = 1 +}; + +enum TSI_DELAY { + TSI_DELAY_0SLOTS = 0, + TSI_DELAY_1SLOTS = 1, + TSI_DELAY_2SLOTS = 2, + TSI_DELAY_4SLOTS = 3 +}; + +enum TSI_SLOT_SKIP { + TSI_SKIP_0SLOTS = 0, + TSI_SKIP_2SLOTS = 1, + TSI_SKIP_5SLOTS = 2, + TSI_SKIP_10SLOTS = 3, + TSI_SKIP_30SLOTS = 4, + TSI_SKIP_80SLOTS = 5, + TSI_SKIP_130SLOTS = 6, + TSI_SKIP_330SLOTS = 7 +}; + + +enum TSI_MUX_SEL { + TSI_MUX_XPLUS = 0, + TSI_MUX_YPLUS = 1, + TSI_MUX_XMINUS = 2, + TSI_MUX_YMINUS = 3 +}; + + +enum TSI_IRQ { + TSI_PEN_DWN, + TSI_DATA_RDY +}; + + +enum TSI_COORDINATE { + X_COORDINATE, + Y_COORDINATE, + Z_COORDINATE +}; + +enum TSI_MEASURE_SEQ { + XYZP_MODE, + XP_MODE +}; + +enum TSI_STATE { + TSI_AUTO_MODE, + TSI_MANUAL_COORD_X, + TSI_MANUAL_COORD_Y, + TSI_MANUAL_COORD_Z, + TSI_MANUAL_SET, + TSI_IDLE +}; + +union da9052_tsi_cont_reg { + u8 da9052_tsi_cont_a; + struct { + u8 auto_tsi_en:1; + u8 pen_det_en:1; + u8 tsi_mode:1; + u8 tsi_skip:3; + u8 tsi_delay:2; + } tsi_cont_a; +}; + +union da9052_tsi_man_cont_reg { + u8 da9052_tsi_cont_b; + struct { + u8 tsi_sel_0:1; + u8 tsi_sel_1:1; + u8 tsi_sel_2:1; + u8 tsi_sel_3:1; + u8 tsi_mux:2; + u8 tsi_man:1; + u8 tsi_adc_ref:1; + } tsi_cont_b; +}; + +struct da9052_tsi_conf { + union da9052_tsi_cont_reg auto_cont; + union da9052_tsi_man_cont_reg man_cont; + u8 tsi_adc_sample_intervel:1; + enum TSI_STATE state; + u8 ldo9_en:1; + u8 ldo9_conf:1; + u8 tsi_ready_irq_mask:1; + u8 tsi_pendown_irq_mask:1; +}; + + +struct da9052_tsi_reg { + u8 x_msb; + u8 y_msb; + u8 z_msb; + u8 lsb; +}; + + +struct da9052_tsi_reg_fifo { + struct semaphore lock; + s32 head; + s32 tail; + struct da9052_tsi_reg data[TSI_REG_DATA_BUF_SIZE]; +}; + +struct da9052_tsi_info { + struct da9052_tsi_conf tsi_conf; + struct input_dev *input_devs[NUM_INPUT_DEVS]; + struct calib_cfg_t *tsi_calib; + u32 tsi_data_poll_interval; + u32 tsi_penup_count; + u32 tsi_zero_data_cnt; + u8 pen_dwn_event; + u8 tsi_rdy_event; + u8 pd_reg_status; + u8 datardy_reg_status; +}; + +struct da9052_tsi { + struct da9052_tsi_reg tsi_fifo[TSI_FIFO_SIZE]; + struct mutex tsi_fifo_lock; + u8 tsi_sampling; + u8 tsi_state; + u32 tsi_fifo_start; + u32 tsi_fifo_end; +}; + +struct da9052_ts_priv { + struct da9052 *da9052; + struct da9052_eh_nb pd_nb; + struct da9052_eh_nb datardy_nb; + + struct tsi_thread_type tsi_reg_proc_thread; + struct tsi_thread_type tsi_raw_proc_thread; + + struct da9052_tsi_platform_data *tsi_pdata; + + struct da9052_tsi_reg_fifo tsi_reg_fifo; + struct da9052_tsi_raw_fifo tsi_raw_fifo; + + u32 tsi_reg_data_poll_interval; + u32 tsi_raw_data_poll_interval; + + u8 early_data_flag; + u8 debounce_over; + u8 win_reference_valid; + + int os_data_cnt; + int raw_data_cnt; +}; + +static inline u8 mask_pendwn_irq(u8 val) +{ + return val |= DA9052_IRQMASKB_MPENDOWN; +} + +static inline u8 unmask_pendwn_irq(u8 val) +{ + return val &= ~DA9052_IRQMASKB_MPENDOWN; +} + +static inline u8 mask_tsi_rdy_irq(u8 val) +{ + return val |= DA9052_IRQMASKB_MTSIREADY; +} + +static inline u8 unmask_tsi_rdy_irq(u8 val) +{ + return val &= ~DA9052_IRQMASKB_MTSIREADY; +} + +static inline u8 enable_ldo9(u8 val) +{ + return val |= DA9052_LDO9_LDO9EN; +} + +static inline u8 disable_ldo9(u8 val) +{ + return val &= ~DA9052_LDO9_LDO9EN; +} + +static inline u8 set_auto_tsi_en(u8 val) +{ + return val |= DA9052_TSICONTA_AUTOTSIEN; +} + +static inline u8 reset_auto_tsi_en(u8 val) +{ + return val &= ~DA9052_TSICONTA_AUTOTSIEN; +} + +static inline u8 enable_pen_detect(u8 val) +{ + return val |= DA9052_TSICONTA_PENDETEN; +} + +static inline u8 disable_pen_detect(u8 val) +{ + return val &= ~DA9052_TSICONTA_PENDETEN; +} + +static inline u8 enable_xyzp_mode(u8 val) +{ + return val &= ~DA9052_TSICONTA_TSIMODE; +} + +static inline u8 enable_xp_mode(u8 val) +{ + return val |= DA9052_TSICONTA_TSIMODE; +} + +static inline u8 enable_tsi_manual_mode(u8 val) +{ + return val |= DA9052_TSICONTB_TSIMAN; +} + +static inline u8 disable_tsi_manual_mode(u8 val) +{ + return val &= ~DA9052_TSICONTB_TSIMAN; +} + +static inline u8 tsi_sel_xplus_close(u8 val) +{ + return val |= DA9052_TSICONTB_TSISEL0; +} + +static inline u8 tsi_sel_xplus_open(u8 val) +{ + return val &= ~DA9052_TSICONTB_TSISEL0; +} + +static inline u8 tsi_sel_xminus_close(u8 val) +{ + return val |= DA9052_TSICONTB_TSISEL1; +} + +static inline u8 tsi_sel_xminus_open(u8 val) +{ + return val &= ~DA9052_TSICONTB_TSISEL1; +} + +static inline u8 tsi_sel_yplus_close(u8 val) +{ + return val |= DA9052_TSICONTB_TSISEL2; +} + +static inline u8 tsi_sel_yplus_open(u8 val) +{ + return val &= ~DA9052_TSICONTB_TSISEL2; +} + +static inline u8 tsi_sel_yminus_close(u8 val) +{ + return val |= DA9052_TSICONTB_TSISEL3; +} + +static inline u8 tsi_sel_yminus_open(u8 val) +{ + return val &= ~DA9052_TSICONTB_TSISEL3; +} + +static inline u8 adc_mode_economy_mode(u8 val) +{ + return val &= ~DA9052_ADCCONT_ADCMODE ; +} + +static inline u8 adc_mode_fast_mode(u8 val) +{ + return val |= DA9052_ADCCONT_ADCMODE; +} +int da9052_tsi_get_calib_display_point(struct da9052_tsi_data *display); + +struct da9052_ldo_config { + u16 ldo_volt; + u8 ldo_num; + u8 ldo_conf:1; + u8 ldo_pd:1; +}; + +static inline u8 ldo9_mV_to_reg(u16 value) +{ + return (value - DA9052_LDO9_VOLT_LOWER)/DA9052_LDO9_VOLT_STEP; +} + +static inline u8 validate_ldo9_mV(u16 value) +{ + if ((value >= DA9052_LDO9_VOLT_LOWER) && \ + (value <= DA9052_LDO9_VOLT_UPPER)) + return + (((value - DA9052_LDO9_VOLT_LOWER) + % DA9052_LDO9_VOLT_STEP > 0) ? -1 : 0); + return FAILURE; +} + +s32 da9052_tsi_raw_proc_thread(void *ptr); +void __init da9052_init_tsi_fifos(struct da9052_ts_priv *priv); +void clean_tsi_fifos(struct da9052_ts_priv *priv); +u32 get_reg_data_cnt(struct da9052_ts_priv *priv); +u32 get_reg_free_space_cnt(struct da9052_ts_priv *priv); +void da9052_tsi_process_reg_data(struct da9052_ts_priv *priv); +void da9052_tsi_pen_down_handler(struct da9052_eh_nb *eh_data, u32 event); +void da9052_tsi_data_ready_handler(struct da9052_eh_nb *eh_data, u32 event); + +#endif /* __LINUX_MFD_DA9052_TSI_H */ diff --git a/include/linux/mfd/da9052/tsi_calibrate.h b/include/linux/mfd/da9052/tsi_calibrate.h new file mode 100644 index 0000000..a4b42ea --- /dev/null +++ b/include/linux/mfd/da9052/tsi_calibrate.h @@ -0,0 +1,47 @@ +/* + * da9052 TSI calibration module declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_TSI_CALIBRATE_H +#define __LINUX_MFD_DA9052_TSI_CALIBRATE_H + +#include <linux/mfd/da9052/tsi_filter.h> + +struct Calib_xform_matrix_t { + s32 An; + s32 Bn; + s32 Cn; + s32 Dn; + s32 En; + s32 Fn; + s32 Divider; +} ; + + +struct calib_cfg_t { + u8 calibrate_flag; +} ; + +ssize_t da9052_tsi_set_calib_matrix(struct da9052_tsi_data *displayPtr, + struct da9052_tsi_data *screenPtr); +u8 configure_tsi_calib(struct calib_cfg_t *tsi_calib); +struct calib_cfg_t *get_calib_config(void); +#endif /* __LINUX_MFD_DA9052_TSI_CALIBRATE_H */ + diff --git a/include/linux/mfd/da9052/tsi_cfg.h b/include/linux/mfd/da9052/tsi_cfg.h new file mode 100644 index 0000000..21c091b --- /dev/null +++ b/include/linux/mfd/da9052/tsi_cfg.h @@ -0,0 +1,132 @@ +/* + * da9052 TSI configuration module declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_TSI_CFG_H +#define __LINUX_MFD_DA9052_TSI_CFG_H + +#define DA9052_TSI_DEBUG 0 + +#define AUTO_MODE 0 +#define IDLE 1 +#define DEFAULT_TSI_STATE AUTO_MODE + +#define TSI_SLOT_SKIP_VALUE 0 + +#define TSI_DELAY_VALUE 3 + +#define TSI_MODE_VALUE 0 + +#define ENABLE_AVERAGE_FILTER 1 + +#define DEFAULT_AVERAGE_FILTER_SIZE 3 + +#define ENABLE_WINDOW_FILTER 1 + +#define TSI_X_WINDOW_SIZE 50 +#define TSI_Y_WINDOW_SIZE 50 + +#define SAMPLE_CNT_FOR_WIN_REF 3 + +#define TSI_ECONOMY_MODE 0 +#define TSI_FAST_MODE 1 +#define DEFAULT_TSI_SAMPLING_MODE TSI_FAST_MODE + +#define TSI_USE_CALIBRATION 1 + +#define DA9052_TSI_CALIB_AN 1 +#define DA9052_TSI_CALIB_BN 0 +#define DA9052_TSI_CALIB_CN 0 +#define DA9052_TSI_CALIB_DN 0 +#define DA9052_TSI_CALIB_EN 1 +#define DA9052_TSI_CALIB_FN 0 +#define DA9052_TSI_CALIB_DIVIDER 1 + +#define TS_X_MIN (0) +#define TS_X_MAX (1023) +#define TS_Y_MIN (0) +#define TS_Y_MAX (1023) + +#define DISPLAY_X_MIN (0) +#define DISPLAY_X_MAX (1023) +#define DISPLAY_Y_MIN (0) +#define DISPLAY_Y_MAX (1023) + +#define ENABLE_TSI_DEBOUNCE 0 + +#define TSI_DEBOUNCE_DATA_CNT 3 + + +#define RELEASE +#define DA9052_TSI_RAW_DATA_PROFILING 0 +#define DA9052_TSI_WIN_FLT_DATA_PROFILING 0 +#define DA9052_TSI_AVG_FLT_DATA_PROFILING 0 +#define DA9052_TSI_CALIB_DATA_PROFILING 0 +#define DA9052_TSI_OS_DATA_PROFILING 1 +#define DA9052_TSI_PRINT_DEBOUNCED_DATA 0 +#define DA9052_TSI_PRINT_PREVIOUS_DATA 0 + + +#if ENABLE_AVERAGE_FILTER +#define TSI_AVERAGE_FILTER_SIZE DEFAULT_AVERAGE_FILTER_SIZE +#else +#define TSI_AVERAGE_FILTER_SIZE 1 +#endif + +#define TSI_FAST_MODE_SAMPLE_CNT 1000 +#define TSI_ECO_MODE_SAMPLE_CNT 100 + +#define TSI_POLL_SAMPLE_CNT 10 + +#define TSI_FAST_MODE_REG_DATA_PROCESSING_INTERVAL \ + ((1000 / TSI_FAST_MODE_SAMPLE_CNT) * TSI_POLL_SAMPLE_CNT) +#define TSI_ECO_MODE_REG_DATA_PROCESSING_INTERVAL \ + ((1000 / TSI_ECO_MODE_SAMPLE_CNT) * TSI_POLL_SAMPLE_CNT) + +#if DEFAULT_TSI_SAMPLING_MODE +#define DEFAULT_REG_DATA_PROCESSING_INTERVAL \ + TSI_FAST_MODE_REG_DATA_PROCESSING_INTERVAL +#else +#define DEFAULT_REG_DATA_PROCESSING_INTERVAL \ + TSI_ECO_MODE_REG_DATA_PROCESSING_INTERVAL +#endif + +#define TSI_REG_DATA_BUF_SIZE (2 * TSI_POLL_SAMPLE_CNT) + +#define TSI_FAST_MODE_RAW_DATA_PROCESSING_INTERVAL \ + ((1000 / TSI_FAST_MODE_SAMPLE_CNT) * (TSI_AVERAGE_FILTER_SIZE)) +#define TSI_ECO_MODE_RAW_DATA_PROCESSING_INTERVAL \ + ((1000 / TSI_ECO_MODE_SAMPLE_CNT) * (TSI_AVERAGE_FILTER_SIZE)) + + +#if DEFAULT_TSI_SAMPLING_MODE +#define DEFAULT_RAW_DATA_PROCESSING_INTERVAL \ + TSI_FAST_MODE_RAW_DATA_PROCESSING_INTERVAL +#else +#define DEFAULT_RAW_DATA_PROCESSING_INTERVAL \ + TSI_ECO_MODE_RAW_DATA_PROCESSING_INTERVAL +#endif + + +#define TSI_RAW_DATA_BUF_SIZE \ + (TSI_REG_DATA_BUF_SIZE * \ + ((TSI_AVERAGE_FILTER_SIZE / TSI_POLL_SAMPLE_CNT) + 1)) + +#endif /* __LINUX_MFD_DA9052_TSI_CFG_H */ diff --git a/include/linux/mfd/da9052/tsi_filter.h b/include/linux/mfd/da9052/tsi_filter.h new file mode 100644 index 0000000..4bb7003 --- /dev/null +++ b/include/linux/mfd/da9052/tsi_filter.h @@ -0,0 +1,58 @@ +/* + * da9052 TSI filter module declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_TSI_FILTER_H +#define __LINUX_MFD_DA9052_TSI_FILTER_H + +#include <linux/mfd/da9052/tsi_cfg.h> +#include <linux/semaphore.h> +#include <linux/kthread.h> + +struct da9052_tsi_data { + s16 x; + s16 y; + s16 z; +}; + +struct da9052_tsi_raw_fifo { + struct semaphore lock; + s32 head; + s32 tail; + struct da9052_tsi_data data[TSI_RAW_DATA_BUF_SIZE]; +}; + +struct tsi_thread_type { + u8 pid; + u8 state; + struct completion notifier; + struct task_struct *thread_task; +} ; + +/* State for TSI thread */ +#define ACTIVE 0 +#define INACTIVE 1 + + +extern u32 da9052_tsi_get_input_dev(u8 off); + +ssize_t da9052_tsi_get_calib_display_point(struct da9052_tsi_data *displayPtr); + +#endif /* __LINUX_MFD_DA9052_TSI_FILTER_H */ diff --git a/include/linux/mfd/da9052/wdt.h b/include/linux/mfd/da9052/wdt.h new file mode 100644 index 0000000..6a77bfc --- /dev/null +++ b/include/linux/mfd/da9052/wdt.h @@ -0,0 +1,83 @@ +/* + * da9052 SM (watchdog) module declarations. + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_MFD_DA9052_WDT_H +#define __LINUX_MFD_DA9052_WDT_H + +#include <linux/platform_device.h> + +/* To enable debug output for your module, set this to 1 */ +#define DA9052_SM_DEBUG 0 + +/* Error codes */ +#define BUS_ERR 2 +#define INIT_FAIL 3 +#define SM_OPEN_FAIL 4 +#define NO_IOCTL_CMD 5 +#define INVALID_SCALING_VALUE 6 +#define STROBING_FILTER_ERROR 7 +#define TIMER_DELETE_ERR 8 +#define STROBING_MODE_ERROR 9 + +/* IOCTL Switch */ +/* For strobe watchdog function */ +#define DA9052_SM_IOCTL_STROBE_WDT 1 + +/* For setting watchdog timer time */ +#define DA9052_SM_IOCTL_SET_WDT 2 + +/* For enabling/disabling strobing filter */ +#define DA9052_SM_IOCTL_SET_STROBING_FILTER 3 + +/* For enabling/disabling strobing filter */ +#define DA9052_SM_IOCTL_SET_STROBING_MODE 4 + +/* Watchdog time scaling TWDMAX scaling macros */ +#define DA9052_WDT_DISABLE 0 +#define DA9052_SCALE_1X 1 +#define DA9052_SCALE_2X 2 +#define DA9052_SCALE_4X 3 +#define DA9052_SCALE_8X 4 +#define DA9052_SCALE_16X 5 +#define DA9052_SCALE_32X 6 +#define DA9052_SCALE_64X 7 + +#define DA9052_STROBE_WIN_FILTER_PER 80 +#define DA9052_X1_WINDOW ((1 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100) +#define DA9052_X2_WINDOW ((2 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100) +#define DA9052_X4_WINDOW ((4 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100) +#define DA9052_X8_WINDOW ((8 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100) +#define DA9052_X16_WINDOW ((16 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100) +#define DA9052_X32_WINDOW ((32 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100) +#define DA9052_X64_WINDOW ((64 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100) + +#define DA9052_STROBE_AUTO 1 +#define DA9052_STROBE_MANUAL 0 + +#define DA9052_SM_STROBE_CONF DISABLE + +#define DA9052_ADC_TWDMIN_TIME 500 + +void start_strobing(struct work_struct *work); +/* Create a handler for the scheduling start_strobing function */ +DECLARE_WORK(strobing_action, start_strobing); + +#endif /* __LINUX_MFD_DA9052_WDT_H */
On Friday 10 June 2011, Ying-Chun Liu (PaulLiu) wrote:
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9053 headers source code.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org
include/linux/mfd/da9052/adc.h | 66 +++ include/linux/mfd/da9052/bat.h | 264 +++++++++ include/linux/mfd/da9052/bl.h | 289 ++++++++++ include/linux/mfd/da9052/da9052.h | 209 +++++++ include/linux/mfd/da9052/eh.h | 77 +++ include/linux/mfd/da9052/gpio.h | 253 ++++++++ include/linux/mfd/da9052/led.h | 39 ++ include/linux/mfd/da9052/pm.h | 81 +++ include/linux/mfd/da9052/reg.h | 929 ++++++++++++++++++++++++++++++ include/linux/mfd/da9052/rtc.h | 322 +++++++++++ include/linux/mfd/da9052/tsi.h | 427 ++++++++++++++ include/linux/mfd/da9052/tsi_calibrate.h | 47 ++ include/linux/mfd/da9052/tsi_cfg.h | 132 +++++ include/linux/mfd/da9052/tsi_filter.h | 58 ++ include/linux/mfd/da9052/wdt.h | 83 +++
Make sure that all header files are as local as possible:
* If data is used in only one file, put it into that file, not into a header * If it's used by two files in the same directory, make it a local header file * Anything that is an interface between components in multiple directories goes into include/linux.
Arnd
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9052 gpio driver from Dialog. Modify Kconfig/Makefile for DA9052 gpio driver.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org --- drivers/gpio/Kconfig | 7 + drivers/gpio/Makefile | 1 + drivers/gpio/da9052-gpio.c | 731 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 739 insertions(+), 0 deletions(-) create mode 100644 drivers/gpio/da9052-gpio.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2967002..ab93c7ab 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -453,4 +453,11 @@ config GPIO_TPS65910 help Select this option to enable GPIO driver for the TPS65910 chip family. + +config DA9052_GPIO_ENABLE + bool "Dialog DA9052 GPIO" + depends on PMIC_DIALOG + help + Say Y to enable the GPIO driver for the DA9052 chip + endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index b605f8e..cebe1c3 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o obj-$(CONFIG_AB8500_GPIO) += ab8500-gpio.o obj-$(CONFIG_GPIO_TPS65910) += tps65910-gpio.o +obj-$(CONFIG_DA9052_GPIO_ENABLE)+= da9052-gpio.o diff --git a/drivers/gpio/da9052-gpio.c b/drivers/gpio/da9052-gpio.c new file mode 100644 index 0000000..a9c53f2 --- /dev/null +++ b/drivers/gpio/da9052-gpio.c @@ -0,0 +1,731 @@ +/* + * da9052-gpio.c -- GPIO Driver for Dialog DA9052 + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * Author: Dialog Semiconductor Ltd dchen@diasemi.com + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> +#include <linux/syscalls.h> +#include <linux/seq_file.h> +#include <linux/gpio.h> + +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/reg.h> +#include <linux/mfd/da9052/gpio.h> + +#define DRIVER_NAME "da9052-gpio" +static inline struct da9052_gpio_chip *to_da9052_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct da9052_gpio_chip, gp); +} + +void da9052_gpio_notifier(struct da9052_eh_nb *eh_data, unsigned int event) +{ + struct da9052_gpio_chip *gpio = + container_of(eh_data, struct da9052_gpio_chip, eh_data); + kobject_uevent(&gpio->gp.dev->kobj, KOBJ_CHANGE); + printk(KERN_INFO "Event received from GPIO8\n"); +} + +static u8 create_gpio_config_value(u8 gpio_function, u8 gpio_type, u8 gpio_mode) +{ + /* The format is - + function - 2 bits + type - 1 bit + mode - 1 bit */ + return gpio_function | (gpio_type << 2) | (gpio_mode << 3); +} + +static s32 write_default_gpio_values(struct da9052 *da9052) +{ + struct da9052_ssc_msg msg; + u8 created_val = 0; + +#if (DA9052_GPIO_PIN_0 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO0001_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO0_FUNCTION, + DEFAULT_GPIO0_TYPE, DEFAULT_GPIO0_MODE); + msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +#if (DA9052_GPIO_PIN_1 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO0001_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO1_FUNCTION, + DEFAULT_GPIO1_TYPE, DEFAULT_GPIO1_MODE); + created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT; + msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +/* GPIO 2-3*/ +#if (DA9052_GPIO_PIN_2 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO0203_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO2_FUNCTION, + DEFAULT_GPIO2_TYPE, DEFAULT_GPIO2_MODE); + msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +#if (DA9052_GPIO_PIN_3 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO0203_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO3_FUNCTION, + DEFAULT_GPIO3_TYPE, DEFAULT_GPIO3_MODE); + created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT; + msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +/* GPIO 4-5*/ +#if (DA9052_GPIO_PIN_4 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO0405_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO4_FUNCTION, + DEFAULT_GPIO4_TYPE, DEFAULT_GPIO4_MODE); + msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +#if (DA9052_GPIO_PIN_5 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO0405_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO5_FUNCTION, + DEFAULT_GPIO5_TYPE, DEFAULT_GPIO5_MODE); + created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT; + msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +/* GPIO 6-7*/ +#if (DA9052_GPIO_PIN_6 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO0607_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO6_FUNCTION, + DEFAULT_GPIO6_TYPE, DEFAULT_GPIO6_MODE); + msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +#if (DA9052_GPIO_PIN_7 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO0607_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO7_FUNCTION, + DEFAULT_GPIO7_TYPE, DEFAULT_GPIO7_MODE); + created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT; + msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +/* GPIO 8-9*/ +#if (DA9052_GPIO_PIN_8 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO0809_REG; + msg.data = 0; + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO8_FUNCTION, + DEFAULT_GPIO8_TYPE, DEFAULT_GPIO8_MODE); + msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +#if (DA9052_GPIO_PIN_9 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO0809_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO9_FUNCTION, + DEFAULT_GPIO9_TYPE, DEFAULT_GPIO9_MODE); + created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT; + msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +/* GPIO 10-11*/ +#if (DA9052_GPIO_PIN_10 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO1011_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO10_FUNCTION, + DEFAULT_GPIO10_TYPE, DEFAULT_GPIO10_MODE); + msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +#if (DA9052_GPIO_PIN_11 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO1011_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO11_FUNCTION, + DEFAULT_GPIO11_TYPE, DEFAULT_GPIO11_MODE); + created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT; + msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +/* GPIO 12-13*/ +#if (DA9052_GPIO_PIN_12 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO1213_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO12_FUNCTION, + DEFAULT_GPIO12_TYPE, DEFAULT_GPIO12_MODE); + msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +#if (DA9052_GPIO_PIN_13 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO1213_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO13_FUNCTION, + DEFAULT_GPIO13_TYPE, DEFAULT_GPIO13_MODE); + created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT; + msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +/* GPIO 14-15*/ +#if (DA9052_GPIO_PIN_14 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO1415_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO14_FUNCTION, + DEFAULT_GPIO14_TYPE, DEFAULT_GPIO14_MODE); + msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif +#if (DA9052_GPIO_PIN_15 == DA9052_GPIO_CONFIG) + da9052_lock(da9052); + msg.addr = DA9052_GPIO1415_REG; + msg.data = 0; + + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + + created_val = create_gpio_config_value(DEFAULT_GPIO15_FUNCTION, + DEFAULT_GPIO15_TYPE, DEFAULT_GPIO15_MODE); + created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT; + msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE; + msg.data |= created_val; + + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); +#endif + return 0; +} + +s32 da9052_gpio_read_port(struct da9052_gpio_read_write *read_port, + struct da9052 *da9052) +{ + struct da9052_ssc_msg msg; + u8 shift_value = 0; + u8 port_functionality = 0; + msg.addr = (read_port->port_number / 2) + DA9052_GPIO0001_REG; + msg.data = 0; + da9052_lock(da9052); + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); + port_functionality = + (read_port->port_number % 2) ? + ((msg.data & DA9052_GPIO_ODD_PORT_FUNCTIONALITY) >> + DA9052_GPIO_NIBBLE_SHIFT) : + (msg.data & DA9052_GPIO_EVEN_PORT_FUNCTIONALITY); + + if (port_functionality != INPUT) + return DA9052_GPIO_INVALID_PORTNUMBER; + + if (read_port->port_number >= (DA9052_GPIO_MAX_PORTNUMBER)) + return DA9052_GPIO_INVALID_PORTNUMBER; + + if (read_port->port_number < DA9052_GPIO_MAX_PORTS_PER_REGISTER) + msg.addr = DA9052_STATUSC_REG; + else + msg.addr = DA9052_STATUSD_REG; + msg.data = 0; + + da9052_lock(da9052); + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); + + shift_value = msg.data & + (1 << DA9052_GPIO_SHIFT_COUNT(read_port->port_number)); + read_port->read_write_value = (shift_value >> + DA9052_GPIO_SHIFT_COUNT(read_port->port_number)); + + return 0; +} + +s32 da9052_gpio_multiple_read(struct da9052_gpio_multiple_read *multiple_port, + struct da9052 *da9052) +{ + struct da9052_ssc_msg msg[2]; + u8 port_number = 0; + u8 loop_index = 0; + msg[loop_index++].addr = DA9052_STATUSC_REG; + msg[loop_index++].addr = DA9052_STATUSD_REG; + + da9052_lock(da9052); + if (da9052->read_many(da9052, msg, loop_index)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); + loop_index = 0; + for (port_number = 0; port_number < DA9052_GPIO_MAX_PORTS_PER_REGISTER; + port_number++) { + multiple_port->signal_value[port_number] = + msg[loop_index].data & 1; + msg[loop_index].data = msg[loop_index].data >> 1; + } + loop_index++; + for (port_number = DA9052_GPIO_MAX_PORTS_PER_REGISTER; + port_number < DA9052_GPIO_MAX_PORTNUMBER; port_number++) { + multiple_port->signal_value[port_number] = + msg[loop_index].data & 1; + msg[loop_index].data = msg[loop_index].data >> 1; + } + return 0; +} +EXPORT_SYMBOL(da9052_gpio_multiple_read); + +s32 da9052_gpio_write_port(struct da9052_gpio_read_write *write_port, + struct da9052 *da9052) +{ + struct da9052_ssc_msg msg; + u8 port_functionality = 0; + u8 bit_pos = 0; + msg.addr = DA9052_GPIO0001_REG + (write_port->port_number / 2); + msg.data = 0; + + da9052_lock(da9052); + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); + + port_functionality = + (write_port->port_number % 2) ? + ((msg.data & DA9052_GPIO_ODD_PORT_FUNCTIONALITY) >> + DA9052_GPIO_NIBBLE_SHIFT) : + (msg.data & DA9052_GPIO_EVEN_PORT_FUNCTIONALITY); + + if (port_functionality < 2) + return DA9052_GPIO_INVALID_PORTNUMBER; + + bit_pos = (write_port->port_number % 2) ? + DA9052_GPIO_ODD_PORT_WRITE_MODE : + DA9052_GPIO_EVEN_PORT_WRITE_MODE; + + if (write_port->read_write_value) + msg.data = msg.data | bit_pos; + else + msg.data = (msg.data & ~(bit_pos)); + + da9052_lock(da9052); + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); + return 0; +} + +s32 da9052_gpio_configure_port(struct da9052_gpio *gpio_data, + struct da9052 *da9052) +{ + struct da9052_ssc_msg msg; + u8 register_value = 0; + u8 function = 0; + u8 port_functionality = 0; + msg.addr = (gpio_data->port_number / 2) + DA9052_GPIO0001_REG; + msg.data = 0; + + da9052_lock(da9052); + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); + + port_functionality = + (gpio_data->port_number % 2) ? + ((msg.data & DA9052_GPIO_ODD_PORT_FUNCTIONALITY) >> + DA9052_GPIO_NIBBLE_SHIFT) : + (msg.data & DA9052_GPIO_EVEN_PORT_FUNCTIONALITY); + if (port_functionality < INPUT) + return DA9052_GPIO_INVALID_PORTNUMBER; + if (gpio_data->gpio_config.input.type > ACTIVE_HIGH) + return DA9052_GPIO_INVALID_TYPE; + if (gpio_data->gpio_config.input.mode > DEBOUNCING_ON) + return DA9052_GPIO_INVALID_MODE; + function = gpio_data->gpio_function; + switch (function) { + case INPUT: + register_value = create_gpio_config_value(function, + gpio_data->gpio_config.input.type, + gpio_data->gpio_config.input.mode); + break; + case OUTPUT_OPENDRAIN: + case OUTPUT_PUSHPULL: + register_value = create_gpio_config_value(function, + gpio_data->gpio_config.input.type, + gpio_data->gpio_config.input.mode); + break; + default: + return DA9052_GPIO_INVALID_FUNCTION; + break; + } + + if (gpio_data->port_number % 2) { + msg.data = (msg.data & ~(DA9052_GPIO_MASK_UPPER_NIBBLE)) | + (register_value << DA9052_GPIO_NIBBLE_SHIFT); + } else { + msg.data = (msg.data & ~(DA9052_GPIO_MASK_LOWER_NIBBLE)) | + register_value; + } + da9052_lock(da9052); + if (da9052->write(da9052, &msg)) { + da9052_unlock(da9052); + return -EIO; + } + da9052_unlock(da9052); + return 0; +} + +static s32 da9052_gpio_read(struct gpio_chip *gc, u32 offset) +{ + struct da9052_gpio_chip *gpio; + gpio = to_da9052_gpio(gc); + gpio->read_write.port_number = offset; + da9052_gpio_read_port(&gpio->read_write, gpio->da9052); + return gpio->read_write.read_write_value; +} + +static void da9052_gpio_write(struct gpio_chip *gc, u32 offset, s32 value) +{ + struct da9052_gpio_chip *gpio; + gpio = to_da9052_gpio(gc); + gpio->read_write.port_number = offset; + gpio->read_write.read_write_value = (u8)value; + da9052_gpio_write_port(&gpio->read_write, gpio->da9052); +} + +static s32 da9052_gpio_ip(struct gpio_chip *gc, u32 offset) +{ + struct da9052_gpio_chip *gpio; + gpio = to_da9052_gpio(gc); + gpio->gpio.gpio_function = INPUT; + gpio->gpio.gpio_config.input.type = ACTIVE_LOW; + gpio->gpio.gpio_config.input.mode = DEBOUNCING_ON; + gpio->gpio.port_number = offset; + return da9052_gpio_configure_port(&gpio->gpio, gpio->da9052); +} + +static s32 da9052_gpio_op(struct gpio_chip *gc, u32 offset, s32 value) +{ + struct da9052_gpio_chip *gpio; + gpio = to_da9052_gpio(gc); + gpio->gpio.gpio_function = OUTPUT_PUSHPULL; + gpio->gpio.gpio_config.output.type = SUPPLY_VDD_IO1; + gpio->gpio.gpio_config.output.mode = value; + gpio->gpio.port_number = offset; + return da9052_gpio_configure_port(&gpio->gpio, gpio->da9052); +} + +static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset) +{ + struct da9052_gpio_chip *gpio; + gpio = to_da9052_gpio(gc); + kobject_uevent(&gpio->gp.dev->kobj, KOBJ_CHANGE); + printk(KERN_INFO"gpio->gp.base +offset = %d\n", gpio->gp.base + offset); + printk(KERN_INFO"Test1\n\n"); + return gpio->gp.base + offset; +} + +static int __devinit da9052_gpio_probe(struct platform_device *pdev) +{ + struct da9052_gpio_chip *gpio; + struct da9052_platform_data *pdata = (pdev->dev.platform_data); + s32 ret; + gpio = kzalloc(sizeof(*gpio), GFP_KERNEL); + if (gpio == NULL) + return -ENOMEM; + gpio->da9052 = dev_get_drvdata(pdev->dev.parent); + gpio->gp.get = da9052_gpio_read; + gpio->gp.direction_input = da9052_gpio_ip; + gpio->gp.direction_output = da9052_gpio_op; + gpio->gp.set = da9052_gpio_write; + + gpio->gp.base = pdata->gpio_base; + gpio->gp.ngpio = DA9052_GPIO_MAX_PORTNUMBER; + gpio->gp.can_sleep = 1; + gpio->gp.dev = &pdev->dev; + gpio->gp.owner = THIS_MODULE; + gpio->gp.label = "da9052-gpio"; + gpio->gp.to_irq = da9052_gpio_to_irq; + + gpio->eh_data.eve_type = GPI8_EVE; + gpio->eh_data.call_back = &da9052_gpio_notifier; + ret = gpio->da9052->register_event_notifier(gpio->da9052, + &gpio->eh_data); + + ret = write_default_gpio_values(gpio->da9052); + if (ret < 0) { + dev_err(&pdev->dev, "GPIO initial config failed, %d\n", + ret); + goto ret; + } + + ret = gpiochip_add(&gpio->gp); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", + ret); + goto ret; + } + platform_set_drvdata(pdev, gpio); + + return ret; + +ret: + kfree(gpio); + return ret; + +} + +static int __devexit da9052_gpio_remove(struct platform_device *pdev) +{ + struct da9052_gpio_chip *gpio = platform_get_drvdata(pdev); + int ret; + + gpio->da9052->unregister_event_notifier + (gpio->da9052, &gpio->eh_data); + ret = gpiochip_remove(&gpio->gp); + if (ret == 0) + kfree(gpio); + return 0; +} + +static struct platform_driver da9052_gpio_driver = { + .probe = da9052_gpio_probe, + .remove = __devexit_p(da9052_gpio_remove), + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init da9052_gpio_init(void) +{ + return platform_driver_register(&da9052_gpio_driver); +} + +static void __exit da9052_gpio_exit(void) +{ + return platform_driver_unregister(&da9052_gpio_driver); +} + +module_init(da9052_gpio_init); +module_exit(da9052_gpio_exit); + +MODULE_AUTHOR("David Dajun Chen dchen@diasemi.com"); +MODULE_DESCRIPTION("DA9052 GPIO Device Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRIVER_NAME);
On 06/10/2011 04:50 AM, Somebody in the thread at some point said:
Hi -
Just some small comments...
It's worth running ./scripts/checkpatch.pl if you didn't already.
+#define DRIVER_NAME "da9052-gpio" +static inline struct da9052_gpio_chip *to_da9052_gpio(struct gpio_chip *chip)
Don't need inline.
- printk(KERN_INFO "Event received from GPIO8\n");
You can better use pr_info() or dev_info() if you have a struct device * lying around.
+}
+static u8 create_gpio_config_value(u8 gpio_function, u8 gpio_type, u8 gpio_mode)
Consider separating return type and attributes on different line
static u8 create_gpio_config_value(...
lets you do a nice trick with grep ^functionname to find definition.
+{
- /* The format is -
function - 2 bits
type - 1 bit
mode - 1 bit */
Big comment style needs to be
/* * blah * blah */
- return gpio_function | (gpio_type<< 2) | (gpio_mode<< 3);
+}
+static s32 write_default_gpio_values(struct da9052 *da9052) +{
- struct da9052_ssc_msg msg;
- u8 created_val = 0;
+#if (DA9052_GPIO_PIN_0 == DA9052_GPIO_CONFIG)
What's the story about this #if scheme? There's a lot of duplicated code? Even if it's the right way need to explain why in the patch commitlog due to anti-#if sentimenet out there.
- da9052_lock(da9052);
- msg.addr = DA9052_GPIO0001_REG;
- msg.data = 0;
- if (da9052->read(da9052,&msg)) {
da9052_unlock(da9052);
return -EIO;
- }
It's less error-prone to handle exit from inside a locked region with goto. Eg,
int ret = 0;
...
lock();
...
if (bad) { ret = -EIO; goto bail; }
...
bail: unlock();
return ret;
+s32 da9052_gpio_read_port(struct da9052_gpio_read_write *read_port,
struct da9052 *da9052)
+{
- struct da9052_ssc_msg msg;
- u8 shift_value = 0;
- u8 port_functionality = 0;
It's normal to have a black line separate the local vars from the function body, more than one function needs it.
- msg.addr = (read_port->port_number / 2) + DA9052_GPIO0001_REG;
- msg.data = 0;
- da9052_lock(da9052);
- if (da9052->read(da9052,&msg)) {
da9052_unlock(da9052);
return -EIO;
- }
Again goto to a common unlock exit point is better / less code.
- da9052_unlock(da9052);
- port_functionality =
(read_port->port_number % 2) ?
((msg.data& DA9052_GPIO_ODD_PORT_FUNCTIONALITY)>>
DA9052_GPIO_NIBBLE_SHIFT) :
(msg.data& DA9052_GPIO_EVEN_PORT_FUNCTIONALITY);
- if (port_functionality != INPUT)
return DA9052_GPIO_INVALID_PORTNUMBER;
- if (read_port->port_number>= (DA9052_GPIO_MAX_PORTNUMBER))
Don't need parenthesis around the constant... if it's a compound expression put the parenthesis at the definition of the constant not at the usage.
- if (da9052->read_many(da9052, msg, loop_index)) {
Is this not better called "read_multiple"?
msg.data = msg.data | bit_pos;
You can use |= to simplify.
- else
msg.data = (msg.data& ~(bit_pos));
Outer parenthesis can go away.
- port_functionality =
(gpio_data->port_number % 2) ?
This can go on the same line as the =?
((msg.data& DA9052_GPIO_ODD_PORT_FUNCTIONALITY)>>
DA9052_GPIO_NIBBLE_SHIFT) :
(msg.data& DA9052_GPIO_EVEN_PORT_FUNCTIONALITY);
- if (port_functionality< INPUT)
return DA9052_GPIO_INVALID_PORTNUMBER;
- if (gpio_data->gpio_config.input.type> ACTIVE_HIGH)
return DA9052_GPIO_INVALID_TYPE;
- if (gpio_data->gpio_config.input.mode> DEBOUNCING_ON)
return DA9052_GPIO_INVALID_MODE;
- function = gpio_data->gpio_function;
- switch (function) {
- case INPUT:
register_value = create_gpio_config_value(function,
gpio_data->gpio_config.input.type,
gpio_data->gpio_config.input.mode);
- break;
- case OUTPUT_OPENDRAIN:
- case OUTPUT_PUSHPULL:
register_value = create_gpio_config_value(function,
gpio_data->gpio_config.input.type,
gpio_data->gpio_config.input.mode);
- break;
breaks need to be tabbed in one more everywhere.
+static s32 da9052_gpio_read(struct gpio_chip *gc, u32 offset) +{
- struct da9052_gpio_chip *gpio;
- gpio = to_da9052_gpio(gc);
- gpio->read_write.port_number = offset;
Just a space, not tabs before =
-Andy
On Friday 10 June 2011, Ying-Chun Liu (PaulLiu) wrote:
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9052 gpio driver from Dialog. Modify Kconfig/Makefile for DA9052 gpio driver.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org
drivers/gpio/Kconfig | 7 + drivers/gpio/Makefile | 1 + drivers/gpio/da9052-gpio.c | 731 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 739 insertions(+), 0 deletions(-) create mode 100644 drivers/gpio/da9052-gpio.c
The name should now be 'gpio-da9052.c', not da9052-gpio.c
+#if (DA9052_GPIO_PIN_0 == DA9052_GPIO_CONFIG)
- da9052_lock(da9052);
- msg.addr = DA9052_GPIO0001_REG;
- msg.data = 0;
- if (da9052->read(da9052, &msg)) {
da9052_unlock(da9052);
return -EIO;
- }
- created_val = create_gpio_config_value(DEFAULT_GPIO0_FUNCTION,
DEFAULT_GPIO0_TYPE, DEFAULT_GPIO0_MODE);
- msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE;
- msg.data |= created_val;
- if (da9052->write(da9052, &msg)) {
da9052_unlock(da9052);
return -EIO;
- }
- da9052_unlock(da9052);
+#endif
Why the ifdef? All configuration needs to happen at runtime, not at compile-time if you want to run on multiple different configurations.
You are duplicating this for a number of pins. Please make this an separate function that takes arguments depending on the configuration to avoid having the same code multiple times.
+s32 da9052_gpio_multiple_read(struct da9052_gpio_multiple_read *multiple_port,
struct da9052 *da9052)
+{
+} +EXPORT_SYMBOL(da9052_gpio_multiple_read);
Why does the gpio driver export functions? It should be self-contained AFAICT.
Arnd
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9052 ADC driver from Dialog. Modify Kconfig/Makefile for DA9052 ADC driver.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org --- drivers/hwmon/Kconfig | 10 + drivers/hwmon/Makefile | 1 + drivers/hwmon/da9052-adc.c | 644 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 655 insertions(+), 0 deletions(-) create mode 100644 drivers/hwmon/da9052-adc.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 16db83c..ad652dd 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -39,6 +39,16 @@ config HWMON_DEBUG_CHIP
comment "Native drivers"
+config SENSORS_DA9052 + tristate "Dialog DA9052 HWMon" + depends on PMIC_DIALOG + help + Say y here to support the ADC found on Dialog Semiconductor DA9052 + PMIC. + + This driver can also be built as a module. If so, the module + will be called da9052-adc. + config SENSORS_ABITUGURU tristate "Abit uGuru (rev 1 & 2)" depends on X86 && DMI && EXPERIMENTAL diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 28061cf..e640ff8 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -118,6 +118,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o +obj-$(CONFIG_SENSORS_DA9052) += da9052-adc.o
# PMBus drivers obj-$(CONFIG_PMBUS) += pmbus_core.o diff --git a/drivers/hwmon/da9052-adc.c b/drivers/hwmon/da9052-adc.c new file mode 100644 index 0000000..57985c2 --- /dev/null +++ b/drivers/hwmon/da9052-adc.c @@ -0,0 +1,644 @@ +/* + * da9052-adc.c -- ADC Driver for Dialog DA9052 + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * Author: Dialog Semiconductor Ltd dchen@diasemi.com + * + * 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. + * + */ +#include <linux/platform_device.h> +#include <linux/hwmon-sysfs.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/hwmon.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/reg.h> +#include <linux/mfd/da9052/adc.h> + +#define DRIVER_NAME "da9052-adc" + +static const char * const input_names[] = { + [DA9052_ADC_VDDOUT] = "VDDOUT", + [DA9052_ADC_ICH] = "CHARGING CURRENT", + [DA9052_ADC_TBAT] = "BATTERY TEMP", + [DA9052_ADC_VBAT] = "BATTERY VOLTAGE", + [DA9052_ADC_ADCIN4] = "ADC INPUT 4", + [DA9052_ADC_ADCIN5] = "ADC INPUT 5", + [DA9052_ADC_ADCIN6] = "ADC INPUT 6", + [DA9052_ADC_TSI] = "TSI", + [DA9052_ADC_TJUNC] = "BATTERY JUNCTION TEMP", + [DA9052_ADC_VBBAT] = "BACK-UP BATTERY TEMP", +}; + + +int da9052_manual_read(struct da9052 *da9052, + unsigned char channel) +{ + unsigned char man_timeout_cnt = DA9052_ADC_MAX_MANCONV_RETRY_COUNT; + struct da9052_ssc_msg msg; + unsigned short calc_data; + unsigned int ret; + u16 data = 0; + + msg.addr = DA9052_ADCMAN_REG; + msg.data = channel; + msg.data = (msg.data | DA9052_ADCMAN_MANCONV); + + mutex_lock(&da9052->manconv_lock); + da9052_lock(da9052); + + ret = da9052->write(da9052, &msg); + if (ret) + goto err_ssc_comm; + da9052_unlock(da9052); + + /* Wait for the event */ + do { + msg.addr = DA9052_ADCCONT_REG; + msg.data = 0; + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret) + goto err_ssc_comm; + da9052_unlock(da9052); + + if (DA9052_ADCCONT_ADCMODE & msg.data) + msleep(1); + else + msleep(10); + + msg.addr = DA9052_ADCMAN_REG; + msg.data = 0; + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret) + goto err_ssc_comm; + da9052_unlock(da9052); + + /* Counter to avoid endless while loop */ + man_timeout_cnt--; + if (man_timeout_cnt == 1) { + if (!(msg.data & DA9052_ADCMAN_MANCONV)) + break; + else + goto err_ssc_comm; + } + /* Wait until the MAN_CONV bit is cleared to zero */ + } while (msg.data & DA9052_ADCMAN_MANCONV); + + msg.addr = DA9052_ADCRESH_REG; + msg.data = 0; + + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret) + goto err_ssc_comm; + da9052_unlock(da9052); + + calc_data = (unsigned short)msg.data; + data = (calc_data << 2); + + msg.addr = DA9052_ADCRESL_REG; + msg.data = 0; + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret) + goto err_ssc_comm; + da9052_unlock(da9052); + + /* Clear first 14 bits before ORing */ + calc_data = (unsigned short)msg.data & 0x0003; + data |= calc_data; + + mutex_unlock(&da9052->manconv_lock); + + return data; +err_ssc_comm: + mutex_unlock(&da9052->manconv_lock); + da9052_unlock(da9052); + return -EIO; +} +EXPORT_SYMBOL(da9052_manual_read); + +int da9052_read_tjunc(struct da9052 *da9052, char *buf) +{ + struct da9052_ssc_msg msg; + unsigned char temp; + int ret; + + msg.addr = DA9052_TJUNCRES_REG; + msg.data = 0; + + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret) + goto err_ssc_comm; + + temp = msg.data; + + msg.addr = DA9052_TOFFSET_REG; + msg.data = 0; + ret = da9052->read(da9052, &msg); + if (ret) + goto err_ssc_comm; + da9052_unlock(da9052); + /* Calculate Junction temperature */ + temp = (temp - msg.data); + *buf = temp; + return 0; +err_ssc_comm: + da9052_unlock(da9052); + return -EIO; +} +EXPORT_SYMBOL(da9052_read_tjunc); + +int da9052_read_tbat_ich(struct da9052 *da9052, char *data, int channel_no) +{ + struct da9052_ssc_msg msg; + int ret; + + /* Read TBAT conversion result */ + switch (channel_no) { + case DA9052_ADC_TBAT: + msg.addr = DA9052_TBATRES_REG; + break; + case DA9052_ADC_ICH: + msg.addr = DA9052_ICHGAV_REG; + break; + default: + return -EINVAL; + } + msg.data = 0; + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret) + goto err_ssc_comm; + da9052_unlock(da9052); + *data = msg.data; + printk(KERN_INFO"msg.data 1= %d\n", msg.data); + msg.data = 28; + da9052_lock(da9052); + ret = da9052->write(da9052, &msg); + if (ret) + goto err_ssc_comm; + da9052_unlock(da9052); + printk(KERN_INFO"msg.data2 = %d\n", msg.data); + msg.data = 0; + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret) + goto err_ssc_comm; + da9052_unlock(da9052); + printk(KERN_INFO"msg.data3 = %d\n", msg.data); + return 0; + +err_ssc_comm: + da9052_unlock(da9052); + return ret; +} +EXPORT_SYMBOL(da9052_read_tbat_ich); + +static int da9052_start_adc(struct da9052 *da9052, unsigned channel) +{ + struct da9052_ssc_msg msg; + int ret; + + msg.addr = DA9052_ADCCONT_REG; + msg.data = 0; + + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret != 0) + goto err_ssc_comm; + + if (channel == DA9052_ADC_VDDOUT) + msg.data = (msg.data | DA9052_ADCCONT_AUTOVDDEN); + else if (channel == DA9052_ADC_ADCIN4) + msg.data = (msg.data | DA9052_ADCCONT_AUTOAD4EN); + else if (channel == DA9052_ADC_ADCIN5) + msg.data = (msg.data | DA9052_ADCCONT_AUTOAD5EN); + else if (channel == DA9052_ADC_ADCIN6) + msg.data = (msg.data | DA9052_ADCCONT_AUTOAD6EN); + else + return -EINVAL; + + ret = da9052->write(da9052, &msg); + if (ret != 0) + goto err_ssc_comm; + da9052_unlock(da9052); + return 0; + +err_ssc_comm: + da9052_unlock(da9052); + return -EIO; +} + +static int da9052_stop_adc(struct da9052 *da9052, unsigned channel) +{ + int ret; + struct da9052_ssc_msg msg; + + msg.addr = DA9052_ADCCONT_REG; + msg.data = 0; + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret != 0) + goto err_ssc_comm; + + if (channel == DA9052_ADC_VDDOUT) + msg.data = (msg.data & ~(DA9052_ADCCONT_AUTOVDDEN)); + else if (channel == DA9052_ADC_ADCIN4) + msg.data = (msg.data & ~(DA9052_ADCCONT_AUTOAD4EN)); + else if (channel == DA9052_ADC_ADCIN5) + msg.data = (msg.data & ~(DA9052_ADCCONT_AUTOAD5EN)); + else if (channel == DA9052_ADC_ADCIN6) + msg.data = (msg.data & ~(DA9052_ADCCONT_AUTOAD6EN)); + else + return -EINVAL; + + ret = da9052->write(da9052, &msg); + if (ret != 0) + goto err_ssc_comm; + da9052_unlock(da9052); + + return 0; +err_ssc_comm: + da9052_unlock(da9052); + return -EIO; +} + +static ssize_t da9052_adc_read_start_stop(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct da9052_adc_priv *priv = platform_get_drvdata(pdev); + struct da9052_ssc_msg msg; + int channel = to_sensor_dev_attr(devattr)->index; + int ret; + + ret = da9052_start_adc(priv->da9052, channel); + if (ret < 0) + return ret; + + /* Read the ADC converted value */ + switch (channel) { + case DA9052_ADC_VDDOUT: + msg.addr = DA9052_VDDRES_REG; + break; +#if (DA9052_ADC_CONF_ADC4 == 1) + case DA9052_ADC_ADCIN4: + msg.addr = DA9052_ADCIN4RES_REG; + break; +#endif +#if (DA9052_ADC_CONF_ADC5 == 1) + case DA9052_ADC_ADCIN5: + msg.addr = DA9052_ADCIN5RES_REG; + break; +#endif +#if (DA9052_ADC_CONF_ADC6 == 1) + case DA9052_ADC_ADCIN6: + msg.addr = DA9052_ADCIN6RES_REG; + break; +#endif + default: + return -EINVAL; + } + msg.data = 0; + da9052_lock(priv->da9052); + ret = priv->da9052->read(priv->da9052, &msg); + if (ret != 0) + goto err_ssc_comm; + da9052_unlock(priv->da9052); + + ret = da9052_stop_adc(priv->da9052, channel); + if (ret < 0) + return ret; + + return sprintf(buf, "%u\n", msg.data); + +err_ssc_comm: + da9052_unlock(priv->da9052); + return ret; +} + +static ssize_t da9052_adc_read_ich(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct da9052_adc_priv *priv = platform_get_drvdata(pdev); + int ret; + + ret = da9052_read_tbat_ich(priv->da9052, buf, DA9052_ADC_ICH); + if (ret < 0) + return ret; + return sprintf(buf, "%u\n", *buf); +} + +static ssize_t da9052_adc_read_tbat(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct da9052_adc_priv *priv = platform_get_drvdata(pdev); + int ret; + + ret = da9052_read_tbat_ich(priv->da9052, buf, DA9052_ADC_TBAT); + if (ret < 0) + return ret; + return sprintf(buf, "%u\n", *buf); +} + +static ssize_t da9052_adc_read_vbat(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct da9052_adc_priv *priv = platform_get_drvdata(pdev); + s32 ret; + + ret = da9052_manual_read(priv->da9052, DA9052_ADC_VBAT); + if (ret < 0) + return ret; + return sprintf(buf, "%u\n", ret); +} + +static ssize_t da9052_adc_read_tjunc(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct da9052_adc_priv *priv = platform_get_drvdata(pdev); + int ret; + ret = da9052_read_tjunc(priv->da9052, buf); + if (ret < 0) + return ret; + return sprintf(buf, "%u\n", *buf); +} + +static ssize_t da9052_adc_read_vbbat(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct da9052_adc_priv *priv = platform_get_drvdata(pdev); + s32 ret; + + ret = da9052_manual_read(priv->da9052, DA9052_ADC_VBBAT); + if (ret < 0) + return ret; + return sprintf(buf, "%u\n", ret); +} + +static int da9052_adc_hw_init(struct da9052 *da9052) +{ + struct da9052_ssc_msg msg; + int ret; + + /* ADC channel 4 and 5 are by default enabled */ +#if (DA9052_ADC_CONF_ADC4 == 1) + msg.addr = DA9052_GPIO0001_REG; + msg.data = 0; + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret) + goto err_ssc_comm; + + msg.data = (msg.data & ~(DA9052_GPIO0001_GPIO0PIN)); + ret = da9052->write(da9052, &msg); + if (ret != 0) + goto err_ssc_comm; + da9052_unlock(da9052); +#endif + +#if (DA9052_ADC_CONF_ADC5 == 1) + msg.addr = DA9052_GPIO0001_REG; + msg.data = 0; + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret) + goto err_ssc_comm; + + msg.data = (msg.data & ~(DA9052_GPIO0001_GPIO0PIN)); + ret = da9052->write(da9052, &msg); + if (ret != 0) + goto err_ssc_comm; + da9052_unlock(da9052); +#endif + +#if (DA9052_ADC_CONF_ADC6 == 1) + msg.addr = DA9052_GPIO0203_REG; + msg.data = 0; + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret) + goto err_ssc_comm; + + msg.data = (msg.data & ~(DA9052_GPIO0203_GPIO2PIN)); + ret = da9052->write(da9052, &msg); + if (ret != 0) + goto err_ssc_comm; + da9052_unlock(da9052); +#endif +#if 0 + /* By default configure the Measurement sequence interval to 10ms */ + msg.addr = DA9052_ADCCONT_REG; + msg.data = 0; + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret != 0) + goto err_ssc_comm; + + /* Set the ADC MODE bit for 10msec sampling timer */ + msg.data = (msg.data & ~(DA9052_ADCCONT_ADCMODE)); + ret = da9052->write(da9052, &msg); + if (ret != 0) + goto err_ssc_comm; + da9052_unlock(da9052); +#endif + return 0; +err_ssc_comm: + da9052_unlock(da9052); + return -EIO; +} + +static ssize_t da9052_adc_show_name(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "da9052-adc\n"); +} + +static ssize_t show_label(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int channel = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%s\n", input_names[channel]); +} +#define DA9052_ADC_CHANNELS(id, name) \ + static SENSOR_DEVICE_ATTR(in##id##_label, S_IRUGO, show_label, \ + NULL, name) + +DA9052_ADC_CHANNELS(0, DA9052_ADC_VDDOUT); +DA9052_ADC_CHANNELS(1, DA9052_ADC_ICH); +DA9052_ADC_CHANNELS(2, DA9052_ADC_TBAT); +DA9052_ADC_CHANNELS(3, DA9052_ADC_VBAT); +#if (DA9052_ADC_CONF_ADC4 == 1) +DA9052_ADC_CHANNELS(4, DA9052_ADC_ADCIN4); +#endif +#if (DA9052_ADC_CONF_ADC5 == 1) +DA9052_ADC_CHANNELS(5, DA9052_ADC_ADCIN5); +#endif +#if (DA9052_ADC_CONF_ADC6 == 1) +DA9052_ADC_CHANNELS(6, DA9052_ADC_ADCIN6); +#endif +DA9052_ADC_CHANNELS(7, DA9052_ADC_TSI); +DA9052_ADC_CHANNELS(8, DA9052_ADC_TJUNC); +DA9052_ADC_CHANNELS(9, DA9052_ADC_VBBAT); + + +static DEVICE_ATTR(name, S_IRUGO, da9052_adc_show_name, NULL); +static SENSOR_DEVICE_ATTR(read_vddout, S_IRUGO, + da9052_adc_read_start_stop, NULL, + DA9052_ADC_VDDOUT); +static SENSOR_DEVICE_ATTR(read_ich, S_IRUGO, da9052_adc_read_ich, NULL, + DA9052_ADC_ICH); +static SENSOR_DEVICE_ATTR(read_tbat, S_IRUGO, da9052_adc_read_tbat, NULL, + DA9052_ADC_TBAT); +static SENSOR_DEVICE_ATTR(read_vbat, S_IRUGO, da9052_adc_read_vbat, NULL, + DA9052_ADC_VBAT); +#if (DA9052_ADC_CONF_ADC4 == 1) +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, da9052_adc_read_start_stop, NULL, + DA9052_ADC_ADCIN4); +#endif +#if (DA9052_ADC_CONF_ADC5 == 1) +static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, da9052_adc_read_start_stop, NULL, + DA9052_ADC_ADCIN5); +#endif +#if (DA9052_ADC_CONF_ADC6 == 1) +static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, da9052_adc_read_start_stop, NULL, + DA9052_ADC_ADCIN6); +#endif +static SENSOR_DEVICE_ATTR(read_tjunc, S_IRUGO, da9052_adc_read_tjunc, NULL, + DA9052_ADC_TJUNC); +static SENSOR_DEVICE_ATTR(read_vbbat, S_IRUGO, da9052_adc_read_vbbat, NULL, + DA9052_ADC_VBBAT); + +static struct attribute *da9052_attr[] = { + &dev_attr_name.attr, + &sensor_dev_attr_read_vddout.dev_attr.attr, + &sensor_dev_attr_in0_label.dev_attr.attr, + &sensor_dev_attr_read_ich.dev_attr.attr, + &sensor_dev_attr_in1_label.dev_attr.attr, + &sensor_dev_attr_read_tbat.dev_attr.attr, + &sensor_dev_attr_in2_label.dev_attr.attr, + &sensor_dev_attr_read_vbat.dev_attr.attr, + &sensor_dev_attr_in3_label.dev_attr.attr, +#if (DA9052_ADC_CONF_ADC4 == 1) + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_label.dev_attr.attr, +#endif +#if (DA9052_ADC_CONF_ADC5 == 1) + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in5_label.dev_attr.attr, +#endif +#if (DA9052_ADC_CONF_ADC6 == 1) + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in6_label.dev_attr.attr, +#endif + &sensor_dev_attr_in7_label.dev_attr.attr, + &sensor_dev_attr_read_tjunc.dev_attr.attr, + &sensor_dev_attr_in8_label.dev_attr.attr, + &sensor_dev_attr_read_vbbat.dev_attr.attr, + &sensor_dev_attr_in9_label.dev_attr.attr, + NULL +}; + +static const struct attribute_group da9052_group = { + .attrs = da9052_attr, +}; + +static int __init da9052_adc_probe(struct platform_device *pdev) +{ + struct da9052_adc_priv *priv; + int ret; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->da9052 = dev_get_drvdata(pdev->dev.parent); + + platform_set_drvdata(pdev, priv); + + /* Register sysfs hooks */ + ret = sysfs_create_group(&pdev->dev.kobj, &da9052_group); + if (ret) + goto out_err_create1; + + priv->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(priv->hwmon_dev)) { + ret = PTR_ERR(priv->hwmon_dev); + goto out_err_create2; + } + /* Initializes the hardware for ADC module */ + da9052_adc_hw_init(priv->da9052); + + /* Initialize mutex required for ADC Manual read */ + mutex_init(&priv->da9052->manconv_lock); + + return 0; + +out_err_create2: + sysfs_remove_group(&pdev->dev.kobj, &da9052_group); +out_err_create1: + platform_set_drvdata(pdev, NULL); + kfree(priv); + + return ret; +} + +static int __devexit da9052_adc_remove(struct platform_device *pdev) +{ + struct da9052_adc_priv *priv = platform_get_drvdata(pdev); + + mutex_destroy(&priv->da9052->manconv_lock); + + hwmon_device_unregister(priv->hwmon_dev); + + sysfs_remove_group(&pdev->dev.kobj, &da9052_group); + + platform_set_drvdata(pdev, NULL); + kfree(priv); + + return 0; +} + +static struct platform_driver da9052_adc_driver = { + .remove = __devexit_p(da9052_adc_remove), + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + }, +}; + +static int __init da9052_adc_init(void) +{ + return platform_driver_probe(&da9052_adc_driver, da9052_adc_probe); +} +module_init(da9052_adc_init); + +static void __exit da9052_adc_exit(void) +{ + platform_driver_unregister(&da9052_adc_driver); +} +module_exit(da9052_adc_exit); + +MODULE_AUTHOR("David Dajun Chen dchen@diasemi.com"); +MODULE_DESCRIPTION("DA9052 ADC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME);
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9052 TSI/misc input driver from Dialog. Modify Kconfig/Makefile for DA9052 TSI/misc input driver.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org --- drivers/input/misc/Kconfig | 10 + drivers/input/misc/Makefile | 1 + drivers/input/misc/da9052_onkey.c | 133 ++ drivers/input/touchscreen/Kconfig | 7 + drivers/input/touchscreen/Makefile | 2 + drivers/input/touchscreen/da9052_tsi.c | 1446 ++++++++++++++++++++++ drivers/input/touchscreen/da9052_tsi_calibrate.c | 107 ++ drivers/input/touchscreen/da9052_tsi_filter.c | 489 ++++++++ 8 files changed, 2195 insertions(+), 0 deletions(-) create mode 100644 drivers/input/misc/da9052_onkey.c create mode 100644 drivers/input/touchscreen/da9052_tsi.c create mode 100644 drivers/input/touchscreen/da9052_tsi_calibrate.c create mode 100644 drivers/input/touchscreen/da9052_tsi_filter.c
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 45dc6aa..6fb3607 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -478,4 +478,14 @@ config INPUT_XEN_KBDDEV_FRONTEND To compile this driver as a module, choose M here: the module will be called xen-kbdfront.
+config INPUT_DA9052_ONKEY + tristate "Dialog DA9052 Onkey" + depends on PMIC_DIALOG + help + Support the ONKEY of Dialog DA9052 PMICs as an input device + reporting power button status. + + To compile this driver as a module, choose M here: the module + will be called da9052_onkey. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 38efb2c..4caa60c 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -45,4 +45,5 @@ obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o +obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c new file mode 100644 index 0000000..295b200 --- /dev/null +++ b/drivers/input/misc/da9052_onkey.c @@ -0,0 +1,133 @@ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/platform_device.h> + +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/reg.h> + +#define DRIVER_NAME "da9052-onkey" + +struct da9052_onkey_data { + struct da9052 *da9052; + struct da9052_eh_nb eh_data; + struct input_dev *input; +}; + +static void da9052_onkey_report_event(struct da9052_eh_nb *eh_data, + unsigned int event) +{ + struct da9052_onkey_data *da9052_onkey = + container_of(eh_data, struct da9052_onkey_data, eh_data); + struct da9052_ssc_msg msg; + unsigned int ret; + + /* Read the Evnet Register */ + msg.addr = DA9052_EVENTB_REG; + da9052_lock(da9052_onkey->da9052); + ret = da9052_onkey->da9052->read(da9052_onkey->da9052, &msg); + if (ret) { + da9052_unlock(da9052_onkey->da9052); + return; + } + da9052_unlock(da9052_onkey->da9052); + msg.data = msg.data & DA9052_EVENTB_ENONKEY; + + input_report_key(da9052_onkey->input, KEY_POWER, msg.data); + input_sync(da9052_onkey->input); + printk(KERN_INFO "DA9052 ONKEY EVENT REPORTED\n"); +} + +static int __devinit da9052_onkey_probe(struct platform_device *pdev) +{ + struct da9052_onkey_data *da9052_onkey; + int error; + + da9052_onkey = kzalloc(sizeof(*da9052_onkey), GFP_KERNEL); + da9052_onkey->input = input_allocate_device(); + if (!da9052_onkey->input) { + dev_err(&pdev->dev, "failed to allocate data device\n"); + error = -ENOMEM; + goto fail1; + } + da9052_onkey->da9052 = dev_get_drvdata(pdev->dev.parent); + + if (!da9052_onkey->input) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + error = -ENOMEM; + goto fail2; + } + + da9052_onkey->input->evbit[0] = BIT_MASK(EV_KEY); + da9052_onkey->input->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); + da9052_onkey->input->name = "da9052-onkey"; + da9052_onkey->input->phys = "da9052-onkey/input0"; + da9052_onkey->input->dev.parent = &pdev->dev; + + /* Set the EH structure */ + da9052_onkey->eh_data.eve_type = ONKEY_EVE; + da9052_onkey->eh_data.call_back = &da9052_onkey_report_event; + error = da9052_onkey->da9052->register_event_notifier( + da9052_onkey->da9052, + &da9052_onkey->eh_data); + if (error) + goto fail2; + + error = input_register_device(da9052_onkey->input); + if (error) { + dev_err(&pdev->dev, "Unable to register input " + "device,error: %d\n", error); + goto fail3; + } + + platform_set_drvdata(pdev, da9052_onkey); + + return 0; + +fail3: + da9052_onkey->da9052->unregister_event_notifier(da9052_onkey->da9052, + &da9052_onkey->eh_data); +fail2: + input_free_device(da9052_onkey->input); +fail1: + kfree(da9052_onkey); + return error; +} + +static int __devexit da9052_onkey_remove(struct platform_device *pdev) +{ + struct da9052_onkey_data *da9052_onkey = pdev->dev.platform_data; + da9052_onkey->da9052->unregister_event_notifier(da9052_onkey->da9052, + &da9052_onkey->eh_data); + input_unregister_device(da9052_onkey->input); + kfree(da9052_onkey); + + return 0; +} + +static struct platform_driver da9052_onkey_driver = { + .probe = da9052_onkey_probe, + .remove = __devexit_p(da9052_onkey_remove), + .driver = { + .name = "da9052-onkey", + .owner = THIS_MODULE, + } +}; + +static int __init da9052_onkey_init(void) +{ + return platform_driver_register(&da9052_onkey_driver); +} + +static void __exit da9052_onkey_exit(void) +{ + platform_driver_unregister(&da9052_onkey_driver); +} + +module_init(da9052_onkey_init); +module_exit(da9052_onkey_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Dajun Chen dchen@diasemi.com"); +MODULE_DESCRIPTION("Onkey driver for DA9052"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index cabd9e5..fd4366d 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -726,4 +726,11 @@ config TOUCHSCREEN_TPS6507X To compile this driver as a module, choose M here: the module will be called tps6507x_ts.
+config TOUCHSCREEN_DA9052 + tristate "Dialog DA9052 TSI" + depends on PMIC_DIALOG + help + Say y here to support the touchscreen found on + Dialog Semiconductor DA9052 PMIC + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 282d6f7..0647195 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -6,6 +6,8 @@
wm97xx-ts-y := wm97xx-core.o
+da9052-tsi-objs := da9052_tsi.o da9052_tsi_filter.o da9052_tsi_calibrate.o +obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052-tsi.o obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c new file mode 100644 index 0000000..fa250ab --- /dev/null +++ b/drivers/input/touchscreen/da9052_tsi.c @@ -0,0 +1,1446 @@ +/* + * da9052_tsi.c -- TSI driver for Dialog DA9052 + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * Author: Dialog Semiconductor Ltd dchen@diasemi.com + * + * 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. + * + */ +#include <linux/module.h> +#include <linux/input.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/uaccess.h> +#include <linux/freezer.h> +#include <linux/kthread.h> + +#include <linux/mfd/da9052/reg.h> +#include <linux/mfd/da9052/tsi_cfg.h> +#include <linux/mfd/da9052/tsi.h> +#include <linux/mfd/da9052/gpio.h> +#include <linux/mfd/da9052/adc.h> + +#define WAIT_FOR_PEN_DOWN 0 +#define WAIT_FOR_SAMPLING 1 +#define SAMPLING_ACTIVE 2 + +static ssize_t __init da9052_tsi_create_input_dev(struct input_dev **ip_dev, + u8 n); +static ssize_t read_da9052_reg(struct da9052 *da9052, u8 reg_addr); +static ssize_t write_da9052_reg(struct da9052 *da9052, u8 reg_addr, u8 data); + +static void da9052_tsi_reg_pendwn_event(struct da9052_ts_priv *priv); +static void da9052_tsi_reg_datardy_event(struct da9052_ts_priv *priv); +static ssize_t da9052_tsi_config_delay(struct da9052_ts_priv *priv, + enum TSI_DELAY delay); +static ssize_t da9052_tsi_config_measure_seq(struct da9052_ts_priv *priv, + enum TSI_MEASURE_SEQ seq); +static ssize_t da9052_tsi_config_state(struct da9052_ts_priv *ts, + enum TSI_STATE state); +static ssize_t da9052_tsi_set_sampling_mode(struct da9052_ts_priv *priv, + u8 interval); +static ssize_t da9052_tsi_config_skip_slots(struct da9052_ts_priv *priv, + enum TSI_SLOT_SKIP skip); +static ssize_t da9052_tsi_config_pen_detect(struct da9052_ts_priv *priv, + u8 flag); +static ssize_t da9052_tsi_disable_irq(struct da9052_ts_priv *priv, + enum TSI_IRQ tsi_irq); +static ssize_t da9052_tsi_enable_irq(struct da9052_ts_priv *priv, + enum TSI_IRQ tsi_irq); +static ssize_t da9052_tsi_config_manual_mode(struct da9052_ts_priv *priv, + u8 coordinate); +static ssize_t da9052_tsi_config_auto_mode(struct da9052_ts_priv *priv, + u8 state); +static ssize_t da9052_tsi_config_gpio(struct da9052_ts_priv *priv); +static ssize_t da9052_tsi_config_power_supply(struct da9052_ts_priv *priv, + u8 state); +static struct da9052_tsi_info *get_tsi_drvdata(void); +static void da9052_tsi_penup_event(struct da9052_ts_priv *priv); +static s32 da9052_tsi_get_rawdata(struct da9052_tsi_reg *buf, u8 cnt); +static ssize_t da9052_tsi_reg_proc_thread(void *ptr); +static ssize_t da9052_tsi_resume(struct platform_device *dev); +static ssize_t da9052_tsi_suspend(struct platform_device *dev, + pm_message_t state); +struct da9052_tsi tsi_reg; +struct da9052_tsi_info gda9052_tsi_info; + +static ssize_t write_da9052_reg(struct da9052 *da9052, u8 reg_addr, u8 data) +{ + ssize_t ret = 0; + struct da9052_ssc_msg ssc_msg; + + ssc_msg.addr = reg_addr; + ssc_msg.data = data; + ret = da9052->write(da9052, &ssc_msg); + if (ret) { + DA9052_DEBUG("%s: ", __func__); + DA9052_DEBUG("da9052_ssc_write Failed %d\n", ret); + } + + return ret; +} + +static ssize_t read_da9052_reg(struct da9052 *da9052, u8 reg_addr) +{ + ssize_t ret = 0; + struct da9052_ssc_msg ssc_msg; + + ssc_msg.addr = reg_addr; + ssc_msg.data = 0; + ret = da9052->read(da9052, &ssc_msg); + if (ret) { + DA9052_DEBUG("%s: ", __func__); + DA9052_DEBUG("da9052_ssc_read Failed => %d\n", ret); + return -ret; + } + return ssc_msg.data; +} + +static struct da9052_tsi_info *get_tsi_drvdata(void) +{ + return &gda9052_tsi_info; +} + +static ssize_t da9052_tsi_config_measure_seq(struct da9052_ts_priv *priv, + enum TSI_MEASURE_SEQ seq) +{ + ssize_t ret = 0; + u8 data = 0; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + if (seq > 1) + return -EINVAL; + + da9052_lock(priv->da9052); + ret = read_da9052_reg(priv->da9052, DA9052_TSICONTA_REG); + if (ret < 0) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG("read_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + + data = (u8)ret; + + if (seq == XYZP_MODE) + data = enable_xyzp_mode(data); + else if (seq == XP_MODE) + data = enable_xp_mode(data); + else { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG("Invalid Value passed\n"); + da9052_unlock(priv->da9052); + return -EINVAL; + } + + ret = write_da9052_reg(priv->da9052, DA9052_TSICONTA_REG, data); + if (ret) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG(" write_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + da9052_unlock(priv->da9052); + + ts->tsi_conf.auto_cont.da9052_tsi_cont_a = data; + + return 0; +} + +static ssize_t da9052_tsi_set_sampling_mode(struct da9052_ts_priv *priv, + u8 mode) +{ + u8 data = 0; + ssize_t ret = 0; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + da9052_lock(priv->da9052); + + ret = read_da9052_reg(priv->da9052, DA9052_ADCCONT_REG); + if (ret < 0) { + DA9052_DEBUG("DA9052_TSI:%s:", __func__); + DA9052_DEBUG("read_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + data = (u8)ret; + + if (mode == ECONOMY_MODE) + data = adc_mode_economy_mode(data); + else if (mode == FAST_MODE) + data = adc_mode_fast_mode(data); + else { + DA9052_DEBUG("DA9052_TSI:%s:", __func__); + DA9052_DEBUG("Invalid interval passed\n"); + da9052_unlock(priv->da9052); + return -EINVAL; + } + + ret = write_da9052_reg(priv->da9052, DA9052_ADCCONT_REG, data); + if (ret) { + DA9052_DEBUG("DA9052_TSI:%s:", __func__); + DA9052_DEBUG("write_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + da9052_unlock(priv->da9052); + + switch (mode) { + case ECONOMY_MODE: + priv->tsi_reg_data_poll_interval = + TSI_ECO_MODE_REG_DATA_PROCESSING_INTERVAL; + priv->tsi_raw_data_poll_interval = + TSI_ECO_MODE_RAW_DATA_PROCESSING_INTERVAL; + break; + case FAST_MODE: + priv->tsi_reg_data_poll_interval = + TSI_FAST_MODE_REG_DATA_PROCESSING_INTERVAL; + priv->tsi_raw_data_poll_interval = + TSI_FAST_MODE_RAW_DATA_PROCESSING_INTERVAL; + break; + default: + DA9052_DEBUG("DA9052_TSI:%s:", __func__); + DA9052_DEBUG("Invalid interval passed\n"); + return -EINVAL; + } + + ts->tsi_penup_count = + (u32)priv->tsi_pdata->pen_up_interval / + priv->tsi_reg_data_poll_interval; + + return 0; +} + +static ssize_t da9052_tsi_config_delay(struct da9052_ts_priv *priv, + enum TSI_DELAY delay) +{ + ssize_t ret = 0; + u8 data = 0; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + if (delay > priv->tsi_pdata->max_tsi_delay) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG(" invalid value for tsi delay!!!\n"); + return -EINVAL; + } + + da9052_lock(priv->da9052); + + ret = read_da9052_reg(priv->da9052, DA9052_TSICONTA_REG); + if (ret < 0) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG("read_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + + data = clear_bits((u8)ret, DA9052_TSICONTA_TSIDELAY); + + data = set_bits(data, (delay << priv->tsi_pdata->tsi_delay_bit_shift)); + + ret = write_da9052_reg(priv->da9052, DA9052_TSICONTA_REG, data); + if (ret) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG(" write_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + da9052_unlock(priv->da9052); + + ts->tsi_conf.auto_cont.da9052_tsi_cont_a = data; + + return 0; +} + +ssize_t da9052_tsi_config_skip_slots(struct da9052_ts_priv *priv, + enum TSI_SLOT_SKIP skip) +{ + ssize_t ret = 0; + u8 data = 0; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + if (skip > priv->tsi_pdata->max_tsi_skip_slot) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG(" invalid value for tsi skip slots!!!\n"); + return -EINVAL; + } + + da9052_lock(priv->da9052); + + ret = read_da9052_reg(priv->da9052, DA9052_TSICONTA_REG); + if (ret < 0) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG("read_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + + data = clear_bits((u8)ret, DA9052_TSICONTA_TSISKIP); + + data = set_bits(data, (skip << priv->tsi_pdata->tsi_skip_bit_shift)); + + ret = write_da9052_reg(priv->da9052, DA9052_TSICONTA_REG, data); + if (ret) { + DA9052_DEBUG("DA9052_TSI:da9052_tsi_config_skip_slots:"); + DA9052_DEBUG(" write_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + da9052_unlock(priv->da9052); + + ts->tsi_conf.auto_cont.da9052_tsi_cont_a = data; + + return 0; +} + +static ssize_t da9052_tsi_config_state(struct da9052_ts_priv *priv, + enum TSI_STATE state) +{ + s32 ret; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + if (ts->tsi_conf.state == state) + return 0; + + switch (state) { + case TSI_AUTO_MODE: + ts->tsi_zero_data_cnt = 0; + priv->early_data_flag = TRUE; + priv->debounce_over = FALSE; + priv->win_reference_valid = FALSE; + + clean_tsi_fifos(priv); + + ret = da9052_tsi_config_auto_mode(priv, DISABLE); + if (ret) + return ret; + + ret = da9052_tsi_config_manual_mode(priv, DISABLE); + if (ret) + return ret; + + ret = da9052_tsi_config_power_supply(priv, DISABLE); + if (ret) + return ret; + + ret = da9052_tsi_enable_irq(priv, TSI_PEN_DWN); + if (ret) + return ret; + ts->tsi_conf.tsi_pendown_irq_mask = RESET; + + ret = da9052_tsi_disable_irq(priv, TSI_DATA_RDY); + if (ret) + return ret; + ts->tsi_conf.tsi_ready_irq_mask = SET; + + da9052_tsi_reg_pendwn_event(priv); + da9052_tsi_reg_datardy_event(priv); + + ret = da9052_tsi_config_pen_detect(priv, ENABLE); + if (ret) + return ret; + break; + + case TSI_IDLE: + ts->pen_dwn_event = RESET; + + ret = da9052_tsi_config_pen_detect(priv, DISABLE); + if (ret) + return ret; + + ret = da9052_tsi_config_auto_mode(priv, DISABLE); + if (ret) + return ret; + + ret = da9052_tsi_config_manual_mode(priv, DISABLE); + if (ret) + return ret; + + ret = da9052_tsi_config_power_supply(priv, DISABLE); + if (ret) + return ret; + + if (ts->pd_reg_status) { + priv->da9052->unregister_event_notifier(priv->da9052, + &priv->pd_nb); + ts->pd_reg_status = RESET; + } + break; + + default: + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG(" Invalid state passed"); + return -EINVAL; + } + + ts->tsi_conf.state = state; + + return 0; +} + +static void da9052_tsi_reg_pendwn_event(struct da9052_ts_priv *priv) +{ + ssize_t ret = 0; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + if (ts->pd_reg_status) { + DA9052_DEBUG("%s: Pen down ", __func__); + DA9052_DEBUG("Registeration is already done\n"); + return; + } + + priv->pd_nb.eve_type = PEN_DOWN_EVE; + priv->pd_nb.call_back = &da9052_tsi_pen_down_handler; + + ret = priv->da9052->register_event_notifier(priv->da9052, &priv->pd_nb); + if (ret) { + DA9052_DEBUG("%s: EH Registeration", __func__); + DA9052_DEBUG(" Failed: ret = %d\n", ret); + ts->pd_reg_status = RESET; + } else + ts->pd_reg_status = SET; + + priv->os_data_cnt = 0; + priv->raw_data_cnt = 0; + + return; +} + +static void da9052_tsi_reg_datardy_event(struct da9052_ts_priv *priv) +{ + ssize_t ret = 0; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + if (ts->datardy_reg_status) { + DA9052_DEBUG("%s: Data Ready ", __func__); + DA9052_DEBUG("Registeration is already done\n"); + return; + } + + priv->datardy_nb.eve_type = TSI_READY_EVE; + priv->datardy_nb.call_back = &da9052_tsi_data_ready_handler; + + ret = priv->da9052->register_event_notifier(priv->da9052, + &priv->datardy_nb); + + if (ret) { + DA9052_DEBUG("%s: EH Registeration", __func__); + DA9052_DEBUG(" Failed: ret = %d\n", ret); + ts->datardy_reg_status = RESET; + } else + ts->datardy_reg_status = SET; + + return; +} + +static ssize_t __init da9052_tsi_create_input_dev(struct input_dev **ip_dev, + u8 n) +{ + u8 i; + s32 ret; + struct input_dev *dev = NULL; + + if (!n) + return -EINVAL; + + for (i = 0; i < n; i++) { + dev = input_allocate_device(); + if (!dev) { + DA9052_DEBUG(KERN_ERR "%s:%s():memory allocation for "\ + "inputdevice failed\n", __FILE__, + __func__); + return -ENOMEM; + } + + ip_dev[i] = dev; + switch (i) { + case TSI_INPUT_DEVICE_OFF: + dev->name = DA9052_TSI_INPUT_DEV; + dev->phys = "input(tsi)"; + break; + default: + break; + } + } + dev->id.vendor = DA9052_VENDOR_ID; + dev->id.product = DA9052_PRODUCT_ID; + dev->id.bustype = BUS_RS232; + dev->id.version = TSI_VERSION; + dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + dev->evbit[0] = (BIT_MASK(EV_SYN) | + BIT_MASK(EV_KEY) | + BIT_MASK(EV_ABS)); + + input_set_abs_params(dev, ABS_X, 0, DA9052_DISPLAY_X_MAX, 0, 0); + input_set_abs_params(dev, ABS_Y, 0, DA9052_DISPLAY_Y_MAX, 0, 0); + input_set_abs_params(dev, ABS_PRESSURE, 0, DA9052_TOUCH_PRESSURE_MAX, + 0, 0); + + ret = input_register_device(dev); + if (ret) { + DA9052_DEBUG(KERN_ERR "%s: Could ", __func__); + DA9052_DEBUG("not register input device(touchscreen)!\n"); + ret = -EIO; + goto fail; + } + return 0; + +fail: + for (; i-- != 0; ) + input_free_device(ip_dev[i]); + return -EINVAL; +} + +static ssize_t __init da9052_tsi_init_drv(struct da9052_ts_priv *priv) +{ + u8 cnt = 0; + ssize_t ret = 0; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + if ((DA9052_GPIO_PIN_3 != DA9052_GPIO_CONFIG_TSI) || + (DA9052_GPIO_PIN_4 != DA9052_GPIO_CONFIG_TSI) || + (DA9052_GPIO_PIN_5 != DA9052_GPIO_CONFIG_TSI) || + (DA9052_GPIO_PIN_6 != DA9052_GPIO_CONFIG_TSI) || + (DA9052_GPIO_PIN_7 != DA9052_GPIO_CONFIG_TSI)) { + printk(KERN_ERR"DA9052_TSI: Configure DA9052 GPIO "); + printk(KERN_ERR"pins for TSI\n"); + return -EINVAL; + } + + ret = da9052_tsi_config_gpio(priv); + + ret = da9052_tsi_config_state(priv, TSI_IDLE); + ts->tsi_conf.state = TSI_IDLE; + + da9052_tsi_config_measure_seq(priv, TSI_MODE_VALUE); + + da9052_tsi_config_skip_slots(priv, TSI_SLOT_SKIP_VALUE); + + da9052_tsi_config_delay(priv, TSI_DELAY_VALUE); + + da9052_tsi_set_sampling_mode(priv, DEFAULT_TSI_SAMPLING_MODE); + + ts->tsi_calib = get_calib_config(); + + ret = da9052_tsi_create_input_dev(ts->input_devs, NUM_INPUT_DEVS); + if (ret) { + DA9052_DEBUG("DA9052_TSI: %s: ", __func__); + DA9052_DEBUG("da9052_tsi_create_input_dev Failed\n"); + return ret; + } + + da9052_init_tsi_fifos(priv); + + init_completion(&priv->tsi_reg_proc_thread.notifier); + priv->tsi_reg_proc_thread.state = ACTIVE; + priv->tsi_reg_proc_thread.thread_task = + kthread_run(da9052_tsi_reg_proc_thread, + priv, "da9052_tsi_reg"); + + init_completion(&priv->tsi_raw_proc_thread.notifier); + priv->tsi_raw_proc_thread.state = ACTIVE; + priv->tsi_raw_proc_thread.thread_task = + kthread_run(da9052_tsi_raw_proc_thread, + priv, "da9052_tsi_raw"); + + ret = da9052_tsi_config_state(priv, DEFAULT_TSI_STATE); + if (ret) { + for (cnt = 0; cnt < NUM_INPUT_DEVS; cnt++) { + if (ts->input_devs[cnt] != NULL) + input_free_device(ts->input_devs[cnt]); + } + } + + return 0; +} + +u32 da9052_tsi_get_input_dev(u8 off) +{ + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + if (off > NUM_INPUT_DEVS-1) + return -EINVAL; + + return (u32)ts->input_devs[off]; +} + +static ssize_t da9052_tsi_config_pen_detect(struct da9052_ts_priv *priv, + u8 flag) +{ + u8 data; + u32 ret; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + da9052_lock(priv->da9052); + ret = read_da9052_reg(priv->da9052, DA9052_TSICONTA_REG); + if (ret < 0) { + DA9052_DEBUG("%s:", __func__); + DA9052_DEBUG(" read_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + + if (flag == ENABLE) + data = set_bits((u8)ret, DA9052_TSICONTA_PENDETEN); + else if (flag == DISABLE) + data = clear_bits((u8)ret, DA9052_TSICONTA_PENDETEN); + else { + DA9052_DEBUG("%s:", __func__); + DA9052_DEBUG(" Invalid flag passed\n"); + da9052_unlock(priv->da9052); + return -EINVAL; + } + + ret = write_da9052_reg(priv->da9052, DA9052_TSICONTA_REG, data); + if (ret < 0) { + DA9052_DEBUG("%s:", __func__); + DA9052_DEBUG(" write_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + da9052_unlock(priv->da9052); + + ts->tsi_conf.auto_cont.da9052_tsi_cont_a = data; + return 0; +} + +static ssize_t da9052_tsi_disable_irq(struct da9052_ts_priv *priv, + enum TSI_IRQ tsi_irq) +{ + u8 data = 0; + ssize_t ret = 0; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + da9052_lock(priv->da9052); + ret = read_da9052_reg(priv->da9052, DA9052_IRQMASKB_REG); + if (ret < 0) { + DA9052_DEBUG("DA9052_TSI:da9052_tsi_disable_irq:"); + DA9052_DEBUG("read_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + data = ret; + switch (tsi_irq) { + case TSI_PEN_DWN: + data = mask_pendwn_irq(data); + break; + case TSI_DATA_RDY: + data = mask_tsi_rdy_irq(data); + break; + default: + DA9052_DEBUG("DA9052_TSI:da9052_tsi_disable_irq:"); + DA9052_DEBUG("Invalid IRQ passed\n"); + da9052_unlock(priv->da9052); + return -EINVAL; + } + ret = write_da9052_reg(priv->da9052, DA9052_IRQMASKB_REG, data); + if (ret) { + DA9052_DEBUG("DA9052_TSI:da9052_tsi_disable_irq:"); + DA9052_DEBUG("write_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + da9052_unlock(priv->da9052); + switch (tsi_irq) { + case TSI_PEN_DWN: + ts->tsi_conf.tsi_pendown_irq_mask = SET; + break; + case TSI_DATA_RDY: + ts->tsi_conf.tsi_ready_irq_mask = SET; + break; + default: + return -EINVAL; + } + + return 0; + +} + +static ssize_t da9052_tsi_enable_irq(struct da9052_ts_priv *priv, + enum TSI_IRQ tsi_irq) +{ + u8 data = 0; + ssize_t ret = 0; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + da9052_lock(priv->da9052); + ret = read_da9052_reg(priv->da9052, DA9052_IRQMASKB_REG); + if (ret < 0) { + DA9052_DEBUG("DA9052_TSI:da9052_tsi_enable_irq:"); + DA9052_DEBUG("read_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + + data = ret; + switch (tsi_irq) { + case TSI_PEN_DWN: + data = unmask_pendwn_irq(data); + break; + case TSI_DATA_RDY: + data = unmask_tsi_rdy_irq(data); + break; + default: + DA9052_DEBUG("DA9052_TSI:da9052_tsi_enable_irq:"); + DA9052_DEBUG("Invalid IRQ passed\n"); + da9052_unlock(priv->da9052); + return -EINVAL; + } + ret = write_da9052_reg(priv->da9052, DA9052_IRQMASKB_REG, data); + if (ret) { + DA9052_DEBUG("DA9052_TSI:da9052_tsi_enable_irq:"); + DA9052_DEBUG("write_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + da9052_unlock(priv->da9052); + switch (tsi_irq) { + case TSI_PEN_DWN: + ts->tsi_conf.tsi_pendown_irq_mask = RESET; + break; + case TSI_DATA_RDY: + ts->tsi_conf.tsi_ready_irq_mask = RESET; + break; + default: + return -EINVAL; + } + + return 0; +} + +static ssize_t da9052_tsi_config_gpio(struct da9052_ts_priv *priv) +{ + u8 idx = 0; + ssize_t ret = 0; + struct da9052_ssc_msg ssc_msg[priv->tsi_pdata->num_gpio_tsi_register]; + + ssc_msg[idx++].addr = DA9052_GPIO0203_REG; + ssc_msg[idx++].addr = DA9052_GPIO0405_REG; + ssc_msg[idx++].addr = DA9052_GPIO0607_REG; + + da9052_lock(priv->da9052); + ret = priv->da9052->read_many(priv->da9052, ssc_msg, idx); + if (ret) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG("da9052_ssc_read_many Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + + idx = 0; + ssc_msg[idx].data = clear_bits(ssc_msg[idx].data, + DA9052_GPIO0203_GPIO3PIN); + idx++; + ssc_msg[idx].data = clear_bits(ssc_msg[idx].data, + (DA9052_GPIO0405_GPIO4PIN | DA9052_GPIO0405_GPIO5PIN)); + idx++; + ssc_msg[idx].data = clear_bits(ssc_msg[idx].data, + (DA9052_GPIO0607_GPIO6PIN | DA9052_GPIO0607_GPIO7PIN)); + idx++; + + ret = priv->da9052->write_many(priv->da9052, ssc_msg, idx); + if (ret) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG("da9052_ssc_read_many Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + da9052_unlock(priv->da9052); + + return 0; +} + +s32 da9052_pm_configure_ldo(struct da9052_ts_priv *priv, + struct da9052_ldo_config ldo_config) +{ + struct da9052_ssc_msg msg; + u8 reg_num; + u8 ldo_volt; + u8 ldo_volt_bit = 0; + u8 ldo_conf_bit = 0; + u8 ldo_en_bit = 0; + s8 ldo_pd_bit = -1; + s32 ret = 0; + + if (validate_ldo9_mV(ldo_config.ldo_volt)) + return INVALID_LDO9_VOLT_VALUE; + + ldo_volt = ldo9_mV_to_reg(ldo_config.ldo_volt); + + reg_num = DA9052_LDO9_REG; + ldo_volt_bit = DA9052_LDO9_VLDO9; + ldo_conf_bit = DA9052_LDO9_LDO9CONF; + ldo_en_bit = DA9052_LDO9_LDO9EN; + + da9052_lock(priv->da9052); + + msg.addr = reg_num; + + ret = priv->da9052->read(priv->da9052, &msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EINVAL; + } + msg.data = ldo_volt | + (ldo_config.ldo_conf ? ldo_conf_bit : 0) | + (msg.data & ldo_en_bit); + + ret = priv->da9052->write(priv->da9052, &msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EINVAL; + } + + if (-1 != ldo_pd_bit) { + msg.addr = DA9052_PULLDOWN_REG; + ret = priv->da9052->read(priv->da9052, &msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EINVAL; + } + + msg.data = (ldo_config.ldo_pd ? + set_bits(msg.data, ldo_pd_bit) : + clear_bits(msg.data, ldo_pd_bit)); + + ret = priv->da9052->write(priv->da9052, &msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EINVAL; + } + + } + da9052_unlock(priv->da9052); + + return 0; +} + + +s32 da9052_pm_set_ldo(struct da9052_ts_priv *priv, u8 ldo_num, u8 flag) +{ + struct da9052_ssc_msg msg; + u8 reg_num = 0; + u8 value = 0; + s32 ret = 0; + + DA9052_DEBUG("I am in function: %s\n", __func__); + + reg_num = DA9052_LDO9_REG; + value = DA9052_LDO9_LDO9EN; + da9052_lock(priv->da9052); + + msg.addr = reg_num; + + ret = priv->da9052->read(priv->da9052, &msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EINVAL; + } + + msg.data = flag ? + set_bits(msg.data, value) : + clear_bits(msg.data, value); + + ret = priv->da9052->write(priv->da9052, &msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EINVAL; + } + + da9052_unlock(priv->da9052); + + return 0; +} + +static ssize_t da9052_tsi_config_power_supply(struct da9052_ts_priv *priv, + u8 state) +{ + struct da9052_ldo_config ldo_config; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + if (state != ENABLE && state != DISABLE) { + DA9052_DEBUG("DA9052_TSI: %s: ", __func__); + DA9052_DEBUG("Invalid state Passed\n"); + return -EINVAL; + } + + ldo_config.ldo_volt = priv->tsi_pdata->tsi_supply_voltage; + ldo_config.ldo_num = priv->tsi_pdata->tsi_ref_source; + ldo_config.ldo_conf = RESET; + + if (da9052_pm_configure_ldo(priv, ldo_config)) + return -EINVAL; + + if (da9052_pm_set_ldo(priv, priv->tsi_pdata->tsi_ref_source, state)) + return -EINVAL; + + if (state == ENABLE) + ts->tsi_conf.ldo9_en = SET; + else + ts->tsi_conf.ldo9_en = RESET; + + return 0; +} + +static ssize_t da9052_tsi_config_auto_mode(struct da9052_ts_priv *priv, + u8 state) +{ + u8 data; + s32 ret = 0; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + if (state != ENABLE && state != DISABLE) + return -EINVAL; + + da9052_lock(priv->da9052); + + ret = read_da9052_reg(priv->da9052, DA9052_TSICONTA_REG); + if (ret < 0) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG("read_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + + data = (u8)ret; + + if (state == ENABLE) + data = set_auto_tsi_en(data); + else if (state == DISABLE) + data = reset_auto_tsi_en(data); + else { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG("Invalid Parameter Passed\n"); + da9052_unlock(priv->da9052); + return -EINVAL; + } + + ret = write_da9052_reg(priv->da9052, DA9052_TSICONTA_REG, data); + if (ret) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG(" Failed to configure Auto TSI mode\n"); + da9052_unlock(priv->da9052); + return ret; + } + da9052_unlock(priv->da9052); + ts->tsi_conf.auto_cont.da9052_tsi_cont_a = data; + return 0; +} + +static ssize_t da9052_tsi_config_manual_mode(struct da9052_ts_priv *priv, + u8 state) +{ + u8 data = 0; + ssize_t ret = 0; + struct da9052_tsi_info *ts = get_tsi_drvdata(); + + if (state != ENABLE && state != DISABLE) { + DA9052_DEBUG("DA9052_TSI: %s: ", __func__); + DA9052_DEBUG("Invalid state Passed\n"); + return -EINVAL; + } + + da9052_lock(priv->da9052); + + ret = read_da9052_reg(priv->da9052, DA9052_TSICONTB_REG); + if (ret < 0) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG("read_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + + data = (u8)ret; + if (state == DISABLE) + data = disable_tsi_manual_mode(data); + else + data = enable_tsi_manual_mode(data); + + ret = write_da9052_reg(priv->da9052, DA9052_TSICONTB_REG, data); + if (ret) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG("write_da9052_reg Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + + if (state == DISABLE) + ts->tsi_conf.man_cont.tsi_cont_b.tsi_man = RESET; + else + ts->tsi_conf.man_cont.tsi_cont_b.tsi_man = SET; + + data = 0; + data = set_bits(data, DA9052_ADC_TSI); + + ret = write_da9052_reg(priv->da9052, DA9052_ADCMAN_REG, data); + if (ret) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG("ADC write Failed\n"); + da9052_unlock(priv->da9052); + return ret; + } + da9052_unlock(priv->da9052); + + return 0; +} + +static u32 da9052_tsi_get_reg_data(struct da9052_ts_priv *priv) +{ + u32 free_cnt, copy_cnt, cnt; + + if (down_interruptible(&priv->tsi_reg_fifo.lock)) + return 0; + + copy_cnt = 0; + + if ((priv->tsi_reg_fifo.head - priv->tsi_reg_fifo.tail) > 1) { + free_cnt = get_reg_free_space_cnt(priv); + if (free_cnt > TSI_POLL_SAMPLE_CNT) + free_cnt = TSI_POLL_SAMPLE_CNT; + + cnt = da9052_tsi_get_rawdata( + &priv->tsi_reg_fifo.data[priv->tsi_reg_fifo.tail], + free_cnt); + + if (cnt > free_cnt) { + DA9052_DEBUG("EH copied more data"); + return -EINVAL; + } + + copy_cnt = cnt; + + while (cnt--) + incr_with_wrap_reg_fifo(priv->tsi_reg_fifo.tail); + + } else if ((priv->tsi_reg_fifo.head - priv->tsi_reg_fifo.tail) <= 0) { + + free_cnt = (TSI_REG_DATA_BUF_SIZE - priv->tsi_reg_fifo.tail); + if (free_cnt > TSI_POLL_SAMPLE_CNT) { + free_cnt = TSI_POLL_SAMPLE_CNT; + + cnt = da9052_tsi_get_rawdata( + &priv->tsi_reg_fifo.data[priv->tsi_reg_fifo.tail], + free_cnt); + if (cnt > free_cnt) { + DA9052_DEBUG("EH copied more data"); + return -EINVAL; + } + copy_cnt = cnt; + + while (cnt--) + incr_with_wrap_reg_fifo( + priv->tsi_reg_fifo.tail); + } else { + if (free_cnt) { + cnt = da9052_tsi_get_rawdata( + &priv-> + tsi_reg_fifo.data[priv-> + tsi_reg_fifo.tail], + free_cnt + ); + if (cnt > free_cnt) { + DA9052_DEBUG("EH copied more data"); + return -EINVAL; + } + copy_cnt = cnt; + while (cnt--) + incr_with_wrap_reg_fifo( + priv->tsi_reg_fifo.tail); + } + free_cnt = priv->tsi_reg_fifo.head; + if (free_cnt > TSI_POLL_SAMPLE_CNT - copy_cnt) + free_cnt = TSI_POLL_SAMPLE_CNT - copy_cnt; + if (free_cnt) { + cnt = da9052_tsi_get_rawdata( + &priv->tsi_reg_fifo.data[priv-> + tsi_reg_fifo.tail], free_cnt + ); + if (cnt > free_cnt) { + DA9052_DEBUG("EH copied more data"); + return -EINVAL; + } + + copy_cnt += cnt; + + while (cnt--) + incr_with_wrap_reg_fifo( + priv->tsi_reg_fifo.tail); + } + } + } else + copy_cnt = 0; + + up(&priv->tsi_reg_fifo.lock); + + return copy_cnt; +} + + +static ssize_t da9052_tsi_reg_proc_thread(void *ptr) +{ + u32 data_cnt; + ssize_t ret = 0; + struct da9052_tsi_info *ts; + struct da9052_ts_priv *priv = (struct da9052_ts_priv *)ptr; + + set_freezable(); + + while (priv->tsi_reg_proc_thread.state == ACTIVE) { + + try_to_freeze(); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(priv-> + tsi_reg_data_poll_interval)); + + ts = get_tsi_drvdata(); + + if (!ts->pen_dwn_event) + continue; + + data_cnt = da9052_tsi_get_reg_data(priv); + + da9052_tsi_process_reg_data(priv); + + if (data_cnt) + ts->tsi_zero_data_cnt = 0; + else { + if ((++(ts->tsi_zero_data_cnt)) > + ts->tsi_penup_count) { + ts->pen_dwn_event = RESET; + da9052_tsi_penup_event(priv); + } + } + } + + complete_and_exit(&priv->tsi_reg_proc_thread.notifier, 0); + return 0; +} + + +static void da9052_tsi_penup_event(struct da9052_ts_priv *priv) +{ + + struct da9052_tsi_info *ts = get_tsi_drvdata(); + struct input_dev *ip_dev = + (struct input_dev *)da9052_tsi_get_input_dev( + (u8)TSI_INPUT_DEVICE_OFF); + + if (da9052_tsi_config_auto_mode(priv, DISABLE)) + goto exit; + ts->tsi_conf.auto_cont.tsi_cont_a.auto_tsi_en = RESET; + + if (da9052_tsi_config_power_supply(priv, ENABLE)) + goto exit; + + ts->tsi_conf.ldo9_en = RESET; + + if (da9052_tsi_enable_irq(priv, TSI_PEN_DWN)) + goto exit; + ts->tsi_conf.tsi_pendown_irq_mask = RESET; + tsi_reg.tsi_state = WAIT_FOR_PEN_DOWN; + + if (da9052_tsi_disable_irq(priv, TSI_DATA_RDY)) + goto exit; + + ts->tsi_zero_data_cnt = 0; + priv->early_data_flag = TRUE; + priv->debounce_over = FALSE; + priv->win_reference_valid = FALSE; + + printk(KERN_INFO "The raw data count is %d\n", priv->raw_data_cnt); + printk(KERN_INFO "The OS data count is %d\n", priv->os_data_cnt); + printk(KERN_INFO "PEN UP DECLARED\n"); + input_report_abs(ip_dev, BTN_TOUCH, 0); + input_sync(ip_dev); + priv->os_data_cnt = 0; + priv->raw_data_cnt = 0; + +exit: + clean_tsi_fifos(priv); + return; +} + +void da9052_tsi_pen_down_handler(struct da9052_eh_nb *eh_data, u32 event) +{ + ssize_t ret = 0; + struct da9052_ts_priv *priv = + container_of(eh_data, struct da9052_ts_priv, pd_nb); + struct da9052_tsi_info *ts = get_tsi_drvdata(); + struct input_dev *ip_dev = + (struct input_dev *)da9052_tsi_get_input_dev( + (u8)TSI_INPUT_DEVICE_OFF); + + if (tsi_reg.tsi_state != WAIT_FOR_PEN_DOWN) + return; + + tsi_reg.tsi_state = WAIT_FOR_SAMPLING; + + if (ts->tsi_conf.state != TSI_AUTO_MODE) { + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG(" Configure TSI to auto mode.\n"); + DA9052_DEBUG("DA9052_TSI: %s:", __func__); + DA9052_DEBUG(" Then call this API.\n"); + goto fail; + } + + if (da9052_tsi_config_power_supply(priv, ENABLE)) + goto fail; + + if (da9052_tsi_disable_irq(priv, TSI_PEN_DWN)) + goto fail; + + if (da9052_tsi_config_auto_mode(priv, ENABLE)) + goto fail; + ts->tsi_conf.auto_cont.tsi_cont_a.auto_tsi_en = SET; + + if (da9052_tsi_enable_irq(priv, TSI_DATA_RDY)) + goto fail; + + input_sync(ip_dev); + + ts->tsi_rdy_event = (DA9052_EVENTB_ETSIREADY & (event>>8)); + ts->pen_dwn_event = (DA9052_EVENTB_EPENDOWN & (event>>8)); + + tsi_reg.tsi_state = SAMPLING_ACTIVE; + + goto success; + +fail: + if (ts->pd_reg_status) { + priv->da9052->unregister_event_notifier(priv->da9052, + &priv->pd_nb); + ts->pd_reg_status = RESET; + + priv->da9052->register_event_notifier(priv->da9052, + &priv->datardy_nb); + da9052_tsi_reg_pendwn_event(priv); + } + +success: + ret = 0; + printk(KERN_INFO "Exiting PEN DOWN HANDLER\n"); +} + +void da9052_tsi_data_ready_handler(struct da9052_eh_nb *eh_data, u32 event) +{ + struct da9052_ssc_msg tsi_data[4]; + s32 ret; + struct da9052_ts_priv *priv = + container_of(eh_data, struct da9052_ts_priv, datardy_nb); + + if (tsi_reg.tsi_state != SAMPLING_ACTIVE) + return; + + tsi_data[0].addr = DA9052_TSIXMSB_REG; + tsi_data[1].addr = DA9052_TSIYMSB_REG; + tsi_data[2].addr = DA9052_TSILSB_REG; + tsi_data[3].addr = DA9052_TSIZMSB_REG; + + tsi_data[0].data = 0; + tsi_data[1].data = 0; + tsi_data[2].data = 0; + tsi_data[3].data = 0; + + da9052_lock(priv->da9052); + + ret = priv->da9052->read_many(priv->da9052, tsi_data, 4); + if (ret) { + DA9052_DEBUG("Error in reading TSI data\n"); + da9052_unlock(priv->da9052); + return; + } + da9052_unlock(priv->da9052); + +#if 1 + mutex_lock(&tsi_reg.tsi_fifo_lock); + + tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_end].x_msb = tsi_data[0].data; + tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_end].y_msb = tsi_data[1].data; + tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_end].lsb = tsi_data[2].data; + tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_end].z_msb = tsi_data[3].data; + incr_with_wrap(tsi_reg.tsi_fifo_end); + + if (tsi_reg.tsi_fifo_end == tsi_reg.tsi_fifo_start) + tsi_reg.tsi_fifo_start++; + + mutex_unlock(&tsi_reg.tsi_fifo_lock); +#endif +/* printk(KERN_INFO "Exiting Data ready handler\n");*/ +} + +static s32 da9052_tsi_get_rawdata(struct da9052_tsi_reg *buf, u8 cnt) +{ + u32 data_cnt = 0; + u32 rem_data_cnt = 0; + + mutex_lock(&tsi_reg.tsi_fifo_lock); + + if (tsi_reg.tsi_fifo_start < tsi_reg.tsi_fifo_end) { + data_cnt = (tsi_reg.tsi_fifo_end - tsi_reg.tsi_fifo_start); + + if (cnt < data_cnt) + data_cnt = cnt; + + memcpy(buf, &tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_start], + sizeof(struct da9052_tsi_reg) * data_cnt); + + tsi_reg.tsi_fifo_start += data_cnt; + + if (tsi_reg.tsi_fifo_start == tsi_reg.tsi_fifo_end) { + tsi_reg.tsi_fifo_start = 0; + tsi_reg.tsi_fifo_end = 0; + } + } else if (tsi_reg.tsi_fifo_start > tsi_reg.tsi_fifo_end) { + data_cnt = ((TSI_FIFO_SIZE - tsi_reg.tsi_fifo_start) + + tsi_reg.tsi_fifo_end); + + if (cnt < data_cnt) + data_cnt = cnt; + + if (data_cnt <= (TSI_FIFO_SIZE - tsi_reg.tsi_fifo_start)) { + memcpy(buf, &tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_start], + sizeof(struct da9052_tsi_reg) * data_cnt); + + tsi_reg.tsi_fifo_start += data_cnt; + if (tsi_reg.tsi_fifo_start >= TSI_FIFO_SIZE) + tsi_reg.tsi_fifo_start = 0; + } else { + memcpy(buf, &tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_start], + sizeof(struct da9052_tsi_reg) + * (TSI_FIFO_SIZE - tsi_reg.tsi_fifo_start)); + + rem_data_cnt = (data_cnt - + (TSI_FIFO_SIZE - tsi_reg.tsi_fifo_start)); + + memcpy(buf, &tsi_reg.tsi_fifo[0], + sizeof(struct da9052_tsi_reg) * rem_data_cnt); + + tsi_reg.tsi_fifo_start = rem_data_cnt; + } + + if (tsi_reg.tsi_fifo_start == tsi_reg.tsi_fifo_end) { + tsi_reg.tsi_fifo_start = 0; + tsi_reg.tsi_fifo_end = 0; + } + } else + data_cnt = 0; + + mutex_unlock(&tsi_reg.tsi_fifo_lock); + + return data_cnt; +} + +static ssize_t da9052_tsi_suspend(struct platform_device *dev, + pm_message_t state) +{ + printk(KERN_INFO "%s: called\n", __func__); + return 0; +} + +static ssize_t da9052_tsi_resume(struct platform_device *dev) +{ + printk(KERN_INFO "%s: called\n", __func__); + return 0; +} + +static s32 __devinit da9052_tsi_probe(struct platform_device *pdev) +{ + + struct da9052_ts_priv *priv; + struct da9052_tsi_platform_data *pdata = pdev->dev.platform_data; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->da9052 = dev_get_drvdata(pdev->dev.parent); + platform_set_drvdata(pdev, priv); + + priv->tsi_pdata = pdata; + + if (da9052_tsi_init_drv(priv)) + return -EFAULT; + + mutex_init(&tsi_reg.tsi_fifo_lock); + tsi_reg.tsi_state = WAIT_FOR_PEN_DOWN; + + printk(KERN_INFO "TSI Drv Successfully Inserted %s\n", + DA9052_TSI_DEVICE_NAME); + return 0; +} + +static int __devexit da9052_tsi_remove(struct platform_device *pdev) +{ + struct da9052_ts_priv *priv = platform_get_drvdata(pdev); + struct da9052_tsi_info *ts = get_tsi_drvdata(); + s32 ret = 0, i = 0; + + ret = da9052_tsi_config_state(priv, TSI_IDLE); + if (!ret) + return -EINVAL; + + if (ts->pd_reg_status) { + priv->da9052->unregister_event_notifier(priv->da9052, + &priv->pd_nb); + ts->pd_reg_status = RESET; + } + + if (ts->datardy_reg_status) { + priv->da9052->unregister_event_notifier(priv->da9052, + &priv->datardy_nb); + ts->datardy_reg_status = RESET; + } + + mutex_destroy(&tsi_reg.tsi_fifo_lock); + + priv->tsi_reg_proc_thread.state = INACTIVE; + wait_for_completion(&priv->tsi_reg_proc_thread.notifier); + + priv->tsi_raw_proc_thread.state = INACTIVE; + wait_for_completion(&priv->tsi_raw_proc_thread.notifier); + + for (i = 0; i < NUM_INPUT_DEVS; i++) + input_unregister_device(ts->input_devs[i]); + + platform_set_drvdata(pdev, NULL); + DA9052_DEBUG(KERN_DEBUG "Removing %s\n", DA9052_TSI_DEVICE_NAME); + + return 0; +} + +static struct platform_driver da9052_tsi_driver = { + .probe = da9052_tsi_probe, + .remove = __devexit_p(da9052_tsi_remove), + .suspend = da9052_tsi_suspend, + .resume = da9052_tsi_resume, + .driver = { + .name = DA9052_TSI_DEVICE_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init da9052_tsi_init(void) +{ + printk(KERN_DEBUG "DA9052 TSI Device Driver, v1.0\n"); + return platform_driver_register(&da9052_tsi_driver); +} +module_init(da9052_tsi_init); + +static void __exit da9052_tsi_exit(void) +{ + printk(KERN_ERR "TSI Driver %s Successfully Removed\n", + DA9052_TSI_DEVICE_NAME); + return; + +} +module_exit(da9052_tsi_exit); + +MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9052"); +MODULE_AUTHOR("Dialog Semiconductor Ltd dchen@diasemi.com"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/input/touchscreen/da9052_tsi_calibrate.c b/drivers/input/touchscreen/da9052_tsi_calibrate.c new file mode 100644 index 0000000..6208462 --- /dev/null +++ b/drivers/input/touchscreen/da9052_tsi_calibrate.c @@ -0,0 +1,107 @@ +/* + * da9052_tsi_calibrate.c -- TSI Calibration driver for Dialog DA9052 + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * Author: Dialog Semiconductor Ltd dchen@diasemi.com + * + * 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. + * + */ + +#include <linux/mfd/da9052/tsi.h> + +static struct Calib_xform_matrix_t xform = { + .An = DA9052_TSI_CALIB_AN, + .Bn = DA9052_TSI_CALIB_BN, + .Cn = DA9052_TSI_CALIB_CN, + .Dn = DA9052_TSI_CALIB_DN, + .En = DA9052_TSI_CALIB_EN, + .Fn = DA9052_TSI_CALIB_FN, + .Divider = DA9052_TSI_CALIB_DIVIDER +}; + +static struct calib_cfg_t calib = { + .calibrate_flag = TSI_USE_CALIBRATION, +}; + +struct calib_cfg_t *get_calib_config(void) +{ + return &calib; +} + +ssize_t da9052_tsi_set_calib_matrix(struct da9052_tsi_data *displayPtr, + struct da9052_tsi_data *screenPtr) +{ + + int retValue = SUCCESS ; + + xform.Divider = ((screenPtr[0].x - screenPtr[1].x) + * (screenPtr[1].y - screenPtr[2].y)) + - ((screenPtr[1].x - screenPtr[2].x) + * (screenPtr[0].y - screenPtr[1].y)); + + if (xform.Divider == 0) + retValue = -FAILURE; + else { + xform.An = ((displayPtr[0].x - displayPtr[1].x) + * (screenPtr[1].y - screenPtr[2].y)) + - ((displayPtr[1].x - displayPtr[2].x) + * (screenPtr[0].y - screenPtr[1].y)); + + xform.Bn = ((displayPtr[1].x - displayPtr[2].x) + * (screenPtr[0].x - screenPtr[1].x)) + - ((screenPtr[1].x - screenPtr[2].x) + * (displayPtr[0].x - displayPtr[1].x)); + + xform.Cn = (displayPtr[0].x * xform.Divider) + - (screenPtr[0].x * xform.An) + - (screenPtr[0].y * xform.Bn); + + xform.Dn = ((displayPtr[0].y - displayPtr[1].y) + * (screenPtr[1].y - screenPtr[2].y)) + - ((displayPtr[1].y - displayPtr[2].y) + * (screenPtr[0].y - screenPtr[1].y)); + + xform.En = ((displayPtr[1].y - displayPtr[2].y) + * (screenPtr[0].x - screenPtr[1].x)) + - ((screenPtr[1].x - screenPtr[2].x) + * (displayPtr[0].y - displayPtr[1].y)); + + xform.Fn = (displayPtr[0].y * xform.Divider) + - (screenPtr[0].x * xform.Dn) + - (screenPtr[0].y * xform.En); + } + + return retValue; +} + +ssize_t da9052_tsi_get_calib_display_point(struct da9052_tsi_data *displayPtr) +{ + int retValue = TRUE; + struct da9052_tsi_data screen_coord; + + screen_coord = *displayPtr; + if (xform.Divider != 0) { + displayPtr->x = ((xform.An * screen_coord.x) + + (xform.Bn * screen_coord.y) + + xform.Cn + ) / xform.Divider; + + displayPtr->y = ((xform.Dn * screen_coord.x) + + (xform.En * screen_coord.y) + + xform.Fn + ) / xform.Divider; + } else + retValue = FALSE; + +#if DA9052_TSI_CALIB_DATA_PROFILING + printk(KERN_DEBUG "C\tX\t%4d\tY\t%4d\n", + displayPtr->x, + displayPtr->y); +#endif + return retValue; +} diff --git a/drivers/input/touchscreen/da9052_tsi_filter.c b/drivers/input/touchscreen/da9052_tsi_filter.c new file mode 100644 index 0000000..c29dd01 --- /dev/null +++ b/drivers/input/touchscreen/da9052_tsi_filter.c @@ -0,0 +1,489 @@ +/* + * da9052_tsi_filter.c -- TSI filter driver for Dialog DA9052 + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * Author: Dialog Semiconductor Ltd dchen@diasemi.com + * + * 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. + * + */ + +#include <linux/input.h> +#include <linux/freezer.h> +#include <linux/mfd/da9052/tsi.h> + +#define get_abs(x) (x < 0 ? ((-1) * x) : (x)) + +#define WITHIN_WINDOW(x, y) ((get_abs(x) <= TSI_X_WINDOW_SIZE) && \ + (get_abs(y) <= TSI_Y_WINDOW_SIZE)) + +#define FIRST_SAMPLE 0 + +#define incr_with_wrap_raw_fifo(x) \ + if (++x >= TSI_RAW_DATA_BUF_SIZE) \ + x = 0 + +#define decr_with_wrap_raw_fifo(x) \ + if (--x < 0) \ + x = (TSI_RAW_DATA_BUF_SIZE-1) + +static u32 get_raw_data_cnt(struct da9052_ts_priv *priv); +static void da9052_tsi_convert_reg_to_coord(struct da9052_ts_priv *priv, + struct da9052_tsi_data *raw_data); +static inline void clean_tsi_reg_fifo(struct da9052_ts_priv *priv); +static inline void clean_tsi_raw_fifo(struct da9052_ts_priv *priv); + +#if (ENABLE_AVERAGE_FILTER) +static void da9052_tsi_avrg_filter(struct da9052_ts_priv *priv, + struct da9052_tsi_data *tsi_avg_data); + +#endif +#if (ENABLE_TSI_DEBOUNCE) +static s32 da9052_tsi_calc_debounce_data(struct da9052_ts_priv *priv, + struct da9052_tsi_data *raw_data); + +#endif +# if (ENABLE_WINDOW_FILTER) +static s32 diff_within_window(struct da9052_tsi_data *prev_raw_data, + struct da9052_tsi_data *cur_raw_data); +#endif +static s32 da9052_tsi_window_filter(struct da9052_ts_priv *ts, + struct da9052_tsi_data *raw_data); + +void clean_tsi_fifos(struct da9052_ts_priv *priv) +{ + clean_tsi_raw_fifo(priv); + clean_tsi_reg_fifo(priv); +} + +void __init da9052_init_tsi_fifos(struct da9052_ts_priv *priv) +{ + sema_init(&priv->tsi_raw_fifo.lock, 1); + sema_init(&priv->tsi_reg_fifo.lock, 1); + + clean_tsi_raw_fifo(priv); + clean_tsi_reg_fifo(priv); +} + +u32 get_reg_data_cnt(struct da9052_ts_priv *priv) +{ + u8 reg_data_cnt; + + if (priv->tsi_reg_fifo.head <= priv->tsi_reg_fifo.tail) { + reg_data_cnt = (priv->tsi_reg_fifo.tail - + priv->tsi_reg_fifo.head); + } else { + reg_data_cnt = (priv->tsi_reg_fifo.tail + + (TSI_REG_DATA_BUF_SIZE - + priv->tsi_reg_fifo.head)); + } + + return reg_data_cnt; +} + +u32 get_reg_free_space_cnt(struct da9052_ts_priv *priv) +{ + u32 free_cnt; + + if (priv->tsi_reg_fifo.head <= priv->tsi_reg_fifo.tail) { + free_cnt = ((TSI_REG_DATA_BUF_SIZE - 1) - + (priv->tsi_reg_fifo.tail - priv->tsi_reg_fifo.head)); + } else + free_cnt = ((priv->tsi_reg_fifo.head - priv->tsi_reg_fifo.tail) + - 1); + + return free_cnt; +} + +void da9052_tsi_process_reg_data(struct da9052_ts_priv *priv) +{ + s32 ret; + struct da9052_tsi_data tmp_raw_data; + u32 reg_data_cnt; + + if (down_interruptible(&priv->tsi_reg_fifo.lock)) + return; + + reg_data_cnt = get_reg_data_cnt(priv); + + while (reg_data_cnt-- > 0) { + + ret = 0; + + if (get_raw_data_cnt(priv) >= (TSI_RAW_DATA_BUF_SIZE - 1)) { + DA9052_DEBUG("%s: RAW data FIFO is full\n", + __func__); + break; + } + + da9052_tsi_convert_reg_to_coord(priv, &tmp_raw_data); + + if ((tmp_raw_data.x < TS_X_MIN) || + (tmp_raw_data.x > TS_X_MAX) || + (tmp_raw_data.y < TS_Y_MIN) || + (tmp_raw_data.y > TS_Y_MAX)) { + DA9052_DEBUG("%s: ", __func__); + DA9052_DEBUG("sample beyond touchscreen panel "); + DA9052_DEBUG("dimensions\n"); + continue; + } + +#if (ENABLE_TSI_DEBOUNCE) + if (debounce_over == FALSE) { + ret = + da9052_tsi_calc_debounce_data(priv, &tmp_raw_data); + if (ret != SUCCESS) + continue; + } +#endif + +# if (ENABLE_WINDOW_FILTER) + ret = da9052_tsi_window_filter(priv, &tmp_raw_data); + if (ret != SUCCESS) + continue; +#endif + priv->early_data_flag = FALSE; + + if (down_interruptible(&priv->tsi_raw_fifo.lock)) { + DA9052_DEBUG("%s: Failed to ", __func__); + DA9052_DEBUG("acquire RAW FIFO Lock!\n"); + + up(&priv->tsi_reg_fifo.lock); + return; + } + + priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.tail] = tmp_raw_data; + incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.tail); + + up(&priv->tsi_raw_fifo.lock); + } + + + up(&priv->tsi_reg_fifo.lock); + + return; +} + +static u32 get_raw_data_cnt(struct da9052_ts_priv *priv) +{ + u32 raw_data_cnt; + + if (priv->tsi_raw_fifo.head <= priv->tsi_raw_fifo.tail) + raw_data_cnt = + (priv->tsi_raw_fifo.tail - priv->tsi_raw_fifo.head); + else + raw_data_cnt = + (priv->tsi_raw_fifo.tail + (TSI_RAW_DATA_BUF_SIZE - + priv->tsi_raw_fifo.head)); + + return raw_data_cnt; +} + +static void da9052_tsi_convert_reg_to_coord(struct da9052_ts_priv *priv, + struct da9052_tsi_data *raw_data) +{ + + struct da9052_tsi_reg *src; + struct da9052_tsi_data *dst = raw_data; + + src = &priv->tsi_reg_fifo.data[priv->tsi_reg_fifo.head]; + + dst->x = (src->x_msb << X_MSB_SHIFT); + dst->x |= (src->lsb & X_LSB_MASK) >> X_LSB_SHIFT; + + dst->y = (src->y_msb << Y_MSB_SHIFT); + dst->y |= (src->lsb & Y_LSB_MASK) >> Y_LSB_SHIFT; + + dst->z = (src->z_msb << Z_MSB_SHIFT); + dst->z |= (src->lsb & Z_LSB_MASK) >> Z_LSB_SHIFT; + +#if DA9052_TSI_RAW_DATA_PROFILING + printk(KERN_DEBUG "R\tX\t%4d\tY\t%4d\tZ\t%4d\n", + (u16)dst->x, + (u16)dst->y, + (u16)dst->z); +#endif + priv->raw_data_cnt++; + incr_with_wrap_reg_fifo(priv->tsi_reg_fifo.head); +} + +#if (ENABLE_AVERAGE_FILTER) +static void da9052_tsi_avrg_filter(struct da9052_ts_priv *priv, + struct da9052_tsi_data *tsi_avg_data) +{ + u8 cnt; + + if (down_interruptible(&priv->tsi_raw_fifo.lock)) { + printk(KERN_DEBUG "%s: No RAW Lock !\n", __func__); + return; + } + + (*tsi_avg_data) = priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head]; + incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.head); + + for (cnt = 2; cnt <= TSI_AVERAGE_FILTER_SIZE; cnt++) { + + tsi_avg_data->x += + priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head].x; + tsi_avg_data->y += + priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head].y; + tsi_avg_data->z += + priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head].z; + + incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.head); + } + + up(&priv->tsi_raw_fifo.lock); + + tsi_avg_data->x /= TSI_AVERAGE_FILTER_SIZE; + tsi_avg_data->y /= TSI_AVERAGE_FILTER_SIZE; + tsi_avg_data->z /= TSI_AVERAGE_FILTER_SIZE; + +#if DA9052_TSI_AVG_FLT_DATA_PROFILING + printk(KERN_DEBUG "A\tX\t%4d\tY\t%4d\tZ\t%4d\n", + (u16)tsi_avg_data->x, + (u16)tsi_avg_data->y, + (u16)tsi_avg_data->z); +#endif + + return; +} +#endif + +s32 da9052_tsi_raw_proc_thread(void *ptr) +{ + struct da9052_tsi_data coord; + u8 calib_ok, range_ok; + struct calib_cfg_t *tsi_calib = get_calib_config(); + struct input_dev *ip_dev = (struct input_dev *) + da9052_tsi_get_input_dev( + (u8)TSI_INPUT_DEVICE_OFF); + struct da9052_ts_priv *priv = (struct da9052_ts_priv *)ptr; + + set_freezable(); + + while (priv->tsi_raw_proc_thread.state == ACTIVE) { + + try_to_freeze(); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout( + msecs_to_jiffies(priv->tsi_raw_data_poll_interval)); + + if (priv->early_data_flag || (get_raw_data_cnt(priv) == 0)) + continue; + + calib_ok = TRUE; + range_ok = TRUE; + +#if (ENABLE_AVERAGE_FILTER) + + if (get_raw_data_cnt(priv) < TSI_AVERAGE_FILTER_SIZE) + continue; + + da9052_tsi_avrg_filter(priv, &coord); + +#else + + if (down_interruptible(&priv->tsi_raw_fifo.lock)) + continue; + + coord = priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head]; + incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.head); + + up(&priv->tsi_raw_fifo.lock); + +#endif + + if (tsi_calib->calibrate_flag) { + calib_ok = da9052_tsi_get_calib_display_point(&coord); + + if ((coord.x < DISPLAY_X_MIN) || + (coord.x > DISPLAY_X_MAX) || + (coord.y < DISPLAY_Y_MIN) || + (coord.y > DISPLAY_Y_MAX)) + range_ok = FALSE; + } + + if (calib_ok && range_ok) { + input_report_abs(ip_dev, BTN_TOUCH, 1); + input_report_abs(ip_dev, ABS_X, coord.x); + input_report_abs(ip_dev, ABS_Y, coord.y); + input_sync(ip_dev); + + priv->os_data_cnt++; + +#if DA9052_TSI_OS_DATA_PROFILING + printk(KERN_DEBUG "O\tX\t%4d\tY\t%4d\tZ\t%4d\n", (u16)coord.x, + (u16)coord.y, (u16)coord.z); +#endif + } else { + if (!calib_ok) { + DA9052_DEBUG("%s: ", __func__); + DA9052_DEBUG("calibration Failed\n"); + } + if (!range_ok) { + DA9052_DEBUG("%s: ", __func__); + DA9052_DEBUG("sample beyond display "); + DA9052_DEBUG("panel dimension\n"); + } + } + } + priv->tsi_raw_proc_thread.thread_task = NULL; + complete_and_exit(&priv->tsi_raw_proc_thread.notifier, 0); + return 0; + +} + +#if (ENABLE_TSI_DEBOUNCE) +static s32 da9052_tsi_calc_debounce_data(struct da9052_tsi_data *raw_data) +{ +#if (TSI_DEBOUNCE_DATA_CNT) + u8 cnt; + struct da9052_tsi_data temp = {.x = 0, .y = 0, .z = 0}; + + priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.tail] = (*raw_data); + incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.tail); + + if (get_raw_data_cnt(priv) <= TSI_DEBOUNCE_DATA_CNT) + return -FAILURE; + + for (cnt = 1; cnt <= TSI_DEBOUNCE_DATA_CNT; cnt++) { + temp.x += priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head].x; + temp.y += priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head].y; + temp.z += priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head].z; + + incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.head); + } + + temp.x /= TSI_DEBOUNCE_DATA_CNT; + temp.y /= TSI_DEBOUNCE_DATA_CNT; + temp.z /= TSI_DEBOUNCE_DATA_CNT; + + priv->tsi_raw_fifo.tail = priv->tsi_raw_fifo.head; + priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.tail] = temp; + incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.tail); + +#if DA9052_TSI_PRINT_DEBOUNCED_DATA + printk(KERN_DEBUG "D: X: %d Y: %d Z: %d\n", + (u16)temp.x, (u16)temp.y, (u16)temp.z); +#endif + +#endif + priv->debounce_over = TRUE; + + return 0; +} +#endif + +# if (ENABLE_WINDOW_FILTER) +static s32 diff_within_window(struct da9052_tsi_data *prev_raw_data, + struct da9052_tsi_data *cur_raw_data) +{ + s32 ret = -EINVAL; + s32 x, y; + x = ((cur_raw_data->x) - (prev_raw_data->x)); + y = ((cur_raw_data->y) - (prev_raw_data->y)); + + if (WITHIN_WINDOW(x, y)) { + +#if DA9052_TSI_WIN_FLT_DATA_PROFILING + printk(KERN_DEBUG "W\tX\t%4d\tY\t%4d\tZ\t%4d\n", + (u16)cur_raw_data->x, + (u16)cur_raw_data->y, + (u16)cur_raw_data->z); +#endif + ret = 0; + } + return ret; +} + +static s32 da9052_tsi_window_filter(struct da9052_ts_priv *priv, + struct da9052_tsi_data *raw_data) +{ + u8 ref_found; + u32 cur, next; + s32 ret = -EINVAL; + static struct da9052_tsi_data prev_raw_data; + + if (priv->win_reference_valid == TRUE) { + +#if DA9052_TSI_PRINT_PREVIOUS_DATA + printk(KERN_DEBUG "P: X: %d Y: %d Z: %d\n", + (u16)prev_raw_data.x, (u16)prev_raw_data.y, + (u16)prev_raw_data.z); +#endif + ret = diff_within_window(&prev_raw_data, raw_data); + if (!ret) + prev_raw_data = (*raw_data); + } else { + priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.tail] = (*raw_data); + incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.tail); + + if (get_raw_data_cnt(priv) == SAMPLE_CNT_FOR_WIN_REF) { + + ref_found = FALSE; + + next = cur = priv->tsi_raw_fifo.head; + incr_with_wrap_raw_fifo(next); + + while (next <= priv->tsi_raw_fifo.tail) { + ret = diff_within_window( + &priv->tsi_raw_fifo.data[cur], + &priv->tsi_raw_fifo.data[next] + ); + if (ret == SUCCESS) { + ref_found = TRUE; + break; + } + incr_with_wrap_raw_fifo(cur); + incr_with_wrap_raw_fifo(next); + + } + + if (ref_found == FALSE) + priv->tsi_raw_fifo.tail = + priv->tsi_raw_fifo.head; + else { + prev_raw_data = priv->tsi_raw_fifo.data[cur]; + + prev_raw_data.x += + priv->tsi_raw_fifo.data[next].x; + prev_raw_data.y += + priv->tsi_raw_fifo.data[next].y; + prev_raw_data.z += + priv->tsi_raw_fifo.data[next].z; + + prev_raw_data.x = prev_raw_data.x / 2; + prev_raw_data.y = prev_raw_data.y / 2; + prev_raw_data.z = prev_raw_data.z / 2; + + (*raw_data) = prev_raw_data; + + priv->tsi_raw_fifo.tail = + priv->tsi_raw_fifo.head; + + priv->win_reference_valid = TRUE; + ret = SUCCESS; + } + } + } + return ret; +} +#endif +static inline void clean_tsi_reg_fifo(struct da9052_ts_priv *priv) +{ + priv->tsi_reg_fifo.head = FIRST_SAMPLE; + priv->tsi_reg_fifo.tail = FIRST_SAMPLE; +} + +static inline void clean_tsi_raw_fifo(struct da9052_ts_priv *priv) +{ + priv->tsi_raw_fifo.head = FIRST_SAMPLE; + priv->tsi_raw_fifo.tail = FIRST_SAMPLE; +} +
On 06/10/2011 04:50 AM, Somebody in the thread at some point said:
+static ssize_t write_da9052_reg(struct da9052 *da9052, u8 reg_addr, u8 data) +{
- ssize_t ret = 0;
- struct da9052_ssc_msg ssc_msg;
- ssc_msg.addr = reg_addr;
- ssc_msg.data = data;
- ret = da9052->write(da9052,&ssc_msg);
- if (ret) {
DA9052_DEBUG("%s: ", __func__);
DA9052_DEBUG("da9052_ssc_write Failed %d\n", ret);
- }
- return ret;
+}
+static ssize_t read_da9052_reg(struct da9052 *da9052, u8 reg_addr) +{
ssize_t ret = 0;
struct da9052_ssc_msg ssc_msg;
- ssc_msg.addr = reg_addr;
- ssc_msg.data = 0;
- ret = da9052->read(da9052,&ssc_msg);
- if (ret) {
DA9052_DEBUG("%s: ", __func__);
DA9052_DEBUG("da9052_ssc_read Failed => %d\n", ret);
return -ret;
Huh... you return -ret on error here, but on write_da9052_reg() you return ret on error... is that right?
- }
- return ssc_msg.data;
+}
+static struct da9052_tsi_info *get_tsi_drvdata(void) +{
- return&gda9052_tsi_info;
+}
+static ssize_t da9052_tsi_config_measure_seq(struct da9052_ts_priv *priv,
enum TSI_MEASURE_SEQ seq)
+{
- ssize_t ret = 0;
- u8 data = 0;
- struct da9052_tsi_info *ts = get_tsi_drvdata();
- if (seq> 1)
return -EINVAL;
- da9052_lock(priv->da9052);
- ret = read_da9052_reg(priv->da9052, DA9052_TSICONTA_REG);
- if (ret< 0) {
DA9052_DEBUG("DA9052_TSI: %s:", __func__);
DA9052_DEBUG("read_da9052_reg Failed\n");
da9052_unlock(priv->da9052);
return ret;
- }
- data = (u8)ret;
- if (seq == XYZP_MODE)
data = enable_xyzp_mode(data);
- else if (seq == XP_MODE)
data = enable_xp_mode(data);
- else {
DA9052_DEBUG("DA9052_TSI: %s:", __func__);
DA9052_DEBUG("Invalid Value passed\n");
da9052_unlock(priv->da9052);
return -EINVAL;
- }
When I see else if I wonder if I should be looking at switch()
switch (seq) { case XYZP_MODE: data = enable_xyzp_mode(data); break; case XP_MODE: data = enable_xp_mode(data); break; default: DA9052_DEBUG("DA9052_TSI: %s:", __func__); DA9052_DEBUG("Invalid Value passed\n"); ret = -EINVAL; goto bail; }
- switch (mode) {
- case ECONOMY_MODE:
Hey you like switch too... good!
- da9052_lock(priv->da9052);
- ret = read_da9052_reg(priv->da9052, DA9052_TSICONTA_REG);
Just an idea... some places in the kernel use a nice convention, if a function requires a lock they prepend it with __, eg, __read_da9052_reg. That makes it real clear at the usage if you should check for lock, or rename the function using it also to use __ since it depends on the lock. Just an idea to make it easier to see lock requirement.
- if ((DA9052_GPIO_PIN_3 != DA9052_GPIO_CONFIG_TSI) ||
(DA9052_GPIO_PIN_4 != DA9052_GPIO_CONFIG_TSI) ||
(DA9052_GPIO_PIN_5 != DA9052_GPIO_CONFIG_TSI) ||
(DA9052_GPIO_PIN_6 != DA9052_GPIO_CONFIG_TSI) ||
(DA9052_GPIO_PIN_7 != DA9052_GPIO_CONFIG_TSI)) {
printk(KERN_ERR"DA9052_TSI: Configure DA9052 GPIO ");
printk(KERN_ERR"pins for TSI\n");
return -EINVAL;
- }
Dunno what I am looking at there... it's all preprocessor defines known at compiletime? Better to use #if and #error then?
- ret = da9052_tsi_config_gpio(priv);
Can it fail? If not lose the ret = otherwise test it.
- ret = da9052_tsi_config_state(priv, DEFAULT_TSI_STATE);
- if (ret) {
for (cnt = 0; cnt< NUM_INPUT_DEVS; cnt++) {
if (ts->input_devs[cnt] != NULL)
input_free_device(ts->input_devs[cnt]);
}
- }
None of the { } are needed.
+static ssize_t da9052_tsi_config_gpio(struct da9052_ts_priv *priv) +{
- u8 idx = 0;
- ssize_t ret = 0;
- struct da9052_ssc_msg ssc_msg[priv->tsi_pdata->num_gpio_tsi_register];
I am not sure if dynamic local array sizing is good news in kernel code, I don't recall seeing it anywhere else in kernel. Consider just defining it to be the maximum extent?
- idx = 0;
- ssc_msg[idx].data = clear_bits(ssc_msg[idx].data,
DA9052_GPIO0203_GPIO3PIN);
- idx++;
Simplify to ssg_msg[idx++].data...
- if (state == ENABLE)
data = set_auto_tsi_en(data);
- else if (state == DISABLE)
data = reset_auto_tsi_en(data);
- else {
DA9052_DEBUG("DA9052_TSI: %s:", __func__);
DA9052_DEBUG("Invalid Parameter Passed\n");
da9052_unlock(priv->da9052);
return -EINVAL;
- }
Maybe switch? I guess it's just matter of taste.
You can change the code structure a bit to get away from excessive indentation -->
+static u32 da9052_tsi_get_reg_data(struct da9052_ts_priv *priv) +{
- u32 free_cnt, copy_cnt, cnt;
- if (down_interruptible(&priv->tsi_reg_fifo.lock))
return 0;
- copy_cnt = 0;
- if ((priv->tsi_reg_fifo.head - priv->tsi_reg_fifo.tail)> 1) {
free_cnt = get_reg_free_space_cnt(priv);
if (free_cnt> TSI_POLL_SAMPLE_CNT)
free_cnt = TSI_POLL_SAMPLE_CNT;
cnt = da9052_tsi_get_rawdata(
&priv->tsi_reg_fifo.data[priv->tsi_reg_fifo.tail],
free_cnt);
if (cnt> free_cnt) {
DA9052_DEBUG("EH copied more data");
return -EINVAL;
}
copy_cnt = cnt;
while (cnt--)
incr_with_wrap_reg_fifo(priv->tsi_reg_fifo.tail);
goto bail;
} if ((priv->tsi_reg_fifo.head - priv->tsi_reg_fifo.tail) > 0) {
copy_cnt = 0; goto bail; }
[ loses one level of tabbing ]
free_cnt = (TSI_REG_DATA_BUF_SIZE - priv->tsi_reg_fifo.tail);
if (free_cnt> TSI_POLL_SAMPLE_CNT) {
free_cnt = TSI_POLL_SAMPLE_CNT;
cnt = da9052_tsi_get_rawdata(
&priv->tsi_reg_fifo.data[priv->tsi_reg_fifo.tail],
free_cnt);
if (cnt> free_cnt) {
DA9052_DEBUG("EH copied more data");
return -EINVAL;
}
copy_cnt = cnt;
while (cnt--)
incr_with_wrap_reg_fifo(
priv->tsi_reg_fifo.tail);
goto bail; }
[ loses second level of tabbing ]
if (free_cnt) {
cnt = da9052_tsi_get_rawdata(
&priv->
tsi_reg_fifo.data[priv->
tsi_reg_fifo.tail],
free_cnt
);
if (cnt> free_cnt) {
DA9052_DEBUG("EH copied more data");
return -EINVAL;
}
copy_cnt = cnt;
while (cnt--)
incr_with_wrap_reg_fifo(
priv->tsi_reg_fifo.tail);
}
free_cnt = priv->tsi_reg_fifo.head;
if (free_cnt> TSI_POLL_SAMPLE_CNT - copy_cnt)
free_cnt = TSI_POLL_SAMPLE_CNT - copy_cnt;
if (free_cnt) {
cnt = da9052_tsi_get_rawdata(
&priv->tsi_reg_fifo.data[priv->
tsi_reg_fifo.tail], free_cnt
);
if (cnt> free_cnt) {
DA9052_DEBUG("EH copied more data");
return -EINVAL;
}
copy_cnt += cnt;
while (cnt--)
incr_with_wrap_reg_fifo(
priv->tsi_reg_fifo.tail);
}
bail:
if (data_cnt)
ts->tsi_zero_data_cnt = 0;
else {
Don't need { } on else
- } else if (tsi_reg.tsi_fifo_start> tsi_reg.tsi_fifo_end) {
data_cnt = ((TSI_FIFO_SIZE - tsi_reg.tsi_fifo_start)
+ tsi_reg.tsi_fifo_end);
Trailing operator + should go at end of previous line
- xform.Divider = ((screenPtr[0].x - screenPtr[1].x)
* (screenPtr[1].y - screenPtr[2].y))
- ((screenPtr[1].x - screenPtr[2].x)
* (screenPtr[0].y - screenPtr[1].y));
Trailing operators again need to go at end of previous line... several more instances here.
+#if (ENABLE_AVERAGE_FILTER)
Dude I feel your pain.
I tried a couple of years ago to add a touchscreen driver for Openmoko which had generic awesome median filtering code I wrote.
The median filter effectiveness for resistive touchscreen noise (low probability excursions) was really amazing.
Maybe the opinion changed, or this is small enough it won't get noticed -- my patches established a filter chain class at that time so it was pretty easy to hate on -- but while some people liked it, mainly there were many people following what they thought was the received wisdom that filtering should be done in userspace. Never mind the issue of decimation vs userspace wakeups.
So good luck.
- if (priv->tsi_reg_fifo.head<= priv->tsi_reg_fifo.tail) {
reg_data_cnt = (priv->tsi_reg_fifo.tail -
priv->tsi_reg_fifo.head);
- } else {
reg_data_cnt = (priv->tsi_reg_fifo.tail +
(TSI_REG_DATA_BUF_SIZE -
priv->tsi_reg_fifo.head));
- }
None of the {} are needed.
- if (priv->tsi_reg_fifo.head<= priv->tsi_reg_fifo.tail) {
free_cnt = ((TSI_REG_DATA_BUF_SIZE - 1) -
(priv->tsi_reg_fifo.tail - priv->tsi_reg_fifo.head));
- } else
{} not needed
+# if (ENABLE_WINDOW_FILTER)
ret = da9052_tsi_window_filter(priv,&tmp_raw_data);
if (ret != SUCCESS)
continue;
+#endif
It might make sense to eliminate #if here by always defining the filter functions, and giving them empty body via #if just in there if not enabled.
priv->early_data_flag = FALSE;
if (down_interruptible(&priv->tsi_raw_fifo.lock)) {
DA9052_DEBUG("%s: Failed to ", __func__);
DA9052_DEBUG("acquire RAW FIFO Lock!\n");
up(&priv->tsi_reg_fifo.lock);
return;
}
priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.tail] = tmp_raw_data;
incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.tail);
up(&priv->tsi_raw_fifo.lock);
- }
Can lose a blank line.
- up(&priv->tsi_reg_fifo.lock);
- return;
Lose the "return" on void function, does nothing.
+}
+static u32 get_raw_data_cnt(struct da9052_ts_priv *priv) +{
- u32 raw_data_cnt;
- if (priv->tsi_raw_fifo.head<= priv->tsi_raw_fifo.tail)
raw_data_cnt =
(priv->tsi_raw_fifo.tail - priv->tsi_raw_fifo.head);
- else
raw_data_cnt =
(priv->tsi_raw_fifo.tail + (TSI_RAW_DATA_BUF_SIZE -
priv->tsi_raw_fifo.head));
- return raw_data_cnt;
+}
+static void da9052_tsi_convert_reg_to_coord(struct da9052_ts_priv *priv,
struct da9052_tsi_data *raw_data)
+{
- struct da9052_tsi_reg *src;
- struct da9052_tsi_data *dst = raw_data;
- src =&priv->tsi_reg_fifo.data[priv->tsi_reg_fifo.head];
- dst->x = (src->x_msb<< X_MSB_SHIFT);
- dst->x |= (src->lsb& X_LSB_MASK)>> X_LSB_SHIFT;
Unify into one expression with |
- tsi_avg_data->x /= TSI_AVERAGE_FILTER_SIZE;
- tsi_avg_data->y /= TSI_AVERAGE_FILTER_SIZE;
- tsi_avg_data->z /= TSI_AVERAGE_FILTER_SIZE;
Snif so many memories...
+#if DA9052_TSI_AVG_FLT_DATA_PROFILING
- printk(KERN_DEBUG "A\tX\t%4d\tY\t%4d\tZ\t%4d\n",
(u16)tsi_avg_data->x,
(u16)tsi_avg_data->y,
(u16)tsi_avg_data->z);
+#endif
- return;
Lose the return.
+static s32 diff_within_window(struct da9052_tsi_data *prev_raw_data,
struct da9052_tsi_data *cur_raw_data)
+{
- s32 ret = -EINVAL;
- s32 x, y;
- x = ((cur_raw_data->x) - (prev_raw_data->x));
- y = ((cur_raw_data->y) - (prev_raw_data->y));
No need for any ()
- if (priv->win_reference_valid == TRUE) {
Do you really need to have == TRUE? How about
if (priv->win_reference_valid) {
prev_raw_data = (*raw_data);
- } else {
priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.tail] = (*raw_data);
Lose the () in both cases
incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.tail);
if (get_raw_data_cnt(priv) == SAMPLE_CNT_FOR_WIN_REF) {
ref_found = FALSE;
I think you can use 1 or 0 or true or false in this kind of situation.
if (ref_found == FALSE)
if (!ref_found)
priv->tsi_raw_fifo.tail =
priv->tsi_raw_fifo.head;
else {
prev_raw_data = priv->tsi_raw_fifo.data[cur];
prev_raw_data.x +=
priv->tsi_raw_fifo.data[next].x;
prev_raw_data.y +=
priv->tsi_raw_fifo.data[next].y;
prev_raw_data.z +=
priv->tsi_raw_fifo.data[next].z;
prev_raw_data.x = prev_raw_data.x / 2;
prev_raw_data.y = prev_raw_data.y / 2;
prev_raw_data.z = prev_raw_data.z / 2;
prev_raw_data.z /= 2;
(*raw_data) = prev_raw_data;
Lose the ()
priv->tsi_raw_fifo.tail =
priv->tsi_raw_fifo.head;
priv->win_reference_valid = TRUE;
ret = SUCCESS;
Just ret = 0 is fine
}
}
- }
- return ret;
+} +#endif +static inline void clean_tsi_reg_fifo(struct da9052_ts_priv *priv) +{
- priv->tsi_reg_fifo.head = FIRST_SAMPLE;
- priv->tsi_reg_fifo.tail = FIRST_SAMPLE;
+}
+static inline void clean_tsi_raw_fifo(struct da9052_ts_priv *priv) +{
- priv->tsi_raw_fifo.head = FIRST_SAMPLE;
- priv->tsi_raw_fifo.tail = FIRST_SAMPLE;
+}
No need for inline
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9052 led driver from Dialog. Modify Kconfig/Makefile for DA9052 led driver.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org --- drivers/leds/Kconfig | 10 ++ drivers/leds/Makefile | 1 + drivers/leds/leds-da9052.c | 308 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 319 insertions(+), 0 deletions(-) create mode 100644 drivers/leds/leds-da9052.c
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 23f0d5e..e92dfc1 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -469,4 +469,14 @@ config LEDS_TRIGGER_DEFAULT_ON comment "iptables trigger is under Netfilter config (LED target)" depends on LEDS_TRIGGERS
+config LEDS_DA9052 + tristate "Dialog DA9052 LEDS" + depends on PMIC_DIALOG + select LEDS_CLASS + help + This option enables support for on-chip LED drivers found + on Dialog Semiconductor DA9052 PMICs. + +comment "LED Triggers" + endif # NEW_LEDS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index bbfd2e3..f29faa0 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o obj-$(CONFIG_LEDS_NS2) += leds-ns2.o obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o +obj-$(CONFIG_LEDS_DA9052) += leds-da9052.o
# LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/leds-da9052.c b/drivers/leds/leds-da9052.c new file mode 100644 index 0000000..f829a0e --- /dev/null +++ b/drivers/leds/leds-da9052.c @@ -0,0 +1,308 @@ +/* + * leds-da9052.c -- LED Driver for Dialog DA9052 + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * Author: Dialog Semiconductor Ltd dchen@diasemi.com + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/leds.h> +#include <linux/workqueue.h> +#include <linux/slab.h> + +#include <linux/mfd/da9052/reg.h> +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/led.h> + +#define DRIVER_NAME "da9052-leds" + +#define DA9052_LED4_PRESENT 1 +#define DA9052_LED5_PRESENT 1 + + +struct da9052_led_data { + struct led_classdev cdev; + struct work_struct work; + struct da9052 *da9052; + int id; + int new_brightness; + int is_led4_present; + int is_led5_present; +}; + +#define GPIO14_PIN 2 /* GPO Open Drain */ +#define GPIO14_TYPE 0 /* VDD_IO1 */ +#define GPIO14_MODE 1 /* Output High */ + +#define GPIO15_PIN 2 /* GPO Open Drain */ +#define GPIO15_TYPE 0 /* VDD_IO1 */ +#define GPIO15_MODE 1 /* Output High */ + +#define MAXIMUM_PWM 95 +#define MASK_GPIO14 0x0F +#define MASK_GPIO15 0xF0 +#define GPIO15_PIN_BIT_POSITION 4 + +static void da9052_led_work(struct work_struct *work) +{ + struct da9052_led_data *led = container_of(work, + struct da9052_led_data, work); + int reg = 0; + int led_dim_bit = 0; + struct da9052_ssc_msg msg; + int ret = 0; + + switch (led->id) { + case DA9052_LED_4: + reg = DA9052_LED4CONT_REG; + led_dim_bit = DA9052_LED4CONT_LED4DIM; + break; + case DA9052_LED_5: + reg = DA9052_LED5CONT_REG; + led_dim_bit = DA9052_LED5CONT_LED5DIM; + break; + } + + if (led->new_brightness > MAXIMUM_PWM) + led->new_brightness = MAXIMUM_PWM; + + /* Always enable DIM feature + * This feature can be disabled if required + */ + msg.addr = reg; + msg.data = led->new_brightness | led_dim_bit; + da9052_lock(led->da9052); + ret = led->da9052->write(led->da9052, &msg); + if (ret) { + da9052_unlock(led->da9052); + return; + } + da9052_unlock(led->da9052); +} + +static void da9052_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct da9052_led_data *led; + + led = container_of(led_cdev, struct da9052_led_data, cdev); + led->new_brightness = value; + schedule_work(&led->work); +} + +static int __devinit da9052_led_setup(struct da9052_led_data *led) +{ + int reg = 0; + int ret = 0; + + struct da9052_ssc_msg msg; + + switch (led->id) { + case DA9052_LED_4: + reg = DA9052_LED4CONT_REG; + break; + case DA9052_LED_5: + reg = DA9052_LED5CONT_REG; + break; + } + + msg.addr = reg; + msg.data = 0; + + da9052_lock(led->da9052); + ret = led->da9052->write(led->da9052, &msg); + if (ret) { + da9052_unlock(led->da9052); + return ret; + } + da9052_unlock(led->da9052); + return ret; +} + +static int da9052_leds_prepare(struct da9052_led_data *led) +{ + int ret = 0; + struct da9052_ssc_msg msg; + + da9052_lock(led->da9052); + + if (1 == led->is_led4_present) { + msg.addr = DA9052_GPIO1415_REG; + msg.data = 0; + + ret = led->da9052->read(led->da9052, &msg); + if (ret) + goto out; + msg.data = msg.data & ~(MASK_GPIO14); + msg.data = msg.data | ( + GPIO14_PIN | + (GPIO14_TYPE ? DA9052_GPIO1415_GPIO14TYPE : 0) | + (GPIO14_MODE ? DA9052_GPIO1415_GPIO14MODE : 0)); + + ret = led->da9052->write(led->da9052, &msg); + if (ret) + goto out; + } + + if (1 == led->is_led5_present) { + msg.addr = DA9052_GPIO1415_REG; + msg.data = 0; + + ret = led->da9052->read(led->da9052, &msg); + if (ret) + goto out; + msg.data = msg.data & ~(MASK_GPIO15); + msg.data = msg.data | + (((GPIO15_PIN << GPIO15_PIN_BIT_POSITION) | + (GPIO15_TYPE ? DA9052_GPIO1415_GPIO15TYPE : 0) | + (GPIO15_MODE ? DA9052_GPIO1415_GPIO15MODE : 0)) + ); + ret = led->da9052->write(led->da9052, &msg); + if (ret) + goto out; + } + + da9052_unlock(led->da9052); + return ret; +out: + da9052_unlock(led->da9052); + return ret; +} + +static int __devinit da9052_led_probe(struct platform_device *pdev) +{ + struct da9052_leds_platform_data *pdata = (pdev->dev.platform_data); + struct da9052_led_platform_data *led_cur; + struct da9052_led_data *led, *led_dat; + int ret, i; + int init_led = 0; + + if (pdata->num_leds < 1 || pdata->num_leds > DA9052_LED_MAX) { + dev_err(&pdev->dev, "Invalid led count %d\n", pdata->num_leds); + return -EINVAL; + } + + led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL); + if (led == NULL) { + dev_err(&pdev->dev, "failed to alloc memory\n"); + return -ENOMEM; + } + + led->is_led4_present = DA9052_LED4_PRESENT; + led->is_led5_present = DA9052_LED5_PRESENT; + + for (i = 0; i < pdata->num_leds; i++) { + led_dat = &led[i]; + led_cur = &pdata->led[i]; + if (led_cur->id < 0) { + dev_err(&pdev->dev, "invalid id %d\n", led_cur->id); + ret = -EINVAL; + goto err_register; + } + + if (init_led & (1 << led_cur->id)) { + dev_err(&pdev->dev, "led %d already initialized\n", + led_cur->id); + ret = -EINVAL; + goto err_register; + } + + init_led |= 1 << led_cur->id; + + led_dat->cdev.name = led_cur->name; + /* led_dat->cdev.default_trigger = + led_cur[i]->default_trigger; */ + led_dat->cdev.brightness_set = da9052_led_set; + led_dat->cdev.brightness = LED_OFF; + led_dat->id = led_cur->id; + led_dat->da9052 = dev_get_drvdata(pdev->dev.parent); + + INIT_WORK(&led_dat->work, da9052_led_work); + + ret = led_classdev_register(pdev->dev.parent, &led_dat->cdev); + if (ret) { + dev_err(&pdev->dev, "failed to register led %d\n", + led_dat->id); + goto err_register; + + } + ret = da9052_led_setup(led_dat); + if (ret) { + dev_err(&pdev->dev, "unable to init led %d\n", + led_dat->id); + i++; + goto err_register; + } + } + ret = da9052_leds_prepare(led); + if (ret) { + dev_err(&pdev->dev, "unable to init led driver\n"); + goto err_free; + } + + platform_set_drvdata(pdev, led); + return 0; + +err_register: + for (i = i - 1; i >= 0; i--) { + led_classdev_unregister(&led[i].cdev); + cancel_work_sync(&led[i].work); + } + +err_free: + kfree(led); + return ret; +} + +static int __devexit da9052_led_remove(struct platform_device *pdev) +{ + struct da9052_leds_platform_data *pdata = + (struct da9052_leds_platform_data *)pdev->dev.platform_data; + struct da9052_led_data *led = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < pdata->num_leds; i++) { + da9052_led_setup(&led[i]); + led_classdev_unregister(&led[i].cdev); + cancel_work_sync(&led[i].work); + } + + kfree(led); + return 0; +} + +static struct platform_driver da9052_led_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = da9052_led_probe, + .remove = __devexit_p(da9052_led_remove), +}; + +static int __init da9052_led_init(void) +{ + return platform_driver_register(&da9052_led_driver); +} +module_init(da9052_led_init); + +static void __exit da9052_led_exit(void) +{ + platform_driver_unregister(&da9052_led_driver); +} +module_exit(da9052_led_exit); + +MODULE_AUTHOR("Dialog Semiconductor Ltd dchen@diasemi.com "); +MODULE_DESCRIPTION("LED driver for Dialog DA9052 PMIC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME);
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9052 mfd driver from Dialog. Modify Kconfig/Makefile for DA9052 mfd driver.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org --- drivers/mfd/Kconfig | 37 +++ drivers/mfd/Makefile | 2 + drivers/mfd/da9052-core.c | 536 +++++++++++++++++++++++++++++++++++++++++++++ drivers/mfd/da9052-i2c.c | 378 ++++++++++++++++++++++++++++++++ drivers/mfd/da9052-spi.c | 402 +++++++++++++++++++++++++++++++++ 5 files changed, 1355 insertions(+), 0 deletions(-) create mode 100644 drivers/mfd/da9052-core.c create mode 100644 drivers/mfd/da9052-i2c.c create mode 100644 drivers/mfd/da9052-spi.c
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 0f09c05..a3d0568 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -483,6 +483,43 @@ config PCF50633_GPIO Say yes here if you want to include support GPIO for pins on the PCF50633 chip.
+config PMIC_DIALOG + bool "Support Dialog Semiconductor PMIC" + depends on I2C=y + depends on SPI=y + select MFD_CORE + help + Support for Dialog semiconductor PMIC chips. + Use the options provided to support the desired PMIC's. +choice + prompt "Chip Type" + depends on PMIC_DIALOG +config PMIC_DA9052 + bool "Support Dialog Semiconductor DA9052 PMIC" + help + Support for Dialog semiconductor DA9052 PMIC with inbuilt + SPI & I2C connectivities. + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the + functionality of the device. +config PMIC_DA9053AA + bool "Support Dialog Semiconductor DA9053 AA PMIC" + help + Support for Dialog semiconductor DA9053 AA PMIC with inbuilt + SPI & I2C connectivities. + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the + functionality of the device. +config PMIC_DA9053Bx + bool "Support Dialog Semiconductor DA9053 BA/BB PMIC" + help + Support for Dialog semiconductor DA9053 BA/BB PMIC with inbuilt + SPI & I2C connectivities. + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the + functionality of the device. +endchoice + config MFD_MC13783 tristate
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index efe3cc3..d30b69c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -94,3 +94,5 @@ obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o +da9052-objs := da9052-spi.o da9052-i2c.o da9052-core.o +obj-$(CONFIG_PMIC_DIALOG) += da9052.o diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c new file mode 100644 index 0000000..002cf50 --- /dev/null +++ b/drivers/mfd/da9052-core.c @@ -0,0 +1,536 @@ +/* + * da9052-core.c -- Device access for Dialog DA9052 + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * Author: Dialog Semiconductor Ltd dchen@diasemi.com + * + * 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. + * + */ + +#include <linux/device.h> +#include <linux/jiffies.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/irq.h> +#include <linux/list.h> +#include <linux/mfd/core.h> +#include <linux/spi/spi.h> +#include <linux/i2c.h> +#include <linux/semaphore.h> + +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/adc.h> + +#define SUCCESS 0 +#define FAILURE 1 + +struct da9052_eh_nb eve_nb_array[EVE_CNT]; +static struct da9052_ssc_ops ssc_ops; +struct mutex manconv_lock; +static struct semaphore eve_nb_array_lock; + +void da9052_lock(struct da9052 *da9052) +{ + mutex_lock(&da9052->ssc_lock); +} +EXPORT_SYMBOL(da9052_lock); + +void da9052_unlock(struct da9052 *da9052) +{ + mutex_unlock(&da9052->ssc_lock); +} +EXPORT_SYMBOL(da9052_unlock); + +int da9052_ssc_write(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg) +{ + int ret = 0; + + /* Reg address should be a valid address on PAGE0 or PAGE1 */ + if ((sscmsg->addr < DA9052_PAGE0_REG_START) || + (sscmsg->addr > DA9052_PAGE1_REG_END) || + ((sscmsg->addr > DA9052_PAGE0_REG_END) && + (sscmsg->addr < DA9052_PAGE1_REG_START))) + return INVALID_REGISTER; + + ret = ssc_ops.write(da9052, sscmsg); + + /* Update local cache if required */ + if (!ret) { + /* Check if this register is Non-volatile*/ + if (da9052->ssc_cache[sscmsg->addr].type != VOLATILE) { + /* Update value */ + da9052->ssc_cache[sscmsg->addr].val = sscmsg->data; + /* Make this cache entry valid */ + da9052->ssc_cache[sscmsg->addr].status = VALID; + } + } + + return ret; +} + +int da9052_ssc_read(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg) +{ + int ret = 0; + + /* Reg addr should be a valid address on PAGE0 or PAGE1 */ + if ((sscmsg->addr < DA9052_PAGE0_REG_START) || + (sscmsg->addr > DA9052_PAGE1_REG_END) || + ((sscmsg->addr > DA9052_PAGE0_REG_END) && + (sscmsg->addr < DA9052_PAGE1_REG_START))) + return INVALID_REGISTER; + + /* + * Check if this is a Non-volatile register, if yes then return value - + * from cache instead of actual reading from hardware. Before reading - + * cache entry, make sure that the entry is valid + */ + /* The read request is for Non-volatile register */ + /* Check if we have valid cached value for this */ + if (da9052->ssc_cache[sscmsg->addr].status == VALID) { + /* We have valid cached value, copy this value */ + sscmsg->data = da9052->ssc_cache[sscmsg->addr].val; + + return 0; + } + + ret = ssc_ops.read(da9052, sscmsg); + + /* Update local cache if required */ + if (!ret) { + /* Check if this register is Non-volatile*/ + if (da9052->ssc_cache[sscmsg->addr].type != VOLATILE) { + /* Update value */ + da9052->ssc_cache[sscmsg->addr].val = sscmsg->data; + /* Make this cache entry valid */ + da9052->ssc_cache[sscmsg->addr].status = VALID; + } + } + + return ret; +} + +int da9052_ssc_write_many(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg, + int msg_no) +{ + int ret = 0; + int cnt = 0; + + /* Check request size */ + if (msg_no > MAX_READ_WRITE_CNT) + return -EIO; + + ret = ssc_ops.write_many(da9052, sscmsg, msg_no); + /* Update local cache, if required */ + for (cnt = 0; cnt < msg_no; cnt++) { + /* Check if this register is Non-volatile*/ + if (da9052->ssc_cache[sscmsg[cnt].addr].type != VOLATILE) { + /* Update value */ + da9052->ssc_cache[sscmsg[cnt].addr].val = + sscmsg[cnt].data; + /* Make this cache entry valid */ + da9052->ssc_cache[sscmsg[cnt].addr].status = VALID; + } + } + return ret; +} + +int da9052_ssc_read_many(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg, + int msg_no) +{ + int ret = 0; + int cnt = 0; + + /* Check request size */ + if (msg_no > MAX_READ_WRITE_CNT) + return -EIO; + + ret = ssc_ops.read_many(da9052, sscmsg, msg_no); + /* Update local cache, if required */ + for (cnt = 0; cnt < msg_no; cnt++) { + /* Check if this register is Non-volatile*/ + if (da9052->ssc_cache[sscmsg[cnt].addr].type + != VOLATILE) { + /* Update value */ + da9052->ssc_cache[sscmsg[cnt].addr].val = + sscmsg[cnt].data; + /* Make this cache entry valid */ + da9052->ssc_cache[sscmsg[cnt].addr].status = VALID; + } + } + return ret; +} + +static irqreturn_t da9052_eh_isr(int irq, void *dev_id) +{ + struct da9052 *da9052 = dev_id; + /* Schedule work to be done */ + schedule_work(&da9052->eh_isr_work); + /* Disable IRQ */ + disable_irq_nosync(da9052->irq); + return IRQ_HANDLED; +} + +int eh_register_nb(struct da9052 *da9052, struct da9052_eh_nb *nb) +{ + + if (nb == NULL) { + printk(KERN_INFO "EH REGISTER FUNCTION FAILED\n"); + return -EINVAL; + } + + if (nb->eve_type >= EVE_CNT) { + printk(KERN_INFO "Invalid DA9052 Event Type\n"); + return -EINVAL; + } + + /* Initialize list head inside notifier block */ + INIT_LIST_HEAD(&nb->nb_list); + + /* Acquire NB array lock */ + if (down_interruptible(&eve_nb_array_lock)) + return -EAGAIN; + + /* Add passed NB to corresponding EVENT list */ + list_add_tail(&nb->nb_list, &(eve_nb_array[nb->eve_type].nb_list)); + + /* Release NB array lock */ + up(&eve_nb_array_lock); + + return 0; +} + +int eh_unregister_nb(struct da9052 *da9052, struct da9052_eh_nb *nb) +{ + + if (nb == NULL) + return -EINVAL; + + /* Acquire nb array lock */ + if (down_interruptible(&eve_nb_array_lock)) + return -EAGAIN; + + /* Remove passed NB from list */ + list_del_init(&(nb->nb_list)); + + /* Release NB array lock */ + up(&eve_nb_array_lock); + + return 0; +} + +static int process_events(struct da9052 *da9052, int events_sts) +{ + + int cnt = 0; + int tmp_events_sts = 0; + unsigned char event = 0; + + struct list_head *ptr; + struct da9052_eh_nb *nb_ptr; + + /* Now we have retrieved all events, process them one by one */ + for (cnt = 0; cnt < EVE_CNT; cnt++) { + /* + * Starting with highest priority event, + * traverse through all event + */ + tmp_events_sts = events_sts; + + /* Find the event associated with higher priority */ + event = cnt; + + /* Check if interrupt is received for this event */ + if (!((tmp_events_sts >> cnt) & 0x1)) + /* Event bit is not set for this event */ + /* Move to next event */ + continue; + + if (event == PEN_DOWN_EVE) { + if (list_empty(&(eve_nb_array[event].nb_list))) + continue; + } + + /* Event bit is set, execute all registered call backs */ + if (down_interruptible(&eve_nb_array_lock)) { + printk(KERN_CRIT "Can't acquire eve_nb_array_lock\n"); + return -EIO; + } + + list_for_each(ptr, &(eve_nb_array[event].nb_list)) { + /* + * nb_ptr will point to the structure in which + * nb_list is embedded + */ + nb_ptr = list_entry(ptr, struct da9052_eh_nb, nb_list); + nb_ptr->call_back(nb_ptr, events_sts); + } + up(&eve_nb_array_lock); + } + return 0; +} + +void eh_workqueue_isr(struct work_struct *work) +{ + struct da9052 *da9052 = + container_of(work, struct da9052, eh_isr_work); + + struct da9052_ssc_msg eve_data[4]; + struct da9052_ssc_msg eve_mask_data[4]; + int events_sts, ret; + u32 mask; + unsigned char cnt = 0; + + /* nIRQ is asserted, read event registeres to know what happened */ + events_sts = 0; + mask = 0; + + /* Prepare ssc message to read all four event registers */ + for (cnt = 0; cnt < DA9052_EVE_REGISTERS; cnt++) { + eve_data[cnt].addr = (DA9052_EVENTA_REG + cnt); + eve_data[cnt].data = 0; + } + + /* Prepare ssc message to read all four event registers */ + for (cnt = 0; cnt < DA9052_EVE_REGISTERS; cnt++) { + eve_mask_data[cnt].addr = (DA9052_IRQMASKA_REG + cnt); + eve_mask_data[cnt].data = 0; + } + + /* Now read all event and mask registers */ + da9052_lock(da9052); + + ret = da9052_ssc_read_many(da9052, eve_data, DA9052_EVE_REGISTERS); + if (ret) { + enable_irq(da9052->irq); + da9052_unlock(da9052); + return; + } + + ret = da9052_ssc_read_many(da9052, eve_mask_data, DA9052_EVE_REGISTERS); + if (ret) { + enable_irq(da9052->irq); + da9052_unlock(da9052); + return; + } + /* Collect all events */ + for (cnt = 0; cnt < DA9052_EVE_REGISTERS; cnt++) + events_sts |= (eve_data[cnt].data << (DA9052_EVE_REGISTER_SIZE + * cnt)); + /* Collect all mask */ + for (cnt = 0; cnt < DA9052_EVE_REGISTERS; cnt++) + mask |= (eve_mask_data[cnt].data << (DA9052_EVE_REGISTER_SIZE + * cnt)); + events_sts &= ~mask; + da9052_unlock(da9052); + + /* Check if we really got any event */ + if (events_sts == 0) { + enable_irq(da9052->irq); + da9052_unlock(da9052); + return; + } + + /* Process all events occurred */ + process_events(da9052, events_sts); + + da9052_lock(da9052); + /* Now clear EVENT registers */ + for (cnt = 0; cnt < 4; cnt++) { + if (eve_data[cnt].data) { + ret = da9052_ssc_write(da9052, &eve_data[cnt]); + if (ret) { + enable_irq(da9052->irq); + da9052_unlock(da9052); + return; + } + } + } + da9052_unlock(da9052); + + /* + * This delay is necessary to avoid hardware fake interrupts + * from DA9052. + */ +#if defined CONFIG_PMIC_DA9052 || defined CONFIG_PMIC_DA9053AA + udelay(50); +#endif + /* Enable HOST interrupt */ + enable_irq(da9052->irq); +} + +static void da9052_eh_restore_irq(struct da9052 *da9052) +{ + /* Put your platform and board specific code here */ + free_irq(da9052->irq, NULL); +} + +static int da9052_add_subdevice_pdata(struct da9052 *da9052, + const char *name, void *pdata, size_t pdata_size) +{ + struct mfd_cell cell = { + .name = name, + .platform_data = pdata, + .pdata_size = pdata_size, + }; + return mfd_add_devices(da9052->dev, -1, &cell, 1, NULL, 0); +} + +static int da9052_add_subdevice(struct da9052 *da9052, const char *name) +{ + return da9052_add_subdevice_pdata(da9052, name, NULL, 0); +} + +static int add_da9052_devices(struct da9052 *da9052) +{ + s32 ret = 0; + struct da9052_platform_data *pdata = da9052->dev->platform_data; + struct da9052_leds_platform_data leds_data = { + .num_leds = pdata->led_data->num_leds, + .led = pdata->led_data->led, + }; + struct da9052_regulator_platform_data regulator_pdata = { + .regulators = pdata->regulators, + }; + + struct da9052_tsi_platform_data tsi_data = *(pdata->tsi_data); + + if (pdata && pdata->init) { + ret = pdata->init(da9052); + if (ret != 0) + return ret; + } else + pr_err("No platform initialisation supplied\n"); + + ret = da9052_add_subdevice(da9052, "da9052-rtc"); + if (ret) + return ret; + ret = da9052_add_subdevice(da9052, "da9052-onkey"); + if (ret) + return ret; + + ret = da9052_add_subdevice(da9052, "WLED-1"); + if (ret) + return ret; + + ret = da9052_add_subdevice(da9052, "WLED-2"); + if (ret) + return ret; + + ret = da9052_add_subdevice(da9052, "WLED-3"); + if (ret) + return ret; + + ret = da9052_add_subdevice(da9052, "da9052-adc"); + if (ret) + return ret; + + ret = da9052_add_subdevice(da9052, "da9052-wdt"); + if (ret) + return ret; + + ret = da9052_add_subdevice_pdata(da9052, "da9052-leds", + &leds_data, sizeof(leds_data)); + if (ret) + return ret; + + ret = da9052_add_subdevice_pdata(da9052, "da9052-regulator", + ®ulator_pdata, sizeof(regulator_pdata)); + if (ret) + return ret; + + ret = da9052_add_subdevice_pdata(da9052, "da9052-tsi", + &tsi_data, sizeof(tsi_data)); + if (ret) + return ret; + + ret = da9052_add_subdevice(da9052, "da9052-bat"); + if (ret) + return ret; + + return ret; +} + +int da9052_ssc_init(struct da9052 *da9052) +{ + int cnt; + struct da9052_platform_data *pdata; + struct da9052_ssc_msg ssc_msg; + + /* Initialize eve_nb_array */ + for (cnt = 0; cnt < EVE_CNT; cnt++) + INIT_LIST_HEAD(&(eve_nb_array[cnt].nb_list)); + + /* Initialize mutex required for ADC Manual read */ + mutex_init(&manconv_lock); + + /* Initialize NB array lock */ + sema_init(&eve_nb_array_lock, 1); + + /* Assign the read-write function pointers */ + da9052->read = da9052_ssc_read; + da9052->write = da9052_ssc_write; + da9052->read_many = da9052_ssc_read_many; + da9052->write_many = da9052_ssc_write_many; + + if (SPI == da9052->connecting_device && ssc_ops.write == NULL) { + /* Assign the read/write pointers to SPI/read/write */ + ssc_ops.write = da9052_spi_write; + ssc_ops.read = da9052_spi_read; + ssc_ops.write_many = da9052_spi_write_many; + ssc_ops.read_many = da9052_spi_read_many; + } else if (I2C == da9052->connecting_device + && ssc_ops.write == NULL) { + /* Assign the read/write pointers to SPI/read/write */ + ssc_ops.write = da9052_i2c_write; + ssc_ops.read = da9052_i2c_read; + ssc_ops.write_many = da9052_i2c_write_many; + ssc_ops.read_many = da9052_i2c_read_many; + } else + return -1; + /* Assign the EH notifier block register/de-register functions */ + da9052->register_event_notifier = eh_register_nb; + da9052->unregister_event_notifier = eh_unregister_nb; + + /* Initialize ssc lock */ + mutex_init(&da9052->ssc_lock); + + pdata = da9052->dev->platform_data; + add_da9052_devices(da9052); + + INIT_WORK(&da9052->eh_isr_work, eh_workqueue_isr); + ssc_msg.addr = DA9052_IRQMASKA_REG; + ssc_msg.data = 0xff; + da9052->write(da9052, &ssc_msg); + ssc_msg.addr = DA9052_IRQMASKC_REG; + ssc_msg.data = 0xff; + da9052->write(da9052, &ssc_msg); + if (request_irq(da9052->irq, da9052_eh_isr, IRQ_TYPE_LEVEL_LOW, + DA9052_EH_DEVICE_NAME, da9052)) + return -EIO; + enable_irq_wake(da9052->irq); + + return 0; +} + +void da9052_ssc_exit(struct da9052 *da9052) +{ + printk(KERN_INFO "DA9052: Unregistering SSC device.\n"); + mutex_destroy(&manconv_lock); + /* Restore IRQ line */ + da9052_eh_restore_irq(da9052); + free_irq(da9052->irq, NULL); + mutex_destroy(&da9052->ssc_lock); + mutex_destroy(&da9052->eve_nb_lock); + return; +} + +MODULE_AUTHOR("Dialog Semiconductor Ltd dchen@diasemi.com"); +MODULE_DESCRIPTION("DA9052 MFD Core"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DA9052_SSC_DEVICE_NAME); diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c new file mode 100644 index 0000000..5fd966a --- /dev/null +++ b/drivers/mfd/da9052-i2c.c @@ -0,0 +1,378 @@ +/* + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * da9052-i2c.c: I2C SSC (Synchronous Serial Communication) driver for DA9052 + */ + +#include <linux/device.h> +#include <linux/mfd/core.h> +#include <linux/i2c.h> +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/reg.h> + +static struct da9052 *da9052_i2c; + +#define I2C_CONNECTED 0 + +static int da9052_i2c_is_connected(void) +{ + + struct da9052_ssc_msg msg; + + /* printk("Entered da9052_i2c_is_connected.............\n"); */ + + msg.addr = DA9052_INTERFACE_REG; + + /* Test spi connectivity by performing read of the GPIO_0-1 register */ + if (0 != da9052_i2c_read(da9052_i2c, &msg)) { + printk(KERN_DEBUG "da9052_i2c_is_connected - "\ + "i2c read failed.............\n"); + return -1; + } else { + printk(KERN_DEBUG "da9052_i2c_is_connected - "\ + "i2c read success..............\n"); + return 0; + } + +} + +static int __devinit da9052_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter; + /* printk("\n\tEntered da9052_i2c_is_probe.............\n"); */ + + da9052_i2c = kzalloc(sizeof(struct da9052), GFP_KERNEL); + + if (!da9052_i2c) + return -ENOMEM; + + /* Get the bus driver handler */ + adapter = to_i2c_adapter(client->dev.parent); + + /* Check i2c bus driver supports byte data transfer */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_info(&client->dev,\ + "Error in %s:i2c_check_functionality\n", __func__); + return -ENODEV; + } + + /* Store handle to i2c client */ + da9052_i2c->i2c_client = client; + da9052_i2c->irq = client->irq; + + da9052_i2c->dev = &client->dev; + + /* Initialize i2c data structure here*/ + da9052_i2c->adapter = adapter; + + /* host i2c driver looks only first 7 bits for the slave address */ + da9052_i2c->slave_addr = DA9052_I2C_ADDR >> 1; + + /* Store the i2c client data */ + i2c_set_clientdata(client, da9052_i2c); + + /* Validate I2C connectivity */ + if (I2C_CONNECTED == da9052_i2c_is_connected()) { + /* I2C is connected */ + da9052_i2c->connecting_device = I2C; + if (0 != da9052_ssc_init(da9052_i2c)) + return -ENODEV; + } else { + return -ENODEV; + } + + /* printk("Exiting da9052_i2c_probe.....\n"); */ + + return 0; +} + +static int da9052_i2c_remove(struct i2c_client *client) +{ + + struct da9052 *da9052 = i2c_get_clientdata(client); + + mfd_remove_devices(da9052->dev); + kfree(da9052); + return 0; +} + +int da9052_i2c_write(struct da9052 *da9052, struct da9052_ssc_msg *msg) +{ + struct i2c_msg i2cmsg; + unsigned char buf[2] = {0}; + int ret = 0; + + /* Copy the ssc msg to local character buffer */ + buf[0] = msg->addr; + buf[1] = msg->data; + + /*Construct a i2c msg for a da9052 driver ssc message request */ + i2cmsg.addr = da9052->slave_addr; + i2cmsg.len = 2; + i2cmsg.buf = buf; + + /* To write the data on I2C set flag to zero */ + i2cmsg.flags = 0; + + /* Start the i2c transfer by calling host i2c driver function */ + ret = i2c_transfer(da9052->adapter, &i2cmsg, 1); + + if (ret < 0) { + dev_info(&da9052->i2c_client->dev,\ + "_%s:master_xfer Failed!!\n", __func__); + return ret; + } + + return 0; +} + +int da9052_i2c_read(struct da9052 *da9052, struct da9052_ssc_msg *msg) +{ + + /*Get the da9052_i2c client details*/ + unsigned char buf[2] = {0, 0}; + struct i2c_msg i2cmsg[2]; + int ret = 0; + + /* Copy SSC Msg to local character buffer */ + buf[0] = msg->addr; + + /*Construct a i2c msg for a da9052 driver ssc message request */ + i2cmsg[0].addr = da9052->slave_addr ; + i2cmsg[0].len = 1; + i2cmsg[0].buf = &buf[0]; + + /*To write the data on I2C set flag to zero */ + i2cmsg[0].flags = 0; + + /* Read the data from da9052*/ + /*Construct a i2c msg for a da9052 driver ssc message request */ + i2cmsg[1].addr = da9052->slave_addr ; + i2cmsg[1].len = 1; + i2cmsg[1].buf = &buf[1]; + + /*To read the data on I2C set flag to I2C_M_RD */ + i2cmsg[1].flags = I2C_M_RD; + + /* Start the i2c transfer by calling host i2c driver function */ + ret = i2c_transfer(da9052->adapter, i2cmsg, 2); + if (ret < 0) { + dev_info(&da9052->i2c_client->dev,\ + "2 - %s:master_xfer Failed!!\n", __func__); + return ret; + } + + msg->data = *i2cmsg[1].buf; + + return 0; +} + +int da9052_i2c_write_many(struct da9052 *da9052, + struct da9052_ssc_msg *sscmsg, int msg_no) +{ + + struct i2c_msg i2cmsg; + unsigned char data_buf[MAX_READ_WRITE_CNT+1]; + struct da9052_ssc_msg ctrlb_msg; + struct da9052_ssc_msg *msg_queue = sscmsg; + int ret = 0; + /* Flag to check if requested registers are contiguous */ + unsigned char cont_data = 1; + unsigned char cnt = 0; + + /* Check if requested registers are contiguous */ + for (cnt = 1; cnt < msg_no; cnt++) { + if ((msg_queue[cnt].addr - msg_queue[cnt-1].addr) != 1) { + /* Difference is not 1, i.e. non-contiguous registers */ + cont_data = 0; + break; + } + } + + if (cont_data == 0) { + /* Requested registers are non-contiguous */ + for (cnt = 0; cnt < msg_no; cnt++) { + ret = da9052->write(da9052, &msg_queue[cnt]); + if (ret != 0) + return ret; + } + return 0; + } + /* + * Requested registers are contiguous + * or PAGE WRITE sequence of I2C transactions is as below + * (slave_addr + reg_addr + data_1 + data_2 + ...) + * First read current WRITE MODE via CONTROL_B register of DA9052 + */ + ctrlb_msg.addr = DA9052_CONTROLB_REG; + ctrlb_msg.data = 0x0; + ret = da9052->read(da9052, &ctrlb_msg); + + if (ret != 0) + return ret; + + /* Check if PAGE WRITE mode is set */ + if (ctrlb_msg.data & DA9052_CONTROLB_WRITEMODE) { + /* REPEAT WRITE mode is configured */ + /* Now set DA9052 into PAGE WRITE mode */ + ctrlb_msg.data &= ~DA9052_CONTROLB_WRITEMODE; + ret = da9052->write(da9052, &ctrlb_msg); + + if (ret != 0) + return ret; + } + + /* Put first register address */ + data_buf[0] = msg_queue[0].addr; + + for (cnt = 0; cnt < msg_no; cnt++) + data_buf[cnt+1] = msg_queue[cnt].data; + + /* Construct a i2c msg for PAGE WRITE */ + i2cmsg.addr = da9052->slave_addr ; + /* First register address + all data*/ + i2cmsg.len = (msg_no + 1); + i2cmsg.buf = data_buf; + + /*To write the data on I2C set flag to zero */ + i2cmsg.flags = 0; + + /* Start the i2c transfer by calling host i2c driver function */ + ret = i2c_transfer(da9052->adapter, &i2cmsg, 1); + if (ret < 0) { + dev_info(&da9052->i2c_client->dev,\ + "1 - i2c_transfer function falied in [%s]!!!\n", __func__); + return ret; + } + + return 0; +} + +int da9052_i2c_read_many(struct da9052 *da9052, + struct da9052_ssc_msg *sscmsg, int msg_no) +{ + + struct i2c_msg i2cmsg; + unsigned char data_buf[MAX_READ_WRITE_CNT]; + struct da9052_ssc_msg *msg_queue = sscmsg; + int ret = 0; + /* Flag to check if requested registers are contiguous */ + unsigned char cont_data = 1; + unsigned char cnt = 0; + + /* Check if requested registers are contiguous */ + for (cnt = 1; cnt < msg_no; cnt++) { + if ((msg_queue[cnt].addr - msg_queue[cnt-1].addr) != 1) { + /* Difference is not 1, i.e. non-contiguous registers */ + cont_data = 0; + break; + } + } + + if (cont_data == 0) { + /* Requested registers are non-contiguous */ + for (cnt = 0; cnt < msg_no; cnt++) { + ret = da9052->read(da9052, &msg_queue[cnt]); + if (ret != 0) { + dev_info(&da9052->i2c_client->dev,\ + "Error in %s", __func__); + return ret; + } + } + return 0; + } + + /* + * We want to perform PAGE READ via I2C + * For PAGE READ sequence of I2C transactions is as below + * (slave_addr + reg_addr) + (slave_addr + data_1 + data_2 + ...) + */ + /* Copy address of first register */ + data_buf[0] = msg_queue[0].addr; + + /* Construct a i2c msg for first transaction of PAGE READ i.e. write */ + i2cmsg.addr = da9052->slave_addr ; + i2cmsg.len = 1; + i2cmsg.buf = data_buf; + + /*To write the data on I2C set flag to zero */ + i2cmsg.flags = 0; + + /* Start the i2c transfer by calling host i2c driver function */ + ret = i2c_transfer(da9052->adapter, &i2cmsg, 1); + if (ret < 0) { + dev_info(&da9052->i2c_client->dev,\ + "1 - i2c_transfer function falied in [%s]!!!\n", __func__); + return ret; + } + + /* Now Read the data from da9052 */ + /* Construct a i2c msg for second transaction of PAGE READ i.e. read */ + i2cmsg.addr = da9052->slave_addr ; + i2cmsg.len = msg_no; + i2cmsg.buf = data_buf; + + /*To read the data on I2C set flag to I2C_M_RD */ + i2cmsg.flags = I2C_M_RD; + + /* Start the i2c transfer by calling host i2c driver function */ + ret = i2c_transfer(da9052->adapter, + &i2cmsg, 1); + if (ret < 0) { + dev_info(&da9052->i2c_client->dev,\ + "2 - i2c_transfer function falied in [%s]!!!\n", __func__); + return ret; + } + + /* Gather READ data */ + for (cnt = 0; cnt < msg_no; cnt++) + sscmsg[cnt].data = data_buf[cnt]; + + return 0; +} + +static struct i2c_device_id da9052_ssc_id[] = { + { DA9052_SSC_I2C_DEVICE_NAME, 0}, + {} +}; + +static struct i2c_driver da9052_i2c_driver = { + .driver = { + .name = DA9052_SSC_I2C_DEVICE_NAME, + .owner = THIS_MODULE, + }, + .probe = da9052_i2c_probe, + .remove = da9052_i2c_remove, + .id_table = da9052_ssc_id, +}; + +static int __init da9052_i2c_init(void) +{ + int ret = 0; + /* printk("\n\nEntered da9052_i2c_init................\n\n"); */ + ret = i2c_add_driver(&da9052_i2c_driver); + if (ret != 0) { + printk(KERN_ERR "Unable to register %s\n", + DA9052_SSC_I2C_DEVICE_NAME); + return ret; + } + return 0; +} +subsys_initcall(da9052_i2c_init); + +static void __exit da9052_i2c_exit(void) +{ + i2c_del_driver(&da9052_i2c_driver); +} +module_exit(da9052_i2c_exit); + +MODULE_AUTHOR("Dialog Semiconductor Ltd dchen@diasemi.com"); +MODULE_DESCRIPTION("I2C driver for Dialog DA9052 PMIC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DA9052_SSC_I2C_DEVICE_NAME); diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c new file mode 100644 index 0000000..f25e188f --- /dev/null +++ b/drivers/mfd/da9052-spi.c @@ -0,0 +1,402 @@ +/* + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * da9052-spi.c: SPI SSC (Synchronous Serial Communication) driver for DA9052 + */ + +#include <linux/device.h> +#include <linux/mfd/core.h> +#include <linux/spi/spi.h> +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/reg.h> + + +struct da9052 *da9052_spi; + +#define SPI_CONNECTED 0 + +static int da9052_spi_is_connected(void) +{ + + struct da9052_ssc_msg msg; + + /* printk("Entered da9052_spi_is_connected.............\n"); */ + + msg.addr = DA9052_INTERFACE_REG; + + /* Test spi connectivity by performing read of the GPIO_0-1 register + and then verify the read value*/ + if (0 != da9052_spi_read(da9052_spi, &msg)) { + printk(KERN_DEBUG "da9052_spi_is_connected - "\ + "spi read failed.............\n"); + return -1; + } else if (0x88 != msg.data) { + printk(KERN_DEBUG "da9052_spi_is_connected - " \ + "spi read failed. Msg data =%x ..............\n", + msg.data); + return -1; + } + + return 0; + +} + +static int da9052_spi_probe(struct spi_device *spi) +{ + /* printk("\n\tEntered da9052_spi_probe.....\n"); */ + + da9052_spi = kzalloc(sizeof(struct da9052), GFP_KERNEL); + + if (!da9052_spi) + return -ENOMEM; + + + spi->mode = SPI_MODE_0 | SPI_CPOL; + spi->bits_per_word = 8; + spi_setup(spi); + + da9052_spi->dev = &spi->dev; + + da9052_spi->spi_dev = spi; + + /* + * Allocate memory for RX/TX bufferes used in single register + * read/write + */ + da9052_spi->spi_rx_buf = kmalloc(2, GFP_KERNEL | GFP_DMA); + if (!da9052_spi->spi_rx_buf) + return -ENOMEM; + + da9052_spi->spi_tx_buf = kmalloc(2, GFP_KERNEL | GFP_DMA); + if (!da9052_spi->spi_tx_buf) + return -ENOMEM; + + da9052_spi->spi_active_page = PAGECON_0; + da9052_spi->rw_pol = 1; + + + dev_set_drvdata(&spi->dev, da9052_spi); + + + /* Validate SPI connectivity */ + if (SPI_CONNECTED == da9052_spi_is_connected()) { + /* SPI is connected */ + da9052_spi->connecting_device = SPI; + if (0 != da9052_ssc_init(da9052_spi)) + return -ENODEV; + } else { + return -ENODEV; + } + + /* printk("Exiting da9052_spi_probe.....\n"); */ + + return 0; +} + +static int da9052_spi_remove(struct spi_device *spi) +{ + struct da9052 *da9052 = dev_get_drvdata(&spi->dev); + + printk("Entered da9052_spi_remove()\n"); + if (SPI == da9052->connecting_device) + da9052_ssc_exit(da9052); + mfd_remove_devices(&spi->dev); + kfree(da9052->spi_rx_buf); + kfree(da9052->spi_tx_buf); + kfree(da9052); + return 0; +} + +static struct spi_driver da9052_spi_driver = { + .driver = { + .name = DA9052_SSC_SPI_DEVICE_NAME, + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = da9052_spi_probe, + .remove = __devexit_p(da9052_spi_remove), +}; + + +static int da9052_spi_set_page(struct da9052 *da9052, unsigned char page) +{ + + struct da9052_ssc_msg sscmsg; + struct spi_message message; + struct spi_transfer xfer; + int ret = 0; + + printk(KERN_DEBUG "Entered da9052_spi_set_page.....\n"); + if ((page != PAGECON_0) && ((page != PAGECON_128))) + return INVALID_PAGE; + + /* Current configuration is PAGE-0 and write request for PAGE-1 */ + /* set register address */ + sscmsg.addr = DA9052_PAGECON0_REG; + /* set value */ + sscmsg.data = page; + + /* Check value of R/W_POL bit of INTERFACE register */ + if (!da9052->rw_pol) { + /* We need to set 0th bit for write operation */ + sscmsg.addr = ((sscmsg.addr << 1) | RW_POL); + } else { + /* We need to reset 0th bit for write operation */ + sscmsg.addr = (sscmsg.addr << 1); + } + + /* SMDK-6410 host SPI driver specific stuff */ + + /* Build our spi message */ + printk(KERN_DEBUG "da9052_spi_set_page - "\ + "Calling spi_message_init.....\n"); + spi_message_init(&message); + memset(&xfer, 0, sizeof(xfer)); + + xfer.len = 2; + xfer.tx_buf = da9052->spi_tx_buf; + xfer.rx_buf = da9052->spi_rx_buf; + + da9052->spi_tx_buf[0] = sscmsg.addr; + da9052->spi_tx_buf[1] = sscmsg.data; + + printk(KERN_DEBUG "da9052_spi_set_page - "\ + "Calling spi_message_add_tail.....\n"); + spi_message_add_tail(&xfer, &message); + + /* Now, do the i/o */ + printk(KERN_DEBUG "da9052_spi_set_page - Calling spi_sync.....\n"); + ret = spi_sync(da9052->spi_dev, &message); + + if (ret == 0) { + /* Active Page set successfully */ + da9052->spi_active_page = page; + return 0; + } else { + /* Error in setting Active Page */ + return ret; + } + + return 0; +} + +int da9052_spi_write(struct da9052 *da9052, struct da9052_ssc_msg *msg) +{ + + struct spi_message message; + struct spi_transfer xfer; + int ret; + + /* + * We need a seperate copy of da9052_ssc_msg so that caller's + * copy remains intact + */ + struct da9052_ssc_msg sscmsg; + + /* Copy callers data in to our local copy */ + sscmsg.addr = msg->addr; + sscmsg.data = msg->data; + + if ((sscmsg.addr > PAGE_0_END) && + (da9052->spi_active_page == PAGECON_0)) { + /* + * Current configuration is PAGE-0 and write request + * for PAGE-1 + */ + da9052_spi_set_page(da9052, PAGECON_128); + /* Set register address accordindly */ + sscmsg.addr = (sscmsg.addr - PAGE_1_START); + } else if ((sscmsg.addr < PAGE_1_START) && + (da9052->spi_active_page == PAGECON_128)) { + /* + * Current configuration is PAGE-1 and write request + * for PAGE-0 + */ + da9052_spi_set_page(da9052, PAGECON_0); + } else if (sscmsg.addr > PAGE_0_END) { + /* + * Current configuration is PAGE-1 and write request + * for PAGE-1. Just need to adjust register address + */ + sscmsg.addr = (sscmsg.addr - PAGE_1_START); + } + + /* Check value of R/W_POL bit of INTERFACE register */ + if (!da9052->rw_pol) { + /* We need to set 0th bit for write operation */ + sscmsg.addr = ((sscmsg.addr << 1) | RW_POL); + } else { + /* We need to reset 0th bit for write operation */ + sscmsg.addr = (sscmsg.addr << 1); + } + + /* SMDK-6410 host SPI driver specific stuff */ + + /* Build our spi message */ + spi_message_init(&message); + memset(&xfer, 0, sizeof(xfer)); + + xfer.len = 2; + xfer.tx_buf = da9052->spi_tx_buf; + xfer.rx_buf = da9052->spi_rx_buf; + + da9052->spi_tx_buf[0] = sscmsg.addr; + da9052->spi_tx_buf[1] = sscmsg.data; + + spi_message_add_tail(&xfer, &message); + + /* Now, do the i/o */ + ret = spi_sync(da9052->spi_dev, &message); + + return ret; +} + +int da9052_spi_write_many(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg, + int msg_no) +{ + int cnt, ret = 0; + + for (cnt = 0; cnt < msg_no; cnt++, sscmsg++) { + ret = da9052_ssc_write(da9052, sscmsg); + if (ret != 0) { + printk(KERN_DEBUG "Error in %s\n", __func__); + return -EIO; + } + } + + return 0; +} + +int da9052_spi_read(struct da9052 *da9052, struct da9052_ssc_msg *msg) +{ + + struct spi_message message; + struct spi_transfer xfer; + int ret; + + /* + * We need a seperate copy of da9052_ssc_msg so that + * caller's copy remains intact + */ + struct da9052_ssc_msg sscmsg; + + + /* Copy callers data in to our local copy */ + sscmsg.addr = msg->addr; + sscmsg.data = msg->data; + + if ((sscmsg.addr > PAGE_0_END) && + (da9052->spi_active_page == PAGECON_0)) { + /* + * Current configuration is PAGE-0 and + * read request for PAGE-1 + */ + printk(KERN_DEBUG "da9052_spi_read - if PAGECON_128.....\n"); + da9052_spi_set_page(da9052, PAGECON_128); + /* Set register address accordindly */ + sscmsg.addr = (sscmsg.addr - PAGE_1_START); + } else if ((sscmsg.addr < PAGE_1_START) && + (da9052->spi_active_page == PAGECON_128)) { + /* + * Current configuration is PAGE-1 and + * write request for PAGE-0 + */ + printk(KERN_DEBUG "da9052_spi_read - if PAGECON_0.....\n"); + da9052_spi_set_page(da9052, PAGECON_0); + } else if (sscmsg.addr > PAGE_0_END) { + /* + * Current configuration is PAGE-1 and write + * request for PAGE-1 + * Just need to adjust register address + */ + sscmsg.addr = (sscmsg.addr - PAGE_1_START); + } + + /* Check value of R/W_POL bit of INTERFACE register */ + if (da9052->rw_pol) { + /* We need to set 0th bit for read operation */ + sscmsg.addr = ((sscmsg.addr << 1) | RW_POL); + } else { + /* We need to reset 0th bit for write operation */ + sscmsg.addr = (sscmsg.addr << 1); + } + + /* SMDK-6410 host SPI driver specific stuff */ + + /* Build our spi message */ + spi_message_init(&message); + memset(&xfer, 0, sizeof(xfer)); + + xfer.len = 2; + xfer.tx_buf = da9052->spi_tx_buf; + xfer.rx_buf = da9052->spi_rx_buf; + + da9052->spi_tx_buf[0] = sscmsg.addr; + da9052->spi_tx_buf[1] = 0xff; + + da9052->spi_rx_buf[0] = 0; + da9052->spi_rx_buf[1] = 0; + + spi_message_add_tail(&xfer, &message); + + /* Now, do the i/o */ + ret = spi_sync(da9052->spi_dev, &message); + + if (ret == 0) { + /* Update read value in callers copy */ + msg->data = da9052->spi_rx_buf[1]; + return 0; + } else { + return ret; + } + + + return 0; +} + +int da9052_spi_read_many(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg, + int msg_no) +{ + int cnt, ret = 0; + + for (cnt = 0; cnt < msg_no; cnt++, sscmsg++) { + ret = da9052_ssc_read(da9052, sscmsg); + if (ret != 0) { + printk(KERN_DEBUG "Error in %s\n", __func__); + return -EIO; + } + } + + return 0; +} + +static int __init da9052_spi_init(void) +{ + int ret = 0; + /*printk("Entered da9052_spi_init.....\n");*/ + ret = spi_register_driver(&da9052_spi_driver); + if (ret != 0) { + printk(KERN_ERR "Unable to register %s\n", + DA9052_SSC_SPI_DEVICE_NAME); + return ret; + } + return 0; +} +module_init(da9052_spi_init); + +static void __exit da9052_spi_exit(void) +{ + spi_unregister_driver(&da9052_spi_driver); +} + +module_exit(da9052_spi_exit); + +MODULE_AUTHOR("Dialog Semiconductor Ltd dchen@diasemi.com"); +MODULE_DESCRIPTION("SPI driver for Dialog DA9052 PMIC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DA9052_SSC_SPI_DEVICE_NAME);
On Fri, Jun 10, 2011 at 11:51:00AM +0800, Ying-Chun Liu (PaulLiu) wrote:
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9052 mfd driver from Dialog. Modify Kconfig/Makefile for DA9052 mfd driver.
This needs to be the first patch in the series, all the other patches need it to work. Essentially all of this code has been rewritten in the current Dialog code to address a number of system integration issues and use standard kernel APIs.
On Friday 10 June 2011, Ying-Chun Liu (PaulLiu) wrote:
+config PMIC_DIALOG
- bool "Support Dialog Semiconductor PMIC"
- depends on I2C=y
- depends on SPI=y
- select MFD_CORE
- help
- Support for Dialog semiconductor PMIC chips.
- Use the options provided to support the desired PMIC's.
+choice
- prompt "Chip Type"
- depends on PMIC_DIALOG
+config PMIC_DA9052
- bool "Support Dialog Semiconductor DA9052 PMIC"
- help
- Support for Dialog semiconductor DA9052 PMIC with inbuilt
- SPI & I2C connectivities.
- This driver provides common support for accessing the device,
- additional drivers must be enabled in order to use the
- functionality of the device.
+config PMIC_DA9053AA
- bool "Support Dialog Semiconductor DA9053 AA PMIC"
- help
- Support for Dialog semiconductor DA9053 AA PMIC with inbuilt
- SPI & I2C connectivities.
- This driver provides common support for accessing the device,
- additional drivers must be enabled in order to use the
- functionality of the device.
+config PMIC_DA9053Bx
- bool "Support Dialog Semiconductor DA9053 BA/BB PMIC"
- help
- Support for Dialog semiconductor DA9053 BA/BB PMIC with inbuilt
- SPI & I2C connectivities.
- This driver provides common support for accessing the device,
- additional drivers must be enabled in order to use the
- functionality of the device.
+endchoice
This can use a few lines of whitespace.
Why do you need a choice statement here? I would think that you need to be able to build a kernel with all three chips builtin at the same time, in order to run on all boards that have one of them.
+#define SUCCESS 0 +#define FAILURE 1
Remove these. We use negative error codes from linux/errno.h to indicate failure.
+struct da9052_eh_nb eve_nb_array[EVE_CNT];
Why do you need this array? Better keep the information local to your devices.
+static struct da9052_ssc_ops ssc_ops;
Make this const and statically initialize it with the functions instead of assigning the function pointers at runtime.
+struct mutex manconv_lock;
use DEFINE_MUTEX
+static struct semaphore eve_nb_array_lock;
No new semaphores. Use a mutex.
+void da9052_lock(struct da9052 *da9052) +{
- mutex_lock(&da9052->ssc_lock);
+} +EXPORT_SYMBOL(da9052_lock);
+void da9052_unlock(struct da9052 *da9052) +{
- mutex_unlock(&da9052->ssc_lock);
+} +EXPORT_SYMBOL(da9052_unlock);
use EXPORT_SYMBOL_GPL()
+int da9052_ssc_write(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg) +{
- int ret = 0;
- /* Reg address should be a valid address on PAGE0 or PAGE1 */
- if ((sscmsg->addr < DA9052_PAGE0_REG_START) ||
- (sscmsg->addr > DA9052_PAGE1_REG_END) ||
- ((sscmsg->addr > DA9052_PAGE0_REG_END) &&
- (sscmsg->addr < DA9052_PAGE1_REG_START)))
return INVALID_REGISTER;
return a proper error code, e.g. "-EINVAL"
- ret = ssc_ops.write(da9052, sscmsg);
Take the ops from the device, e.g.
ret = da9052->scc_ops.write(da9052, sscmsg);
+static irqreturn_t da9052_eh_isr(int irq, void *dev_id) +{
- struct da9052 *da9052 = dev_id;
- /* Schedule work to be done */
- schedule_work(&da9052->eh_isr_work);
- /* Disable IRQ */
- disable_irq_nosync(da9052->irq);
- return IRQ_HANDLED;
+}
You shouldn't need to disable the interrupt if you don't clear the event bits at the source.
- ret = da9052_add_subdevice(da9052, "da9052-rtc");
- if (ret)
return ret;
- ret = da9052_add_subdevice(da9052, "da9052-onkey");
- if (ret)
return ret;
- ret = da9052_add_subdevice(da9052, "WLED-1");
- if (ret)
return ret;
- ret = da9052_add_subdevice(da9052, "WLED-2");
- if (ret)
return ret;
- ret = da9052_add_subdevice(da9052, "WLED-3");
- if (ret)
return ret;
Why not add them all at once?
- /* Initialize mutex required for ADC Manual read */
- mutex_init(&manconv_lock);
- /* Initialize NB array lock */
- sema_init(&eve_nb_array_lock, 1);
these are not needed if you use DEFINE_MUTEX
- /* Assign the read-write function pointers */
- da9052->read = da9052_ssc_read;
- da9052->write = da9052_ssc_write;
- da9052->read_many = da9052_ssc_read_many;
- da9052->write_many = da9052_ssc_write_many;
- if (SPI == da9052->connecting_device && ssc_ops.write == NULL) {
/* Assign the read/write pointers to SPI/read/write */
ssc_ops.write = da9052_spi_write;
ssc_ops.read = da9052_spi_read;
ssc_ops.write_many = da9052_spi_write_many;
ssc_ops.read_many = da9052_spi_read_many;
- } else if (I2C == da9052->connecting_device
&& ssc_ops.write == NULL) {
/* Assign the read/write pointers to SPI/read/write */
ssc_ops.write = da9052_i2c_write;
ssc_ops.read = da9052_i2c_read;
ssc_ops.write_many = da9052_i2c_write_many;
ssc_ops.read_many = da9052_i2c_read_many;
- } else
return -1;
Just define two different operations structures for the difference.
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c new file mode 100644 index 0000000..5fd966a --- /dev/null +++ b/drivers/mfd/da9052-i2c.c
+static struct da9052 *da9052_i2c;
A static pointer should not be necessary, just pass the device around to all the functions. This is especially necessary if you have more than one instance.
- /* Test spi connectivity by performing read of the GPIO_0-1 register */
- if (0 != da9052_i2c_read(da9052_i2c, &msg)) {
Do comparisons like
if (da9052_i2c_read(da9052_i2c, &msg) != 0)
or better
if (da9052_i2c_read(da9052_i2c, &msg))
printk(KERN_DEBUG "da9052_i2c_is_connected - "\
"i2c read failed.............\n");
return -1;
- } else {
printk(KERN_DEBUG "da9052_i2c_is_connected - "\
"i2c read success..............\n");
return 0;
- }
Use proper error codes, don't return -1.
- /* Validate I2C connectivity */
- if (I2C_CONNECTED == da9052_i2c_is_connected()) {
/* I2C is connected */
da9052_i2c->connecting_device = I2C;
if (0 != da9052_ssc_init(da9052_i2c))
return -ENODEV;
- } else {
return -ENODEV;
- }
See above for the comparisons.
Make sure you free the memory in the error path. The best way to do that is to have a "goto error" statement to a place where you free the memory and return.
- /* printk("Exiting da9052_i2c_probe.....\n"); */
Remove stale comments like this.
+struct da9052 *da9052_spi;
+#define SPI_CONNECTED 0
+static int da9052_spi_is_connected(void) +{
- struct da9052_ssc_msg msg;
- /* printk("Entered da9052_spi_is_connected.............\n"); */
- msg.addr = DA9052_INTERFACE_REG;
- /* Test spi connectivity by performing read of the GPIO_0-1 register
and then verify the read value*/
- if (0 != da9052_spi_read(da9052_spi, &msg)) {
printk(KERN_DEBUG "da9052_spi_is_connected - "\
"spi read failed.............\n");
return -1;
- } else if (0x88 != msg.data) {
printk(KERN_DEBUG "da9052_spi_is_connected - " \
"spi read failed. Msg data =%x ..............\n",
msg.data);
return -1;
Same comments as above apply.
+int da9052_spi_write(struct da9052 *da9052, struct da9052_ssc_msg *msg) +{
The functions should probably all be static. Just pass the ssc_ops to da9052_ssc_init.
Arnd
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9052 battery driver from Dialog. Modify Kconfig/Makefile for DA9052 battery driver.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org --- drivers/power/Kconfig | 7 + drivers/power/Makefile | 1 + drivers/power/da9052-battery.c | 847 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 855 insertions(+), 0 deletions(-) create mode 100644 drivers/power/da9052-battery.c
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index e57b50b..8145ff8 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -235,4 +235,11 @@ config CHARGER_GPIO This driver can be build as a module. If so, the module will be called gpio-charger.
+config BATTERY_DA9052 + tristate "Dialog DA9052 Battery" + depends on PMIC_DIALOG + help + Say Y here to enable support for batteries charger integrated into + DA9052 PMIC. + endif # POWER_SUPPLY diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 009a90f..ad6493a 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -36,3 +36,4 @@ obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o +obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o diff --git a/drivers/power/da9052-battery.c b/drivers/power/da9052-battery.c new file mode 100644 index 0000000..210e8ed --- /dev/null +++ b/drivers/power/da9052-battery.c @@ -0,0 +1,847 @@ +/* + * da9052-battery.c -- Batttery Driver for Dialog DA9052 + * + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * Author: Dialog Semiconductor Ltd dchen@diasemi.com + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/uaccess.h> +#include <linux/jiffies.h> +#include <linux/power_supply.h> +#include <linux/platform_device.h> +#include <linux/freezer.h> + +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/reg.h> +#include <linux/mfd/da9052/bat.h> +#include <linux/mfd/da9052/adc.h> + +#define DA9052_BAT_DEVICE_NAME "da9052-bat" + +static const char __initdata banner[] = KERN_INFO \ + "DA9052 BAT, (c) 2009 Dialog semiconductor Ltd.\n"; + +static struct da9052_bat_hysteresis bat_hysteresis; +static struct da9052_bat_event_registration event_status; + + +static u16 array_hys_batvoltage[2]; +static u16 bat_volt_arr[3]; +static u8 hys_flag = FALSE; + +static int da9052_read(struct da9052 *da9052, u8 reg_address, u8 *reg_data) +{ + struct da9052_ssc_msg msg; + int ret; + + msg.addr = reg_address; + msg.data = 0; + + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret) + goto ssc_comm_err; + da9052_unlock(da9052); + + *reg_data = msg.data; + return 0; +ssc_comm_err: + da9052_unlock(da9052); + return ret; +} + +static s32 da9052_adc_read_ich(struct da9052 *da9052, u16 *data) +{ + struct da9052_ssc_msg msg; + da9052_lock(da9052); + /* Read charging conversion register */ + msg.addr = DA9052_ICHGAV_REG; + msg.data = 0; + if (da9052->read(da9052, &msg)) { + da9052_unlock(da9052); + return DA9052_SSC_FAIL; + } + da9052_unlock(da9052); + + *data = (u16)msg.data; + DA9052_DEBUG("In function: %s, ICHGAV_REG value read (1)= 0x%X\n", + __func__, msg.data); + return SUCCESS; +} + + +static s32 da9052_adc_read_tbat(struct da9052 *da9052, u16 *data) +{ + s32 ret; + u8 reg_data; + + ret = da9052_read(da9052, DA9052_TBATRES_REG, ®_data); + if (ret) + return ret; + *data = (u16)reg_data; + + DA9052_DEBUG("In function: %s, TBATRES_REG value read (1)= 0x%X\n", + __func__, msg.data); + return SUCCESS; +} + +s32 da9052_adc_read_vbat(struct da9052 *da9052, u16 *data) +{ + s32 ret; + + ret = da9052_manual_read(da9052, DA9052_ADC_VBAT); + DA9052_DEBUG("In function: %s, VBAT value read (1)= 0x%X\n", + __func__, temp); + if (ret == -EIO) { + *data = 0; + return ret; + } else { + *data = ret; + return 0; + } + return 0; +} + + +static u16 filter_sample(u16 *buffer) +{ + u8 count; + u16 tempvalue = 0; + u16 ret; + + if (buffer == NULL) + return -EINVAL; + + for (count = 0; count < DA9052_FILTER_SIZE; count++) + tempvalue = tempvalue + *(buffer + count); + + ret = tempvalue/DA9052_FILTER_SIZE; + return ret; +} + +static s32 da9052_bat_get_battery_temperature(struct da9052_charger_device + *chg_device, u16 *buffer) +{ + + u8 count; + u16 filterqueue[DA9052_FILTER_SIZE]; + + /* Measure the battery temperature using ADC function. + Number of read equal to average filter size*/ + + for (count = 0; count < DA9052_FILTER_SIZE; count++) + if (da9052_adc_read_tbat(chg_device->da9052, + &filterqueue[count])) + return -EIO; + + /* Apply Average filter */ + filterqueue[0] = filter_sample(filterqueue); + + chg_device->bat_temp = filterqueue[0]; + *buffer = chg_device->bat_temp; + + return SUCCESS; +} + +static s32 da9052_bat_get_chg_current(struct da9052_charger_device + *chg_device, u16 *buffer) +{ + if (chg_device->status == POWER_SUPPLY_STATUS_DISCHARGING) + return -EIO; + + /* Measure the Charger current using ADC function */ + if (da9052_adc_read_ich(chg_device->da9052, buffer)) + return -EIO; + + /* Convert the raw value in terms of mA */ + chg_device->chg_current = ichg_reg_to_mA(*buffer); + *buffer = chg_device->chg_current; + + return 0; +} + + +s32 da9052_bat_get_battery_voltage(struct da9052_charger_device *chg_device, + u16 *buffer) +{ + u8 count; + u16 filterqueue[DA9052_FILTER_SIZE]; + + /* Measure the battery voltage using ADC function. + Number of read equal to average filter size*/ + for (count = 0; count < DA9052_FILTER_SIZE; count++) + if (da9052_adc_read_vbat(chg_device->da9052, + &filterqueue[count])) + return -EIO; + + /* Apply average filter */ + filterqueue[0] = filter_sample(filterqueue); + + /* Convert battery voltage raw value in terms of mV */ + chg_device->bat_voltage = volt_reg_to_mV(filterqueue[0]); + *buffer = chg_device->bat_voltage; + return 0; +} + +static void da9052_bat_status_update(struct da9052_charger_device + *chg_device) +{ + struct da9052_ssc_msg msg; + u16 current_value = 0; + u16 buffer = 0; + u8 regvalue = 0; + u8 old_status = chg_device->status; + + DA9052_DEBUG("FUNCTION = %s\n", __func__); + + /* Read Status A register */ + msg.addr = DA9052_STATUSA_REG; + msg.data = 0; + da9052_lock(chg_device->da9052); + + if (chg_device->da9052->read(chg_device->da9052, &msg)) { + DA9052_DEBUG("%s : failed\n", __func__); + da9052_unlock(chg_device->da9052); + return; + } + regvalue = msg.data; + + /* Read Status B register */ + msg.addr = DA9052_STATUSB_REG; + msg.data = 0; + if (chg_device->da9052->read(chg_device->da9052, &msg)) { + DA9052_DEBUG("%s : failed\n", __func__); + da9052_unlock(chg_device->da9052); + return; + } + da9052_unlock(chg_device->da9052); + + /* If DCINDET and DCINSEL are set then connected charger is + WALL Charger unit */ + if ((regvalue & DA9052_STATUSA_DCINSEL) + && (regvalue & DA9052_STATUSA_DCINDET)) { + + chg_device->charger_type = DA9052_WALL_CHARGER; + } else if ((regvalue & DA9052_STATUSA_VBUSSEL) + && (regvalue & DA9052_STATUSA_VBUSDET)) { + /* If VBUS_DET and VBUSEL are set then connected charger is + USB Type */ + if (regvalue & DA9052_STATUSA_VDATDET) { + chg_device->charger_type = DA9052_USB_CHARGER; + } else { + /* Else it has to be USB Host charger */ + chg_device->charger_type = DA9052_USB_HUB; + } + } else { + /* Battery is discharging since charging device is not present */ + chg_device->charger_type = DA9052_NOCHARGER; + /* Eqv to DISCHARGING_WITHOUT_CHARGER state */ + chg_device->status = POWER_SUPPLY_STATUS_DISCHARGING; + } + + + if (chg_device->charger_type != DA9052_NOCHARGER) { + /* if Charging end flag is set and Charging current is greater + than charging end limit then battery is charging */ + if ((msg.data & DA9052_STATUSB_CHGEND) != 0) { + if (da9052_bat_get_chg_current(chg_device, + ¤t_value)) { + return; + } + if (current_value >= chg_device->chg_end_current) { + chg_device->status = + POWER_SUPPLY_STATUS_CHARGING; + } else { + /* Eqv to DISCHARGING_WITH_CHARGER state*/ + chg_device->status = + POWER_SUPPLY_STATUS_NOT_CHARGING; + } + } else { + /* if Charging end flag is cleared then battery is charging */ + chg_device->status = POWER_SUPPLY_STATUS_CHARGING; + } + + if (POWER_SUPPLY_STATUS_CHARGING == chg_device->status) { + if (msg.data != DA9052_STATUSB_CHGPRE) { + /* Measure battery voltage. if battery + voltage is greater than + (VCHG_BAT - VCHG_DROP) then battery is in + the termintation mode. */ + if (da9052_bat_get_battery_voltage( + chg_device, &buffer)) { + DA9052_DEBUG("%s : failed\n" + , __func__); + return ; + } + if (buffer > (chg_device->bat_target_voltage - + chg_device->charger_voltage_drop) && + (chg_device->cal_capacity >= 99)) { + chg_device->status = + POWER_SUPPLY_STATUS_FULL; + } + } + } + } + + if (chg_device->illegal) + chg_device->health = POWER_SUPPLY_HEALTH_UNKNOWN; + else if (chg_device->cal_capacity < chg_device->bat_capacity_limit_low) + chg_device->health = POWER_SUPPLY_HEALTH_DEAD; + else + chg_device->health = POWER_SUPPLY_HEALTH_GOOD; + + if (chg_device->status != old_status) + power_supply_changed(&chg_device->psy); + + return; +} + +static s32 da9052_bat_suspend_charging(struct da9052_charger_device *chg_device) +{ + struct da9052_ssc_msg msg; + + if ((chg_device->status == POWER_SUPPLY_STATUS_DISCHARGING) || + (chg_device->status == POWER_SUPPLY_STATUS_NOT_CHARGING)) + return 0; + + msg.addr = DA9052_INPUTCONT_REG; + msg.data = 0; + da9052_lock(chg_device->da9052); + /* Read Input condition register */ + if (chg_device->da9052->read(chg_device->da9052, &msg)) { + da9052_unlock(chg_device->da9052); + return DA9052_SSC_FAIL; + } + + /* set both Wall charger and USB charger suspend bit */ + msg.data = set_bits(msg.data, DA9052_INPUTCONT_DCINSUSP); + msg.data = set_bits(msg.data, DA9052_INPUTCONT_VBUSSUSP); + + /* Write to Input control register */ + if (chg_device->da9052->write(chg_device->da9052, &msg)) { + da9052_unlock(chg_device->da9052); + DA9052_DEBUG("%s : failed\n", __func__); + return DA9052_SSC_FAIL; + } + da9052_unlock(chg_device->da9052); + + DA9052_DEBUG("%s : Sucess\n", __func__); + return 0; +} + +u32 interpolated(u32 vbat_lower, u32 vbat_upper, u32 level_lower, + u32 level_upper, u32 bat_voltage) +{ + s32 temp; + /*apply formula y= yk + (x - xk) * (yk+1 -yk)/(xk+1 -xk) */ + temp = ((level_upper - level_lower) * 1000)/(vbat_upper - vbat_lower); + temp = level_lower + (((bat_voltage - vbat_lower) * temp)/1000); + + return temp; +} + +s32 capture_first_correct_vbat_sample(struct da9052_charger_device *chg_device, +u16 *battery_voltage) +{ + static u8 count; + s32 ret = 0; + u32 temp_data = 0; + + ret = da9052_bat_get_battery_voltage(chg_device, + &bat_volt_arr[count]); + if (ret) + return ret; + count++; + + if (count < chg_device->vbat_first_valid_detect_iteration) + return FAILURE; + for (count = 0; count < + (chg_device->vbat_first_valid_detect_iteration - 1); + count++) { + temp_data = (bat_volt_arr[count] * + (chg_device->hysteresis_window_size))/100; + bat_hysteresis.upper_limit = bat_volt_arr[count] + temp_data; + bat_hysteresis.lower_limit = bat_volt_arr[count] - temp_data; + + if ((bat_volt_arr[count + 1] < bat_hysteresis.upper_limit) && + (bat_volt_arr[count + 1] > + bat_hysteresis.lower_limit)) { + *battery_voltage = (bat_volt_arr[count] + + bat_volt_arr[count+1]) / 2; + hys_flag = TRUE; + return 0; + } + } + + for (count = 0; count < + (chg_device->vbat_first_valid_detect_iteration - 1); + count++) + bat_volt_arr[count] = bat_volt_arr[count + 1]; + + return FAILURE; +} + + +s32 check_hystersis(struct da9052_charger_device *chg_device, u16 *bat_voltage) +{ + u8 ret = 0; + u32 offset = 0; + + /* Measure battery voltage using BAT internal function*/ + if (hys_flag == FALSE) { + ret = capture_first_correct_vbat_sample + (chg_device, &array_hys_batvoltage[0]); + if (ret) + return ret; + } + + ret = da9052_bat_get_battery_voltage + (chg_device, &array_hys_batvoltage[1]); + if (ret) + return ret; + *bat_voltage = array_hys_batvoltage[1]; + +#if DA9052_BAT_FILTER_HYS + printk(KERN_CRIT "\nBAT_LOG: Previous Battery Voltage = %d mV\n", + array_hys_batvoltage[0]); + printk(KERN_CRIT "\nBAT_LOG:Battery Voltage Before Filter = %d mV\n", + array_hys_batvoltage[1]); +#endif + /* Check if measured battery voltage value is within the hysteresis + window limit using measured battey votlage value */ + if ((bat_hysteresis.upper_limit < *bat_voltage) || + (bat_hysteresis.lower_limit > *bat_voltage)) { + + bat_hysteresis.index++; + if (bat_hysteresis.index == + chg_device->hysteresis_no_of_reading) { + /* Hysteresis Window is set to +- of + HYSTERESIS_WINDOW_SIZE percentage of current VBAT */ + bat_hysteresis.index = 0; + offset = ((*bat_voltage) * + chg_device->hysteresis_window_size)/ + 100; + bat_hysteresis.upper_limit = (*bat_voltage) + offset; + bat_hysteresis.lower_limit = (*bat_voltage) - offset; + } else { +#if DA9052_BAT_FILTER_HYS + printk(KERN_CRIT "CheckHystersis: Failed\n"); +#endif + return -EIO; + } + } else { + bat_hysteresis.index = 0; + offset = ((*bat_voltage) * + chg_device->hysteresis_window_size)/100; + bat_hysteresis.upper_limit = (*bat_voltage) + offset; + bat_hysteresis.lower_limit = (*bat_voltage) - offset; + } + + /* Digital C Filter, formula Yn = k Yn-1 + (1-k) Xn */ + *bat_voltage = ((chg_device->chg_hysteresis_const * + array_hys_batvoltage[0])/100) + + (((100 - chg_device->chg_hysteresis_const) * + array_hys_batvoltage[1])/100); + + if ((chg_device->status == POWER_SUPPLY_STATUS_DISCHARGING) && + (*bat_voltage > array_hys_batvoltage[0])) { + *bat_voltage = array_hys_batvoltage[0]; + } + + array_hys_batvoltage[0] = *bat_voltage; + +#if DA9052_BAT_FILTER_HYS + printk(KERN_CRIT "\nBAT_LOG:Battery Voltage After Filter = %d mV\n",\ + *bat_voltage); + +#endif + return 0; +} + +u8 select_temperature(u8 temp_index, u16 bat_temperature) +{ + u16 temp_temperature = 0; + temp_temperature = (temperature_lookup_ref[temp_index] + + temperature_lookup_ref[temp_index+1]) / 2; + + if (bat_temperature >= temp_temperature) { + temp_index += 1; + return temp_index; + } else + return temp_index; +} + +s32 da9052_bat_level_update(struct da9052_charger_device *chg_device) +{ + u16 bat_temperature; + u16 bat_voltage; + u32 vbat_lower, vbat_upper, level_upper, level_lower, level; + u8 access_index = 0; + u8 index = 0, ret; + u8 flag = FALSE; + + ret = 0; + vbat_lower = 0; + vbat_upper = 0; + level_upper = 0; + level_lower = 0; + + ret = check_hystersis(chg_device, &bat_voltage); + if (ret) + return ret; + + ret = da9052_bat_get_battery_temperature(chg_device, + &bat_temperature); + if (ret) + return ret; + + for (index = 0; index < (DA9052_NO_OF_LOOKUP_TABLE-1); index++) { + if (bat_temperature <= temperature_lookup_ref[0]) { + access_index = 0; + break; + } else if (bat_temperature > + temperature_lookup_ref[DA9052_NO_OF_LOOKUP_TABLE]){ + access_index = DA9052_NO_OF_LOOKUP_TABLE - 1; + break; + } else if ((bat_temperature >= temperature_lookup_ref[index]) && + (bat_temperature >= temperature_lookup_ref[index+1])) { + access_index = select_temperature(index, + bat_temperature); + break; + } + } + if (bat_voltage >= vbat_vs_capacity_look_up[access_index][0][0]) { + chg_device->cal_capacity = 100; + return 0; + } + if (bat_voltage <= vbat_vs_capacity_look_up[access_index] + [DA9052_LOOK_UP_TABLE_SIZE-1][0]){ + chg_device->cal_capacity = 0; + return 0; + } + flag = FALSE; + + for (index = 0; index < (DA9052_LOOK_UP_TABLE_SIZE-1); index++) { + if ((bat_voltage <= + vbat_vs_capacity_look_up[access_index][index][0]) && + (bat_voltage >= + vbat_vs_capacity_look_up[access_index][index+1][0])) { + vbat_upper = + vbat_vs_capacity_look_up[access_index][index][0]; + vbat_lower = + vbat_vs_capacity_look_up[access_index][index+1][0]; + level_upper = + vbat_vs_capacity_look_up[access_index][index][1]; + level_lower = + vbat_vs_capacity_look_up[access_index][index+1][1]; + flag = TRUE; + break; + } + } + if (!flag) + return -EIO; + + level = interpolated(vbat_lower, vbat_upper, level_lower, + level_upper, bat_voltage); + chg_device->cal_capacity = level; + DA9052_DEBUG(" TOTAl_BAT_CAPACITY : %d\n", chg_device->cal_capacity); + return 0; +} + +void da9052_bat_tbat_handler(struct da9052_eh_nb *eh_data, unsigned int event) +{ + struct da9052_charger_device *chg_device = + container_of(eh_data, struct da9052_charger_device, tbat_eh_data); + + chg_device->health = POWER_SUPPLY_HEALTH_OVERHEAT; + +} + +static s32 da9052_bat_register_event(struct da9052_charger_device *chg_device) +{ + s32 ret; + + if (event_status.da9052_event_tbat == FALSE) { + chg_device->tbat_eh_data.eve_type = TBAT_EVE; + chg_device->tbat_eh_data.call_back = da9052_bat_tbat_handler; + DA9052_DEBUG("events = %d\n", TBAT_EVE); + ret = chg_device->da9052->register_event_notifier + (chg_device->da9052, &chg_device->tbat_eh_data); + if (ret) + return -EIO; + event_status.da9052_event_tbat = TRUE; + } + + return 0; +} + +static s32 da9052_bat_unregister_event(struct da9052_charger_device *chg_device) +{ + s32 ret; + + if (event_status.da9052_event_tbat) { + ret = + chg_device->da9052->unregister_event_notifier + (chg_device->da9052, &chg_device->tbat_eh_data); + if (ret) + return -EIO; + event_status.da9052_event_tbat = FALSE; + } + + return 0; +} + +static int da9052_bat_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct da9052_charger_device *chg_device = + container_of(psy, struct da9052_charger_device, psy); + + /* Validate battery presence */ + if (chg_device->illegal && psp != POWER_SUPPLY_PROP_PRESENT) + return -ENODEV; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = chg_device->status; + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = (chg_device->charger_type == DA9052_NOCHARGER) + ? 0 : 1; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = chg_device->illegal; + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = chg_device->health; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = chg_device->bat_target_voltage * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = chg_device->bat_volt_cutoff * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + val->intval = chg_device->bat_voltage * 1000; + break; + case POWER_SUPPLY_PROP_CURRENT_AVG: + val->intval = chg_device->chg_current * 1000; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = chg_device->cal_capacity; + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = bat_temp_reg_to_C(chg_device->bat_temp); + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = chg_device->technology; + break; + default: + return -EINVAL; + break; + } + return 0; +} + + +static u8 detect_illegal_battery(struct da9052_charger_device *chg_device) +{ + u16 buffer = 0; + s32 ret = 0; + + /* Measure battery temeperature */ + ret = da9052_bat_get_battery_temperature(chg_device, &buffer); + if (ret) { + DA9052_DEBUG("%s: Battery temperature measurement failed\n", + __func__); + return ret; + } + + if (buffer > chg_device->bat_with_no_resistor) + chg_device->illegal = TRUE; + else + chg_device->illegal = FALSE; + + + /* suspend charging of battery if illegal battey is detected */ + if (chg_device->illegal) + da9052_bat_suspend_charging(chg_device); + + return chg_device->illegal; +} + +void da9052_update_bat_properties(struct da9052_charger_device *chg_device) +{ + /* Get Bat status and type */ + da9052_bat_status_update(chg_device); + da9052_bat_level_update(chg_device); +} + +static void da9052_bat_external_power_changed(struct power_supply *psy) +{ + struct da9052_charger_device *chg_device = + container_of(psy, struct da9052_charger_device, psy); + + cancel_delayed_work(&chg_device->monitor_work); + queue_delayed_work(chg_device->monitor_wqueue, + &chg_device->monitor_work, HZ/10); +} + + +static void da9052_bat_work(struct work_struct *work) +{ + struct da9052_charger_device *chg_device = container_of(work, + struct da9052_charger_device, monitor_work.work); + + da9052_update_bat_properties(chg_device); + queue_delayed_work(chg_device->monitor_wqueue, + &chg_device->monitor_work, HZ * 8); +} + +static enum power_supply_property da9052_bat_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_AVG, + POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TECHNOLOGY, + +}; + +static s32 __devinit da9052_bat_probe(struct platform_device *pdev) +{ + struct da9052_charger_device *chg_device; + u8 reg_data; + int ret; + + chg_device = kzalloc(sizeof(*chg_device), GFP_KERNEL); + if (!chg_device) + return -ENOMEM; + + chg_device->da9052 = dev_get_drvdata(pdev->dev.parent); + platform_set_drvdata(pdev, chg_device); + + chg_device->psy.name = DA9052_BAT_DEVICE_NAME; + chg_device->psy.type = POWER_SUPPLY_TYPE_BATTERY; + chg_device->psy.properties = da9052_bat_props; + chg_device->psy.num_properties = ARRAY_SIZE(da9052_bat_props); + chg_device->psy.get_property = da9052_bat_get_property; + chg_device->psy.external_power_changed = + da9052_bat_external_power_changed; + chg_device->psy.use_for_apm = 1; + chg_device->charger_type = DA9052_NOCHARGER; + chg_device->status = POWER_SUPPLY_STATUS_UNKNOWN; + chg_device->health = POWER_SUPPLY_HEALTH_UNKNOWN; + chg_device->technology = POWER_SUPPLY_TECHNOLOGY_LION; + chg_device->bat_with_no_resistor = 62; + chg_device->bat_capacity_limit_low = 4; + chg_device->bat_capacity_limit_high = 70; + chg_device->bat_capacity_full = 100; + chg_device->bat_volt_cutoff = 2800; + chg_device->vbat_first_valid_detect_iteration = 3; + chg_device->hysteresis_window_size = 1; + chg_device->chg_hysteresis_const = 89; + chg_device->hysteresis_reading_interval = 1000; + chg_device->hysteresis_no_of_reading = 10; + + ret = da9052_read(chg_device->da9052, DA9052_CHGCONT_REG, ®_data); + if (ret) + goto err_charger_init; + chg_device->charger_voltage_drop = bat_drop_reg_to_mV(reg_data && + DA9052_CHGCONT_TCTR); + chg_device->bat_target_voltage = + bat_reg_to_mV(reg_data && DA9052_CHGCONT_VCHGBAT); + + ret = da9052_read(chg_device->da9052, DA9052_ICHGEND_REG, ®_data); + if (ret) + goto err_charger_init; + chg_device->chg_end_current = ichg_reg_to_mA(reg_data); + + bat_hysteresis.upper_limit = 0; + bat_hysteresis.lower_limit = 0; + bat_hysteresis.hys_flag = 0; + + chg_device->illegal = FALSE; + detect_illegal_battery(chg_device); + + da9052_bat_register_event(chg_device); + if (ret) + goto err_charger_init; + + ret = power_supply_register(&pdev->dev, &chg_device->psy); + if (ret) + goto err_charger_init; + + INIT_DELAYED_WORK(&chg_device->monitor_work, da9052_bat_work); + chg_device->monitor_wqueue = create_singlethread_workqueue( + pdev->dev.bus_id); + if (!chg_device->monitor_wqueue) + goto err_charger_init; + queue_delayed_work(chg_device->monitor_wqueue, + &chg_device->monitor_work, HZ * 1); + + return 0; + +err_charger_init: + platform_set_drvdata(pdev, NULL); + kfree(chg_device); + return ret; +} +static int __devexit da9052_bat_remove(struct platform_device *dev) +{ + struct da9052_charger_device *chg_device = platform_get_drvdata(dev); + + /* unregister the events.*/ + da9052_bat_unregister_event(chg_device); + + cancel_rearming_delayed_workqueue(chg_device->monitor_wqueue, + &chg_device->monitor_work); + destroy_workqueue(chg_device->monitor_wqueue); + + power_supply_unregister(&chg_device->psy); + + return 0; +} + +static struct platform_driver da9052_bat_driver = { + .probe = da9052_bat_probe, + .remove = __devexit_p(da9052_bat_remove), + .driver.name = DA9052_BAT_DEVICE_NAME, + .driver.owner = THIS_MODULE, +}; + +static int __init da9052_bat_init(void) +{ + printk(banner); + return platform_driver_register(&da9052_bat_driver); +} + +static void __exit da9052_bat_exit(void) +{ + /* To remove printk("DA9052: Unregistering BAT device.\n");*/ + platform_driver_unregister(&da9052_bat_driver); +} + +module_init(da9052_bat_init); +module_exit(da9052_bat_exit); + +MODULE_AUTHOR("Dialog Semiconductor Ltd"); +MODULE_DESCRIPTION("DA9052 BAT Device Driver"); +MODULE_LICENSE("GPL");
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9052 regulator driver from Dialog. Modify Kconfig/Makefile for DA9052 regulator driver.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org --- drivers/regulator/Kconfig | 7 + drivers/regulator/Makefile | 2 + drivers/regulator/da9052-regulator.c | 490 ++++++++++++++++++++++++++++ include/linux/regulator/da9052-regulator.h | 15 + 4 files changed, 514 insertions(+), 0 deletions(-) create mode 100644 drivers/regulator/da9052-regulator.c create mode 100644 include/linux/regulator/da9052-regulator.h
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index d7ed20f..4ae56ac 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -303,5 +303,12 @@ config REGULATOR_TPS65910 help This driver supports TPS65910 voltage regulator chips.
+config REGULATOR_DA9052 + tristate "Dialog DA9052 regulators" + depends on PMIC_DIALOG + help + Say y here to support the BUCKs and LDOs regulators found on + Dialog Semiconductor DA9052 PMIC. + endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 3932d2e..2aa6496 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o +obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o @@ -43,5 +44,6 @@ obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o +obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c new file mode 100644 index 0000000..612fe60 --- /dev/null +++ b/drivers/regulator/da9052-regulator.c @@ -0,0 +1,490 @@ +/* + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * da9052-regulator.c: Regulator driver for DA9052 + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> + +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/reg.h> +#include <linux/mfd/da9052/pm.h> + +static struct regulator_ops da9052_ldo_buck_ops; + + +struct regulator { + struct device *dev; + struct list_head list; + int uA_load; + int min_uV; + int max_uV; + int enabled; /* client has called enabled */ + char *supply_name; + struct device_attribute dev_attr; + struct regulator_dev *rdev; +}; + + + + +#define DA9052_LDO(_id, max, min, step_v, reg, mbits, cbits) \ +{\ + .reg_desc = {\ + .name = #_id,\ + .ops = &da9052_ldo_buck_ops,\ + .type = REGULATOR_VOLTAGE,\ + .id = _id,\ + .owner = THIS_MODULE,\ + },\ + .reg_const = {\ + .max_uV = (max) * 1000,\ + .min_uV = (min) * 1000,\ + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE\ + | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE,\ + .valid_modes_mask = REGULATOR_MODE_NORMAL,\ + },\ + .step_uV = (step_v) * 1000,\ + .reg_add = (reg),\ + .mask_bits = (mbits),\ + .en_bit_mask = (cbits),\ +} + +struct regulator_info { + struct regulator_desc reg_desc; + struct regulation_constraints reg_const; + int step_uV; + unsigned char reg_add; + unsigned char mask_bits; + unsigned char en_bit_mask; +}; + +struct da9052_regulator_priv { + struct da9052 *da9052; + struct regulator_dev *regulators[]; +}; + +struct regulator_info da9052_regulators[] = { + /* LD01 - LDO10*/ + DA9052_LDO(DA9052_LDO1, DA9052_LDO1_VOLT_UPPER, DA9052_LDO1_VOLT_LOWER, + DA9052_LDO1_VOLT_STEP, DA9052_LDO1_REG, + DA9052_LDO1_VLDO1, DA9052_LDO1_LDO1EN), + + DA9052_LDO(DA9052_LDO2, + DA9052_LDO2_VOLT_UPPER, DA9052_LDO2_VOLT_LOWER, + DA9052_LDO2_VOLT_STEP, DA9052_LDO2_REG, + DA9052_LDO2_VLDO2, + DA9052_LDO2_LDO2EN), + + DA9052_LDO(DA9052_LDO3, DA9052_LDO34_VOLT_UPPER, + DA9052_LDO34_VOLT_LOWER, + DA9052_LDO34_VOLT_STEP, DA9052_LDO3_REG, + DA9052_LDO3_VLDO3, DA9052_LDO3_LDO3EN), + + DA9052_LDO(DA9052_LDO4, DA9052_LDO34_VOLT_UPPER, + DA9052_LDO34_VOLT_LOWER, + DA9052_LDO34_VOLT_STEP, DA9052_LDO4_REG, + DA9052_LDO4_VLDO4, DA9052_LDO4_LDO4EN), + + DA9052_LDO(DA9052_LDO5, DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, + DA9052_LDO567810_VOLT_STEP, DA9052_LDO5_REG, + DA9052_LDO5_VLDO5, DA9052_LDO5_LDO5EN), + + DA9052_LDO(DA9052_LDO6, DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, + DA9052_LDO567810_VOLT_STEP, DA9052_LDO6_REG, + DA9052_LDO6_VLDO6, DA9052_LDO6_LDO6EN), + + DA9052_LDO(DA9052_LDO7, DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, + DA9052_LDO567810_VOLT_STEP, DA9052_LDO7_REG, + DA9052_LDO7_VLDO7, DA9052_LDO7_LDO7EN), + + DA9052_LDO(DA9052_LDO8, DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, + DA9052_LDO567810_VOLT_STEP, DA9052_LDO8_REG, + DA9052_LDO8_VLDO8, DA9052_LDO8_LDO8EN), + + DA9052_LDO(DA9052_LDO9, DA9052_LDO9_VOLT_UPPER, + DA9052_LDO9_VOLT_LOWER, + DA9052_LDO9_VOLT_STEP, + DA9052_LDO9_REG, DA9052_LDO9_VLDO9, + DA9052_LDO9_LDO9EN), + + DA9052_LDO(DA9052_LDO10, DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, + DA9052_LDO567810_VOLT_STEP, DA9052_LDO10_REG, + DA9052_LDO10_VLDO10, DA9052_LDO10_LDO10EN), + + /* BUCKS */ + DA9052_LDO(DA9052_BUCK_CORE, DA9052_BUCK_CORE_PRO_VOLT_UPPER, + DA9052_BUCK_CORE_PRO_VOLT_LOWER, + DA9052_BUCK_CORE_PRO_STEP, DA9052_BUCKCORE_REG, + DA9052_BUCKCORE_VBCORE, DA9052_BUCKCORE_BCOREEN), + + DA9052_LDO(DA9052_BUCK_PRO, DA9052_BUCK_CORE_PRO_VOLT_UPPER, + DA9052_BUCK_CORE_PRO_VOLT_LOWER, + DA9052_BUCK_CORE_PRO_STEP, DA9052_BUCKPRO_REG, + DA9052_BUCKPRO_VBPRO, DA9052_BUCKPRO_BPROEN), + + DA9052_LDO(DA9052_BUCK_MEM, DA9052_BUCK_MEM_VOLT_UPPER, + DA9052_BUCK_MEM_VOLT_LOWER, + DA9052_BUCK_MEM_STEP, DA9052_BUCKMEM_REG, + DA9052_BUCKMEM_VBMEM, DA9052_BUCKMEM_BMEMEN), +#if defined(CONFIG_PMIC_DA9052) + DA9052_LDO(DA9052_BUCK_PERI, DA9052_BUCK_PERI_VOLT_UPPER, + DA9052_BUCK_PERI_VOLT_LOWER, + DA9052_BUCK_PERI_STEP_BELOW_3000, DA9052_BUCKPERI_REG, + DA9052_BUCKPERI_VBPERI, DA9052_BUCKPERI_BPERIEN), +#elif defined(CONFIG_PMIC_DA9053AA) || (CONFIG_PMIC_DA9053Bx) + DA9052_LDO(DA9052_BUCK_PERI, DA9052_BUCK_PERI_VOLT_UPPER, + DA9052_BUCK_PERI_VOLT_LOWER, + DA9052_BUCK_PERI_STEP, DA9052_BUCKPERI_REG, + DA9052_BUCKPERI_VBPERI, DA9052_BUCKPERI_BPERIEN), +#endif +}; + +int da9052_ldo_buck_enable(struct regulator_dev *rdev) +{ + struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int ret = 0; + struct da9052_ssc_msg ssc_msg; + + ssc_msg.addr = da9052_regulators[id].reg_add; + ssc_msg.data = 0; + + da9052_lock(priv->da9052); + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + ssc_msg.data = (ssc_msg.data | da9052_regulators[id].en_bit_mask); + + ret = priv->da9052->write(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + da9052_unlock(priv->da9052); + + return 0; +} +EXPORT_SYMBOL_GPL(da9052_ldo_buck_enable); +/* Code added to support additional attribure in sysfs - changestate */ + + + +int da9052_ldo_buck_disable(struct regulator_dev *rdev) +{ + struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int ret; + struct da9052_ssc_msg ssc_msg; + + ssc_msg.addr = da9052_regulators[id].reg_add; + ssc_msg.data = 0; + + da9052_lock(priv->da9052); + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + ssc_msg.data = (ssc_msg.data & ~(da9052_regulators[id].en_bit_mask)); + + ret = priv->da9052->write(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + da9052_unlock(priv->da9052); + + return 0; +} +EXPORT_SYMBOL_GPL(da9052_ldo_buck_disable); +/* Code added to support additional attribure in sysfs - changestate */ + +static int da9052_ldo_buck_is_enabled(struct regulator_dev *rdev) +{ + struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int ret; + struct da9052_ssc_msg ssc_msg; + ssc_msg.addr = da9052_regulators[id].reg_add; + ssc_msg.data = 0; + + da9052_lock(priv->da9052); + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + da9052_unlock(priv->da9052); + return (ssc_msg.data & da9052_regulators[id].en_bit_mask) != 0; +} + +int da9052_ldo_buck_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, + unsigned *selector) +{ + struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev); + struct da9052_ssc_msg ssc_msg; + int id = rdev_get_id(rdev); + int ret; + int ldo_volt = 0; + selector; + + /* Below if condition is there for added setvoltage attribute + in sysfs */ + if (0 == max_uV) + max_uV = da9052_regulators[id].reg_const.max_uV; + + /* Compare voltage range */ + if (min_uV > max_uV) + return -EINVAL; + + /* Check Minimum/ Maximum voltage range */ + if (min_uV < da9052_regulators[id].reg_const.min_uV || + min_uV > da9052_regulators[id].reg_const.max_uV) + return -EINVAL; + if (max_uV < da9052_regulators[id].reg_const.min_uV || + max_uV > da9052_regulators[id].reg_const.max_uV) + return -EINVAL; +#if defined(CONFIG_PMIC_DA9052) + /* Get the ldo register value */ + /* Varying step size for BUCK PERI */ + if ((da9052_regulators[id].reg_desc.id == DA9052_BUCK_PERI) && + (min_uV >= DA9052_BUCK_PERI_VALUES_3000)) { + ldo_volt = (DA9052_BUCK_PERI_VALUES_3000 - + da9052_regulators[id].reg_const.min_uV)/ + (da9052_regulators[id].step_uV); + ldo_volt += (min_uV - DA9052_BUCK_PERI_VALUES_3000)/ + (DA9052_BUCK_PERI_STEP_ABOVE_3000); + } else{ + ldo_volt = (min_uV - da9052_regulators[id].reg_const.min_uV)/ + (da9052_regulators[id].step_uV); + /* Check for maximum value */ + if ((ldo_volt * da9052_regulators[id].step_uV) + + da9052_regulators[id].reg_const.min_uV > max_uV) + return -EINVAL; + } +#elif defined(CONFIG_PMIC_DA9053AA) || (CONFIG_PMIC_DA9053Bx) + ldo_volt = (min_uV - da9052_regulators[id].reg_const.min_uV)/ + (da9052_regulators[id].step_uV); + /* Check for maximum value */ + if ((ldo_volt * da9052_regulators[id].step_uV) + + da9052_regulators[id].reg_const.min_uV > max_uV) + return -EINVAL; +#endif + /* Configure LDO Voltage, CONF bits */ + ssc_msg.addr = da9052_regulators[id].reg_add; + ssc_msg.data = 0; + + /* Read register */ + da9052_lock(priv->da9052); + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + ssc_msg.data = (ssc_msg.data & ~(da9052_regulators[id].mask_bits)); + ssc_msg.data |= ldo_volt; + + ret = priv->da9052->write(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + /* Set the GO LDO/BUCk bits so that the voltage changes */ + ssc_msg.addr = DA9052_SUPPLY_REG; + ssc_msg.data = 0; + + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + switch (id) { + case DA9052_LDO2: + ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VLDO2GO); + break; + case DA9052_LDO3: + ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VLDO3GO); + break; + case DA9052_BUCK_CORE: + ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VBCOREGO); + break; + case DA9052_BUCK_PRO: + ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VBPROGO); + break; + case DA9052_BUCK_MEM: + ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VBMEMGO); + break; + default: + da9052_unlock(priv->da9052); + return -EINVAL; + } + + ret = priv->da9052->write(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + + da9052_unlock(priv->da9052); + + return 0; +} +EXPORT_SYMBOL_GPL(da9052_ldo_buck_set_voltage); +/* Code added to support additional attributes in sysfs - setvoltage */ + + +int da9052_ldo_buck_get_voltage(struct regulator_dev *rdev) +{ + struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev); + struct da9052_ssc_msg ssc_msg; + int id = rdev_get_id(rdev); + int ldo_volt = 0; + int ldo_volt_uV = 0; + int ret; + + ssc_msg.addr = da9052_regulators[id].reg_add; + ssc_msg.data = 0; + /* Read register */ + da9052_lock(priv->da9052); + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret) { + da9052_unlock(priv->da9052); + return -EIO; + } + da9052_unlock(priv->da9052); + + ldo_volt = ssc_msg.data & da9052_regulators[id].mask_bits; +#if defined(CONFIG_PMIC_DA9052) + if (da9052_regulators[id].reg_desc.id == DA9052_BUCK_PERI) { + if (ldo_volt >= DA9052_BUCK_PERI_VALUES_UPTO_3000) { + ldo_volt_uV = ((DA9052_BUCK_PERI_VALUES_UPTO_3000 * + da9052_regulators[id].step_uV) + + da9052_regulators[id].reg_const.min_uV); + ldo_volt_uV = (ldo_volt_uV + + (ldo_volt - DA9052_BUCK_PERI_VALUES_UPTO_3000) + * (DA9052_BUCK_PERI_STEP_ABOVE_3000)); + } else { + ldo_volt_uV = + (ldo_volt * da9052_regulators[id].step_uV) + + da9052_regulators[id].reg_const.min_uV; + } + } else { + ldo_volt_uV = (ldo_volt * da9052_regulators[id].step_uV) + + da9052_regulators[id].reg_const.min_uV; + } +#elif defined(CONFIG_PMIC_DA9053AA) || (CONFIG_PMIC_DA9053Bx) + ldo_volt_uV = (ldo_volt * da9052_regulators[id].step_uV) + + da9052_regulators[id].reg_const.min_uV; +#endif + return ldo_volt_uV; +} +EXPORT_SYMBOL_GPL(da9052_ldo_buck_get_voltage); +/* Code added to support additional attributes in sysfs - setvoltage */ + + +static struct regulator_ops da9052_ldo_buck_ops = { + .is_enabled = da9052_ldo_buck_is_enabled, + .enable = da9052_ldo_buck_enable, + .disable = da9052_ldo_buck_disable, + .get_voltage = da9052_ldo_buck_get_voltage, + .set_voltage = da9052_ldo_buck_set_voltage, +}; + +static int __devinit da9052_regulator_probe(struct platform_device *pdev) +{ + struct da9052_regulator_priv *priv; + struct da9052_regulator_platform_data *pdata = + (pdev->dev.platform_data); + struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent); + struct regulator_init_data *init_data; + int i, ret = 0; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + priv->da9052 = da9052; + for (i = 0; i < 14; i++) { + + init_data = &pdata->regulators[i]; + init_data->driver_data = da9052; + pdev->dev.platform_data = init_data; + priv->regulators[i] = regulator_register( + &da9052_regulators[i].reg_desc, + &pdev->dev, init_data, + priv); + if (IS_ERR(priv->regulators[i])) { + ret = PTR_ERR(priv->regulators[i]); + goto err; + } + } + platform_set_drvdata(pdev, priv); + return 0; +err: + while (--i >= 0) + regulator_unregister(priv->regulators[i]); + kfree(priv); + return ret; +} + +static int __devexit da9052_regulator_remove(struct platform_device *pdev) +{ + struct da9052_regulator_priv *priv = platform_get_drvdata(pdev); + struct da9052_platform_data *pdata = pdev->dev.platform_data; + int i; + + for (i = 0; i < pdata->num_regulators; i++) + regulator_unregister(priv->regulators[i]); + + return 0; +} + +static struct platform_driver da9052_regulator_driver = { + .probe = da9052_regulator_probe, + .remove = __devexit_p(da9052_regulator_remove), + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init da9052_regulator_init(void) +{ + return platform_driver_register(&da9052_regulator_driver); +} +subsys_initcall(da9052_regulator_init); + +static void __exit da9052_regulator_exit(void) +{ + platform_driver_unregister(&da9052_regulator_driver); +} +module_exit(da9052_regulator_exit); + +MODULE_AUTHOR("David Dajun Chen dchen@diasemi.com"); +MODULE_DESCRIPTION("Power Regulator driver for Dialog DA9052 PMIC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/include/linux/regulator/da9052-regulator.h b/include/linux/regulator/da9052-regulator.h new file mode 100644 index 0000000..d09b69c --- /dev/null +++ b/include/linux/regulator/da9052-regulator.h @@ -0,0 +1,15 @@ +/* This file is there to support additional attributes in + sysfs - changestate and setvoltage +*/ +#ifndef _DA9052_REGULATOR_H +#define _DA9052_REGULATOR_H + +int da9052_ldo_buck_enable(struct regulator_dev *rdev); +int da9052_ldo_buck_disable(struct regulator_dev *rdev); + + +int da9052_ldo_buck_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV); +int da9052_ldo_buck_get_voltage(struct regulator_dev *rdev); + +#endif
On Fri, Jun 10, 2011 at 11:51:02AM +0800, Ying-Chun Liu (PaulLiu) wrote:
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9052 regulator driver from Dialog. Modify Kconfig/Makefile for DA9052 regulator driver.
This has *many* of the serious shortcomings that were present in the original driver submission from Dialog. While they've still got issues their current mainline code is much better than what they originally tried to submit, please sync up with them.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org
Given that this bears a remarkable resemblance
+++ b/drivers/regulator/Kconfig @@ -303,5 +303,12 @@ config REGULATOR_TPS65910 help This driver supports TPS65910 voltage regulator chips. +config REGULATOR_DA9052
- tristate "Dialog DA9052 regulators"
- depends on PMIC_DIALOG
- help
Keep Kconfig and Makefile sorted (or at least don't make the situation worse).
+#if defined(CONFIG_PMIC_DA9052)
- DA9052_LDO(DA9052_BUCK_PERI, DA9052_BUCK_PERI_VOLT_UPPER,
DA9052_BUCK_PERI_VOLT_LOWER,
DA9052_BUCK_PERI_STEP_BELOW_3000, DA9052_BUCKPERI_REG,
DA9052_BUCKPERI_VBPERI, DA9052_BUCKPERI_BPERIEN),
+#elif defined(CONFIG_PMIC_DA9053AA) || (CONFIG_PMIC_DA9053Bx)
- DA9052_LDO(DA9052_BUCK_PERI, DA9052_BUCK_PERI_VOLT_UPPER,
DA9052_BUCK_PERI_VOLT_LOWER,
DA9052_BUCK_PERI_STEP, DA9052_BUCKPERI_REG,
DA9052_BUCKPERI_VBPERI, DA9052_BUCKPERI_BPERIEN),
+#endif
You need to be able to support all three chips in a single kernel image.
+int da9052_ldo_buck_enable(struct regulator_dev *rdev) +{
- struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
- int ret = 0;
- struct da9052_ssc_msg ssc_msg;
- ssc_msg.addr = da9052_regulators[id].reg_add;
- ssc_msg.data = 0;
- da9052_lock(priv->da9052);
- ret = priv->da9052->read(priv->da9052, &ssc_msg);
All the register access stuff hsa been totally redone to save having to implement basic things like locking for register write operations in every single caller (never mind driver...) using them.
- return 0;
+} +EXPORT_SYMBOL_GPL(da9052_ldo_buck_enable); +/* Code added to support additional attribure in sysfs - changestate */
This should be setting off warning flags...
I've stopped reviewing here.
On 06/10/2011 01:17 PM, Somebody in the thread at some point said:
On Fri, Jun 10, 2011 at 11:51:02AM +0800, Ying-Chun Liu (PaulLiu) wrote:
From: "Ying-Chun Liu (PaulLiu)"paul.liu@linaro.org
Add DA9052 regulator driver from Dialog. Modify Kconfig/Makefile for DA9052 regulator driver.
This has *many* of the serious shortcomings that were present in the original driver submission from Dialog. While they've still got issues their current mainline code is much better than what they originally tried to submit, please sync up with them.
I've stopped reviewing here.
Hum it sounds like you guys need to talk to Dialog as Mark suggests.
-Andy
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9052 rtc driver from Dialog. Modify Kconfig/Makefile for DA9052 rtc driver.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org --- drivers/rtc/Kconfig | 7 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-da9052.c | 694 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 702 insertions(+), 0 deletions(-) create mode 100644 drivers/rtc/rtc-da9052.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index f822e13..58515a2 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1051,4 +1051,11 @@ config RTC_DRV_TILE Enable support for the Linux driver side of the Tilera hypervisor's real-time clock interface.
+config RTC_DRV_DA9052 + tristate "Dialog DA9052 RTC" + depends on PMIC_DIALOG + help + Say y here to support the RTC found on + Dialog Semiconductor DA9052 PMIC. + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 213d725..20c8b27 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -107,3 +107,4 @@ obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o +obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c new file mode 100644 index 0000000..17ca177 --- /dev/null +++ b/drivers/rtc/rtc-da9052.c @@ -0,0 +1,694 @@ +/* + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * rtc-da9052.c: RTC driver for DA9052 + */ + +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/reg.h> +#include <linux/mfd/da9052/rtc.h> + +#define DRIVER_NAME "da9052-rtc" +#define ENABLE 1 +#define DISABLE 0 + +struct da9052_rtc { + struct rtc_device *rtc; + struct da9052 *da9052; + struct da9052_eh_nb eh_data; + unsigned char is_min_alarm; + unsigned char enable_tick_alarm; + unsigned char enable_clk_buffer; + unsigned char set_osc_trim_freq; +}; + +static int da9052_rtc_enable_alarm(struct da9052 *da9052, unsigned char flag); + +void da9052_rtc_notifier(struct da9052_eh_nb *eh_data, unsigned int event) +{ + struct da9052_rtc *rtc = + container_of(eh_data, struct da9052_rtc, eh_data); + struct da9052_ssc_msg msg; + unsigned int ret; + + /* Check the alarm type - TIMER or TICK */ + msg.addr = DA9052_ALARMMI_REG; + + da9052_lock(rtc->da9052); + ret = rtc->da9052->read(rtc->da9052, &msg); + if (ret != 0) { + da9052_unlock(rtc->da9052); + return; + } + + da9052_unlock(rtc->da9052); + + + if (msg.data & DA9052_ALARMMI_ALARMTYPE) { + da9052_rtc_enable_alarm(rtc->da9052, 0); + printk(KERN_INFO "RTC: TIMER ALARM\n"); + } else { + kobject_uevent(&rtc->rtc->dev.kobj, KOBJ_CHANGE); + printk(KERN_INFO "RTC: TICK ALARM\n"); + } +} + +static int da9052_rtc_validate_parameters(struct rtc_time *rtc_tm) +{ + + if (rtc_tm->tm_sec > DA9052_RTC_SECONDS_LIMIT) + return DA9052_RTC_INVALID_SECONDS; + + if (rtc_tm->tm_min > DA9052_RTC_MINUTES_LIMIT) + return DA9052_RTC_INVALID_MINUTES; + + if (rtc_tm->tm_hour > DA9052_RTC_HOURS_LIMIT) + return DA9052_RTC_INVALID_HOURS; + + if (rtc_tm->tm_mday == 0) + return DA9052_RTC_INVALID_DAYS; + + if ((rtc_tm->tm_mon > DA9052_RTC_MONTHS_LIMIT) || + (rtc_tm->tm_mon == 0)) + return DA9052_RTC_INVALID_MONTHS; + + if (rtc_tm->tm_year > DA9052_RTC_YEARS_LIMIT) + return DA9052_RTC_INVALID_YEARS; + + if ((rtc_tm->tm_mon == FEBRUARY)) { + if (((rtc_tm->tm_year % 4 == 0) && + (rtc_tm->tm_year % 100 != 0)) || + (rtc_tm->tm_year % 400 == 0)) { + if (rtc_tm->tm_mday > 29) + return DA9052_RTC_INVALID_DAYS; + } else if (rtc_tm->tm_mday > 28) { + return DA9052_RTC_INVALID_DAYS; + } + } + + if (((rtc_tm->tm_mon == APRIL) || (rtc_tm->tm_mon == JUNE) || + (rtc_tm->tm_mon == SEPTEMBER) || (rtc_tm->tm_mon == NOVEMBER)) + && (rtc_tm->tm_mday == 31)) { + return DA9052_RTC_INVALID_DAYS; + } + + + return 0; +} + +static int da9052_rtc_settime(struct da9052 *da9052, struct rtc_time *rtc_tm) +{ + + struct da9052_ssc_msg msg_arr[6]; + int validate_param = 0; + unsigned char loop_index = 0; + int ret = 0; + + + /* System compatability */ + rtc_tm->tm_year -= 100; + rtc_tm->tm_mon += 1; + + validate_param = da9052_rtc_validate_parameters(rtc_tm); + if (validate_param) + return validate_param; + + msg_arr[loop_index].addr = DA9052_COUNTS_REG; + msg_arr[loop_index++].data = DA9052_COUNTS_MONITOR | rtc_tm->tm_sec; + + msg_arr[loop_index].addr = DA9052_COUNTMI_REG; + msg_arr[loop_index].data = 0; + msg_arr[loop_index++].data = rtc_tm->tm_min; + + msg_arr[loop_index].addr = DA9052_COUNTH_REG; + msg_arr[loop_index].data = 0; + msg_arr[loop_index++].data = rtc_tm->tm_hour; + + msg_arr[loop_index].addr = DA9052_COUNTD_REG; + msg_arr[loop_index].data = 0; + msg_arr[loop_index++].data = rtc_tm->tm_mday; + + msg_arr[loop_index].addr = DA9052_COUNTMO_REG; + msg_arr[loop_index].data = 0; + msg_arr[loop_index++].data = rtc_tm->tm_mon; + + msg_arr[loop_index].addr = DA9052_COUNTY_REG; + msg_arr[loop_index].data = 0; + msg_arr[loop_index++].data = rtc_tm->tm_year; + + da9052_lock(da9052); + ret = da9052->write_many(da9052, msg_arr, loop_index); + if (ret != 0) { + da9052_unlock(da9052); + return ret; + } + + da9052_unlock(da9052); + return 0; +} + +static int da9052_rtc_gettime(struct da9052 *da9052, struct rtc_time *rtc_tm) +{ + + struct da9052_ssc_msg msg[6]; + unsigned char loop_index = 0; + int validate_param = 0; + int ret = 0; + + msg[loop_index].data = 0; + msg[loop_index++].addr = DA9052_COUNTS_REG; + + msg[loop_index].data = 0; + msg[loop_index++].addr = DA9052_COUNTMI_REG; + + msg[loop_index].data = 0; + msg[loop_index++].addr = DA9052_COUNTH_REG; + + msg[loop_index].data = 0; + msg[loop_index++].addr = DA9052_COUNTD_REG; + + msg[loop_index].data = 0; + msg[loop_index++].addr = DA9052_COUNTMO_REG; + + msg[loop_index].data = 0; + msg[loop_index++].addr = DA9052_COUNTY_REG; + + da9052_lock(da9052); + ret = da9052->read_many(da9052, msg, loop_index); + if (ret != 0) { + da9052_unlock(da9052); + return ret; + } + da9052_unlock(da9052); + + rtc_tm->tm_year = msg[--loop_index].data & DA9052_COUNTY_COUNTYEAR; + rtc_tm->tm_mon = msg[--loop_index].data & DA9052_COUNTMO_COUNTMONTH; + rtc_tm->tm_mday = msg[--loop_index].data & DA9052_COUNTD_COUNTDAY; + rtc_tm->tm_hour = msg[--loop_index].data & DA9052_COUNTH_COUNTHOUR; + rtc_tm->tm_min = msg[--loop_index].data & DA9052_COUNTMI_COUNTMIN; + rtc_tm->tm_sec = msg[--loop_index].data & DA9052_COUNTS_COUNTSEC; + + validate_param = da9052_rtc_validate_parameters(rtc_tm); + if (validate_param) + return validate_param; + + /* System compatability */ + rtc_tm->tm_year += 100; + rtc_tm->tm_mon -= 1; + return 0; +} + +static int da9052_alarm_gettime(struct da9052 *da9052, struct rtc_time *rtc_tm) +{ + struct da9052_ssc_msg msg[5]; + unsigned char loop_index = 0; + int validate_param = 0; + int ret = 0; + + msg[loop_index].data = 0; + msg[loop_index++].addr = DA9052_ALARMMI_REG; + + msg[loop_index].data = 0; + msg[loop_index++].addr = DA9052_ALARMH_REG; + + msg[loop_index].data = 0; + msg[loop_index++].addr = DA9052_ALARMD_REG; + + msg[loop_index].data = 0; + msg[loop_index++].addr = DA9052_ALARMMO_REG; + + msg[loop_index].data = 0; + msg[loop_index++].addr = DA9052_ALARMY_REG; + + da9052_lock(da9052); + ret = da9052->read_many(da9052, msg, loop_index); + if (ret != 0) { + da9052_unlock(da9052); + return ret; + } + da9052_unlock(da9052); + + rtc_tm->tm_year = msg[--loop_index].data & DA9052_ALARMY_ALARMYEAR; + rtc_tm->tm_mon = msg[--loop_index].data & DA9052_ALARMMO_ALARMMONTH; + rtc_tm->tm_mday = msg[--loop_index].data & DA9052_ALARMD_ALARMDAY; + rtc_tm->tm_hour = msg[--loop_index].data & DA9052_ALARMH_ALARMHOUR; + rtc_tm->tm_min = msg[--loop_index].data & DA9052_ALARMMI_ALARMMIN; + + validate_param = da9052_rtc_validate_parameters(rtc_tm); + if (validate_param) + return validate_param; + + /* System compatability */ + rtc_tm->tm_year += 100; + rtc_tm->tm_mon -= 1; + + return 0; +} + +static int da9052_alarm_settime(struct da9052 *da9052, struct rtc_time *rtc_tm) +{ + + struct da9052_ssc_msg msg_arr[5]; + struct da9052_ssc_msg msg; + int validate_param = 0; + unsigned char loop_index = 0; + int ret = 0; + + rtc_tm->tm_sec = 0; + + /* System compatability */ + rtc_tm->tm_year -= 100; + rtc_tm->tm_mon += 1; + + validate_param = da9052_rtc_validate_parameters(rtc_tm); + if (validate_param) + return validate_param; + + msg.addr = DA9052_ALARMMI_REG; + msg.data = 0; + + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret != 0) { + da9052_unlock(da9052); + return ret; + } + + msg.data = msg.data & ~(DA9052_ALARMMI_ALARMMIN); + msg.data |= rtc_tm->tm_min; + + msg_arr[loop_index].addr = DA9052_ALARMMI_REG; + msg_arr[loop_index].data = 0; + msg_arr[loop_index++].data = msg.data; + + msg_arr[loop_index].addr = DA9052_ALARMH_REG; + msg_arr[loop_index].data = 0; + msg_arr[loop_index++].data = rtc_tm->tm_hour; + + msg_arr[loop_index].addr = DA9052_ALARMD_REG; + msg_arr[loop_index].data = 0; + msg_arr[loop_index++].data = rtc_tm->tm_mday; + + msg_arr[loop_index].addr = DA9052_ALARMMO_REG; + msg_arr[loop_index].data = 0; + msg_arr[loop_index++].data = rtc_tm->tm_mon; + + msg.addr = DA9052_ALARMY_REG; + msg.data = 0; + ret = da9052->read(da9052, &msg); + if (ret != 0) { + da9052_unlock(da9052); + return ret; + } + + msg.data = msg.data & ~(DA9052_ALARMY_ALARMYEAR); + + + msg.data |= rtc_tm->tm_year; + msg_arr[loop_index].addr = DA9052_ALARMY_REG; + msg_arr[loop_index].data = 0; + msg_arr[loop_index++].data = msg.data; + + ret = da9052->write_many(da9052, msg_arr, loop_index); + if (ret) { + da9052_unlock(da9052); + return ret; + } + + da9052_unlock(da9052); + return 0; +} + +static int da9052_rtc_get_alarm_status(struct da9052 *da9052) +{ + struct da9052_ssc_msg msg; + int ret = 0; + + msg.addr = DA9052_ALARMY_REG; + msg.data = 0; + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret != 0) { + da9052_unlock(da9052); + return ret; + } + + da9052_unlock(da9052); + msg.data &= DA9052_ALARMY_ALARMON; + + return (msg.data > 0) ? 1 : 0; +} + + +static int da9052_rtc_enable_alarm(struct da9052 *da9052, unsigned char flag) +{ + struct da9052_ssc_msg msg; + int ret = 0; + + msg.addr = DA9052_ALARMY_REG; + da9052_lock(da9052); + ret = da9052->read(da9052, &msg); + if (ret != 0) { + da9052_unlock(da9052); + return ret; + } + + if (flag) + msg.data = msg.data | DA9052_ALARMY_ALARMON; + else + msg.data = msg.data & ~(DA9052_ALARMY_ALARMON); + + ret = da9052->write(da9052, &msg); + if (ret != 0) { + da9052_unlock(da9052); + return ret; + } + da9052_unlock(da9052); + + return 0; +} + + +static ssize_t da9052_rtc_mask_irq(struct da9052 *da9052) +{ + unsigned char data = 0; + ssize_t ret = 0; + struct da9052_ssc_msg ssc_msg; + + ssc_msg.addr = DA9052_IRQMASKA_REG; + ssc_msg.data = 0; + + da9052_lock(da9052); + ret = da9052->read(da9052, &ssc_msg); + if (ret != 0) { + da9052_unlock(da9052); + return ret; + } + + data = ret; + ssc_msg.data = data |= DA9052_IRQMASKA_MALRAM; + + ret = da9052->write(da9052, &ssc_msg); + if (ret != 0) { + da9052_unlock(da9052); + return ret; + } + + da9052_unlock(da9052); + return 0; +} + + +static ssize_t da9052_rtc_unmask_irq(struct da9052 *da9052) +{ + unsigned char data = 0; + ssize_t ret = 0; + struct da9052_ssc_msg ssc_msg; + + ssc_msg.addr = DA9052_IRQMASKA_REG; + ssc_msg.data = 0; + + da9052_lock(da9052); + ret = da9052->read(da9052, &ssc_msg); + if (ret != 0) { + da9052_unlock(da9052); + return ret; + } + + data = ret; + ssc_msg.data = data &= ~DA9052_IRQMASKA_MALRAM; + + ret = da9052->write(da9052, &ssc_msg); + if (ret != 0) { + da9052_unlock(da9052); + return ret; + } + + da9052_unlock(da9052); + return 0; + +} + +static int da9052_rtc_class_ops_gettime + (struct device *dev, struct rtc_time *rtc_tm) +{ + int ret; + struct da9052 *da9052 = dev_get_drvdata(dev->parent); + ret = da9052_rtc_gettime(da9052, rtc_tm); + if (ret) + return ret; + return 0; +} + + +static int da9052_rtc_class_ops_settime(struct device *dev, struct rtc_time *tm) +{ + int ret; + struct da9052 *da9052 = dev_get_drvdata(dev->parent); + ret = da9052_rtc_settime(da9052, tm); + + return ret; +} + +static int da9052_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + int ret; + struct rtc_time *tm = &alrm->time; + struct da9052 *da9052 = dev_get_drvdata(dev->parent); + ret = da9052_alarm_gettime(da9052, tm); + + if (ret) + return ret; + + alrm->enabled = da9052_rtc_get_alarm_status(da9052); + + return 0; + +} + +static int da9052_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + int ret = 0; + struct rtc_time *tm = &alrm->time; + struct da9052 *da9052 = dev_get_drvdata(dev->parent); + + ret = da9052_alarm_settime(da9052, tm); + + if (ret) + return ret; + + ret = da9052_rtc_enable_alarm(da9052, 1); + + return ret; +} + +static int da9052_rtc_update_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct da9052_rtc *priv = dev_get_drvdata(dev); + int ret = -ENODATA; + + da9052_lock(priv->da9052); + + ret = (enabled ? da9052_rtc_unmask_irq : da9052_rtc_mask_irq) + (priv->da9052); + + da9052_unlock(priv->da9052); + + return ret; +} + +static int da9052_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct da9052_rtc *priv = dev_get_drvdata(dev); + + if (enabled) + return da9052_rtc_enable_alarm(priv->da9052, enabled); + else + return da9052_rtc_enable_alarm(priv->da9052, enabled); +} + +static const struct rtc_class_ops da9052_rtc_ops = { + .read_time = da9052_rtc_class_ops_gettime, + .set_time = da9052_rtc_class_ops_settime, + .read_alarm = da9052_rtc_readalarm, + .set_alarm = da9052_rtc_setalarm, +#if 0 + .update_irq_enable = da9052_rtc_update_irq_enable, + .alarm_irq_enable = da9052_rtc_alarm_irq_enable, +#endif +}; + + +static int __devinit da9052_rtc_probe(struct platform_device *pdev) +{ + int ret; + struct da9052_rtc *priv; + struct da9052_ssc_msg ssc_msg; + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->da9052 = dev_get_drvdata(pdev->dev.parent); + platform_set_drvdata(pdev, priv); + + /* Added to support sysfs wakealarm attribute */ + pdev->dev.power.can_wakeup = 1; + /* Added to support sysfs wakealarm attribute */ + + /* Set the EH structure */ + priv->eh_data.eve_type = ALARM_EVE; + priv->eh_data.call_back = &da9052_rtc_notifier; + ret = priv->da9052->register_event_notifier(priv->da9052, + &priv->eh_data); + if (ret) + goto err_register_alarm; + + priv->is_min_alarm = 1; + priv->enable_tick_alarm = 1; + priv->enable_clk_buffer = 1; + priv->set_osc_trim_freq = 5; + /* Enable/Disable TICK Alarm */ + /* Read ALARM YEAR register */ + ssc_msg.addr = DA9052_ALARMY_REG; + ssc_msg.data = 0; + + da9052_lock(priv->da9052); + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret != 0) { + da9052_unlock(priv->da9052); + goto err_ssc_comm; + } + + if (priv->enable_tick_alarm) + ssc_msg.data = (ssc_msg.data | DA9052_ALARMY_TICKON); + else + ssc_msg.data = + ((ssc_msg.data & ~(DA9052_ALARMY_TICKON))); + + ret = priv->da9052->write(priv->da9052, &ssc_msg); + if (ret != 0) { + da9052_unlock(priv->da9052); + goto err_ssc_comm; + } + + /* Set TICK Alarm to 1 minute or 1 sec */ + /* Read ALARM MINUTES register */ + ssc_msg.addr = DA9052_ALARMMI_REG; + ssc_msg.data = 0; + + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret != 0) { + da9052_unlock(priv->da9052); + goto err_ssc_comm; + } + + if (priv->is_min_alarm) + /* Set 1 minute tick type */ + ssc_msg.data = (ssc_msg.data | DA9052_ALARMMI_TICKTYPE); + else + /* Set 1 sec tick type */ + ssc_msg.data = (ssc_msg.data & ~(DA9052_ALARMMI_TICKTYPE)); + + ret = priv->da9052->write(priv->da9052, &ssc_msg); + if (ret != 0) { + da9052_unlock(priv->da9052); + goto err_ssc_comm; + } + + /* Enable/Disable Clock buffer in Power Down Mode */ + ssc_msg.addr = DA9052_PDDIS_REG; + ssc_msg.data = 0; + + ret = priv->da9052->read(priv->da9052, &ssc_msg); + if (ret != 0) { + da9052_unlock(priv->da9052); + goto err_ssc_comm; + } + + if (priv->enable_clk_buffer) + ssc_msg.data = (ssc_msg.data | DA9052_PDDIS_OUT32KPD); + else + ssc_msg.data = (ssc_msg.data & ~(DA9052_PDDIS_OUT32KPD)); + + ret = priv->da9052->write(priv->da9052, &ssc_msg); + if (ret != 0) { + da9052_unlock(priv->da9052); + goto err_ssc_comm; + } + + /* Set clock trim frequency value */ + ssc_msg.addr = DA9052_OSCTRIM_REG; + ssc_msg.data = priv->set_osc_trim_freq; + + ret = priv->da9052->write(priv->da9052, &ssc_msg); + if (ret != 0) { + da9052_unlock(priv->da9052); + goto err_ssc_comm; + } + da9052_unlock(priv->da9052); + + priv->rtc = rtc_device_register(pdev->name, + &pdev->dev, &da9052_rtc_ops, THIS_MODULE); + if (IS_ERR(priv->rtc)) { + ret = PTR_ERR(priv->rtc); + goto err_ssc_comm; + } + return 0; + +err_ssc_comm: + priv->da9052->unregister_event_notifier + (priv->da9052, &priv->eh_data); +err_register_alarm: + platform_set_drvdata(pdev, NULL); + kfree(priv); + + return ret; +} + +static int __devexit da9052_rtc_remove(struct platform_device *pdev) +{ + struct da9052_rtc *priv = platform_get_drvdata(pdev); + rtc_device_unregister(priv->rtc); + da9052_lock(priv->da9052); + priv->da9052->unregister_event_notifier(priv->da9052, &priv->eh_data); + da9052_unlock(priv->da9052); + platform_set_drvdata(pdev, NULL); + kfree(priv); + return 0; +} + +static struct platform_driver da9052_rtc_driver = { + .probe = da9052_rtc_probe, + .remove = __devexit_p(da9052_rtc_remove), + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + + +static int __init da9052_rtc_init(void) +{ + return platform_driver_register(&da9052_rtc_driver); +} +module_init(da9052_rtc_init); + +static void __exit da9052_rtc_exit(void) +{ + platform_driver_unregister(&da9052_rtc_driver); +} +module_exit(da9052_rtc_exit); + +MODULE_AUTHOR("Dialog Semiconductor Ltd dchen@diasemi.com"); +MODULE_DESCRIPTION("RTC driver for Dialog DA9052 PMIC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME);
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9052 video backlight driver from Dialog. Modify Kconfig/Makefile for DA9052 video backlight driver.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org --- drivers/video/backlight/Kconfig | 6 + drivers/video/backlight/Makefile | 2 +- drivers/video/backlight/da9052_bl.c | 461 +++++++++++++++++++++++++++++++++++ 3 files changed, 468 insertions(+), 1 deletions(-) create mode 100644 drivers/video/backlight/da9052_bl.c
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 0c9373b..a233749 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -315,6 +315,12 @@ config BACKLIGHT_PCF50633 If you have a backlight driven by a NXP PCF50633 MFD, say Y here to enable its driver.
+config BACKLIGHT_DA9052 + tristate "Dialog DA9052 WLED" + depends on PMIC_DIALOG + help + Enable the DA9052 Backlight Driver + endif # BACKLIGHT_CLASS_DEVICE
endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index b9ca849..0c8334f 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -36,4 +36,4 @@ obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o - +obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c new file mode 100644 index 0000000..0692194 --- /dev/null +++ b/drivers/video/backlight/da9052_bl.c @@ -0,0 +1,461 @@ +/* + * Copyright(c) 2009 Dialog Semiconductor Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * da9052_bl.c: Backlight driver for DA9052 + */ + +#include <linux/platform_device.h> +#include <linux/fb.h> +#include <linux/backlight.h> + +#include <linux/delay.h> + +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/reg.h> +#include <linux/mfd/da9052/bl.h> + + +#define DRIVER_NAME "da9052-backlight" +#define DRIVER_NAME1 "WLED-1" +#define DRIVER_NAME2 "WLED-2" +#define DRIVER_NAME3 "WLED-3" + +/* These flags define if Backlight LEDs are present */ +/* Set the following macros to 1, if LEDs are present. Otherwise set to 0 */ +#define DA9052_LED1_PRESENT 1 +#define DA9052_LED2_PRESENT 1 +#define DA9052_LED3_PRESENT 1 + +#define DA9052_MAX_BRIGHTNESS 0xFF + +struct da9052_backlight_data { + struct device *da9052_dev; + int current_brightness; + struct da9052 *da9052; + + int is_led1_present; + int is_led2_present; + int is_led3_present; +}; + +enum da9052_led_number { + LED1 = 1, + LED2, + LED3, +}; + +static int da9052_backlight_brightness_set(struct da9052_backlight_data *data, + int brightness, enum da9052_led_number led) +{ + /* + * Mechanism for brightness control: + * For brightness control, current is used. + * PWM feature is not used. + * To use PWM feature, a fixed value of current should be defined. + */ + + int ret = 0; + unsigned int led_ramp_bit; + unsigned int led_current_register; + unsigned int led_current_sink_bit; + unsigned int led_boost_en_bit; + struct da9052_ssc_msg msg; + + switch (led) { + case LED1: + led_ramp_bit = DA9052_LEDCONT_LED1RAMP; + led_current_register = DA9052_LED1CONF_REG; + led_current_sink_bit = DA9052_LEDCONT_LED1EN; + led_boost_en_bit = DA9052_BOOST_LED1INEN; + break; + case LED2: + led_ramp_bit = DA9052_LEDCONT_LED2RAMP; + led_current_register = DA9052_LED2CONF_REG; + led_current_sink_bit = DA9052_LEDCONT_LED2EN; + led_boost_en_bit = DA9052_BOOST_LED2INEN; + break; + case LED3: + led_ramp_bit = DA9052_LEDCONT_LED3RAMP; + led_current_register = DA9052_LED3CONF_REG; + led_current_sink_bit = DA9052_LEDCONT_LED3EN; + led_boost_en_bit = DA9052_BOOST_LED3INEN; + break; + default: + return -EIO; + } + + /* + 1. Configure the boost register + 2. Configure the LED _CONT register + 3. Configure the LEDx_CONF registers to the brightness value. + */ + msg.addr = DA9052_BOOST_REG; + msg.data = 0x3F; + if (brightness) { + da9052_lock(data->da9052); + ret = data->da9052->write(data->da9052, &msg); + if (ret) { + da9052_unlock(data->da9052); + return ret; + } + da9052_unlock(data->da9052); + } + + msg.addr = DA9052_LEDCONT_REG; + msg.data = 0xFF; + if (brightness) { + da9052_lock(data->da9052); + ret = data->da9052->write(data->da9052, &msg); + if (ret) { + da9052_unlock(data->da9052); + return ret; + } + da9052_unlock(data->da9052); + } + + msg.addr = led_current_register; + msg.data = 0; + /* Write to the DA9052 register */ + da9052_lock(data->da9052); + ret = data->da9052->write(data->da9052, &msg); + if (ret) { + da9052_unlock(data->da9052); + return ret; + } + da9052_unlock(data->da9052); + msleep(20); + msg.data = brightness; + /* Write to the DA9052 register */ + da9052_lock(data->da9052); + ret = data->da9052->write(data->da9052, &msg); + if (ret) { + da9052_unlock(data->da9052); + return ret; + } + da9052_unlock(data->da9052); + + return 0; +} + +static int da9052_backlight_set(struct backlight_device *bl, int brightness) +{ + struct da9052_backlight_data *data = bl_get_data(bl); + int ret = 0; + /* Check for LED1 */ + if (1 == data->is_led1_present) { + ret = da9052_backlight_brightness_set(data, brightness, LED1); + if (ret) + return ret; + } + /* Check for LED2 */ + if (1 == data->is_led2_present) { + ret = da9052_backlight_brightness_set(data, brightness, LED2); + if (ret) + return ret; + } + /* Check for LED3 */ + if (1 == data->is_led3_present) { + ret = da9052_backlight_brightness_set(data, brightness, LED3); + if (ret) + return ret; + } + + data->current_brightness = brightness; + return 0; +} + +static int da9052_init_WLED(struct da9052_backlight_data *data, + enum da9052_led_number led) +{ + int ret = 0; + unsigned int led_current_register; + struct da9052_ssc_msg msg; + + switch (led) { + case LED1: + led_current_register = DA9052_LED1CONF_REG; + break; + case LED2: + led_current_register = DA9052_LED2CONF_REG; + break; + case LED3: + led_current_register = DA9052_LED3CONF_REG; + break; + default: + return -EIO; + } + + msg.addr = DA9052_BOOST_REG; + msg.data = 0x00; + da9052_lock(data->da9052); + ret = data->da9052->write(data->da9052, &msg); + if (ret) { + da9052_unlock(data->da9052); + return ret; + } + da9052_unlock(data->da9052); + + msg.addr = DA9052_LEDCONT_REG; + msg.data = 0x00; + da9052_lock(data->da9052); + ret = data->da9052->write(data->da9052, &msg); + if (ret) { + da9052_unlock(data->da9052); + return ret; + } + da9052_unlock(data->da9052); + + msg.addr = led_current_register; + msg.data = 0; + da9052_lock(data->da9052); + ret = data->da9052->write(data->da9052, &msg); + da9052_unlock(data->da9052); + return ret; +} + +static int da9052_backlight_update_status(struct backlight_device *bl) +{ + int brightness = bl->props.brightness; + + if (bl->props.power != FB_BLANK_UNBLANK) + brightness = 0; + + if (bl->props.fb_blank != FB_BLANK_UNBLANK) + brightness = 0; + return da9052_backlight_set(bl, brightness); +} + +static int da9052_backlight_get_brightness(struct backlight_device *bl) +{ + struct da9052_backlight_data *data = bl_get_data(bl); + return data->current_brightness; +} + +const struct backlight_ops da9052_backlight_ops = { + .update_status = da9052_backlight_update_status, + .get_brightness = da9052_backlight_get_brightness, +}; + +static int da9052_backlight_probe1(struct platform_device *pdev) +{ + struct da9052_backlight_data *data; + struct backlight_device *bl; + struct backlight_properties props; + int ret = 0; + struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent); + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + data->da9052_dev = pdev->dev.parent; + data->da9052 = da9052; + data->current_brightness = 0; + data->is_led1_present = DA9052_LED1_PRESENT; + + /* Init the WLED-1 bank */ + ret = da9052_init_WLED(data, LED1); + if (ret) + return ret; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = DA9052_MAX_BRIGHTNESS; + bl = backlight_device_register(pdev->name, data->da9052_dev, + data, &da9052_backlight_ops, &props); + if (IS_ERR(bl)) { + dev_err(&pdev->dev, "failed to register backlight\n"); + kfree(data); + return PTR_ERR(bl); + } + + bl->props.brightness = 0; + + platform_set_drvdata(pdev, bl); + backlight_update_status(bl); + + return 0; +} +static int da9052_backlight_probe2(struct platform_device *pdev) +{ + struct da9052_backlight_data *data; + struct backlight_device *bl; + struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent); + struct backlight_properties props; + int ret = 0; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + data->da9052_dev = pdev->dev.parent; + data->da9052 = da9052; + data->current_brightness = 0; + data->is_led2_present = DA9052_LED2_PRESENT; + + /* Init the WLED-2 bank */ + ret = da9052_init_WLED(data, LED2); + if (ret) + return ret; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = DA9052_MAX_BRIGHTNESS; + bl = backlight_device_register(pdev->name, data->da9052_dev, + data, &da9052_backlight_ops, &props); + if (IS_ERR(bl)) { + dev_err(&pdev->dev, "failed to register backlight\n"); + kfree(data); + return PTR_ERR(bl); + } + + bl->props.brightness = 0; + + platform_set_drvdata(pdev, bl); + backlight_update_status(bl); + + return 0; +} +static int da9052_backlight_probe3(struct platform_device *pdev) +{ + struct da9052_backlight_data *data; + struct backlight_device *bl; + struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent); + struct backlight_properties props; + int ret = 0; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + data->da9052_dev = pdev->dev.parent; + data->da9052 = da9052; + data->current_brightness = 0; + data->is_led3_present = DA9052_LED3_PRESENT; + + /* Init the WLED-2 bank */ + ret = da9052_init_WLED(data, LED3); + if (ret) + return ret; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = DA9052_MAX_BRIGHTNESS; + bl = backlight_device_register(pdev->name, data->da9052_dev, + data, &da9052_backlight_ops, &props); + if (IS_ERR(bl)) { + dev_err(&pdev->dev, "failed to register backlight\n"); + kfree(data); + return PTR_ERR(bl); + } + + bl->props.brightness = 0; + + platform_set_drvdata(pdev, bl); + + backlight_update_status(bl); + return 0; +} + +static int da9052_backlight_remove1(struct platform_device *pdev) +{ + struct backlight_device *bl = platform_get_drvdata(pdev); + struct da9052_backlight_data *data = bl_get_data(bl); + int ret = 0; + + /* Switch off the WLED-1 */ + ret = da9052_init_WLED(data, LED1); + if (ret) + return ret; + + backlight_device_unregister(bl); + kfree(data); + return 0; +} + +static int da9052_backlight_remove2(struct platform_device *pdev) +{ + struct backlight_device *bl = platform_get_drvdata(pdev); + struct da9052_backlight_data *data = bl_get_data(bl); + int ret = 0; + + /* Switch off the WLED-2 */ + ret = da9052_init_WLED(data, LED2); + if (ret) + return ret; + + backlight_device_unregister(bl); + kfree(data); + return 0; +} +static int da9052_backlight_remove3(struct platform_device *pdev) +{ + struct backlight_device *bl = platform_get_drvdata(pdev); + struct da9052_backlight_data *data = bl_get_data(bl); + int ret; + + /* Switch off the WLED-3 */ + ret = da9052_init_WLED(data, LED3); + if (ret) + return ret; + + backlight_device_unregister(bl); + kfree(data); + return 0; +} + +static struct platform_driver da9052_backlight_driver1 = { + .driver = { + .name = DRIVER_NAME1, + .owner = THIS_MODULE, + }, + .probe = da9052_backlight_probe1, + .remove = da9052_backlight_remove1, +}; +static struct platform_driver da9052_backlight_driver2 = { + .driver = { + .name = DRIVER_NAME2, + .owner = THIS_MODULE, + }, + .probe = da9052_backlight_probe2, + .remove = da9052_backlight_remove2, +}; +static struct platform_driver da9052_backlight_driver3 = { + .driver = { + .name = DRIVER_NAME3, + .owner = THIS_MODULE, + }, + .probe = da9052_backlight_probe3, + .remove = da9052_backlight_remove3, +}; + +static int __init da9052_backlight_init(void) +{ + s32 ret; + ret = platform_driver_register(&da9052_backlight_driver1); + if (ret) + return ret; + ret = platform_driver_register(&da9052_backlight_driver2); + if (ret) + return ret; + + ret = platform_driver_register(&da9052_backlight_driver3); + if (ret) + return ret; + + return ret; +} +module_init(da9052_backlight_init); + +static void __exit da9052_backlight_exit(void) +{ + platform_driver_unregister(&da9052_backlight_driver1); + platform_driver_unregister(&da9052_backlight_driver2); + platform_driver_unregister(&da9052_backlight_driver3); +} +module_exit(da9052_backlight_exit); + +MODULE_AUTHOR("Dialog Semiconductor Ltd dchen@diasemi.com"); +MODULE_DESCRIPTION("Backlight driver for Dialog DA9052 PMIC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); +
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Add DA9052 watchdog driver from Dialog. Modify Kconfig/Makefile for DA9052 watchdog driver.
Signed-off-by: Zhou Jingyu Jingyu.Zhou@freescale.com Acked-by: Lily Zhang r58066@freescale.com Signed-off-by: Ying-Chun Liu (PaulLiu) paul.liu@linaro.org --- drivers/watchdog/Kconfig | 5 + drivers/watchdog/Makefile | 1 + drivers/watchdog/da9052_wdt.c | 542 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 548 insertions(+), 0 deletions(-) create mode 100644 drivers/watchdog/da9052_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 022f9eb..f2a8025 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1232,6 +1232,11 @@ config WDTPCI To compile this driver as a module, choose M here: the module will be called wdt_pci.
+config DA9052_WATCHDOG + tristate "Dialog DA9052 Watchdog" + depends on PMIC_DIALOG + help + Support for the watchdog in the DA9052 PMIC. # # USB-based Watchdog Cards # diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index ed26f70..fae2cfc 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -159,3 +159,4 @@ obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o +obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c new file mode 100644 index 0000000..7d0ecd9 --- /dev/null +++ b/drivers/watchdog/da9052_wdt.c @@ -0,0 +1,542 @@ +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/fs.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/uaccess.h> +#include <linux/jiffies.h> +#include <linux/platform_device.h> +#include <linux/time.h> +#include <linux/watchdog.h> +#include <linux/types.h> +#include <linux/kernel.h> + + +#include <linux/mfd/da9052/reg.h> +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/wdt.h> + +#define DRIVER_NAME "da9052-wdt" + +#define DA9052_STROBING_FILTER_ENABLE 0x0001 +#define DA9052_STROBING_FILTER_DISABLE 0x0002 +#define DA9052_SET_STROBING_MODE_MANUAL 0x0004 +#define DA9052_SET_STROBING_MODE_AUTO 0x0008 + +#define KERNEL_MODULE 0 +#define ENABLE 1 +#define DISABLE 0 + +static u8 sm_strobe_filter_flag = DISABLE; +static u8 sm_strobe_mode_flag = DA9052_STROBE_MANUAL; +static u32 sm_mon_interval = DA9052_ADC_TWDMIN_TIME; +static u8 sm_str_req = DISABLE; +static u8 da9052_sm_scale = DA9052_WDT_DISABLE; +module_param(sm_strobe_filter_flag, byte, 0); +MODULE_PARM_DESC(sm_strobe_filter_flag, + "DA9052 SM driver strobe filter flag default = DISABLE"); + +module_param(sm_strobe_mode_flag, byte, 0); +MODULE_PARM_DESC(sm_strobe_mode_flag, + "DA9052 SM driver watchdog strobing mode default"\ + "= DA9052_STROBE_MANUAL"); + +module_param(da9052_sm_scale, byte, 0); +MODULE_PARM_DESC(da9052_sm_scale, + "DA9052 SM driver scaling value used to calculate the"\ + "time for the strobing filter default = 0"); + +module_param(sm_str_req, byte, 0); +MODULE_PARM_DESC(sm_str_req, + "DA9052 SM driver strobe request flag default = DISABLE"); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, + "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +static struct timer_list *monitoring_timer; + +struct da9052_wdt { + struct platform_device *pdev; + struct da9052 *da9052; +}; +static struct miscdevice da9052_wdt_miscdev; +static unsigned long da9052_wdt_users; +static int da9052_wdt_expect_close; + +static struct da9052_wdt *get_wdt_da9052(void) +{ + /*return dev_get_drvdata(da9052_wdt_miscdev.parent);*/ + return platform_get_drvdata + (to_platform_device(da9052_wdt_miscdev.parent)); +} + +void start_strobing(struct work_struct *work) +{ + struct da9052_ssc_msg msg; + int ret; + struct da9052_wdt *wdt = get_wdt_da9052(); + + + if (NULL == wdt) { + mod_timer(monitoring_timer, jiffies + sm_mon_interval); + return; + } + msg.addr = DA9052_CONTROLD_REG; + msg.data = 0; + da9052_lock(wdt->da9052); + ret = wdt->da9052->read(wdt->da9052, &msg); + if (ret) { + da9052_unlock(wdt->da9052); + return; + } + da9052_unlock(wdt->da9052); + + msg.data = (msg.data | DA9052_CONTROLD_WATCHDOG); + da9052_lock(wdt->da9052); + ret = wdt->da9052->write(wdt->da9052, &msg); + if (ret) { + da9052_unlock(wdt->da9052); + return; + } + da9052_unlock(wdt->da9052); + + sm_str_req = DISABLE; + + mod_timer(monitoring_timer, jiffies + sm_mon_interval); + return; +} + + +void timer_callback(void) +{ + if (((sm_strobe_mode_flag) && + (sm_strobe_mode_flag == DA9052_STROBE_MANUAL)) || + (sm_strobe_mode_flag == DA9052_STROBE_AUTO)) { + schedule_work(&strobing_action); + } else { + if (sm_strobe_mode_flag == DA9052_STROBE_MANUAL) { + mod_timer(monitoring_timer, jiffies + + sm_mon_interval); + } + } +} + +static int da9052_sm_hw_init(struct da9052_wdt *wdt) +{ + /* Create timer structure */ + monitoring_timer = kzalloc(sizeof(struct timer_list), GFP_KERNEL); + if (!monitoring_timer) + return -ENOMEM; + + init_timer(monitoring_timer); + monitoring_timer->expires = jiffies + sm_mon_interval; + monitoring_timer->function = (void *)&timer_callback; + + sm_strobe_filter_flag = DA9052_SM_STROBE_CONF; + sm_strobe_mode_flag = DA9052_STROBE_MANUAL; + + return 0; +} + +static int da9052_sm_hw_deinit(struct da9052_wdt *wdt) +{ + struct da9052_ssc_msg msg; + int ret; + + if (monitoring_timer != NULL) + del_timer(monitoring_timer); + kfree(monitoring_timer); + + msg.addr = DA9052_CONTROLD_REG; + msg.data = 0; + + da9052_lock(wdt->da9052); + ret = wdt->da9052->read(wdt->da9052, &msg); + if (ret) + goto ssc_err; + da9052_unlock(wdt->da9052); + + msg.data = (msg.data & ~(DA9052_CONTROLD_TWDSCALE)); + da9052_lock(wdt->da9052); + ret = wdt->da9052->write(wdt->da9052, &msg); + if (ret) + goto ssc_err; + da9052_unlock(wdt->da9052); + + return 0; +ssc_err: + da9052_unlock(wdt->da9052); + return -EIO; +} + +s32 da9052_sm_set_strobing_filter(struct da9052_wdt *wdt, + u8 strobing_filter_state) +{ + struct da9052_ssc_msg msg; + int ret = 0; + + msg.addr = DA9052_CONTROLD_REG; + msg.data = 0; + da9052_lock(wdt->da9052); + ret = wdt->da9052->read(wdt->da9052, &msg); + if (ret) + goto ssc_err; + da9052_unlock(wdt->da9052); + + msg.data = (msg.data & DA9052_CONTROLD_TWDSCALE); + + if (strobing_filter_state == ENABLE) { + sm_strobe_filter_flag = ENABLE; + if (DA9052_WDT_DISABLE == msg.data) { + sm_str_req = DISABLE; + del_timer(monitoring_timer); + return 0; + } + if (DA9052_SCALE_64X == msg.data) + sm_mon_interval = msecs_to_jiffies(DA9052_X64_WINDOW); + else if (DA9052_SCALE_32X == msg.data) + sm_mon_interval = msecs_to_jiffies(DA9052_X32_WINDOW); + else if (DA9052_SCALE_16X == msg.data) + sm_mon_interval = msecs_to_jiffies(DA9052_X16_WINDOW); + else if (DA9052_SCALE_8X == msg.data) + sm_mon_interval = msecs_to_jiffies(DA9052_X8_WINDOW); + else if (DA9052_SCALE_4X == msg.data) + sm_mon_interval = msecs_to_jiffies(DA9052_X4_WINDOW); + else if (DA9052_SCALE_2X == msg.data) + sm_mon_interval = msecs_to_jiffies(DA9052_X2_WINDOW); + else + sm_mon_interval = msecs_to_jiffies(DA9052_X1_WINDOW); + + } else if (strobing_filter_state == DISABLE) { + sm_strobe_filter_flag = DISABLE; + sm_mon_interval = msecs_to_jiffies(DA9052_ADC_TWDMIN_TIME); + if (DA9052_WDT_DISABLE == msg.data) { + sm_str_req = DISABLE; + del_timer(monitoring_timer); + return 0; + } + } else { + return STROBING_FILTER_ERROR; + } + mod_timer(monitoring_timer, jiffies + sm_mon_interval); + + return 0; +ssc_err: + da9052_unlock(wdt->da9052); + return -EIO; +} + +int da9052_sm_set_strobing_mode(u8 strobing_mode_state) +{ + if (strobing_mode_state == DA9052_STROBE_AUTO) + sm_strobe_mode_flag = DA9052_STROBE_AUTO; + else if (strobing_mode_state == DA9052_STROBE_MANUAL) + sm_strobe_mode_flag = DA9052_STROBE_MANUAL; + else + return STROBING_MODE_ERROR; + + return 0; +} + +int da9052_sm_strobe_wdt(void) +{ + sm_str_req = ENABLE; + return 0; +} + +s32 da9052_sm_set_wdt(struct da9052_wdt *wdt, u8 wdt_scaling) +{ + struct da9052_ssc_msg msg; + int ret = 0; + + + if (wdt_scaling > DA9052_SCALE_64X) + return INVALID_SCALING_VALUE; + + msg.addr = DA9052_CONTROLD_REG; + msg.data = 0; + da9052_lock(wdt->da9052); + ret = wdt->da9052->read(wdt->da9052, &msg); + if (ret) + goto ssc_err; + da9052_unlock(wdt->da9052); + + if (!((DA9052_WDT_DISABLE == (msg.data & DA9052_CONTROLD_TWDSCALE)) && + (DA9052_WDT_DISABLE == wdt_scaling))) { + msg.data = (msg.data & ~(DA9052_CONTROLD_TWDSCALE)); + msg.addr = DA9052_CONTROLD_REG; + + + da9052_lock(wdt->da9052); + ret = wdt->da9052->write(wdt->da9052, &msg); + if (ret) + goto ssc_err; + da9052_unlock(wdt->da9052); + + msleep(1); + da9052_lock(wdt->da9052); + ret = wdt->da9052->read(wdt->da9052, &msg); + if (ret) + goto ssc_err; + da9052_unlock(wdt->da9052); + + + msg.data |= wdt_scaling; + + da9052_lock(wdt->da9052); + ret = wdt->da9052->write(wdt->da9052, &msg); + if (ret) + goto ssc_err; + da9052_unlock(wdt->da9052); + + sm_str_req = DISABLE; + if (DA9052_WDT_DISABLE == wdt_scaling) { + del_timer(monitoring_timer); + return 0; + } + if (sm_strobe_filter_flag == ENABLE) { + if (DA9052_SCALE_64X == wdt_scaling) { + sm_mon_interval = + msecs_to_jiffies(DA9052_X64_WINDOW); + } else if (DA9052_SCALE_32X == wdt_scaling) { + sm_mon_interval = + msecs_to_jiffies(DA9052_X32_WINDOW); + } else if (DA9052_SCALE_16X == wdt_scaling) { + sm_mon_interval = + msecs_to_jiffies(DA9052_X16_WINDOW); + } else if (DA9052_SCALE_8X == wdt_scaling) { + sm_mon_interval = + msecs_to_jiffies(DA9052_X8_WINDOW); + } else if (DA9052_SCALE_4X == wdt_scaling) { + sm_mon_interval = + msecs_to_jiffies(DA9052_X4_WINDOW); + } else if (DA9052_SCALE_2X == wdt_scaling) { + sm_mon_interval = + msecs_to_jiffies(DA9052_X2_WINDOW); + } else { + sm_mon_interval = + msecs_to_jiffies(DA9052_X1_WINDOW); + } + } else { + sm_mon_interval = msecs_to_jiffies( + DA9052_ADC_TWDMIN_TIME); + } + mod_timer(monitoring_timer, jiffies + sm_mon_interval); + } + + return 0; +ssc_err: + da9052_unlock(wdt->da9052); + return -EIO; +} + +static int da9052_wdt_open(struct inode *inode, struct file *file) +{ + struct da9052_wdt *wdt = get_wdt_da9052(); + int ret; + printk(KERN_INFO"IN WDT OPEN\n"); + + if (!wdt) { + printk(KERN_INFO"Returning no device\n"); + return -ENODEV; + } + printk(KERN_INFO"IN WDT OPEN 1\n"); + + if (test_and_set_bit(0, &da9052_wdt_users)) + return -EBUSY; + + ret = da9052_sm_hw_init(wdt); + if (ret != 0) { + printk(KERN_ERR "Watchdog hw init failed\n"); + return ret; + } + + return nonseekable_open(inode, file); +} + +static int da9052_wdt_release(struct inode *inode, struct file *file) +{ + struct da9052_wdt *wdt = get_wdt_da9052(); + + if (da9052_wdt_expect_close == 42) + da9052_sm_hw_deinit(wdt); + else + da9052_sm_strobe_wdt(); + da9052_wdt_expect_close = 0; + clear_bit(0, &da9052_wdt_users); + return 0; +} + +static ssize_t da9052_wdt_write(struct file *file, + const char __user *data, size_t count, + loff_t *ppos) +{ + size_t i; + + if (count) { + if (!nowayout) { + /* In case it was set long ago */ + da9052_wdt_expect_close = 0; + for (i = 0; i != count; i++) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + da9052_wdt_expect_close = 42; + } + } + da9052_sm_strobe_wdt(); + } + return count; +} + +static struct watchdog_info da9052_wdt_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + .identity = "DA9052_SM Watchdog", +}; + +static long da9052_wdt_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct da9052_wdt *wdt = get_wdt_da9052(); + void __user *argp = (void __user *)arg; + int __user *p = argp; + unsigned char new_value; + + switch (cmd) { + + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &da9052_wdt_info, + sizeof(da9052_wdt_info)) ? -EFAULT : 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + case WDIOC_SETOPTIONS: + if (get_user(new_value, p)) + return -EFAULT; + if (new_value & DA9052_STROBING_FILTER_ENABLE) + da9052_sm_set_strobing_filter(wdt, ENABLE); + if (new_value & DA9052_STROBING_FILTER_DISABLE) + da9052_sm_set_strobing_filter(wdt, DISABLE); + if (new_value & DA9052_SET_STROBING_MODE_MANUAL) + da9052_sm_set_strobing_mode(DA9052_STROBE_MANUAL); + if (new_value & DA9052_SET_STROBING_MODE_AUTO) + da9052_sm_set_strobing_mode(DA9052_STROBE_AUTO); + return 0; + case WDIOC_KEEPALIVE: + if (da9052_sm_strobe_wdt()) + return -EFAULT; + else + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(new_value, p)) + return -EFAULT; + da9052_sm_scale = new_value; + if (da9052_sm_set_wdt(wdt, da9052_sm_scale)) + return -EFAULT; + case WDIOC_GETTIMEOUT: + return put_user(sm_mon_interval, p); + default: + return -ENOTTY; + } + return 0; +} + +static const struct file_operations da9052_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .unlocked_ioctl = da9052_wdt_ioctl, + .write = da9052_wdt_write, + .open = da9052_wdt_open, + .release = da9052_wdt_release, +}; + +static struct miscdevice da9052_wdt_miscdev = { + .minor = 255, + .name = "da9052-wdt", + .fops = &da9052_wdt_fops, +}; + +static int __devinit da9052_sm_probe(struct platform_device *pdev) +{ + int ret; + struct da9052_wdt *wdt; + struct da9052_ssc_msg msg; + + wdt = kzalloc(sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + wdt->da9052 = dev_get_drvdata(pdev->dev.parent); + platform_set_drvdata(pdev, wdt); + + msg.addr = DA9052_CONTROLD_REG; + msg.data = 0; + + da9052_lock(wdt->da9052); + ret = wdt->da9052->read(wdt->da9052, &msg); + if (ret) { + da9052_unlock(wdt->da9052); + goto err_ssc_comm; + } + printk(KERN_INFO"DA9052 SM probe - 0\n"); + + msg.data = (msg.data & ~(DA9052_CONTROLD_TWDSCALE)); + ret = wdt->da9052->write(wdt->da9052, &msg); + if (ret) { + da9052_unlock(wdt->da9052); + goto err_ssc_comm; + } + da9052_unlock(wdt->da9052); + + da9052_wdt_miscdev.parent = &pdev->dev; + + ret = misc_register(&da9052_wdt_miscdev); + if (ret != 0) { + platform_set_drvdata(pdev, NULL); + kfree(wdt); + return -EFAULT; + } + return 0; +err_ssc_comm: + platform_set_drvdata(pdev, NULL); + kfree(wdt); + return -EIO; +} + +static int __devexit da9052_sm_remove(struct platform_device *dev) +{ + misc_deregister(&da9052_wdt_miscdev); + + return 0; +} + +static struct platform_driver da9052_sm_driver = { + .probe = da9052_sm_probe, + .remove = __devexit_p(da9052_sm_remove), + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init da9052_sm_init(void) +{ + return platform_driver_register(&da9052_sm_driver); +} +module_init(da9052_sm_init); + +static void __exit da9052_sm_exit(void) +{ + platform_driver_unregister(&da9052_sm_driver); +} +module_exit(da9052_sm_exit); + +MODULE_AUTHOR("David Dajun Chen dchen@diasemi.com") +MODULE_DESCRIPTION("DA9052 SM Device Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRIVER_NAME);
On Fri, Jun 10, 2011 at 11:50:54AM +0800, Ying-Chun Liu (PaulLiu) wrote:
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Hi. I'm trying to push DA9053 PMIC driver to mainline kernel. Please help me to review these patches.
Dialog have been submitting separate copies of this into mainline for quite some time now - you might want to coordinate your work with them, they are really struggling with basic aspects of the process and the technical requirements.
On Friday 10 June 2011, Ying-Chun Liu (PaulLiu) wrote:
From: "Ying-Chun Liu (PaulLiu)" paul.liu@linaro.org
Hi. I'm trying to push DA9053 PMIC driver to mainline kernel. Please help me to review these patches.
I've reviewed part of it now. Once you have addressed the issues I pointed out, please do another round of reviews, then I can look at more files.
If the same issues are present in other files of the series, don't wait for comments but fix them now, too.
Arnd
On Fri, Jun 10, 2011 at 07:38:43PM +0200, Arnd Bergmann wrote:
I've reviewed part of it now. Once you have addressed the issues I pointed out, please do another round of reviews, then I can look at more files.
In case you hadn't seen it I previously pointed out that there's a separate series based on the same original Dialog code that Dialog has been pushing. While it's been a very long process and there's still some issues with that there have been massive improvements over time - that code would be a much better starting point than the original Dialog code.
It would be exceptionally frustrating to have to redo all that review :(
On Friday 10 June 2011, Mark Brown wrote:
On Fri, Jun 10, 2011 at 07:38:43PM +0200, Arnd Bergmann wrote:
I've reviewed part of it now. Once you have addressed the issues I pointed out, please do another round of reviews, then I can look at more files.
In case you hadn't seen it I previously pointed out that there's a separate series based on the same original Dialog code that Dialog has been pushing. While it's been a very long process and there's still some issues with that there have been massive improvements over time - that code would be a much better starting point than the original Dialog code.
It would be exceptionally frustrating to have to redo all that review :(
Ok, thanks for the hint.
What's the subject and mailing list of the other submission? I might have a look at that then.
Arnd
On Fri, Jun 10, 2011 at 08:31:12PM +0200, Arnd Bergmann wrote:
What's the subject and mailing list of the other submission? I might have a look at that then.
There's been some insanely large number of submissions (I think we must be over 20 by now) and one of the issues is that they're not threaded together (the actual mechanics of e-mailing patches is still causing difficulties, I've been getting exceptionally fed up with the whole process) - searching lkml for 9053 ought to turn stuff up, there were some posts today.
On Friday 10 June 2011 20:46:25 Mark Brown wrote:
On Fri, Jun 10, 2011 at 08:31:12PM +0200, Arnd Bergmann wrote:
What's the subject and mailing list of the other submission? I might have a look at that then.
There's been some insanely large number of submissions (I think we must be over 20 by now) and one of the issues is that they're not threaded together (the actual mechanics of e-mailing patches is still causing difficulties, I've been getting exceptionally fed up with the whole process) - searching lkml for 9053 ought to turn stuff up, there were some posts today.
Ah, I found it now after Rob's comment, as he pointed out that the patches on the list are for 9052 and these are called 9053. Obviously, anything that is this similar needs to have a combined driver that works for either version, which may already be the case for the driver posted on lkml. I'll have a look.
Arnd
Hi Andy, Mark, Arnd, Rob,
Thanks for the reviews. As Mark said, there's already same and better patches on LKML. Thus I'm going to try using the patches posted on LKML on my board (imx53) to see if they work or not. And then add some comments.
Here's the list: * LED https://lkml.org/lkml/2011/5/13/168 * MFD https://lkml.org/lkml/2011/5/3/128 * GPIO https://lkml.org/lkml/2011/4/13/107 * Backlight https://lkml.org/lkml/2011/5/4/81 * Regulator http://lkml.org/lkml/2011/5/3/126 * HWMON https://lkml.org/lkml/2011/5/4/118 * Battery https://lkml.org/lkml/2011/4/13/110 * RTC https://lkml.org/lkml/2011/4/6/179 * TSI https://lkml.org/lkml/2011/4/13/112 * Watchdog https://lkml.org/lkml/2011/4/6/159
Regards, Paul
On Saturday 11 June 2011 19:29:20 Ying-Chun Liu (PaulLiu) wrote:
Hi Andy, Mark, Arnd, Rob,
Thanks for the reviews. As Mark said, there's already same and better patches on LKML. Thus I'm going to try using the patches posted on LKML on my board (imx53) to see if they work or not. And then add some comments.
Ok, sounds good. Note the other patches are for da9052, not da9053, so they might not work for you out of the box. However, I think it's important to make the common parts work for both hardware and possibly others, so please work with Dajun Chen to make sure that as much code as possible is shared.
Arnd
Hi Dajun,
I didn't track the patch series you sent out. Did you receive any review and feedback and got them all addressed?
Would you please send the updated version if available? And Cc linaro-dev is more than welcome. We have people eager to get this upstreamed.
Thanks - eric
On Sun, Jun 12, 2011 at 1:29 AM, Ying-Chun Liu (PaulLiu) paul.liu@linaro.org wrote:
Hi Andy, Mark, Arnd, Rob,
Thanks for the reviews. As Mark said, there's already same and better patches on LKML. Thus I'm going to try using the patches posted on LKML on my board (imx53) to see if they work or not. And then add some comments.
Here's the list: * LED https://lkml.org/lkml/2011/5/13/168 * MFD https://lkml.org/lkml/2011/5/3/128 * GPIO https://lkml.org/lkml/2011/4/13/107 * Backlight https://lkml.org/lkml/2011/5/4/81 * Regulator http://lkml.org/lkml/2011/5/3/126 * HWMON https://lkml.org/lkml/2011/5/4/118 * Battery https://lkml.org/lkml/2011/4/13/110 * RTC https://lkml.org/lkml/2011/4/6/179 * TSI https://lkml.org/lkml/2011/4/13/112 * Watchdog https://lkml.org/lkml/2011/4/6/159
Regards, Paul
linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
On 06/09/2011 10:50 PM, Ying-Chun Liu (PaulLiu) wrote:
From: "Ying-Chun Liu (PaulLiu)"paul.liu@linaro.org
Hi. I'm trying to push DA9053 PMIC driver to mainline kernel. Please help me to review these patches. Many Thanks.
Ying-Chun Liu (PaulLiu) (11): PMIC: Add DA9053 headers from Dialog
Is this for the 9053 or...
PMIC: Add GPIO Driver for Dialog DA9052
9052... Probably should be 905x as they are supposed to be similar.
Did the 9052 stuff ever go in?
Rob