diff options
author | Peter Li | 2017-08-03 08:46:36 -0500 |
---|---|---|
committer | Peter Li | 2017-08-03 08:46:36 -0500 |
commit | 2aa9a7bb8ed0794453fa05d7034a595821e5dbcf (patch) | |
tree | 65a796cbbbd4f9f65796be252d082441924b247d | |
parent | c6d2ed49c012233fc05a668d781d52bad89b2d35 (diff) | |
download | drv2605-android-driver-2aa9a7bb8ed0794453fa05d7034a595821e5dbcf.tar.gz drv2605-android-driver-2aa9a7bb8ed0794453fa05d7034a595821e5dbcf.tar.xz drv2605-android-driver-2aa9a7bb8ed0794453fa05d7034a595821e5dbcf.zip |
-rwxr-xr-x | arch_arm_mach-msm_lge_mako_board-mako-haptics.c | 188 | ||||
-rwxr-xr-x | drivers_haptics_drv2605.c | 1002 | ||||
-rwxr-xr-x | drv2605.c | 1306 | ||||
-rwxr-xr-x | drv2605.h | 229 | ||||
-rwxr-xr-x | dts.readme | 12 | ||||
-rwxr-xr-x | include_linux_haptics_drv2605.h | 462 |
6 files changed, 1547 insertions, 1652 deletions
diff --git a/arch_arm_mach-msm_lge_mako_board-mako-haptics.c b/arch_arm_mach-msm_lge_mako_board-mako-haptics.c deleted file mode 100755 index 7f2eefb..0000000 --- a/arch_arm_mach-msm_lge_mako_board-mako-haptics.c +++ /dev/null | |||
@@ -1,188 +0,0 @@ | |||
1 | /* | ||
2 | ** ============================================================================= | ||
3 | ** Copyright (c) 2014 Texas Instruments Inc. | ||
4 | ** | ||
5 | ** This program is free software; you can redistribute it and/or | ||
6 | ** modify it under the terms of the GNU General Public License | ||
7 | ** as published by the Free Software Foundation; either version 2 | ||
8 | ** of the License, or (at your option) any later version. | ||
9 | ** | ||
10 | ** This program is distributed in the hope that it will be useful, | ||
11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | ** GNU General Public License for more details. | ||
14 | ** | ||
15 | ** You should have received a copy of the GNU General Public License | ||
16 | ** along with this program; if not, write to the Free Software | ||
17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
18 | ** | ||
19 | ** File: | ||
20 | ** board-mako-haptics.c | ||
21 | ** | ||
22 | ** Description: | ||
23 | ** platform data for Haptics devices | ||
24 | ** | ||
25 | ** ============================================================================= | ||
26 | */ | ||
27 | |||
28 | #include <linux/i2c.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <mach/board_lge.h> | ||
31 | #include <linux/regulator/consumer.h> | ||
32 | #include "devices.h" | ||
33 | #include "board-mako.h" | ||
34 | #if defined(CONFIG_HAPTICS_DRV2605) | ||
35 | #include <linux/haptics/drv2605.h> | ||
36 | #elif defined(CONFIG_HAPTICS_DRV2604) | ||
37 | #include <linux/haptics/drv2604.h> | ||
38 | #elif defined(CONFIG_HAPTICS_DRV2604L) | ||
39 | #include <linux/haptics/drv2604l.h> | ||
40 | #elif defined(CONFIG_HAPTICS_DRV2667) | ||
41 | #include <linux/haptics/drv2667.h> | ||
42 | #endif | ||
43 | |||
44 | #define APQ8064_GSBI3_QUP_I2C_BUS_ID 3 | ||
45 | |||
46 | #if defined(CONFIG_HAPTICS_DRV2605) | ||
47 | static struct drv2605_platform_data drv2605_plat_data = { | ||
48 | .GpioEnable = 0, //enable the chip | ||
49 | .GpioTrigger = 0, //external trigger pin, (0: internal trigger) | ||
50 | #if defined(CONFIG_HAPTICS_LRA_SEMCO1030) | ||
51 | //rated = 1.5Vrms, ov=2.1Vrms, f=204hz | ||
52 | .loop = CLOSE_LOOP, | ||
53 | .RTPFormat = Signed, | ||
54 | .BIDIRInput = BiDirectional, | ||
55 | .actuator = { | ||
56 | .device_type = LRA, | ||
57 | .rated_vol = 0x3d, | ||
58 | .g_effect_bank = LIBRARY_F, | ||
59 | .over_drive_vol = 0x87, | ||
60 | .LRAFreq = 204, | ||
61 | }, | ||
62 | .a2h = { | ||
63 | .a2h_min_input = AUDIO_HAPTICS_MIN_INPUT_VOLTAGE, | ||
64 | .a2h_max_input = AUDIO_HAPTICS_MAX_INPUT_VOLTAGE, | ||
65 | .a2h_min_output = AUDIO_HAPTICS_MIN_OUTPUT_VOLTAGE, | ||
66 | .a2h_max_output = AUDIO_HAPTICS_MAX_OUTPUT_VOLTAGE, | ||
67 | }, | ||
68 | #elif defined(CONFIG_HAPTICS_ERM_EVOWAVE_Z4TJGB1512658) | ||
69 | //rated vol = 3.0 v, ov = 3.6 v, risetime = 150 ms | ||
70 | .loop = CLOSE_LOOP, | ||
71 | .RTPFormat = Signed, | ||
72 | .BIDIRInput = BiDirectional, | ||
73 | .actuator = { | ||
74 | .device_type = ERM, | ||
75 | .g_effect_bank = LIBRARY_E, | ||
76 | .rated_vol = 0x8d, | ||
77 | .over_drive_vol = 0xa9, | ||
78 | }, | ||
79 | .a2h = { | ||
80 | .a2h_min_input = AUDIO_HAPTICS_MIN_INPUT_VOLTAGE, | ||
81 | .a2h_max_input = AUDIO_HAPTICS_MAX_INPUT_VOLTAGE, | ||
82 | .a2h_min_output = AUDIO_HAPTICS_MIN_OUTPUT_VOLTAGE, | ||
83 | .a2h_max_output = AUDIO_HAPTICS_MAX_OUTPUT_VOLTAGE, | ||
84 | }, | ||
85 | #else | ||
86 | #error "please define actuator type" | ||
87 | #endif | ||
88 | }; | ||
89 | #elif defined(CONFIG_HAPTICS_DRV2604) | ||
90 | static struct drv2604_platform_data drv2604_plat_data = { | ||
91 | .GpioEnable = 0, //enable the chip | ||
92 | .GpioTrigger = 0, //external trigger pin, (0: internal trigger) | ||
93 | #if defined(CONFIG_HAPTICS_LRA_SEMCO1030) | ||
94 | //rated = 1.5Vrms, ov=2.1Vrms, f=204hz | ||
95 | .loop = CLOSE_LOOP, | ||
96 | .RTPFormat = Signed, | ||
97 | .BIDIRInput = BiDirectional, | ||
98 | .actuator = { | ||
99 | .device_type = LRA, | ||
100 | .rated_vol = 0x3d, | ||
101 | .over_drive_vol = 0x87, | ||
102 | .LRAFreq = 204, | ||
103 | }, | ||
104 | #elif defined(CONFIG_HAPTICS_ERM_EVOWAVE_Z4TJGB1512658) | ||
105 | //rated vol = 3.0 v, ov = 3.6 v, risetime = 150 ms | ||
106 | .loop = CLOSE_LOOP, | ||
107 | .RTPFormat = Signed, | ||
108 | .BIDIRInput = BiDirectional, | ||
109 | .actuator = { | ||
110 | .device_type = ERM, | ||
111 | .rated_vol = 0x8d, | ||
112 | .over_drive_vol = 0xa9, | ||
113 | }, | ||
114 | #else | ||
115 | #error "please define actuator type" | ||
116 | #endif | ||
117 | }; | ||
118 | #elif defined(CONFIG_HAPTICS_DRV2604L) | ||
119 | static struct DRV2604L_platform_data drv2604l_plat_data = { | ||
120 | .GpioEnable = 0, //enable the chip | ||
121 | .GpioTrigger = 0, //external trigger pin, (0: internal trigger) | ||
122 | #if defined(CONFIG_HAPTICS_LRA_SEMCO1030) | ||
123 | //rated = 1.5Vrms, ov=2.1Vrms, f=204hz | ||
124 | .loop = CLOSE_LOOP, | ||
125 | .RTPFormat = Signed, | ||
126 | .BIDIRInput = BiDirectional, | ||
127 | .actuator = { | ||
128 | .device_type = LRA, | ||
129 | .rated_vol = 0x3d, | ||
130 | .over_drive_vol = 0x87, | ||
131 | .LRAFreq = 204, | ||
132 | }, | ||
133 | #elif defined(CONFIG_HAPTICS_ERM_EVOWAVE_Z4TJGB1512658) | ||
134 | //rated vol = 3.0 v, ov = 3.6 v, risetime = 150 ms | ||
135 | .loop = CLOSE_LOOP, | ||
136 | .RTPFormat = Signed, | ||
137 | .BIDIRInput = BiDirectional, | ||
138 | .actuator = { | ||
139 | .device_type = ERM, | ||
140 | .rated_vol = 0x8d, | ||
141 | .over_drive_vol = 0xa9, | ||
142 | }, | ||
143 | #else | ||
144 | #error "please define actuator type" | ||
145 | #endif | ||
146 | }; | ||
147 | #elif defined(CONFIG_HAPTICS_DRV2667) | ||
148 | static struct drv2667_platform_data drv2667_plat_data = { | ||
149 | .inputGain = DRV2667_GAIN_50VPP, | ||
150 | .boostTimeout = DRV2667_IDLE_TIMEOUT_20MS, | ||
151 | }; | ||
152 | #endif | ||
153 | |||
154 | static struct i2c_board_info haptics_dev[] __initdata = { | ||
155 | #if defined(CONFIG_HAPTICS_DRV2605) | ||
156 | { | ||
157 | I2C_BOARD_INFO(HAPTICS_DEVICE_NAME, 0x5a), | ||
158 | .platform_data = &drv2605_plat_data, | ||
159 | }, | ||
160 | #elif defined(CONFIG_HAPTICS_DRV2604) | ||
161 | { | ||
162 | I2C_BOARD_INFO(HAPTICS_DEVICE_NAME, 0x5a), | ||
163 | .platform_data = &drv2604_plat_data, | ||
164 | }, | ||
165 | #elif defined(CONFIG_HAPTICS_DRV2604L) | ||
166 | { | ||
167 | I2C_BOARD_INFO(HAPTICS_DEVICE_NAME, 0x5a), | ||
168 | .platform_data = &drv2604l_plat_data, | ||
169 | }, | ||
170 | #elif defined(CONFIG_HAPTICS_DRV2667) | ||
171 | { | ||
172 | I2C_BOARD_INFO(HAPTICS_DEVICE_NAME, 0x59), | ||
173 | .platform_data = &drv2667_plat_data, | ||
174 | }, | ||
175 | #endif | ||
176 | }; | ||
177 | |||
178 | static void __init lge_add_i2c_haptics_device(void) | ||
179 | { | ||
180 | i2c_register_board_info(APQ8064_GSBI3_QUP_I2C_BUS_ID, | ||
181 | haptics_dev, | ||
182 | ARRAY_SIZE(haptics_dev)); | ||
183 | } | ||
184 | |||
185 | void __init lge_add_haptics_device(void) | ||
186 | { | ||
187 | lge_add_i2c_haptics_device(); | ||
188 | } | ||
diff --git a/drivers_haptics_drv2605.c b/drivers_haptics_drv2605.c deleted file mode 100755 index 346fb71..0000000 --- a/drivers_haptics_drv2605.c +++ /dev/null | |||
@@ -1,1002 +0,0 @@ | |||
1 | /* | ||
2 | ** ============================================================================= | ||
3 | ** Copyright (c) 2014 Texas Instruments Inc. | ||
4 | ** | ||
5 | ** This program is free software; you can redistribute it and/or | ||
6 | ** modify it under the terms of the GNU General Public License | ||
7 | ** as published by the Free Software Foundation; either version 2 | ||
8 | ** of the License, or (at your option) any later version. | ||
9 | ** | ||
10 | ** This program is distributed in the hope that it will be useful, | ||
11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | ** GNU General Public License for more details. | ||
14 | ** | ||
15 | ** You should have received a copy of the GNU General Public License | ||
16 | ** along with this program; if not, write to the Free Software | ||
17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
18 | ** | ||
19 | ** File: | ||
20 | ** drv2605.c | ||
21 | ** | ||
22 | ** Description: | ||
23 | ** DRV2605 chip driver | ||
24 | ** | ||
25 | ** ============================================================================= | ||
26 | */ | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/types.h> | ||
32 | #include <linux/fs.h> | ||
33 | #include <linux/i2c.h> | ||
34 | #include <linux/semaphore.h> | ||
35 | #include <linux/device.h> | ||
36 | #include <linux/syscalls.h> | ||
37 | #include <asm/uaccess.h> | ||
38 | #include <linux/gpio.h> | ||
39 | #include <linux/sched.h> | ||
40 | #include <linux/spinlock_types.h> | ||
41 | #include <linux/spinlock.h> | ||
42 | #include <linux/delay.h> | ||
43 | #include <linux/jiffies.h> | ||
44 | #include <linux/err.h> | ||
45 | #include <linux/clk.h> | ||
46 | #include <linux/haptics/drv2605.h> | ||
47 | |||
48 | static struct drv2605_data *pDRV2605data = NULL; | ||
49 | |||
50 | static int drv2605_reg_read(struct drv2605_data *pDrv2605data, unsigned int reg) | ||
51 | { | ||
52 | unsigned int val; | ||
53 | int ret; | ||
54 | |||
55 | ret = regmap_read(pDrv2605data->regmap, reg, &val); | ||
56 | |||
57 | if (ret < 0) | ||
58 | return ret; | ||
59 | else | ||
60 | return val; | ||
61 | } | ||
62 | |||
63 | static int drv2605_reg_write(struct drv2605_data *pDrv2605data, unsigned char reg, char val) | ||
64 | { | ||
65 | return regmap_write(pDrv2605data->regmap, reg, val); | ||
66 | } | ||
67 | |||
68 | static int drv2605_bulk_read(struct drv2605_data *pDrv2605data, unsigned char reg, unsigned int count, u8 *buf) | ||
69 | { | ||
70 | return regmap_bulk_read(pDrv2605data->regmap, reg, buf, count); | ||
71 | } | ||
72 | |||
73 | static int drv2605_bulk_write(struct drv2605_data *pDrv2605data, unsigned char reg, unsigned int count, const u8 *buf) | ||
74 | { | ||
75 | return regmap_bulk_write(pDrv2605data->regmap, reg, buf, count); | ||
76 | } | ||
77 | |||
78 | static int drv2605_set_bits(struct drv2605_data *pDrv2605data, unsigned char reg, unsigned char mask, unsigned char val) | ||
79 | { | ||
80 | return regmap_update_bits(pDrv2605data->regmap, reg, mask, val); | ||
81 | } | ||
82 | |||
83 | static int drv2605_set_go_bit(struct drv2605_data *pDrv2605data, unsigned char val) | ||
84 | { | ||
85 | return drv2605_reg_write(pDrv2605data, GO_REG, (val&0x01)); | ||
86 | } | ||
87 | |||
88 | static void drv2605_poll_go_bit(struct drv2605_data *pDrv2605data) | ||
89 | { | ||
90 | while (drv2605_reg_read(pDrv2605data, GO_REG) == GO) | ||
91 | schedule_timeout_interruptible(msecs_to_jiffies(GO_BIT_POLL_INTERVAL)); | ||
92 | } | ||
93 | |||
94 | static int drv2605_select_library(struct drv2605_data *pDrv2605data, unsigned char lib) | ||
95 | { | ||
96 | return drv2605_reg_write(pDrv2605data, LIBRARY_SELECTION_REG, (lib&0x07)); | ||
97 | } | ||
98 | |||
99 | static int drv2605_set_rtp_val(struct drv2605_data *pDrv2605data, char value) | ||
100 | { | ||
101 | /* please be noted: in unsigned mode, maximum is 0xff, in signed mode, maximum is 0x7f */ | ||
102 | return drv2605_reg_write(pDrv2605data, REAL_TIME_PLAYBACK_REG, value); | ||
103 | } | ||
104 | |||
105 | static int drv2605_set_waveform_sequence(struct drv2605_data *pDrv2605data, unsigned char* seq, unsigned int size) | ||
106 | { | ||
107 | return drv2605_bulk_write(pDrv2605data, WAVEFORM_SEQUENCER_REG, (size>WAVEFORM_SEQUENCER_MAX)?WAVEFORM_SEQUENCER_MAX:size, seq); | ||
108 | } | ||
109 | |||
110 | static void drv2605_change_mode(struct drv2605_data *pDrv2605data, char work_mode, char dev_mode) | ||
111 | { | ||
112 | /* please be noted : LRA open loop cannot be used with analog input mode */ | ||
113 | if(dev_mode == DEV_IDLE){ | ||
114 | pDrv2605data->dev_mode = dev_mode; | ||
115 | pDrv2605data->work_mode = work_mode; | ||
116 | }else if(dev_mode == DEV_STANDBY){ | ||
117 | if(pDrv2605data->dev_mode != DEV_STANDBY){ | ||
118 | pDrv2605data->dev_mode = DEV_STANDBY; | ||
119 | drv2605_reg_write(pDrv2605data, MODE_REG, MODE_STANDBY); | ||
120 | schedule_timeout_interruptible(msecs_to_jiffies(WAKE_STANDBY_DELAY)); | ||
121 | } | ||
122 | pDrv2605data->work_mode = WORK_IDLE; | ||
123 | }else if(dev_mode == DEV_READY){ | ||
124 | if((work_mode != pDrv2605data->work_mode) | ||
125 | ||(dev_mode != pDrv2605data->dev_mode)){ | ||
126 | pDrv2605data->work_mode = work_mode; | ||
127 | pDrv2605data->dev_mode = dev_mode; | ||
128 | if((pDrv2605data->work_mode == WORK_VIBRATOR) | ||
129 | ||(pDrv2605data->work_mode == WORK_PATTERN_RTP_ON) | ||
130 | ||(pDrv2605data->work_mode == WORK_SEQ_RTP_ON) | ||
131 | ||(pDrv2605data->work_mode == WORK_RTP)){ | ||
132 | drv2605_reg_write(pDrv2605data, MODE_REG, MODE_REAL_TIME_PLAYBACK); | ||
133 | }else if(pDrv2605data->work_mode == WORK_AUDIO2HAPTIC){ | ||
134 | drv2605_reg_write(pDrv2605data, MODE_REG, MODE_AUDIOHAPTIC); | ||
135 | }else if(pDrv2605data->work_mode == WORK_CALIBRATION){ | ||
136 | drv2605_reg_write(pDrv2605data, MODE_REG, AUTO_CALIBRATION); | ||
137 | }else{ | ||
138 | drv2605_reg_write(pDrv2605data, MODE_REG, MODE_INTERNAL_TRIGGER); | ||
139 | schedule_timeout_interruptible(msecs_to_jiffies(STANDBY_WAKE_DELAY)); | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static void setAudioHapticsEnabled(struct drv2605_data *pDrv2605data, int enable) | ||
146 | { | ||
147 | if (enable) | ||
148 | { | ||
149 | if(pDrv2605data->work_mode != WORK_AUDIO2HAPTIC){ | ||
150 | pDrv2605data->vibrator_is_playing = YES; | ||
151 | drv2605_change_mode(pDrv2605data, WORK_IDLE, DEV_READY); | ||
152 | |||
153 | drv2605_set_bits(pDrv2605data, | ||
154 | Control1_REG, | ||
155 | Control1_REG_AC_COUPLE_MASK, | ||
156 | AC_COUPLE_ENABLED ); | ||
157 | |||
158 | drv2605_set_bits(pDrv2605data, | ||
159 | Control3_REG, | ||
160 | Control3_REG_PWMANALOG_MASK, | ||
161 | INPUT_ANALOG); | ||
162 | |||
163 | drv2605_change_mode(pDrv2605data, WORK_AUDIO2HAPTIC, DEV_READY); | ||
164 | switch_set_state(&pDrv2605data->sw_dev, SW_STATE_AUDIO2HAPTIC); | ||
165 | } | ||
166 | } else { | ||
167 | // Chip needs to be brought out of standby to change the registers | ||
168 | if(pDrv2605data->work_mode == WORK_AUDIO2HAPTIC){ | ||
169 | pDrv2605data->vibrator_is_playing = NO; | ||
170 | drv2605_change_mode(pDrv2605data, WORK_IDLE, DEV_READY); | ||
171 | |||
172 | drv2605_set_bits(pDrv2605data, | ||
173 | Control1_REG, | ||
174 | Control1_REG_AC_COUPLE_MASK, | ||
175 | AC_COUPLE_DISABLED ); | ||
176 | |||
177 | drv2605_set_bits(pDrv2605data, | ||
178 | Control3_REG, | ||
179 | Control3_REG_PWMANALOG_MASK, | ||
180 | INPUT_PWM); | ||
181 | |||
182 | switch_set_state(&pDrv2605data->sw_dev, SW_STATE_IDLE); | ||
183 | drv2605_change_mode(pDrv2605data, WORK_IDLE, DEV_STANDBY); // Disable audio-to-haptics | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | |||
188 | static void play_effect(struct drv2605_data *pDrv2605data) | ||
189 | { | ||
190 | switch_set_state(&pDrv2605data->sw_dev, SW_STATE_SEQUENCE_PLAYBACK); | ||
191 | drv2605_change_mode(pDrv2605data, WORK_SEQ_PLAYBACK, DEV_READY); | ||
192 | drv2605_set_waveform_sequence(pDrv2605data, pDrv2605data->sequence, WAVEFORM_SEQUENCER_MAX); | ||
193 | pDrv2605data->vibrator_is_playing = YES; | ||
194 | drv2605_set_go_bit(pDrv2605data, GO); | ||
195 | |||
196 | while((drv2605_reg_read(pDrv2605data, GO_REG) == GO) && (pDrv2605data->should_stop == NO)){ | ||
197 | schedule_timeout_interruptible(msecs_to_jiffies(GO_BIT_POLL_INTERVAL)); | ||
198 | } | ||
199 | |||
200 | if(pDrv2605data->should_stop == YES){ | ||
201 | drv2605_set_go_bit(pDrv2605data, STOP); | ||
202 | } | ||
203 | |||
204 | if (pDrv2605data->audio_haptics_enabled){ | ||
205 | setAudioHapticsEnabled(pDrv2605data, YES); | ||
206 | } else { | ||
207 | drv2605_change_mode(pDrv2605data, WORK_IDLE, DEV_STANDBY); | ||
208 | switch_set_state(&pDrv2605data->sw_dev, SW_STATE_IDLE); | ||
209 | pDrv2605data->vibrator_is_playing = NO; | ||
210 | wake_unlock(&pDrv2605data->wklock); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | static void play_Pattern_RTP(struct drv2605_data *pDrv2605data) | ||
215 | { | ||
216 | if(pDrv2605data->work_mode == WORK_PATTERN_RTP_ON){ | ||
217 | drv2605_change_mode(pDrv2605data, WORK_PATTERN_RTP_OFF, DEV_READY); | ||
218 | if(pDrv2605data->repeat_times == 0){ | ||
219 | drv2605_change_mode(pDrv2605data, WORK_IDLE, DEV_STANDBY); | ||
220 | pDrv2605data->vibrator_is_playing = NO; | ||
221 | switch_set_state(&pDrv2605data->sw_dev, SW_STATE_IDLE); | ||
222 | wake_unlock(&pDrv2605data->wklock); | ||
223 | }else{ | ||
224 | hrtimer_start(&pDrv2605data->timer, ns_to_ktime((u64)pDrv2605data->silience_time * NSEC_PER_MSEC), HRTIMER_MODE_REL); | ||
225 | } | ||
226 | }else if(pDrv2605data->work_mode == WORK_PATTERN_RTP_OFF){ | ||
227 | pDrv2605data->repeat_times--; | ||
228 | drv2605_change_mode(pDrv2605data, WORK_PATTERN_RTP_ON, DEV_READY); | ||
229 | hrtimer_start(&pDrv2605data->timer, ns_to_ktime((u64)pDrv2605data->vibration_time * NSEC_PER_MSEC), HRTIMER_MODE_REL); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | static void play_Seq_RTP(struct drv2605_data *pDrv2605data) | ||
234 | { | ||
235 | if(pDrv2605data->RTPSeq.RTPindex < pDrv2605data->RTPSeq.RTPCounts){ | ||
236 | int RTPTime = pDrv2605data->RTPSeq.RTPData[pDrv2605data->RTPSeq.RTPindex] >> 8; | ||
237 | int RTPVal = pDrv2605data->RTPSeq.RTPData[pDrv2605data->RTPSeq.RTPindex] & 0x00ff ; | ||
238 | |||
239 | pDrv2605data->vibrator_is_playing = YES; | ||
240 | pDrv2605data->RTPSeq.RTPindex++; | ||
241 | drv2605_change_mode(pDrv2605data, WORK_SEQ_RTP_ON, DEV_READY); | ||
242 | drv2605_set_rtp_val(pDrv2605data, RTPVal); | ||
243 | |||
244 | hrtimer_start(&pDrv2605data->timer, ns_to_ktime((u64)RTPTime * NSEC_PER_MSEC), HRTIMER_MODE_REL); | ||
245 | }else{ | ||
246 | drv2605_change_mode(pDrv2605data, WORK_IDLE, DEV_STANDBY); | ||
247 | pDrv2605data->vibrator_is_playing = NO; | ||
248 | switch_set_state(&pDrv2605data->sw_dev, SW_STATE_IDLE); | ||
249 | wake_unlock(&pDrv2605data->wklock); | ||
250 | } | ||
251 | } | ||
252 | |||
253 | static void vibrator_off(struct drv2605_data *pDrv2605data) | ||
254 | { | ||
255 | if (pDrv2605data->vibrator_is_playing) { | ||
256 | if(pDrv2605data->audio_haptics_enabled == YES){ | ||
257 | setAudioHapticsEnabled(pDrv2605data, YES); | ||
258 | }else{ | ||
259 | pDrv2605data->vibrator_is_playing = NO; | ||
260 | drv2605_set_go_bit(pDrv2605data, STOP); | ||
261 | drv2605_change_mode(pDrv2605data, WORK_IDLE, DEV_STANDBY); | ||
262 | switch_set_state(&pDrv2605data->sw_dev, SW_STATE_IDLE); | ||
263 | wake_unlock(&pDrv2605data->wklock); | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | |||
268 | static void drv2605_stop(struct drv2605_data *pDrv2605data) | ||
269 | { | ||
270 | if(pDrv2605data->vibrator_is_playing){ | ||
271 | if(pDrv2605data->work_mode == WORK_AUDIO2HAPTIC){ | ||
272 | setAudioHapticsEnabled(pDrv2605data, NO); | ||
273 | }else if((pDrv2605data->work_mode == WORK_VIBRATOR) | ||
274 | ||(pDrv2605data->work_mode == WORK_PATTERN_RTP_ON) | ||
275 | ||(pDrv2605data->work_mode == WORK_PATTERN_RTP_OFF) | ||
276 | ||(pDrv2605data->work_mode == WORK_SEQ_RTP_ON) | ||
277 | ||(pDrv2605data->work_mode == WORK_SEQ_RTP_OFF) | ||
278 | ||(pDrv2605data->work_mode == WORK_RTP)){ | ||
279 | vibrator_off(pDrv2605data); | ||
280 | }else if(pDrv2605data->work_mode == WORK_SEQ_PLAYBACK){ | ||
281 | }else{ | ||
282 | printk("%s, err mode=%d \n", __FUNCTION__, pDrv2605data->work_mode); | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | |||
287 | static int vibrator_get_time(struct timed_output_dev *dev) | ||
288 | { | ||
289 | struct drv2605_data *pDrv2605data = container_of(dev, struct drv2605_data, to_dev); | ||
290 | |||
291 | if (hrtimer_active(&pDrv2605data->timer)) { | ||
292 | ktime_t r = hrtimer_get_remaining(&pDrv2605data->timer); | ||
293 | return ktime_to_ms(r); | ||
294 | } | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static void vibrator_enable( struct timed_output_dev *dev, int value) | ||
300 | { | ||
301 | struct drv2605_data *pDrv2605data = container_of(dev, struct drv2605_data, to_dev); | ||
302 | |||
303 | pDrv2605data->should_stop = YES; | ||
304 | hrtimer_cancel(&pDrv2605data->timer); | ||
305 | cancel_work_sync(&pDrv2605data->vibrator_work); | ||
306 | |||
307 | mutex_lock(&pDrv2605data->lock); | ||
308 | |||
309 | drv2605_stop(pDrv2605data); | ||
310 | |||
311 | if (value > 0) { | ||
312 | if(pDrv2605data->audio_haptics_enabled == NO){ | ||
313 | wake_lock(&pDrv2605data->wklock); | ||
314 | } | ||
315 | |||
316 | drv2605_change_mode(pDrv2605data, WORK_VIBRATOR, DEV_READY); | ||
317 | pDrv2605data->vibrator_is_playing = YES; | ||
318 | switch_set_state(&pDrv2605data->sw_dev, SW_STATE_RTP_PLAYBACK); | ||
319 | |||
320 | value = (value>MAX_TIMEOUT)?MAX_TIMEOUT:value; | ||
321 | hrtimer_start(&pDrv2605data->timer, ns_to_ktime((u64)value * NSEC_PER_MSEC), HRTIMER_MODE_REL); | ||
322 | } | ||
323 | |||
324 | mutex_unlock(&pDrv2605data->lock); | ||
325 | } | ||
326 | |||
327 | static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer) | ||
328 | { | ||
329 | struct drv2605_data *pDrv2605data = container_of(timer, struct drv2605_data, timer); | ||
330 | |||
331 | schedule_work(&pDrv2605data->vibrator_work); | ||
332 | |||
333 | return HRTIMER_NORESTART; | ||
334 | } | ||
335 | |||
336 | static void vibrator_work_routine(struct work_struct *work) | ||
337 | { | ||
338 | struct drv2605_data *pDrv2605data = container_of(work, struct drv2605_data, vibrator_work); | ||
339 | |||
340 | mutex_lock(&pDrv2605data->lock); | ||
341 | |||
342 | if((pDrv2605data->work_mode == WORK_VIBRATOR) | ||
343 | ||(pDrv2605data->work_mode == WORK_RTP)){ | ||
344 | vibrator_off(pDrv2605data); | ||
345 | }else if(pDrv2605data->work_mode == WORK_SEQ_PLAYBACK){ | ||
346 | play_effect(pDrv2605data); | ||
347 | }else if((pDrv2605data->work_mode == WORK_PATTERN_RTP_ON)||(pDrv2605data->work_mode == WORK_PATTERN_RTP_OFF)){ | ||
348 | play_Pattern_RTP(pDrv2605data); | ||
349 | }else if((pDrv2605data->work_mode == WORK_SEQ_RTP_ON)||(pDrv2605data->work_mode == WORK_SEQ_RTP_OFF)){ | ||
350 | play_Seq_RTP(pDrv2605data); | ||
351 | } | ||
352 | |||
353 | mutex_unlock(&pDrv2605data->lock); | ||
354 | } | ||
355 | |||
356 | static int dev2605_open (struct inode * i_node, struct file * filp) | ||
357 | { | ||
358 | if(pDRV2605data == NULL){ | ||
359 | return -ENODEV; | ||
360 | } | ||
361 | |||
362 | filp->private_data = pDRV2605data; | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static ssize_t dev2605_read(struct file* filp, char* buff, size_t length, loff_t* offset) | ||
367 | { | ||
368 | struct drv2605_data *pDrv2605data = (struct drv2605_data *)filp->private_data; | ||
369 | int ret = 0; | ||
370 | |||
371 | if(pDrv2605data->ReadLen > 0){ | ||
372 | ret = copy_to_user(buff, pDrv2605data->ReadBuff, pDrv2605data->ReadLen); | ||
373 | if (ret != 0){ | ||
374 | printk("%s, copy_to_user err=%d \n", __FUNCTION__, ret); | ||
375 | }else{ | ||
376 | ret = pDrv2605data->ReadLen; | ||
377 | } | ||
378 | pDrv2605data->ReadLen = 0; | ||
379 | } | ||
380 | |||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | static bool isforDebug(int cmd){ | ||
385 | return ((cmd == HAPTIC_CMDID_REG_WRITE) | ||
386 | ||(cmd == HAPTIC_CMDID_REG_READ) | ||
387 | ||(cmd == HAPTIC_CMDID_REG_SETBIT)); | ||
388 | } | ||
389 | |||
390 | static ssize_t dev2605_write(struct file* filp, const char* buff, size_t len, loff_t* off) | ||
391 | { | ||
392 | struct drv2605_data *pDrv2605data = (struct drv2605_data *)filp->private_data; | ||
393 | |||
394 | if(isforDebug(buff[0])){ | ||
395 | }else{ | ||
396 | pDrv2605data->should_stop = YES; | ||
397 | hrtimer_cancel(&pDrv2605data->timer); | ||
398 | cancel_work_sync(&pDrv2605data->vibrator_work); | ||
399 | } | ||
400 | |||
401 | mutex_lock(&pDrv2605data->lock); | ||
402 | |||
403 | if(isforDebug(buff[0])){ | ||
404 | }else{ | ||
405 | drv2605_stop(pDrv2605data); | ||
406 | } | ||
407 | |||
408 | switch(buff[0]) | ||
409 | { | ||
410 | case HAPTIC_CMDID_PLAY_SINGLE_EFFECT: | ||
411 | case HAPTIC_CMDID_PLAY_EFFECT_SEQUENCE: | ||
412 | { | ||
413 | memset(&pDrv2605data->sequence, 0, WAVEFORM_SEQUENCER_MAX); | ||
414 | if (!copy_from_user(&pDrv2605data->sequence, &buff[1], len - 1)) | ||
415 | { | ||
416 | if(pDrv2605data->audio_haptics_enabled == NO){ | ||
417 | wake_lock(&pDrv2605data->wklock); | ||
418 | } | ||
419 | pDrv2605data->should_stop = NO; | ||
420 | drv2605_change_mode(pDrv2605data, WORK_SEQ_PLAYBACK, DEV_IDLE); | ||
421 | schedule_work(&pDrv2605data->vibrator_work); | ||
422 | } | ||
423 | break; | ||
424 | } | ||
425 | case HAPTIC_CMDID_PLAY_TIMED_EFFECT: | ||
426 | { | ||
427 | unsigned int value = 0; | ||
428 | value = buff[2]; | ||
429 | value <<= 8; | ||
430 | value |= buff[1]; | ||
431 | |||
432 | if (value > 0) | ||
433 | { | ||
434 | if(pDrv2605data->audio_haptics_enabled == NO){ | ||
435 | wake_lock(&pDrv2605data->wklock); | ||
436 | } | ||
437 | switch_set_state(&pDrv2605data->sw_dev, SW_STATE_RTP_PLAYBACK); | ||
438 | pDrv2605data->vibrator_is_playing = YES; | ||
439 | value = (value > MAX_TIMEOUT)?MAX_TIMEOUT:value; | ||
440 | drv2605_change_mode(pDrv2605data, WORK_RTP, DEV_READY); | ||
441 | |||
442 | hrtimer_start(&pDrv2605data->timer, ns_to_ktime((u64)value * NSEC_PER_MSEC), HRTIMER_MODE_REL); | ||
443 | } | ||
444 | break; | ||
445 | } | ||
446 | |||
447 | case HAPTIC_CMDID_PATTERN_RTP: | ||
448 | { | ||
449 | unsigned char strength = 0; | ||
450 | |||
451 | pDrv2605data->vibration_time = (int)((((int)buff[2])<<8) | (int)buff[1]); | ||
452 | pDrv2605data->silience_time = (int)((((int)buff[4])<<8) | (int)buff[3]); | ||
453 | strength = buff[5]; | ||
454 | pDrv2605data->repeat_times = buff[6]; | ||
455 | |||
456 | if(pDrv2605data->vibration_time > 0){ | ||
457 | if(pDrv2605data->audio_haptics_enabled == NO){ | ||
458 | wake_lock(&pDrv2605data->wklock); | ||
459 | } | ||
460 | switch_set_state(&pDrv2605data->sw_dev, SW_STATE_RTP_PLAYBACK); | ||
461 | pDrv2605data->vibrator_is_playing = YES; | ||
462 | if(pDrv2605data->repeat_times > 0) | ||
463 | pDrv2605data->repeat_times--; | ||
464 | if (pDrv2605data->vibration_time > MAX_TIMEOUT) | ||
465 | pDrv2605data->vibration_time = MAX_TIMEOUT; | ||
466 | drv2605_change_mode(pDrv2605data, WORK_PATTERN_RTP_ON, DEV_READY); | ||
467 | drv2605_set_rtp_val(pDrv2605data, strength); | ||
468 | |||
469 | hrtimer_start(&pDrv2605data->timer, ns_to_ktime((u64)pDrv2605data->vibration_time * NSEC_PER_MSEC), HRTIMER_MODE_REL); | ||
470 | } | ||
471 | break; | ||
472 | } | ||
473 | |||
474 | case HAPTIC_CMDID_RTP_SEQUENCE: | ||
475 | { | ||
476 | memset(&pDrv2605data->RTPSeq, 0, sizeof(struct RTP_Seq)); | ||
477 | if(((len-1)%2) == 0){ | ||
478 | pDrv2605data->RTPSeq.RTPCounts = (len-1)/2; | ||
479 | if((pDrv2605data->RTPSeq.RTPCounts <= MAX_RTP_SEQ)&&(pDrv2605data->RTPSeq.RTPCounts>0)){ | ||
480 | if(copy_from_user(pDrv2605data->RTPSeq.RTPData, &buff[1], pDrv2605data->RTPSeq.RTPCounts*2) != 0){ | ||
481 | printk("%s, rtp_seq copy seq err\n", __FUNCTION__); | ||
482 | break; | ||
483 | } | ||
484 | |||
485 | if(pDrv2605data->audio_haptics_enabled == NO){ | ||
486 | wake_lock(&pDrv2605data->wklock); | ||
487 | } | ||
488 | switch_set_state(&pDrv2605data->sw_dev, SW_STATE_RTP_PLAYBACK); | ||
489 | drv2605_change_mode(pDrv2605data, WORK_SEQ_RTP_OFF, DEV_IDLE); | ||
490 | schedule_work(&pDrv2605data->vibrator_work); | ||
491 | }else{ | ||
492 | printk("%s, rtp_seq count error,maximum=%d\n", __FUNCTION__,MAX_RTP_SEQ); | ||
493 | } | ||
494 | }else{ | ||
495 | printk("%s, rtp_seq len error\n", __FUNCTION__); | ||
496 | } | ||
497 | break; | ||
498 | } | ||
499 | |||
500 | case HAPTIC_CMDID_STOP: | ||
501 | { | ||
502 | break; | ||
503 | } | ||
504 | |||
505 | case HAPTIC_CMDID_AUDIOHAPTIC_ENABLE: | ||
506 | { | ||
507 | if(pDrv2605data->audio_haptics_enabled == NO){ | ||
508 | wake_lock(&pDrv2605data->wklock); | ||
509 | } | ||
510 | pDrv2605data->audio_haptics_enabled = YES; | ||
511 | setAudioHapticsEnabled(pDrv2605data, YES); | ||
512 | break; | ||
513 | } | ||
514 | |||
515 | case HAPTIC_CMDID_AUDIOHAPTIC_DISABLE: | ||
516 | { | ||
517 | if(pDrv2605data->audio_haptics_enabled == YES){ | ||
518 | pDrv2605data->audio_haptics_enabled = NO; | ||
519 | wake_unlock(&pDrv2605data->wklock); | ||
520 | } | ||
521 | break; | ||
522 | } | ||
523 | |||
524 | case HAPTIC_CMDID_REG_READ: | ||
525 | { | ||
526 | if(len == 2){ | ||
527 | pDrv2605data->ReadLen = 1; | ||
528 | pDrv2605data->ReadBuff[0] = drv2605_reg_read(pDrv2605data, buff[1]); | ||
529 | }else if(len == 3){ | ||
530 | pDrv2605data->ReadLen = (buff[2]>MAX_READ_BYTES)?MAX_READ_BYTES:buff[2]; | ||
531 | drv2605_bulk_read(pDrv2605data, buff[1], pDrv2605data->ReadLen, pDrv2605data->ReadBuff); | ||
532 | }else{ | ||
533 | printk("%s, reg_read len error\n", __FUNCTION__); | ||
534 | } | ||
535 | break; | ||
536 | } | ||
537 | |||
538 | case HAPTIC_CMDID_REG_WRITE: | ||
539 | { | ||
540 | if((len-1) == 2){ | ||
541 | drv2605_reg_write(pDrv2605data, buff[1], buff[2]); | ||
542 | }else if((len-1)>2){ | ||
543 | unsigned char *data = (unsigned char *)kzalloc(len-2, GFP_KERNEL); | ||
544 | if(data != NULL){ | ||
545 | if(copy_from_user(data, &buff[2], len-2) != 0){ | ||
546 | printk("%s, reg copy err\n", __FUNCTION__); | ||
547 | }else{ | ||
548 | drv2605_bulk_write(pDrv2605data, buff[1], len-2, data); | ||
549 | } | ||
550 | kfree(data); | ||
551 | } | ||
552 | }else{ | ||
553 | printk("%s, reg_write len error\n", __FUNCTION__); | ||
554 | } | ||
555 | break; | ||
556 | } | ||
557 | |||
558 | case HAPTIC_CMDID_REG_SETBIT: | ||
559 | { | ||
560 | int i=1; | ||
561 | for(i=1; i< len; ){ | ||
562 | drv2605_set_bits(pDrv2605data, buff[i], buff[i+1], buff[i+2]); | ||
563 | i += 3; | ||
564 | } | ||
565 | break; | ||
566 | } | ||
567 | default: | ||
568 | printk("%s, unknown HAPTIC cmd\n", __FUNCTION__); | ||
569 | break; | ||
570 | } | ||
571 | |||
572 | mutex_unlock(&pDrv2605data->lock); | ||
573 | |||
574 | return len; | ||
575 | } | ||
576 | |||
577 | |||
578 | static struct file_operations fops = | ||
579 | { | ||
580 | .open = dev2605_open, | ||
581 | .read = dev2605_read, | ||
582 | .write = dev2605_write, | ||
583 | }; | ||
584 | |||
585 | void drv2605_early_suspend(struct early_suspend *h){ | ||
586 | struct drv2605_data *pDrv2605data = container_of(h, struct drv2605_data, early_suspend); | ||
587 | |||
588 | pDrv2605data->should_stop = YES; | ||
589 | hrtimer_cancel(&pDrv2605data->timer); | ||
590 | cancel_work_sync(&pDrv2605data->vibrator_work); | ||
591 | |||
592 | mutex_lock(&pDrv2605data->lock); | ||
593 | |||
594 | drv2605_stop(pDrv2605data); | ||
595 | if(pDrv2605data->audio_haptics_enabled == YES){ | ||
596 | wake_unlock(&pDrv2605data->wklock); | ||
597 | } | ||
598 | |||
599 | mutex_unlock(&pDrv2605data->lock); | ||
600 | return ; | ||
601 | } | ||
602 | |||
603 | void drv2605_late_resume(struct early_suspend *h) { | ||
604 | struct drv2605_data *pDrv2605data = container_of(h, struct drv2605_data, early_suspend); | ||
605 | |||
606 | mutex_lock(&pDrv2605data->lock); | ||
607 | if(pDrv2605data->audio_haptics_enabled == YES){ | ||
608 | wake_lock(&pDrv2605data->wklock); | ||
609 | setAudioHapticsEnabled(pDrv2605data, YES); | ||
610 | } | ||
611 | mutex_unlock(&pDrv2605data->lock); | ||
612 | return ; | ||
613 | } | ||
614 | |||
615 | static int Haptics_init(struct drv2605_data *pDrv2605data) | ||
616 | { | ||
617 | int reval = -ENOMEM; | ||
618 | |||
619 | pDrv2605data->version = MKDEV(0,0); | ||
620 | reval = alloc_chrdev_region(&pDrv2605data->version, 0, 1, HAPTICS_DEVICE_NAME); | ||
621 | if (reval < 0) | ||
622 | { | ||
623 | printk(KERN_ALERT"drv2605: error getting major number %d\n", reval); | ||
624 | goto fail0; | ||
625 | } | ||
626 | |||
627 | pDrv2605data->class = class_create(THIS_MODULE, HAPTICS_DEVICE_NAME); | ||
628 | if (!pDrv2605data->class) | ||
629 | { | ||
630 | printk(KERN_ALERT"drv2605: error creating class\n"); | ||
631 | goto fail1; | ||
632 | } | ||
633 | |||
634 | pDrv2605data->device = device_create(pDrv2605data->class, NULL, pDrv2605data->version, NULL, HAPTICS_DEVICE_NAME); | ||
635 | if (!pDrv2605data->device) | ||
636 | { | ||
637 | printk(KERN_ALERT"drv2605: error creating device 2605\n"); | ||
638 | goto fail2; | ||
639 | } | ||
640 | |||
641 | cdev_init(&pDrv2605data->cdev, &fops); | ||
642 | pDrv2605data->cdev.owner = THIS_MODULE; | ||
643 | pDrv2605data->cdev.ops = &fops; | ||
644 | reval = cdev_add(&pDrv2605data->cdev, pDrv2605data->version, 1); | ||
645 | if (reval) | ||
646 | { | ||
647 | printk(KERN_ALERT"drv2605: fail to add cdev\n"); | ||
648 | goto fail3; | ||
649 | } | ||
650 | |||
651 | pDrv2605data->sw_dev.name = "haptics"; | ||
652 | reval = switch_dev_register(&pDrv2605data->sw_dev); | ||
653 | if (reval < 0) { | ||
654 | printk(KERN_ALERT"drv2605: fail to register switch\n"); | ||
655 | goto fail4; | ||
656 | } | ||
657 | |||
658 | pDrv2605data->to_dev.name = "vibrator"; | ||
659 | pDrv2605data->to_dev.get_time = vibrator_get_time; | ||
660 | pDrv2605data->to_dev.enable = vibrator_enable; | ||
661 | |||
662 | if (timed_output_dev_register(&(pDrv2605data->to_dev)) < 0) | ||
663 | { | ||
664 | printk(KERN_ALERT"drv2605: fail to create timed output dev\n"); | ||
665 | goto fail3; | ||
666 | } | ||
667 | |||
668 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
669 | pDrv2605data->early_suspend.suspend = drv2605_early_suspend; | ||
670 | pDrv2605data->early_suspend.resume = drv2605_late_resume; | ||
671 | pDrv2605data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 1; | ||
672 | register_early_suspend(&pDrv2605data->early_suspend); | ||
673 | #endif | ||
674 | |||
675 | hrtimer_init(&pDrv2605data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
676 | pDrv2605data->timer.function = vibrator_timer_func; | ||
677 | INIT_WORK(&pDrv2605data->vibrator_work, vibrator_work_routine); | ||
678 | |||
679 | wake_lock_init(&pDrv2605data->wklock, WAKE_LOCK_SUSPEND, "vibrator"); | ||
680 | mutex_init(&pDrv2605data->lock); | ||
681 | |||
682 | return 0; | ||
683 | |||
684 | fail4: | ||
685 | switch_dev_unregister(&pDrv2605data->sw_dev); | ||
686 | fail3: | ||
687 | device_destroy(pDrv2605data->class, pDrv2605data->version); | ||
688 | fail2: | ||
689 | class_destroy(pDrv2605data->class); | ||
690 | fail1: | ||
691 | unregister_chrdev_region(pDrv2605data->version, 1); | ||
692 | fail0: | ||
693 | return reval; | ||
694 | } | ||
695 | |||
696 | static void dev_init_platform_data(struct drv2605_data *pDrv2605data) | ||
697 | { | ||
698 | struct drv2605_platform_data *pDrv2605Platdata = &pDrv2605data->PlatData; | ||
699 | struct actuator_data actuator = pDrv2605Platdata->actuator; | ||
700 | struct audio2haptics_data a2h = pDrv2605Platdata->a2h; | ||
701 | unsigned char temp = 0; | ||
702 | |||
703 | drv2605_select_library(pDrv2605data, actuator.g_effect_bank); | ||
704 | |||
705 | //OTP memory saves data from 0x16 to 0x1a | ||
706 | if(pDrv2605data->OTP == 0) { | ||
707 | if(actuator.rated_vol != 0){ | ||
708 | drv2605_reg_write(pDrv2605data, RATED_VOLTAGE_REG, actuator.rated_vol); | ||
709 | }else{ | ||
710 | printk("%s, ERROR Rated ZERO\n", __FUNCTION__); | ||
711 | } | ||
712 | |||
713 | if(actuator.over_drive_vol != 0){ | ||
714 | drv2605_reg_write(pDrv2605data, OVERDRIVE_CLAMP_VOLTAGE_REG, actuator.over_drive_vol); | ||
715 | }else{ | ||
716 | printk("%s, ERROR OverDriveVol ZERO\n", __FUNCTION__); | ||
717 | } | ||
718 | |||
719 | drv2605_set_bits(pDrv2605data, | ||
720 | FEEDBACK_CONTROL_REG, | ||
721 | FEEDBACK_CONTROL_DEVICE_TYPE_MASK, | ||
722 | (actuator.device_type == LRA)?FEEDBACK_CONTROL_MODE_LRA:FEEDBACK_CONTROL_MODE_ERM); | ||
723 | }else{ | ||
724 | printk("%s, OTP programmed\n", __FUNCTION__); | ||
725 | } | ||
726 | |||
727 | if(pDrv2605Platdata->loop == OPEN_LOOP){ | ||
728 | temp = BIDIR_INPUT_BIDIRECTIONAL; | ||
729 | }else{ | ||
730 | if(pDrv2605Platdata->BIDIRInput == UniDirectional){ | ||
731 | temp = BIDIR_INPUT_UNIDIRECTIONAL; | ||
732 | }else{ | ||
733 | temp = BIDIR_INPUT_BIDIRECTIONAL; | ||
734 | } | ||
735 | } | ||
736 | |||
737 | if(actuator.device_type == LRA){ | ||
738 | unsigned char DriveTime = 5*(1000 - actuator.LRAFreq)/actuator.LRAFreq; | ||
739 | drv2605_set_bits(pDrv2605data, | ||
740 | Control1_REG, | ||
741 | Control1_REG_DRIVE_TIME_MASK, | ||
742 | DriveTime); | ||
743 | printk("%s, LRA = %d, DriveTime=0x%x\n", __FUNCTION__, actuator.LRAFreq, DriveTime); | ||
744 | } | ||
745 | |||
746 | drv2605_set_bits(pDrv2605data, | ||
747 | Control2_REG, | ||
748 | Control2_REG_BIDIR_INPUT_MASK, | ||
749 | temp); | ||
750 | |||
751 | if((pDrv2605Platdata->loop == OPEN_LOOP)&&(actuator.device_type == LRA)) | ||
752 | { | ||
753 | temp = LRA_OpenLoop_Enabled; | ||
754 | } | ||
755 | else if((pDrv2605Platdata->loop == OPEN_LOOP)&&(actuator.device_type == ERM)) | ||
756 | { | ||
757 | temp = ERM_OpenLoop_Enabled; | ||
758 | } | ||
759 | else | ||
760 | { | ||
761 | temp = ERM_OpenLoop_Disable|LRA_OpenLoop_Disable; | ||
762 | } | ||
763 | |||
764 | if((pDrv2605Platdata->loop == CLOSE_LOOP) &&(pDrv2605Platdata->BIDIRInput == UniDirectional)) | ||
765 | { | ||
766 | temp |= RTP_FORMAT_UNSIGNED; | ||
767 | drv2605_reg_write(pDrv2605data, REAL_TIME_PLAYBACK_REG, 0xff); | ||
768 | } | ||
769 | else | ||
770 | { | ||
771 | if(pDrv2605Platdata->RTPFormat == Signed) | ||
772 | { | ||
773 | temp |= RTP_FORMAT_SIGNED; | ||
774 | drv2605_reg_write(pDrv2605data, REAL_TIME_PLAYBACK_REG, 0x7f); | ||
775 | } | ||
776 | else | ||
777 | { | ||
778 | temp |= RTP_FORMAT_UNSIGNED; | ||
779 | drv2605_reg_write(pDrv2605data, REAL_TIME_PLAYBACK_REG, 0xff); | ||
780 | } | ||
781 | } | ||
782 | drv2605_set_bits(pDrv2605data, | ||
783 | Control3_REG, | ||
784 | Control3_REG_LOOP_MASK|Control3_REG_FORMAT_MASK, | ||
785 | temp); | ||
786 | |||
787 | //for audio to haptics | ||
788 | if(pDrv2605Platdata->GpioTrigger == 0) //not used as external trigger | ||
789 | { | ||
790 | drv2605_reg_write(pDrv2605data, AUDIO_HAPTICS_MIN_INPUT_REG, a2h.a2h_min_input); | ||
791 | drv2605_reg_write(pDrv2605data, AUDIO_HAPTICS_MAX_INPUT_REG, a2h.a2h_max_input); | ||
792 | drv2605_reg_write(pDrv2605data, AUDIO_HAPTICS_MIN_OUTPUT_REG, a2h.a2h_min_output); | ||
793 | drv2605_reg_write(pDrv2605data, AUDIO_HAPTICS_MAX_OUTPUT_REG, a2h.a2h_max_output); | ||
794 | } | ||
795 | } | ||
796 | |||
797 | static int dev_auto_calibrate(struct drv2605_data *pDrv2605data) | ||
798 | { | ||
799 | int err = 0, status=0; | ||
800 | |||
801 | drv2605_change_mode(pDrv2605data, WORK_CALIBRATION, DEV_READY); | ||
802 | drv2605_set_go_bit(pDrv2605data, GO); | ||
803 | |||
804 | /* Wait until the procedure is done */ | ||
805 | drv2605_poll_go_bit(pDrv2605data); | ||
806 | /* Read status */ | ||
807 | status = drv2605_reg_read(pDrv2605data, STATUS_REG); | ||
808 | |||
809 | printk("%s, calibration status =0x%x\n", __FUNCTION__, status); | ||
810 | |||
811 | /* Read calibration results */ | ||
812 | drv2605_reg_read(pDrv2605data, AUTO_CALI_RESULT_REG); | ||
813 | drv2605_reg_read(pDrv2605data, AUTO_CALI_BACK_EMF_RESULT_REG); | ||
814 | drv2605_reg_read(pDrv2605data, FEEDBACK_CONTROL_REG); | ||
815 | |||
816 | return err; | ||
817 | } | ||
818 | |||
819 | static struct regmap_config drv2605_i2c_regmap = { | ||
820 | .reg_bits = 8, | ||
821 | .val_bits = 8, | ||
822 | .cache_type = REGCACHE_NONE, | ||
823 | }; | ||
824 | |||
825 | static int drv2605_probe(struct i2c_client* client, const struct i2c_device_id* id) | ||
826 | { | ||
827 | struct drv2605_data *pDrv2605data; | ||
828 | struct drv2605_platform_data *pDrv2605Platdata = client->dev.platform_data; | ||
829 | |||
830 | int err = 0; | ||
831 | int status = 0; | ||
832 | |||
833 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) | ||
834 | { | ||
835 | printk(KERN_ERR"%s:I2C check failed\n", __FUNCTION__); | ||
836 | return -ENODEV; | ||
837 | } | ||
838 | |||
839 | pDrv2605data = devm_kzalloc(&client->dev, sizeof(struct drv2605_data), GFP_KERNEL); | ||
840 | if (pDrv2605data == NULL){ | ||
841 | printk(KERN_ERR"%s:no memory\n", __FUNCTION__); | ||
842 | return -ENOMEM; | ||
843 | } | ||
844 | |||
845 | pDrv2605data->regmap = devm_regmap_init_i2c(client, &drv2605_i2c_regmap); | ||
846 | if (IS_ERR(pDrv2605data->regmap)) { | ||
847 | err = PTR_ERR(pDrv2605data->regmap); | ||
848 | printk(KERN_ERR"%s:Failed to allocate register map: %d\n",__FUNCTION__,err); | ||
849 | return err; | ||
850 | } | ||
851 | |||
852 | memcpy(&pDrv2605data->PlatData, pDrv2605Platdata, sizeof(struct drv2605_platform_data)); | ||
853 | i2c_set_clientdata(client,pDrv2605data); | ||
854 | |||
855 | if(pDrv2605data->PlatData.GpioTrigger){ | ||
856 | err = gpio_request(pDrv2605data->PlatData.GpioTrigger,HAPTICS_DEVICE_NAME"Trigger"); | ||
857 | if(err < 0){ | ||
858 | printk(KERN_ERR"%s: GPIO request Trigger error\n", __FUNCTION__); | ||
859 | goto exit_gpio_request_failed; | ||
860 | } | ||
861 | } | ||
862 | |||
863 | if(pDrv2605data->PlatData.GpioEnable){ | ||
864 | err = gpio_request(pDrv2605data->PlatData.GpioEnable,HAPTICS_DEVICE_NAME"Enable"); | ||
865 | if(err < 0){ | ||
866 | printk(KERN_ERR"%s: GPIO request enable error\n", __FUNCTION__); | ||
867 | goto exit_gpio_request_failed; | ||
868 | } | ||
869 | |||
870 | /* Enable power to the chip */ | ||
871 | gpio_direction_output(pDrv2605data->PlatData.GpioEnable, 1); | ||
872 | |||
873 | /* Wait 30 us */ | ||
874 | udelay(30); | ||
875 | } | ||
876 | |||
877 | err = drv2605_reg_read(pDrv2605data, STATUS_REG); | ||
878 | if(err < 0){ | ||
879 | printk("%s, i2c bus fail (%d)\n", __FUNCTION__, err); | ||
880 | goto exit_gpio_request_failed; | ||
881 | }else{ | ||
882 | printk("%s, i2c status (0x%x)\n", __FUNCTION__, err); | ||
883 | status = err; | ||
884 | } | ||
885 | /* Read device ID */ | ||
886 | pDrv2605data->device_id = (status & DEV_ID_MASK); | ||
887 | switch (pDrv2605data->device_id) | ||
888 | { | ||
889 | case DRV2605_VER_1DOT1: | ||
890 | printk("drv2605 driver found: drv2605 v1.1.\n"); | ||
891 | break; | ||
892 | case DRV2605_VER_1DOT0: | ||
893 | printk("drv2605 driver found: drv2605 v1.0.\n"); | ||
894 | break; | ||
895 | case DRV2604: | ||
896 | printk(KERN_ALERT"drv2605 driver found: drv2604.\n"); | ||
897 | break; | ||
898 | default: | ||
899 | printk(KERN_ERR"drv2605 driver found: unknown.\n"); | ||
900 | break; | ||
901 | } | ||
902 | |||
903 | if((pDrv2605data->device_id != DRV2605_VER_1DOT1) | ||
904 | &&(pDrv2605data->device_id != DRV2605_VER_1DOT0)){ | ||
905 | printk("%s, status(0x%x),device_id(%d) fail\n", | ||
906 | __FUNCTION__, status, pDrv2605data->device_id); | ||
907 | goto exit_gpio_request_failed; | ||
908 | } | ||
909 | |||
910 | drv2605_change_mode(pDrv2605data, WORK_IDLE, DEV_READY); | ||
911 | schedule_timeout_interruptible(msecs_to_jiffies(STANDBY_WAKE_DELAY)); | ||
912 | |||
913 | pDrv2605data->OTP = drv2605_reg_read(pDrv2605data, AUTOCAL_MEM_INTERFACE_REG) & AUTOCAL_MEM_INTERFACE_REG_OTP_MASK; | ||
914 | |||
915 | dev_init_platform_data(pDrv2605data); | ||
916 | |||
917 | if(pDrv2605data->OTP == 0){ | ||
918 | err = dev_auto_calibrate(pDrv2605data); | ||
919 | if(err < 0){ | ||
920 | printk("%s, ERROR, calibration fail\n", __FUNCTION__); | ||
921 | } | ||
922 | } | ||
923 | |||
924 | /* Put hardware in standby */ | ||
925 | drv2605_change_mode(pDrv2605data, WORK_IDLE, DEV_STANDBY); | ||
926 | |||
927 | Haptics_init(pDrv2605data); | ||
928 | |||
929 | pDRV2605data = pDrv2605data; | ||
930 | printk("drv2605 probe succeeded\n"); | ||
931 | |||
932 | return 0; | ||
933 | |||
934 | exit_gpio_request_failed: | ||
935 | if(pDrv2605data->PlatData.GpioTrigger){ | ||
936 | gpio_free(pDrv2605data->PlatData.GpioTrigger); | ||
937 | } | ||
938 | |||
939 | if(pDrv2605data->PlatData.GpioEnable){ | ||
940 | gpio_free(pDrv2605data->PlatData.GpioEnable); | ||
941 | } | ||
942 | |||
943 | printk(KERN_ERR"%s failed, err=%d\n",__FUNCTION__, err); | ||
944 | return err; | ||
945 | } | ||
946 | |||
947 | static int drv2605_remove(struct i2c_client* client) | ||
948 | { | ||
949 | struct drv2605_data *pDrv2605data = i2c_get_clientdata(client); | ||
950 | |||
951 | device_destroy(pDrv2605data->class, pDrv2605data->version); | ||
952 | class_destroy(pDrv2605data->class); | ||
953 | unregister_chrdev_region(pDrv2605data->version, 1); | ||
954 | |||
955 | if(pDrv2605data->PlatData.GpioTrigger) | ||
956 | gpio_free(pDrv2605data->PlatData.GpioTrigger); | ||
957 | |||
958 | if(pDrv2605data->PlatData.GpioEnable) | ||
959 | gpio_free(pDrv2605data->PlatData.GpioEnable); | ||
960 | |||
961 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
962 | unregister_early_suspend(&pDrv2605data->early_suspend); | ||
963 | #endif | ||
964 | |||
965 | printk(KERN_ALERT"drv2605 remove"); | ||
966 | |||
967 | return 0; | ||
968 | } | ||
969 | |||
970 | static struct i2c_device_id drv2605_id_table[] = | ||
971 | { | ||
972 | { HAPTICS_DEVICE_NAME, 0 }, | ||
973 | {} | ||
974 | }; | ||
975 | MODULE_DEVICE_TABLE(i2c, drv2605_id_table); | ||
976 | |||
977 | static struct i2c_driver drv2605_driver = | ||
978 | { | ||
979 | .driver = { | ||
980 | .name = HAPTICS_DEVICE_NAME, | ||
981 | .owner = THIS_MODULE, | ||
982 | }, | ||
983 | .id_table = drv2605_id_table, | ||
984 | .probe = drv2605_probe, | ||
985 | .remove = drv2605_remove, | ||
986 | }; | ||
987 | |||
988 | static int __init drv2605_init(void) | ||
989 | { | ||
990 | return i2c_add_driver(&drv2605_driver); | ||
991 | } | ||
992 | |||
993 | static void __exit drv2605_exit(void) | ||
994 | { | ||
995 | i2c_del_driver(&drv2605_driver); | ||
996 | } | ||
997 | |||
998 | module_init(drv2605_init); | ||
999 | module_exit(drv2605_exit); | ||
1000 | |||
1001 | MODULE_AUTHOR("Texas Instruments Inc."); | ||
1002 | MODULE_DESCRIPTION("Driver for "HAPTICS_DEVICE_NAME); \ No newline at end of file | ||
diff --git a/drv2605.c b/drv2605.c new file mode 100755 index 0000000..dd3308f --- /dev/null +++ b/drv2605.c | |||
@@ -0,0 +1,1306 @@ | |||
1 | /* | ||
2 | ** ============================================================================= | ||
3 | ** Copyright (c) 2016 Texas Instruments Inc. | ||
4 | ** | ||
5 | ** This program is free software; you can redistribute it and/or | ||
6 | ** modify it under the terms of the GNU General Public License | ||
7 | ** as published by the Free Software Foundation; either version 2 | ||
8 | ** of the License, or (at your option) any later version. | ||
9 | ** | ||
10 | ** This program is distributed in the hope that it will be useful, | ||
11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | ** GNU General Public License for more details. | ||
14 | ** | ||
15 | ** File: | ||
16 | ** drv2605.c | ||
17 | ** | ||
18 | ** Description: | ||
19 | ** DRV2605 chip driver | ||
20 | ** | ||
21 | ** ============================================================================= | ||
22 | */ | ||
23 | #define DEBUG | ||
24 | |||
25 | #include <linux/init.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/types.h> | ||
30 | #include <linux/fs.h> | ||
31 | #include <linux/i2c.h> | ||
32 | #include <linux/semaphore.h> | ||
33 | #include <linux/device.h> | ||
34 | #include <linux/syscalls.h> | ||
35 | #include <asm/uaccess.h> | ||
36 | #include <linux/gpio.h> | ||
37 | #include <linux/sched.h> | ||
38 | #include <linux/spinlock_types.h> | ||
39 | #include <linux/spinlock.h> | ||
40 | #include <linux/delay.h> | ||
41 | #include <linux/of.h> | ||
42 | #include <linux/of_gpio.h> | ||
43 | #include <linux/jiffies.h> | ||
44 | #include <linux/err.h> | ||
45 | #include <linux/clk.h> | ||
46 | #include <linux/miscdevice.h> | ||
47 | #include "drv2605.h" | ||
48 | |||
49 | static struct drv2605_data *g_DRV2605data = NULL; | ||
50 | static bool g_logEnable = false; | ||
51 | |||
52 | const char *TS2200EffectNameStr[] = { | ||
53 | "1 Strong Click - 100%", | ||
54 | "2 Strong Click - 60%", | ||
55 | "3 Strong Click - 30%", | ||
56 | "4 Sharp Click - 100%", | ||
57 | "5 Sharp Click - 60%", | ||
58 | "6 Sharp Click - 30%", | ||
59 | "7 Soft Bump - 100%", | ||
60 | "8 Soft Bump - 60%", | ||
61 | "9 Soft Bump - 30%", | ||
62 | "10 Double Click - 100%", | ||
63 | "11 Double Click - 60%", | ||
64 | "12 Triple Click - 100%", | ||
65 | "13 Soft Fuzz - 60%", | ||
66 | "14 Strong Buzz - 100%", | ||
67 | "15 750 ms Alert 100%", | ||
68 | "16 1000 ms Alert 100%", | ||
69 | "17 Strong Click 1 - 100%", | ||
70 | "18 Strong Click 2 - 80%", | ||
71 | "19 Strong Click 3 - 60%", | ||
72 | "20 Strong Click 4 - 30%", | ||
73 | "21 Medium Click 1 - 100%", | ||
74 | "22 Medium Click 2 - 80%", | ||
75 | "23 Medium Click 3 - 60%", | ||
76 | "24 Sharp Tick 1 - 100%", | ||
77 | "25 Sharp Tick 2 - 80%", | ||
78 | "26 Sharp Tick 3 – 60%", | ||
79 | "27 Short Double Click Strong 1 – 100%", | ||
80 | "28 Short Double Click Strong 2 – 80%", | ||
81 | "29 Short Double Click Strong 3 – 60%", | ||
82 | "30 Short Double Click Strong 4 – 30%", | ||
83 | "31 Short Double Click Medium 1 – 100%", | ||
84 | "32 Short Double Click Medium 2 – 80%", | ||
85 | "33 Short Double Click Medium 3 – 60%", | ||
86 | "34 Short Double Sharp Tick 1 – 100%", | ||
87 | "35 Short Double Sharp Tick 2 – 80%", | ||
88 | "36 Short Double Sharp Tick 3 – 60%", | ||
89 | "37 Long Double Sharp Click Strong 1 – 100%", | ||
90 | "38 Long Double Sharp Click Strong 2 – 80%", | ||
91 | "39 Long Double Sharp Click Strong 3 – 60%", | ||
92 | "40 Long Double Sharp Click Strong 4 – 30%", | ||
93 | "41 Long Double Sharp Click Medium 1 – 100%", | ||
94 | "42 Long Double Sharp Click Medium 2 – 80%", | ||
95 | "43 Long Double Sharp Click Medium 3 – 60%", | ||
96 | "44 Long Double Sharp Tick 1 – 100%", | ||
97 | "45 Long Double Sharp Tick 2 – 80%", | ||
98 | "46 Long Double Sharp Tick 3 – 60%", | ||
99 | "47 Buzz 1 – 100%", | ||
100 | "48 Buzz 2 – 80%", | ||
101 | "49 Buzz 3 – 60%", | ||
102 | "50 Buzz 4 – 40%", | ||
103 | "51 Buzz 5 – 20%", | ||
104 | "52 Pulsing Strong 1 – 100%", | ||
105 | "53 Pulsing Strong 2 – 60%", | ||
106 | "54 Pulsing Medium 1 – 100%", | ||
107 | "55 Pulsing Medium 2 – 60%", | ||
108 | "56 Pulsing Sharp 1 – 100%", | ||
109 | "57 Pulsing Sharp 2 – 60%", | ||
110 | "58 Transition Click 1 – 100%", | ||
111 | "59 Transition Click 2 – 80%", | ||
112 | "60 Transition Click 3 – 60%", | ||
113 | "61 Transition Click 4 – 40%", | ||
114 | "62 Transition Click 5 – 20%", | ||
115 | "63 Transition Click 6 – 10%", | ||
116 | "64 Transition Hum 1 – 100%", | ||
117 | "65 Transition Hum 2 – 80%", | ||
118 | "66 Transition Hum 3 – 60%", | ||
119 | "67 Transition Hum 4 – 40%", | ||
120 | "68 Transition Hum 5 – 20%", | ||
121 | "69 Transition Hum 6 – 10%", | ||
122 | "70 Transition Ramp Down Long Smooth 1 – 100 to 0%", | ||
123 | "71 Transition Ramp Down Long Smooth 2 – 100 to 0%", | ||
124 | "72 Transition Ramp Down Medium Smooth 1 – 100 to 0%", | ||
125 | "73 Transition Ramp Down Medium Smooth 2 – 100 to 0%", | ||
126 | "74 Transition Ramp Down Short Smooth 1 – 100 to 0%", | ||
127 | "75 Transition Ramp Down Short Smooth 2 – 100 to 0%", | ||
128 | "76 Transition Ramp Down Long Sharp 1 – 100 to 0%", | ||
129 | "77 Transition Ramp Down Long Sharp 2 – 100 to 0%", | ||
130 | "78 Transition Ramp Down Medium Sharp 1 – 100 to 0%", | ||
131 | "79 Transition Ramp Down Medium Sharp 2 – 100 to 0%", | ||
132 | "80 Transition Ramp Down Short Sharp 1 – 100 to 0%", | ||
133 | "81 Transition Ramp Down Short Sharp 2 – 100 to 0%", | ||
134 | "82 Transition Ramp Up Long Smooth 1 – 0 to 100%", | ||
135 | "83 Transition Ramp Up Long Smooth 2 – 0 to 100%", | ||
136 | "84 Transition Ramp Up Medium Smooth 1 – 0 to 100%", | ||
137 | "85 Transition Ramp Up Medium Smooth 2 – 0 to 100%", | ||
138 | "86 Transition Ramp Up Short Smooth 1 – 0 to 100%", | ||
139 | "87 Transition Ramp Up Short Smooth 2 – 0 to 100%", | ||
140 | "88 Transition Ramp Up Long Sharp 1 – 0 to 100%", | ||
141 | "89 Transition Ramp Up Long Sharp 2 – 0 to 100%", | ||
142 | "90 Transition Ramp Up Medium Sharp 1 – 0 to 100%", | ||
143 | "91 Transition Ramp Up Medium Sharp 2 – 0 to 100%", | ||
144 | "92 Transition Ramp Up Short Sharp 1 – 0 to 100%", | ||
145 | "93 Transition Ramp Up Short Sharp 2 – 0 to 100%", | ||
146 | "94 Transition Ramp Down Long Smooth 1 – 50 to 0%", | ||
147 | "95 Transition Ramp Down Long Smooth 2 – 50 to 0%", | ||
148 | "96 Transition Ramp Down Medium Smooth 1 – 50 to 0%", | ||
149 | "97 Transition Ramp Down Medium Smooth 2 – 50 to 0%", | ||
150 | "98 Transition Ramp Down Short Smooth 1 – 50 to 0%", | ||
151 | "99 Transition Ramp Down Short Smooth 2 – 50 to 0%", | ||
152 | "100 Transition Ramp Down Long Sharp 1 – 50 to 0%", | ||
153 | "101 Transition Ramp Down Long Sharp 2 – 50 to 0%", | ||
154 | "102 Transition Ramp Down Medium Sharp 1 – 50 to 0%", | ||
155 | "103 Transition Ramp Down Medium Sharp 2 – 50 to 0%", | ||
156 | "104 Transition Ramp Down Short Sharp 1 – 50 to 0%", | ||
157 | "105 Transition Ramp Down Short Sharp 2 – 50 to 0%", | ||
158 | "106 Transition Ramp Up Long Smooth 1 – 0 to 50%", | ||
159 | "107 Transition Ramp Up Long Smooth 2 – 0 to 50%", | ||
160 | "108 Transition Ramp Up Medium Smooth 1 – 0 to 50%", | ||
161 | "109 Transition Ramp Up Medium Smooth 2 – 0 to 50%", | ||
162 | "110 Transition Ramp Up Short Smooth 1 – 0 to 50%", | ||
163 | "111 Transition Ramp Up Short Smooth 2 – 0 to 50%", | ||
164 | "112 Transition Ramp Up Long Sharp 1 – 0 to 50%", | ||
165 | "113 Transition Ramp Up Long Sharp 2 – 0 to 50%", | ||
166 | "114 Transition Ramp Up Medium Sharp 1 – 0 to 50%", | ||
167 | "115 Transition Ramp Up Medium Sharp 2 – 0 to 50%", | ||
168 | "116 Transition Ramp Up Short Sharp 1 – 0 to 50%", | ||
169 | "117 Transition Ramp Up Short Sharp 2 – 0 to 50%", | ||
170 | "118 Long buzz for programmatic stopping – 100%", | ||
171 | "119 Smooth Hum 1 (No kick or brake pulse) – 50%", | ||
172 | "120 Smooth Hum 2 (No kick or brake pulse) – 40%", | ||
173 | "121 Smooth Hum 3 (No kick or brake pulse) – 30%", | ||
174 | "122 Smooth Hum 4 (No kick or brake pulse) – 20%", | ||
175 | "123 Smooth Hum 5 (No kick or brake pulse) – 10%" | ||
176 | }; | ||
177 | |||
178 | static int drv2605_reg_read(struct drv2605_data *pDRV2605, | ||
179 | unsigned char reg, unsigned char *pVal) | ||
180 | { | ||
181 | unsigned int val; | ||
182 | int nResult; | ||
183 | |||
184 | mutex_lock(&pDRV2605->dev_lock); | ||
185 | nResult = regmap_read(pDRV2605->mpRegmap, reg, &val); | ||
186 | if (nResult < 0) | ||
187 | dev_err(pDRV2605->dev, "%s I2C error %d\n", __func__, nResult); | ||
188 | else { | ||
189 | if (g_logEnable) | ||
190 | dev_dbg(pDRV2605->dev, "%s, Reg[0x%x]=0x%x\n", __func__, reg, val); | ||
191 | *pVal = (unsigned char)val; | ||
192 | } | ||
193 | mutex_unlock(&pDRV2605->dev_lock); | ||
194 | return nResult; | ||
195 | } | ||
196 | |||
197 | static int drv2605_reg_write(struct drv2605_data *pDRV2605, | ||
198 | unsigned char reg, unsigned char val) | ||
199 | { | ||
200 | int nResult; | ||
201 | |||
202 | mutex_lock(&pDRV2605->dev_lock); | ||
203 | nResult = regmap_write(pDRV2605->mpRegmap, reg, val); | ||
204 | if (nResult < 0) | ||
205 | dev_err(pDRV2605->dev, "%s reg=0x%x, value=0%x error %d\n", | ||
206 | __func__, reg, val, nResult); | ||
207 | else { | ||
208 | if (g_logEnable) | ||
209 | dev_dbg(pDRV2605->dev, "%s, Reg[0x%x]=0x%x\n", __func__, reg, val); | ||
210 | } | ||
211 | mutex_unlock(&pDRV2605->dev_lock); | ||
212 | return nResult; | ||
213 | } | ||
214 | |||
215 | static int drv2605_bulk_read(struct drv2605_data *pDRV2605, | ||
216 | unsigned char reg, unsigned char *buf, unsigned int count) | ||
217 | { | ||
218 | int nResult, i; | ||
219 | |||
220 | mutex_lock(&pDRV2605->dev_lock); | ||
221 | nResult = regmap_bulk_read(pDRV2605->mpRegmap, reg, buf, count); | ||
222 | if (nResult < 0) | ||
223 | dev_err(pDRV2605->dev, "%s reg=0%x, count=%d error %d\n", | ||
224 | __func__, reg, count, nResult); | ||
225 | else { | ||
226 | if (g_logEnable) { | ||
227 | for (i = 0; i < count; i++) | ||
228 | dev_dbg(pDRV2605->dev, "%s, Reg[0x%x]=0x%x\n", | ||
229 | __func__, reg + i, buf[i]); | ||
230 | } | ||
231 | } | ||
232 | mutex_unlock(&pDRV2605->dev_lock); | ||
233 | return nResult; | ||
234 | } | ||
235 | |||
236 | static int drv2605_bulk_write(struct drv2605_data *pDRV2605, | ||
237 | unsigned char reg, const u8 *buf, unsigned int count) | ||
238 | { | ||
239 | int nResult, i; | ||
240 | |||
241 | mutex_lock(&pDRV2605->dev_lock); | ||
242 | nResult = regmap_bulk_write(pDRV2605->mpRegmap, reg, buf, count); | ||
243 | if (nResult < 0) | ||
244 | dev_err(pDRV2605->dev, "%s reg=0%x, count=%d error %d\n", | ||
245 | __func__, reg, count, nResult); | ||
246 | else { | ||
247 | if (g_logEnable) | ||
248 | for (i = 0; i < count; i++) | ||
249 | dev_dbg(pDRV2605->dev, "%s, Reg[0x%x]=0x%x\n", | ||
250 | __func__, reg + i, buf[i]); | ||
251 | } | ||
252 | mutex_unlock(&pDRV2605->dev_lock); | ||
253 | return nResult; | ||
254 | } | ||
255 | |||
256 | static int drv2605_set_bits(struct drv2605_data *pDRV2605, | ||
257 | unsigned char reg, unsigned char mask, unsigned char val) | ||
258 | { | ||
259 | int nResult; | ||
260 | |||
261 | mutex_lock(&pDRV2605->dev_lock); | ||
262 | nResult = regmap_update_bits(pDRV2605->mpRegmap, reg, mask, val); | ||
263 | if (nResult < 0) | ||
264 | dev_err(pDRV2605->dev, "%s reg=%x, mask=0x%x, value=0x%x error %d\n", | ||
265 | __func__, reg, mask, val, nResult); | ||
266 | else { | ||
267 | if (g_logEnable) | ||
268 | dev_dbg(pDRV2605->dev, "%s, Reg[0x%x]:M=0x%x, V=0x%x\n", | ||
269 | __func__, reg, mask, val); | ||
270 | } | ||
271 | mutex_unlock(&pDRV2605->dev_lock); | ||
272 | return nResult; | ||
273 | } | ||
274 | |||
275 | static int drv2605_set_RTPStrength(struct drv2605_data *pDRV2605, char nStrength) | ||
276 | { | ||
277 | int nResult = 0; | ||
278 | |||
279 | nResult = drv2605_reg_write(pDRV2605, DRV2605_REG_RTP_INPUT, nStrength); | ||
280 | return nResult; | ||
281 | } | ||
282 | |||
283 | static int drv2605_set_devMode(struct drv2605_data *pDRV2605, | ||
284 | enum dev_mode mode) | ||
285 | { | ||
286 | int nResult = 0; | ||
287 | |||
288 | nResult = drv2605_reg_write(pDRV2605, DRV2605_REG_MODE, mode); | ||
289 | if (nResult >= 0) { | ||
290 | if (pDRV2605->mnDevMode == MODE_STANDBY) | ||
291 | mdelay(2); | ||
292 | pDRV2605->mnDevMode = mode; | ||
293 | if (pDRV2605->mnDevMode == MODE_STANDBY) | ||
294 | mdelay(2); | ||
295 | dev_dbg(pDRV2605->dev, "%s, mode=0x%x\n", __func__, mode); | ||
296 | } | ||
297 | |||
298 | return nResult; | ||
299 | } | ||
300 | |||
301 | static int drv2605_RTPStop(struct drv2605_data *pDRV2605) | ||
302 | { | ||
303 | int nResult = 0; | ||
304 | |||
305 | /* perform auto brake */ | ||
306 | nResult = drv2605_set_RTPStrength(pDRV2605, 0); | ||
307 | if (nResult >= 0) { | ||
308 | /* wait 20ms for the auto-brake to finish */ | ||
309 | msleep(20); | ||
310 | nResult = drv2605_set_devMode(pDRV2605, MODE_INTL_TRIG); | ||
311 | } | ||
312 | |||
313 | return nResult; | ||
314 | } | ||
315 | |||
316 | static int drv2605_set_go_bit(struct drv2605_data *pDRV2605, unsigned char val) | ||
317 | { | ||
318 | int nResult = 0; | ||
319 | unsigned char value = 0; | ||
320 | int retry = POLL_GO_BIT_RETRY; | ||
321 | |||
322 | val &= 0x01; | ||
323 | nResult = drv2605_reg_write(pDRV2605, DRV2605_REG_GO, val); | ||
324 | if (nResult < 0) | ||
325 | goto end; | ||
326 | |||
327 | mdelay(POLL_GO_BIT_INTERVAL); | ||
328 | nResult = drv2605_reg_read(pDRV2605, DRV2605_REG_GO, &value); | ||
329 | if (nResult < 0) | ||
330 | goto end; | ||
331 | |||
332 | if (val) { | ||
333 | if (value != GO) { | ||
334 | nResult = -EIO; | ||
335 | dev_warn(pDRV2605->dev, "%s, GO fail, stop action\n", __func__); | ||
336 | } | ||
337 | } else { | ||
338 | while (retry > 0) { | ||
339 | nResult = drv2605_reg_read(pDRV2605, DRV2605_REG_GO, &value); | ||
340 | if (nResult < 0) | ||
341 | break; | ||
342 | |||
343 | if(value==0) | ||
344 | break; | ||
345 | |||
346 | mdelay(POLL_GO_BIT_INTERVAL); | ||
347 | retry--; | ||
348 | } | ||
349 | |||
350 | if (retry == 0) | ||
351 | dev_err(pDRV2605->dev, | ||
352 | "%s, ERROR: clear GO fail\n", __func__); | ||
353 | else { | ||
354 | if (g_logEnable) | ||
355 | dev_dbg(pDRV2605->dev, | ||
356 | "%s, clear GO, remain=%d\n", __func__, retry); | ||
357 | } | ||
358 | } | ||
359 | |||
360 | end: | ||
361 | |||
362 | return nResult; | ||
363 | } | ||
364 | |||
365 | |||
366 | static int vibrator_get_time(struct timed_output_dev *dev) | ||
367 | { | ||
368 | struct drv2605_data *pDRV2605 = container_of(dev, struct drv2605_data, to_dev); | ||
369 | |||
370 | if (hrtimer_active(&pDRV2605->timer)) { | ||
371 | ktime_t r = hrtimer_get_remaining(&pDRV2605->timer); | ||
372 | return ktime_to_ms(r); | ||
373 | } | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static void drv2605_set_stopflag(struct drv2605_data *pDRV2605) | ||
379 | { | ||
380 | pDRV2605->mnVibratorPlaying = NO; | ||
381 | pDRV2605->mnWorkMode = WORK_IDLE; | ||
382 | wake_unlock(&pDRV2605->wklock); | ||
383 | if (g_logEnable) | ||
384 | dev_dbg(pDRV2605->dev, "wklock unlock"); | ||
385 | } | ||
386 | |||
387 | static int drv2605_get_diag_result(struct drv2605_data *pDRV2605, unsigned char nStatus) | ||
388 | { | ||
389 | int nResult = 0; | ||
390 | |||
391 | pDRV2605->mDiagResult.mnResult = nStatus; | ||
392 | if ((nStatus & DIAG_MASK) != DIAG_SUCCESS) | ||
393 | dev_err(pDRV2605->dev, "Diagnostic fail\n"); | ||
394 | |||
395 | return nResult; | ||
396 | } | ||
397 | |||
398 | static int drv2605_get_calibration_result(struct drv2605_data *pDRV2605, unsigned char nStatus) | ||
399 | { | ||
400 | int nResult = 0; | ||
401 | unsigned char value; | ||
402 | |||
403 | pDRV2605->mAutoCalResult.mnResult = nStatus; | ||
404 | if ((nStatus & DIAG_MASK) != DIAG_SUCCESS) | ||
405 | dev_err(pDRV2605->dev, "Calibration fail\n"); | ||
406 | else { | ||
407 | nResult = drv2605_reg_read(pDRV2605, DRV2605_REG_CAL_COMP, &value); | ||
408 | if (nResult < 0) | ||
409 | goto end; | ||
410 | pDRV2605->mAutoCalResult.mnCalComp = value; | ||
411 | |||
412 | nResult = drv2605_reg_read(pDRV2605, DRV2605_REG_CAL_BEMF, &value); | ||
413 | if (nResult < 0) | ||
414 | goto end; | ||
415 | pDRV2605->mAutoCalResult.mnCalBemf = value; | ||
416 | |||
417 | nResult = drv2605_reg_read(pDRV2605, DRV2605_REG_LOOP_CONTROL, &value) & BEMFGAIN_MASK; | ||
418 | if (nResult < 0) | ||
419 | goto end; | ||
420 | pDRV2605->mAutoCalResult.mnCalGain = value; | ||
421 | |||
422 | dev_dbg(pDRV2605->dev, "AutoCal : Comp=0x%x, Bemf=0x%x, Gain=0x%x\n", | ||
423 | pDRV2605->mAutoCalResult.mnCalComp, | ||
424 | pDRV2605->mAutoCalResult.mnCalBemf, | ||
425 | pDRV2605->mAutoCalResult.mnCalGain); | ||
426 | } | ||
427 | end: | ||
428 | return nResult; | ||
429 | } | ||
430 | |||
431 | static int drv2605_stop(struct drv2605_data *pDRV2605) | ||
432 | { | ||
433 | int nResult = 0; | ||
434 | |||
435 | if (pDRV2605->mnVibratorPlaying == YES) { | ||
436 | dev_dbg(pDRV2605->dev, "%s\n", __func__); | ||
437 | if (hrtimer_active(&pDRV2605->timer)) | ||
438 | hrtimer_cancel(&pDRV2605->timer); | ||
439 | if (pDRV2605->mnWorkMode == WORK_RTP) | ||
440 | nResult = drv2605_RTPStop(pDRV2605); | ||
441 | else | ||
442 | nResult = drv2605_set_go_bit(pDRV2605, STOP); | ||
443 | |||
444 | drv2605_set_stopflag(pDRV2605); | ||
445 | } | ||
446 | |||
447 | return nResult; | ||
448 | } | ||
449 | |||
450 | static void vibrator_enable( struct timed_output_dev *dev, int value) | ||
451 | { | ||
452 | int nResult = 0; | ||
453 | struct drv2605_data *pDRV2605 = | ||
454 | container_of(dev, struct drv2605_data, to_dev); | ||
455 | |||
456 | dev_dbg(pDRV2605->dev, "%s, value=%d\n", __func__, value); | ||
457 | |||
458 | mutex_lock(&pDRV2605->lock); | ||
459 | |||
460 | nResult = drv2605_stop(pDRV2605); | ||
461 | if (nResult < 0) | ||
462 | goto exit; | ||
463 | |||
464 | if (value > 0) { | ||
465 | wake_lock(&pDRV2605->wklock); | ||
466 | if (g_logEnable) | ||
467 | dev_dbg(pDRV2605->dev, "wklock lock"); | ||
468 | |||
469 | nResult = drv2605_set_devMode(pDRV2605, MODE_INTL_TRIG); | ||
470 | if (nResult < 0) | ||
471 | goto end; | ||
472 | nResult = drv2605_set_RTPStrength(pDRV2605, 0x7f); | ||
473 | if (nResult < 0) | ||
474 | goto end; | ||
475 | nResult = drv2605_set_devMode(pDRV2605, MODE_RTP); | ||
476 | if (nResult >= 0) { | ||
477 | value = (value > MAX_TIMEOUT) ? MAX_TIMEOUT : value; | ||
478 | hrtimer_start(&pDRV2605->timer, | ||
479 | ns_to_ktime((u64)value * NSEC_PER_MSEC), HRTIMER_MODE_REL); | ||
480 | pDRV2605->mnVibratorPlaying = YES; | ||
481 | pDRV2605->mnWorkMode = WORK_RTP; | ||
482 | } | ||
483 | } else { | ||
484 | nResult = drv2605_set_devMode(pDRV2605, MODE_STANDBY); | ||
485 | if (nResult < 0) | ||
486 | goto exit; | ||
487 | } | ||
488 | |||
489 | end: | ||
490 | if (nResult < 0) { | ||
491 | nResult = drv2605_set_devMode(pDRV2605, MODE_STANDBY); | ||
492 | wake_unlock(&pDRV2605->wklock); | ||
493 | if (g_logEnable) | ||
494 | dev_dbg(pDRV2605->dev, "wklock unlock"); | ||
495 | } | ||
496 | exit: | ||
497 | mutex_unlock(&pDRV2605->lock); | ||
498 | } | ||
499 | |||
500 | static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer) | ||
501 | { | ||
502 | struct drv2605_data *pDRV2605 = | ||
503 | container_of(timer, struct drv2605_data, timer); | ||
504 | |||
505 | dev_dbg(pDRV2605->dev, "%s\n", __func__); | ||
506 | schedule_work(&pDRV2605->vibrator_work); | ||
507 | return HRTIMER_NORESTART; | ||
508 | } | ||
509 | |||
510 | static void vibrator_work_routine(struct work_struct *work) | ||
511 | { | ||
512 | struct drv2605_data *pDRV2605 = | ||
513 | container_of(work, struct drv2605_data, vibrator_work); | ||
514 | unsigned char status, GOStatus; | ||
515 | int nResult = 0; | ||
516 | |||
517 | mutex_lock(&pDRV2605->lock); | ||
518 | |||
519 | if (g_logEnable) | ||
520 | dev_dbg(pDRV2605->dev, "%s, afer mnWorkMode=0x%x\n", | ||
521 | __func__, pDRV2605->mnWorkMode); | ||
522 | |||
523 | if (pDRV2605->mnVibratorPlaying == YES) { | ||
524 | dev_dbg(pDRV2605->dev, "%s\n", __func__); | ||
525 | if (pDRV2605->mnWorkMode == WORK_RTP) { | ||
526 | nResult = drv2605_RTPStop(pDRV2605); | ||
527 | goto standby; | ||
528 | } else if ((pDRV2605->mnWorkMode == WORK_CALIBRATION) | ||
529 | || (pDRV2605->mnWorkMode == WORK_DIAGNOSTIC) | ||
530 | || (pDRV2605->mnWorkMode == WORK_SEQER)) { | ||
531 | nResult = drv2605_reg_read(pDRV2605, DRV2605_REG_GO, &GOStatus); | ||
532 | if (nResult < 0) | ||
533 | goto standby; | ||
534 | if ((GOStatus & 0x01) == STOP) { | ||
535 | if (pDRV2605->mnWorkMode == WORK_SEQER) | ||
536 | goto standby; | ||
537 | nResult = drv2605_reg_read(pDRV2605, DRV2605_REG_STATUS, &status); | ||
538 | if (nResult < 0) | ||
539 | goto standby; | ||
540 | if (pDRV2605->mnWorkMode == WORK_CALIBRATION) | ||
541 | nResult = drv2605_get_calibration_result(pDRV2605, status); | ||
542 | else if (pDRV2605->mnWorkMode == WORK_DIAGNOSTIC) | ||
543 | nResult = drv2605_get_diag_result(pDRV2605, status); | ||
544 | } else { | ||
545 | if (!hrtimer_active(&pDRV2605->timer)) { | ||
546 | if (g_logEnable) | ||
547 | dev_dbg(pDRV2605->dev, "will check GO bit after %d ms\n", POLL_STATUS_INTERVAL); | ||
548 | hrtimer_start(&pDRV2605->timer, | ||
549 | ns_to_ktime((u64)POLL_STATUS_INTERVAL * NSEC_PER_MSEC), HRTIMER_MODE_REL); | ||
550 | } | ||
551 | goto exit; | ||
552 | } | ||
553 | } | ||
554 | } | ||
555 | |||
556 | standby: | ||
557 | drv2605_set_devMode(pDRV2605, MODE_STANDBY); | ||
558 | drv2605_set_stopflag(pDRV2605); | ||
559 | exit: | ||
560 | mutex_unlock(&pDRV2605->lock); | ||
561 | } | ||
562 | |||
563 | static int dev_auto_calibrate(struct drv2605_data *pDRV2605) | ||
564 | { | ||
565 | int nResult = 0; | ||
566 | |||
567 | dev_info(pDRV2605->dev, "%s\n", __func__); | ||
568 | wake_lock(&pDRV2605->wklock); | ||
569 | if (g_logEnable) | ||
570 | dev_dbg(pDRV2605->dev, "wklock lock"); | ||
571 | |||
572 | nResult = drv2605_set_devMode(pDRV2605, MODE_INTL_TRIG); | ||
573 | if (nResult < 0) | ||
574 | goto end; | ||
575 | |||
576 | nResult = drv2605_set_devMode(pDRV2605, MODE_CALIBRATION); | ||
577 | if (nResult < 0) | ||
578 | goto end; | ||
579 | |||
580 | nResult = drv2605_set_go_bit(pDRV2605, GO); | ||
581 | if (nResult < 0) | ||
582 | goto end; | ||
583 | |||
584 | dev_dbg(pDRV2605->dev, "calibration start\n"); | ||
585 | pDRV2605->mnVibratorPlaying = YES; | ||
586 | pDRV2605->mnWorkMode = WORK_CALIBRATION; | ||
587 | schedule_work(&pDRV2605->vibrator_work); | ||
588 | |||
589 | end: | ||
590 | if (nResult < 0) { | ||
591 | nResult = drv2605_set_devMode(pDRV2605, MODE_STANDBY); | ||
592 | wake_unlock(&pDRV2605->wklock); | ||
593 | if (g_logEnable) | ||
594 | dev_dbg(pDRV2605->dev, "wklock unlock"); | ||
595 | } | ||
596 | return nResult; | ||
597 | } | ||
598 | |||
599 | static int dev_run_diagnostics(struct drv2605_data *pDRV2605) | ||
600 | { | ||
601 | int nResult = 0; | ||
602 | |||
603 | dev_info(pDRV2605->dev, "%s\n", __func__); | ||
604 | wake_lock(&pDRV2605->wklock); | ||
605 | if (g_logEnable) | ||
606 | dev_dbg(pDRV2605->dev, "wklock lock"); | ||
607 | |||
608 | nResult = drv2605_set_devMode(pDRV2605, MODE_INTL_TRIG); | ||
609 | if (nResult < 0) | ||
610 | goto end; | ||
611 | |||
612 | nResult = drv2605_set_devMode(pDRV2605, MODE_DIAG); | ||
613 | if (nResult < 0) | ||
614 | goto end; | ||
615 | |||
616 | nResult = drv2605_set_go_bit(pDRV2605, GO); | ||
617 | if (nResult < 0) | ||
618 | goto end; | ||
619 | |||
620 | dev_dbg(pDRV2605->dev, "Diag start\n"); | ||
621 | pDRV2605->mnVibratorPlaying = YES; | ||
622 | pDRV2605->mnWorkMode = WORK_DIAGNOSTIC; | ||
623 | schedule_work(&pDRV2605->vibrator_work); | ||
624 | |||
625 | end: | ||
626 | if (nResult < 0) { | ||
627 | nResult = drv2605_set_devMode(pDRV2605, MODE_STANDBY); | ||
628 | wake_unlock(&pDRV2605->wklock); | ||
629 | if (g_logEnable) | ||
630 | dev_dbg(pDRV2605->dev, "wklock unlock"); | ||
631 | } | ||
632 | return nResult; | ||
633 | } | ||
634 | |||
635 | static int drv2605_playEffect(struct drv2605_data *pDRV2605) | ||
636 | { | ||
637 | int nResult = 0; | ||
638 | |||
639 | dev_info(pDRV2605->dev, "%s\n", __func__); | ||
640 | wake_lock(&pDRV2605->wklock); | ||
641 | if (g_logEnable) | ||
642 | dev_dbg(pDRV2605->dev, "wklock lock"); | ||
643 | |||
644 | nResult = drv2605_set_devMode(pDRV2605, MODE_INTL_TRIG); | ||
645 | if (nResult < 0) | ||
646 | goto end; | ||
647 | |||
648 | nResult = drv2605_set_go_bit(pDRV2605, GO); | ||
649 | if (nResult < 0) | ||
650 | goto end; | ||
651 | |||
652 | dev_dbg(pDRV2605->dev, "effects start\n"); | ||
653 | pDRV2605->mnVibratorPlaying = YES; | ||
654 | pDRV2605->mnWorkMode = WORK_SEQER; | ||
655 | schedule_work(&pDRV2605->vibrator_work); | ||
656 | |||
657 | end: | ||
658 | if (nResult < 0) { | ||
659 | nResult = drv2605_set_devMode(pDRV2605, MODE_STANDBY); | ||
660 | wake_unlock(&pDRV2605->wklock); | ||
661 | dev_dbg(pDRV2605->dev, "wklock unlock"); | ||
662 | } | ||
663 | return nResult; | ||
664 | } | ||
665 | |||
666 | static int drv2605_set_waveform(struct drv2605_data *pDRV2605, | ||
667 | struct drv2605_waveform_sequencer *pSequencer) | ||
668 | { | ||
669 | int nResult = 0; | ||
670 | int i = 0; | ||
671 | unsigned char effects[DRV2605_SEQUENCER_SIZE] = {0}; | ||
672 | unsigned char len = 0; | ||
673 | |||
674 | for (i = 0; i < DRV2605_SEQUENCER_SIZE; i++) { | ||
675 | if (pSequencer->msWaveform[i].mnEffect != 0) { | ||
676 | effects[i] = pSequencer->msWaveform[i].mnEffect; | ||
677 | if (effects[i] <= 123) | ||
678 | dev_dbg(pDRV2605->dev, "[%d] %s\n", i, TS2200EffectNameStr[effects[i] - 1]); | ||
679 | else if (effects[i] >= 0x80) | ||
680 | dev_dbg(pDRV2605->dev, "[%d] Delay %d ms\n", i, (effects[i] & 0x7f) * 10); | ||
681 | else { | ||
682 | dev_err(pDRV2605->dev, "[%d] invalid %d effect index\n", i, effects[i]); | ||
683 | goto end; | ||
684 | } | ||
685 | } else | ||
686 | break; | ||
687 | |||
688 | len ++; | ||
689 | } | ||
690 | |||
691 | if (len == 0) | ||
692 | nResult = drv2605_reg_write(pDRV2605, DRV2605_REG_SEQUENCER_1, 0); | ||
693 | else { | ||
694 | len = (len < 8) ? (len + 1) : 8; | ||
695 | nResult = drv2605_bulk_write(pDRV2605, DRV2605_REG_SEQUENCER_1, effects, len); | ||
696 | } | ||
697 | |||
698 | if (nResult < 0) { | ||
699 | dev_err(pDRV2605->dev, "sequence error\n"); | ||
700 | } | ||
701 | |||
702 | end: | ||
703 | |||
704 | return nResult; | ||
705 | } | ||
706 | |||
707 | static int drv2605_file_open(struct inode *inode, struct file *file) | ||
708 | { | ||
709 | if (!try_module_get(THIS_MODULE)) | ||
710 | return -ENODEV; | ||
711 | |||
712 | file->private_data = (void*)g_DRV2605data; | ||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | static int drv2605_file_release(struct inode *inode, struct file *file) | ||
717 | { | ||
718 | file->private_data = (void*)NULL; | ||
719 | module_put(THIS_MODULE); | ||
720 | return 0; | ||
721 | } | ||
722 | |||
723 | static long drv2605_file_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
724 | { | ||
725 | struct drv2605_data *pDRV2605 = file->private_data; | ||
726 | //void __user *user_arg = (void __user *)arg; | ||
727 | int nResult = 0; | ||
728 | |||
729 | mutex_lock(&pDRV2605->lock); | ||
730 | |||
731 | dev_dbg(pDRV2605->dev, "ioctl 0x%x\n", cmd); | ||
732 | |||
733 | switch (cmd) { | ||
734 | |||
735 | } | ||
736 | |||
737 | mutex_unlock(&pDRV2605->lock); | ||
738 | |||
739 | return nResult; | ||
740 | } | ||
741 | |||
742 | static ssize_t drv2605_file_read(struct file* filp, char* buff, size_t length, loff_t* offset) | ||
743 | { | ||
744 | struct drv2605_data *pDRV2605 = (struct drv2605_data *)filp->private_data; | ||
745 | int nResult = 0; | ||
746 | unsigned char value = 0; | ||
747 | unsigned char *p_kBuf = NULL; | ||
748 | |||
749 | mutex_lock(&pDRV2605->lock); | ||
750 | |||
751 | switch (pDRV2605->mnFileCmd) { | ||
752 | case HAPTIC_CMDID_REG_READ: | ||
753 | if (length == 1) { | ||
754 | nResult = drv2605_reg_read(pDRV2605, pDRV2605->mnCurrentReg, &value); | ||
755 | if (nResult >= 0) { | ||
756 | nResult = copy_to_user(buff, &value, 1); | ||
757 | if (0 != nResult) { | ||
758 | /* Failed to copy all the data, exit */ | ||
759 | dev_err(pDRV2605->dev, "copy to user fail %d\n", nResult); | ||
760 | } | ||
761 | } | ||
762 | } else if (length > 1) { | ||
763 | p_kBuf = (unsigned char *)kzalloc(length, GFP_KERNEL); | ||
764 | if (p_kBuf != NULL) { | ||
765 | nResult = drv2605_bulk_read(pDRV2605, | ||
766 | pDRV2605->mnCurrentReg, p_kBuf, length); | ||
767 | if (nResult >= 0) { | ||
768 | nResult = copy_to_user(buff, p_kBuf, length); | ||
769 | if (0 != nResult) { | ||
770 | /* Failed to copy all the data, exit */ | ||
771 | dev_err(pDRV2605->dev, "copy to user fail %d\n", nResult); | ||
772 | } | ||
773 | } | ||
774 | |||
775 | kfree(p_kBuf); | ||
776 | } else { | ||
777 | dev_err(pDRV2605->dev, "read no mem\n"); | ||
778 | nResult = -ENOMEM; | ||
779 | } | ||
780 | } | ||
781 | break; | ||
782 | |||
783 | case HAPTIC_CMDID_RUN_DIAG: | ||
784 | if (pDRV2605->mnVibratorPlaying) | ||
785 | length = 0; | ||
786 | else { | ||
787 | unsigned char buf[3]; | ||
788 | buf[0] = pDRV2605->mDiagResult.mnResult; | ||
789 | nResult = copy_to_user(buff, buf, 1); | ||
790 | if (0 != nResult) { | ||
791 | /* Failed to copy all the data, exit */ | ||
792 | dev_err(pDRV2605->dev, "copy to user fail %d\n", nResult); | ||
793 | } | ||
794 | } | ||
795 | break; | ||
796 | |||
797 | case HAPTIC_CMDID_RUN_CALIBRATION: | ||
798 | if (pDRV2605->mnVibratorPlaying) | ||
799 | length = 0; | ||
800 | else { | ||
801 | unsigned char buf[4]; | ||
802 | |||
803 | buf[0] = pDRV2605->mAutoCalResult.mnResult; | ||
804 | buf[1] = pDRV2605->mAutoCalResult.mnCalComp; | ||
805 | buf[2] = pDRV2605->mAutoCalResult.mnCalBemf; | ||
806 | buf[3] = pDRV2605->mAutoCalResult.mnCalGain; | ||
807 | nResult = copy_to_user(buff, buf, 4); | ||
808 | if (0 != nResult) { | ||
809 | /* Failed to copy all the data, exit */ | ||
810 | dev_err(pDRV2605->dev, "copy to user fail %d\n", nResult); | ||
811 | } | ||
812 | } | ||
813 | break; | ||
814 | |||
815 | case HAPTIC_CMDID_SET_SEQUENCER: | ||
816 | if (length == sizeof(struct drv2605_waveform_sequencer)) { | ||
817 | struct drv2605_waveform_sequencer sequencer; | ||
818 | unsigned char effects[DRV2605_SEQUENCER_SIZE] = {0}; | ||
819 | int i = 0; | ||
820 | |||
821 | nResult = drv2605_bulk_read(pDRV2605, DRV2605_REG_SEQUENCER_1, | ||
822 | effects, DRV2605_SEQUENCER_SIZE); | ||
823 | if (nResult < 0) | ||
824 | break; | ||
825 | |||
826 | for(i = 0; i < DRV2605_SEQUENCER_SIZE; i++) { | ||
827 | if (effects[i] != 0) | ||
828 | sequencer.msWaveform[i].mnEffect = effects[i]; | ||
829 | else | ||
830 | break; | ||
831 | } | ||
832 | |||
833 | nResult = copy_to_user(buff, &sequencer, length); | ||
834 | if (0 != nResult) { | ||
835 | /* Failed to copy all the data, exit */ | ||
836 | dev_err(pDRV2605->dev, "copy to user fail %d\n", nResult); | ||
837 | } | ||
838 | } | ||
839 | break; | ||
840 | |||
841 | case HAPTIC_CMDID_REGLOG_ENABLE: | ||
842 | if (length == 1) { | ||
843 | nResult = copy_to_user(buff, &g_logEnable, 1); | ||
844 | if (0 != nResult) { | ||
845 | /* Failed to copy all the data, exit */ | ||
846 | dev_err(pDRV2605->dev, "copy to user fail %d\n", nResult); | ||
847 | } | ||
848 | } | ||
849 | break; | ||
850 | |||
851 | default: | ||
852 | pDRV2605->mnFileCmd = 0; | ||
853 | break; | ||
854 | } | ||
855 | |||
856 | mutex_unlock(&pDRV2605->lock); | ||
857 | |||
858 | return length; | ||
859 | } | ||
860 | |||
861 | static ssize_t drv2605_file_write(struct file* filp, const char* buff, size_t len, loff_t* off) | ||
862 | { | ||
863 | struct drv2605_data *pDRV2605 = (struct drv2605_data *)filp->private_data; | ||
864 | unsigned char *p_kBuf = NULL; | ||
865 | int nResult = 0; | ||
866 | |||
867 | mutex_lock(&pDRV2605->lock); | ||
868 | |||
869 | p_kBuf = (unsigned char *)kzalloc(len, GFP_KERNEL); | ||
870 | if (p_kBuf == NULL) { | ||
871 | dev_err(pDRV2605->dev, "write no mem\n"); | ||
872 | goto err; | ||
873 | } | ||
874 | |||
875 | nResult = copy_from_user(p_kBuf, buff, len); | ||
876 | if (0 != nResult) { | ||
877 | dev_err(pDRV2605->dev,"copy_from_user failed.\n"); | ||
878 | goto err; | ||
879 | } | ||
880 | |||
881 | pDRV2605->mnFileCmd = p_kBuf[0]; | ||
882 | |||
883 | switch(pDRV2605->mnFileCmd) { | ||
884 | case HAPTIC_CMDID_REG_READ: | ||
885 | if (len == 2) | ||
886 | pDRV2605->mnCurrentReg = p_kBuf[1]; | ||
887 | else | ||
888 | dev_err(pDRV2605->dev, " read cmd len %d err\n", len); | ||
889 | break; | ||
890 | |||
891 | case HAPTIC_CMDID_REG_WRITE: | ||
892 | if ((len - 1) == 2) | ||
893 | nResult = drv2605_reg_write(pDRV2605, p_kBuf[1], p_kBuf[2]); | ||
894 | else if ((len - 1) > 2) | ||
895 | nResult = drv2605_bulk_write(pDRV2605, p_kBuf[1], &p_kBuf[2], len - 2); | ||
896 | else | ||
897 | dev_err(pDRV2605->dev, "%s, reg_write len %d error\n", __func__, len); | ||
898 | break; | ||
899 | |||
900 | case HAPTIC_CMDID_REG_SETBIT: | ||
901 | if (len == 4) | ||
902 | nResult = drv2605_set_bits(pDRV2605, p_kBuf[1], p_kBuf[2], p_kBuf[3]); | ||
903 | else | ||
904 | dev_err(pDRV2605->dev, "setbit len %d error\n", len); | ||
905 | break; | ||
906 | |||
907 | case HAPTIC_CMDID_RUN_DIAG: | ||
908 | nResult = drv2605_stop(pDRV2605); | ||
909 | if (nResult < 0) | ||
910 | break; | ||
911 | nResult = dev_run_diagnostics(pDRV2605); | ||
912 | break; | ||
913 | |||
914 | case HAPTIC_CMDID_RUN_CALIBRATION: | ||
915 | nResult = drv2605_stop(pDRV2605); | ||
916 | if (nResult < 0) | ||
917 | break; | ||
918 | nResult = dev_auto_calibrate(pDRV2605); | ||
919 | break; | ||
920 | |||
921 | case HAPTIC_CMDID_SET_SEQUENCER: | ||
922 | if (len == (1 + sizeof(struct drv2605_waveform_sequencer))) { | ||
923 | struct drv2605_waveform_sequencer sequencer; | ||
924 | |||
925 | memcpy(&sequencer, &p_kBuf[1], sizeof(struct drv2605_waveform_sequencer)); | ||
926 | nResult = drv2605_set_waveform(pDRV2605, &sequencer); | ||
927 | } else | ||
928 | dev_dbg(pDRV2605->dev, "pass cmd, prepare for read\n"); | ||
929 | break; | ||
930 | |||
931 | case HAPTIC_CMDID_PLAY_EFFECT_SEQUENCE: | ||
932 | nResult = drv2605_stop(pDRV2605); | ||
933 | if (nResult < 0) | ||
934 | break; | ||
935 | nResult = drv2605_playEffect(pDRV2605); | ||
936 | break; | ||
937 | |||
938 | case HAPTIC_CMDID_STOP: | ||
939 | nResult = drv2605_stop(pDRV2605); | ||
940 | break; | ||
941 | |||
942 | case HAPTIC_CMDID_REGLOG_ENABLE: | ||
943 | if (len == 2) | ||
944 | g_logEnable = p_kBuf[1]; | ||
945 | break; | ||
946 | |||
947 | default: | ||
948 | dev_err(pDRV2605->dev, "%s, unknown cmd\n", __func__); | ||
949 | break; | ||
950 | } | ||
951 | |||
952 | err: | ||
953 | if (p_kBuf != NULL) | ||
954 | kfree(p_kBuf); | ||
955 | |||
956 | mutex_unlock(&pDRV2605->lock); | ||
957 | |||
958 | return len; | ||
959 | } | ||
960 | |||
961 | static struct file_operations fops = | ||
962 | { | ||
963 | .owner = THIS_MODULE, | ||
964 | .read = drv2605_file_read, | ||
965 | .write = drv2605_file_write, | ||
966 | .unlocked_ioctl = drv2605_file_unlocked_ioctl, | ||
967 | .open = drv2605_file_open, | ||
968 | .release = drv2605_file_release, | ||
969 | }; | ||
970 | |||
971 | static struct miscdevice drv2605_misc = | ||
972 | { | ||
973 | .minor = MISC_DYNAMIC_MINOR, | ||
974 | .name = HAPTICS_DEVICE_NAME, | ||
975 | .fops = &fops, | ||
976 | }; | ||
977 | |||
978 | static int Haptics_init(struct drv2605_data *pDRV2605) | ||
979 | { | ||
980 | int nResult = 0; | ||
981 | |||
982 | pDRV2605->to_dev.name = "vibrator"; | ||
983 | pDRV2605->to_dev.get_time = vibrator_get_time; | ||
984 | pDRV2605->to_dev.enable = vibrator_enable; | ||
985 | |||
986 | nResult = timed_output_dev_register(&(pDRV2605->to_dev)); | ||
987 | if (nResult < 0) { | ||
988 | dev_err(pDRV2605->dev, "drv2605: fail to create timed output dev\n"); | ||
989 | return nResult; | ||
990 | } | ||
991 | |||
992 | nResult = misc_register(&drv2605_misc); | ||
993 | if (nResult) { | ||
994 | dev_err(pDRV2605->dev, "drv2605 misc fail: %d\n", nResult); | ||
995 | return nResult; | ||
996 | } | ||
997 | |||
998 | hrtimer_init(&pDRV2605->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
999 | pDRV2605->timer.function = vibrator_timer_func; | ||
1000 | INIT_WORK(&pDRV2605->vibrator_work, vibrator_work_routine); | ||
1001 | |||
1002 | wake_lock_init(&pDRV2605->wklock, WAKE_LOCK_SUSPEND, "vibrator"); | ||
1003 | mutex_init(&pDRV2605->lock); | ||
1004 | |||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
1008 | static int dev_init_platform_data(struct drv2605_data *pDRV2605) | ||
1009 | { | ||
1010 | struct drv2605_platform_data *pDrv2605Platdata = &pDRV2605->msPlatData; | ||
1011 | struct actuator_data actuator = pDrv2605Platdata->msActuator; | ||
1012 | int nResult = 0; | ||
1013 | |||
1014 | nResult = drv2605_set_devMode(pDRV2605, MODE_INTL_TRIG); | ||
1015 | if (nResult < 0) | ||
1016 | goto end; | ||
1017 | |||
1018 | if (actuator.mnActuatorType == ERM) { | ||
1019 | nResult = drv2605_set_bits(pDRV2605, DRV2605_REG_LOOP_CONTROL, 0x80, 0x00); | ||
1020 | if (pDrv2605Platdata->mnLoop == CLOSE_LOOP) | ||
1021 | nResult = drv2605_set_bits(pDRV2605, DRV2605_REG_CONTROL3, 0x20, 0x00); | ||
1022 | else if (pDrv2605Platdata->mnLoop == OPEN_LOOP) | ||
1023 | nResult = drv2605_set_bits(pDRV2605, DRV2605_REG_CONTROL3, 0x20, 0x20); | ||
1024 | nResult = drv2605_reg_write(pDRV2605, DRV2605_REG_LIBSEL, actuator.mnEffectLib); | ||
1025 | } else if (actuator.mnActuatorType == LRA) { | ||
1026 | nResult = drv2605_set_bits(pDRV2605, DRV2605_REG_LOOP_CONTROL, 0x80, 0x80); | ||
1027 | if (pDrv2605Platdata->mnLoop == CLOSE_LOOP) { | ||
1028 | nResult = drv2605_set_bits(pDRV2605, DRV2605_REG_CONTROL3, 0x01, 0x00); | ||
1029 | nResult = drv2605_reg_write(pDRV2605, DRV2605_REG_LIBSEL, 0x06); | ||
1030 | } else if (pDrv2605Platdata->mnLoop == OPEN_LOOP) | ||
1031 | nResult = drv2605_set_bits(pDRV2605, DRV2605_REG_CONTROL3, 0x01, 0x01); | ||
1032 | } | ||
1033 | |||
1034 | if (actuator.mnRatedVoltage != 0) | ||
1035 | drv2605_reg_write(pDRV2605, DRV2605_REG_RATED_VOLTAGE, actuator.mnRatedVoltage); | ||
1036 | else | ||
1037 | dev_err(pDRV2605->dev, "%s, ERROR Rated ZERO\n", __func__); | ||
1038 | |||
1039 | if (actuator.mnOverDriveClampVoltage != 0) | ||
1040 | drv2605_reg_write(pDRV2605, DRV2605_REG_OVERDRIVE_CLAMP, actuator.mnOverDriveClampVoltage); | ||
1041 | else | ||
1042 | dev_err(pDRV2605->dev,"%s, ERROR OverDriveVol ZERO\n", __func__); | ||
1043 | |||
1044 | if (actuator.mnActuatorType == LRA) { | ||
1045 | unsigned char DriveTime = 5 * (1000 - actuator.mnLRAFreq) / actuator.mnLRAFreq; | ||
1046 | nResult = drv2605_set_bits(pDRV2605, DRV2605_REG_DRIVE_TIME, | ||
1047 | DRIVE_TIME_MASK, DriveTime); | ||
1048 | |||
1049 | dev_info(pDRV2605->dev, "%s, LRA = %d, DriveTime=0x%x\n", | ||
1050 | __func__, actuator.mnLRAFreq, DriveTime); | ||
1051 | } | ||
1052 | |||
1053 | end: | ||
1054 | return nResult; | ||
1055 | } | ||
1056 | |||
1057 | static int drv2605_parse_dt(struct device *dev, struct drv2605_data *pDRV2605) | ||
1058 | { | ||
1059 | struct device_node *np = dev->of_node; | ||
1060 | struct drv2605_platform_data *pPlatData = &pDRV2605->msPlatData; | ||
1061 | int rc= 0, nResult = 0; | ||
1062 | unsigned int value; | ||
1063 | |||
1064 | pPlatData->mnGpioEN = of_get_named_gpio(np, "ti,enable-gpio", 0); | ||
1065 | if (pPlatData->mnGpioEN < 0) { | ||
1066 | dev_err(pDRV2605->dev, "Looking up %s property in node %s failed %d\n", | ||
1067 | "ti,enable-gpio", np->full_name, pPlatData->mnGpioEN); | ||
1068 | nResult = -EINVAL; | ||
1069 | } else | ||
1070 | dev_dbg(pDRV2605->dev, "ti,reset-gpio=%d\n", pPlatData->mnGpioEN); | ||
1071 | |||
1072 | if (nResult >= 0) { | ||
1073 | rc = of_property_read_u32(np, "ti,smart-loop", &value); | ||
1074 | if (rc) { | ||
1075 | dev_err(pDRV2605->dev, "Looking up %s property in node %s failed %d\n", | ||
1076 | "ti,smart-loop", np->full_name, rc); | ||
1077 | nResult = -EINVAL; | ||
1078 | } else { | ||
1079 | pPlatData->mnLoop = value & 0x01; | ||
1080 | dev_dbg(pDRV2605->dev, "ti,smart-loop=%d\n", pPlatData->mnLoop); | ||
1081 | } | ||
1082 | } | ||
1083 | |||
1084 | if (nResult >= 0) { | ||
1085 | rc = of_property_read_u32(np, "ti,actuator", &value); | ||
1086 | if (rc) { | ||
1087 | dev_err(pDRV2605->dev, "Looking up %s property in node %s failed %d\n", | ||
1088 | "ti,actuator", np->full_name, rc); | ||
1089 | nResult = -EINVAL; | ||
1090 | } else { | ||
1091 | pPlatData->msActuator.mnActuatorType = value & 0x01; | ||
1092 | dev_dbg(pDRV2605->dev, "ti,actuator=%d\n", | ||
1093 | pPlatData->msActuator.mnActuatorType); | ||
1094 | } | ||
1095 | } | ||
1096 | |||
1097 | if (nResult >= 0) { | ||
1098 | rc = of_property_read_u32(np, "ti,rated-voltage", &value); | ||
1099 | if (rc) { | ||
1100 | dev_err(pDRV2605->dev, "Looking up %s property in node %s failed %d\n", | ||
1101 | "ti,rated-voltage", np->full_name, rc); | ||
1102 | nResult = -EINVAL; | ||
1103 | }else{ | ||
1104 | pPlatData->msActuator.mnRatedVoltage = value; | ||
1105 | dev_dbg(pDRV2605->dev, "ti,rated-voltage=0x%x\n", | ||
1106 | pPlatData->msActuator.mnRatedVoltage); | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | if (nResult >= 0) { | ||
1111 | rc = of_property_read_u32(np, "ti,odclamp-voltage", &value); | ||
1112 | if (rc) { | ||
1113 | dev_err(pDRV2605->dev, "Looking up %s property in node %s failed %d\n", | ||
1114 | "ti,odclamp-voltage", np->full_name, rc); | ||
1115 | nResult = -EINVAL; | ||
1116 | } else { | ||
1117 | pPlatData->msActuator.mnOverDriveClampVoltage = value; | ||
1118 | dev_dbg(pDRV2605->dev, "ti,odclamp-voltage=0x%x\n", | ||
1119 | pPlatData->msActuator.mnOverDriveClampVoltage); | ||
1120 | } | ||
1121 | } | ||
1122 | |||
1123 | if (nResult >= 0) { | ||
1124 | if (pPlatData->msActuator.mnActuatorType == LRA) { | ||
1125 | rc = of_property_read_u32(np, "ti,lra-frequency", &value); | ||
1126 | if (rc) { | ||
1127 | dev_err(pDRV2605->dev, "Looking up %s property in node %s failed %d\n", | ||
1128 | "ti,lra-frequency", np->full_name, rc); | ||
1129 | nResult = -EINVAL; | ||
1130 | } else { | ||
1131 | if ((value >= 125) && (value <= 300)) { | ||
1132 | pPlatData->msActuator.mnLRAFreq = value; | ||
1133 | dev_dbg(pDRV2605->dev, "ti,lra-frequency=%d\n", | ||
1134 | pPlatData->msActuator.mnLRAFreq); | ||
1135 | } else { | ||
1136 | nResult = -EINVAL; | ||
1137 | dev_err(pDRV2605->dev, "ERROR, ti,lra-frequency=%d, out of range\n", | ||
1138 | pPlatData->msActuator.mnLRAFreq); | ||
1139 | } | ||
1140 | } | ||
1141 | } else if (pPlatData->msActuator.mnActuatorType == ERM) { | ||
1142 | rc = of_property_read_u32(np, "ti,erm-lib", &value); | ||
1143 | if (rc) { | ||
1144 | dev_err(pDRV2605->dev, "Looking up %s property in node %s failed %d\n", | ||
1145 | "ti,lra-frequency", np->full_name, rc); | ||
1146 | nResult = -EINVAL; | ||
1147 | } else { | ||
1148 | if ((value >= 1) && (value <= 5)) { | ||
1149 | pPlatData->msActuator.mnERMLib = value; | ||
1150 | dev_dbg(pDRV2605->dev, "ti,erm-lib = %d\n", | ||
1151 | pPlatData->msActuator.mnERMLib); | ||
1152 | } else { | ||
1153 | nResult = -EINVAL; | ||
1154 | dev_err(pDRV2605->dev, "ERROR, ti,erm-lib=%d, out of range\n", | ||
1155 | pPlatData->msActuator.mnERMLib); | ||
1156 | } | ||
1157 | } | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1161 | return nResult; | ||
1162 | } | ||
1163 | |||
1164 | static struct regmap_config drv2605_i2c_regmap = { | ||
1165 | .reg_bits = 8, | ||
1166 | .val_bits = 8, | ||
1167 | .cache_type = REGCACHE_NONE, | ||
1168 | }; | ||
1169 | |||
1170 | static int drv2605_i2c_probe(struct i2c_client* client, const struct i2c_device_id* id) | ||
1171 | { | ||
1172 | struct drv2605_data *pDRV2605; | ||
1173 | int nResult = 0; | ||
1174 | |||
1175 | dev_info(&client->dev, "%s enter\n", __func__); | ||
1176 | |||
1177 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
1178 | dev_err(&client->dev, "%s:I2C check failed\n", __func__); | ||
1179 | return -ENODEV; | ||
1180 | } | ||
1181 | |||
1182 | pDRV2605 = devm_kzalloc(&client->dev, sizeof(struct drv2605_data), GFP_KERNEL); | ||
1183 | if (pDRV2605 == NULL) { | ||
1184 | dev_err(&client->dev, "%s:no memory\n", __func__); | ||
1185 | return -ENOMEM; | ||
1186 | } | ||
1187 | |||
1188 | pDRV2605->dev = &client->dev; | ||
1189 | i2c_set_clientdata(client,pDRV2605); | ||
1190 | dev_set_drvdata(&client->dev, pDRV2605); | ||
1191 | |||
1192 | pDRV2605->mpRegmap = devm_regmap_init_i2c(client, &drv2605_i2c_regmap); | ||
1193 | if (IS_ERR(pDRV2605->mpRegmap)) { | ||
1194 | nResult = PTR_ERR(pDRV2605->mpRegmap); | ||
1195 | dev_err(pDRV2605->dev, "%s:Failed to allocate register map: %d\n", | ||
1196 | __func__, nResult); | ||
1197 | return nResult; | ||
1198 | } | ||
1199 | |||
1200 | if (client->dev.of_node) { | ||
1201 | dev_dbg(pDRV2605->dev, "of node parse\n"); | ||
1202 | nResult = drv2605_parse_dt(&client->dev, pDRV2605); | ||
1203 | } | ||
1204 | |||
1205 | if ((nResult < 0) || !gpio_is_valid(pDRV2605->msPlatData.mnGpioEN)) { | ||
1206 | dev_err(pDRV2605->dev, "%s: platform data error\n",__func__); | ||
1207 | return -EINVAL; | ||
1208 | } | ||
1209 | |||
1210 | if (gpio_is_valid(pDRV2605->msPlatData.mnGpioEN)) { | ||
1211 | nResult = gpio_request(pDRV2605->msPlatData.mnGpioEN, "DRV2605-EN"); | ||
1212 | if (nResult < 0) { | ||
1213 | dev_err(pDRV2605->dev, "%s: GPIO %d request EN error\n", | ||
1214 | __func__, pDRV2605->msPlatData.mnGpioEN); | ||
1215 | return nResult; | ||
1216 | } | ||
1217 | |||
1218 | gpio_direction_output(pDRV2605->msPlatData.mnGpioEN, 0); | ||
1219 | mdelay(5); | ||
1220 | gpio_direction_output(pDRV2605->msPlatData.mnGpioEN, 1); | ||
1221 | mdelay(2); | ||
1222 | pDRV2605->mnDevMode = MODE_STANDBY; | ||
1223 | } | ||
1224 | |||
1225 | mutex_init(&pDRV2605->dev_lock); | ||
1226 | nResult = drv2605_reg_read(pDRV2605, DRV2605_REG_ID, &pDRV2605->mnDeviceID); | ||
1227 | if (nResult < 0) | ||
1228 | goto exit_gpio_request_failed; | ||
1229 | else | ||
1230 | dev_info(pDRV2605->dev, "%s, ID status (0x%x)\n", __func__, pDRV2605->mnDeviceID); | ||
1231 | |||
1232 | if ((pDRV2605->mnDeviceID & 0xe0) != DRV2605_ID) { | ||
1233 | dev_err(pDRV2605->dev, "%s, device_id(0x%x) fail\n", | ||
1234 | __func__, pDRV2605->mnDeviceID); | ||
1235 | goto exit_gpio_request_failed; | ||
1236 | } | ||
1237 | |||
1238 | nResult = dev_init_platform_data(pDRV2605); | ||
1239 | if (nResult < 0) | ||
1240 | goto exit_gpio_request_failed; | ||
1241 | |||
1242 | g_DRV2605data = pDRV2605; | ||
1243 | Haptics_init(pDRV2605); | ||
1244 | |||
1245 | dev_info(pDRV2605->dev, "drv2605 probe succeeded\n"); | ||
1246 | return 0; | ||
1247 | |||
1248 | exit_gpio_request_failed: | ||
1249 | if (gpio_is_valid(pDRV2605->msPlatData.mnGpioEN)) | ||
1250 | gpio_free(pDRV2605->msPlatData.mnGpioEN); | ||
1251 | |||
1252 | mutex_destroy(&pDRV2605->dev_lock); | ||
1253 | |||
1254 | dev_err(pDRV2605->dev, "%s failed, err=%d\n", __func__, nResult); | ||
1255 | return nResult; | ||
1256 | } | ||
1257 | |||
1258 | static int drv2605_i2c_remove(struct i2c_client* client) | ||
1259 | { | ||
1260 | struct drv2605_data *pDRV2605 = i2c_get_clientdata(client); | ||
1261 | |||
1262 | if(pDRV2605->msPlatData.mnGpioEN) | ||
1263 | gpio_free(pDRV2605->msPlatData.mnGpioEN); | ||
1264 | |||
1265 | misc_deregister(&drv2605_misc); | ||
1266 | |||
1267 | mutex_destroy(&pDRV2605->lock); | ||
1268 | mutex_destroy(&pDRV2605->dev_lock); | ||
1269 | |||
1270 | return 0; | ||
1271 | } | ||
1272 | |||
1273 | static const struct i2c_device_id drv2605_i2c_id[] = { | ||
1274 | {"drv2605", 0}, | ||
1275 | {} | ||
1276 | }; | ||
1277 | |||
1278 | MODULE_DEVICE_TABLE(i2c, drv2605_i2c_id); | ||
1279 | |||
1280 | #if defined(CONFIG_OF) | ||
1281 | static const struct of_device_id drv2605_of_match[] = { | ||
1282 | {.compatible = "ti,drv2605"}, | ||
1283 | {}, | ||
1284 | }; | ||
1285 | |||
1286 | MODULE_DEVICE_TABLE(of, drv2605_of_match); | ||
1287 | #endif | ||
1288 | |||
1289 | static struct i2c_driver drv2605_i2c_driver = { | ||
1290 | .driver = { | ||
1291 | .name = "drv2605", | ||
1292 | .owner = THIS_MODULE, | ||
1293 | #if defined(CONFIG_OF) | ||
1294 | .of_match_table = of_match_ptr(drv2605_of_match), | ||
1295 | #endif | ||
1296 | }, | ||
1297 | .probe = drv2605_i2c_probe, | ||
1298 | .remove = drv2605_i2c_remove, | ||
1299 | .id_table = drv2605_i2c_id, | ||
1300 | }; | ||
1301 | |||
1302 | module_i2c_driver(drv2605_i2c_driver); | ||
1303 | |||
1304 | MODULE_AUTHOR("Texas Instruments Inc."); | ||
1305 | MODULE_DESCRIPTION("DRV2605 I2C Haptics driver"); | ||
1306 | MODULE_LICENSE("GPL v2"); \ No newline at end of file | ||
diff --git a/drv2605.h b/drv2605.h new file mode 100755 index 0000000..32a9c4f --- /dev/null +++ b/drv2605.h | |||
@@ -0,0 +1,229 @@ | |||
1 | #ifndef __DRV2605_H__ | ||
2 | #define __DRV2605_H__ | ||
3 | /* | ||
4 | ** ============================================================================= | ||
5 | ** Copyright (c)2016 Texas Instruments Inc. | ||
6 | ** | ||
7 | ** This program is free software; you can redistribute it and/or | ||
8 | ** modify it under the terms of the GNU General Public License | ||
9 | ** as published by the Free Software Foundation; either version 2 | ||
10 | ** of the License, or (at your option) any later version. | ||
11 | ** | ||
12 | ** This program is distributed in the hope that it will be useful, | ||
13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | ** GNU General Public License for more details. | ||
16 | ** | ||
17 | ** You should have received a copy of the GNU General Public License | ||
18 | ** along with this program; if not, write to the Free Software | ||
19 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | ** | ||
21 | ** File: | ||
22 | ** drv2605.h | ||
23 | ** | ||
24 | ** Description: | ||
25 | ** Header file for drv2605.c | ||
26 | ** | ||
27 | ** ============================================================================= | ||
28 | */ | ||
29 | |||
30 | #include <linux/regmap.h> | ||
31 | #include <linux/timer.h> | ||
32 | #include <linux/workqueue.h> | ||
33 | #include <../../../drivers/staging/android/timed_output.h> | ||
34 | #include <linux/hrtimer.h> | ||
35 | #include <linux/wakelock.h> | ||
36 | #include <linux/mutex.h> | ||
37 | #include <linux/cdev.h> | ||
38 | |||
39 | #define HAPTICS_DEVICE_NAME "drv2605" | ||
40 | |||
41 | #define DRV2605_REG_ID 0x00 | ||
42 | #define DRV2605_ID 0x60 | ||
43 | |||
44 | #define DRV2605_REG_STATUS 0x00 | ||
45 | #define DIAG_MASK 0x08 | ||
46 | #define DIAG_SUCCESS 0x00 | ||
47 | #define DIAG_SHIFT 0x07 | ||
48 | #define INT_MASK 0x1f | ||
49 | #define PRG_ERR_MASK 0x10 | ||
50 | #define PROCESS_DONE_MASK 0x08 | ||
51 | #define ULVO_MASK 0x04 | ||
52 | #define OVERTEMPRATURE_MASK 0x02 | ||
53 | #define OVERCURRENT_MASK 0x01 | ||
54 | |||
55 | #define DRV2605_REG_MODE 0x01 | ||
56 | #define WORKMODE_MASK 0x03 | ||
57 | |||
58 | #define DRV2605_REG_RTP_INPUT 0x02 | ||
59 | |||
60 | #define DRV2605_REG_LIBSEL 0x03 | ||
61 | |||
62 | #define DRV2605_REG_SEQUENCER_1 0x04 | ||
63 | |||
64 | #define DRV2605_REG_CONTROL1 0x08 | ||
65 | #define ACTUATOR_MASK 0x80 | ||
66 | #define ACTUATOR_SHIFT 7 | ||
67 | #define LOOP_MASK 0x40 | ||
68 | #define LOOP_SHIFT 6 | ||
69 | #define AUTOBRK_OK_MASK 0x10 | ||
70 | #define AUTOBRK_OK_ENABLE 0x10 | ||
71 | |||
72 | #define DRV2605_REG_GO 0x0c | ||
73 | |||
74 | #define DRV2605_REG_CONTROL2 0x0d | ||
75 | |||
76 | #define DRV2605_REG_RATED_VOLTAGE 0x16 | ||
77 | #define DRV2605_REG_OVERDRIVE_CLAMP 0x17 | ||
78 | #define DRV2605_REG_CAL_COMP 0x18 | ||
79 | #define DRV2605_REG_CAL_BEMF 0x19 | ||
80 | |||
81 | #define DRV2605_REG_LOOP_CONTROL 0x1a | ||
82 | #define BEMFGAIN_MASK 0x03 | ||
83 | #define DRV2605_REG_CONTROL3 0x1d | ||
84 | |||
85 | #define DRV2605_REG_DRIVE_TIME 0x1b | ||
86 | #define DRIVE_TIME_MASK 0x1f | ||
87 | |||
88 | #define GO_BIT_POLL_INTERVAL 15 | ||
89 | #define STANDBY_WAKE_DELAY 1 | ||
90 | #define WAKE_STANDBY_DELAY 3 | ||
91 | |||
92 | /* Commands */ | ||
93 | #define HAPTIC_CMDID_PLAY_SINGLE_EFFECT 0x01 | ||
94 | #define HAPTIC_CMDID_PLAY_EFFECT_SEQUENCE 0x02 | ||
95 | #define HAPTIC_CMDID_PLAY_TIMED_EFFECT 0x03 | ||
96 | #define HAPTIC_CMDID_GET_DEV_ID 0x04 | ||
97 | #define HAPTIC_CMDID_RUN_DIAG 0x05 | ||
98 | #define HAPTIC_CMDID_AUDIOHAPTIC_ENABLE 0x06 | ||
99 | #define HAPTIC_CMDID_AUDIOHAPTIC_DISABLE 0x07 | ||
100 | #define HAPTIC_CMDID_AUDIOHAPTIC_GETSTATUS 0x08 | ||
101 | #define HAPTIC_CMDID_REG_WRITE 0x09 | ||
102 | #define HAPTIC_CMDID_REG_READ 0x0a | ||
103 | #define HAPTIC_CMDID_REG_SETBIT 0x0b | ||
104 | #define HAPTIC_CMDID_PATTERN_RTP 0x0c | ||
105 | #define HAPTIC_CMDID_RTP_SEQUENCE 0x0d | ||
106 | #define HAPTIC_CMDID_GET_EFFECT_COUNT 0x10 | ||
107 | #define HAPTIC_CMDID_UPDATE_FIRMWARE 0x11 | ||
108 | #define HAPTIC_CMDID_READ_FIRMWARE 0x12 | ||
109 | #define HAPTIC_CMDID_RUN_CALIBRATION 0x13 | ||
110 | #define HAPTIC_CMDID_CONFIG_WAVEFORM 0x14 | ||
111 | #define HAPTIC_CMDID_SET_SEQUENCER 0x15 | ||
112 | #define HAPTIC_CMDID_REGLOG_ENABLE 0x16 | ||
113 | |||
114 | #define HAPTIC_CMDID_STOP 0xFF | ||
115 | |||
116 | #define MAX_TIMEOUT 10000 /* 10s */ | ||
117 | #define MAX_READ_BYTES 0xff | ||
118 | #define DRV2605_SEQUENCER_SIZE 8 | ||
119 | |||
120 | enum dev_mode { | ||
121 | MODE_INTL_TRIG = 0x00, | ||
122 | MODE_EXTL_TRIG_E = 0x01, | ||
123 | MODE_EXTL_TRIG_L = 0x02, | ||
124 | MODE_PWM_ANG = 0x03, | ||
125 | MODE_AUDIOHAPTICS = 0x04, | ||
126 | MODE_RTP = 0x05, | ||
127 | MODE_DIAG = 0x06, | ||
128 | MODE_CALIBRATION = 0x07, | ||
129 | MODE_STANDBY = 0x40 | ||
130 | }; | ||
131 | |||
132 | enum work_mode { | ||
133 | WORK_IDLE = 0, | ||
134 | WORK_SEQER = 0x01, | ||
135 | WORK_RTP = 0x02, | ||
136 | WORK_CALIBRATION = 0x03, | ||
137 | WORK_DIAGNOSTIC = 0x04 | ||
138 | }; | ||
139 | |||
140 | |||
141 | #define YES 1 | ||
142 | #define NO 0 | ||
143 | #define GO 1 | ||
144 | #define STOP 0 | ||
145 | |||
146 | #define POLL_GO_BIT_INTERVAL 2 /* 2 ms */ | ||
147 | #define POLL_STATUS_INTERVAL 10 /* 10 ms */ | ||
148 | #define POLL_GO_BIT_RETRY 20 /* 20 times */ | ||
149 | |||
150 | enum actuator_type { | ||
151 | ERM, | ||
152 | LRA | ||
153 | }; | ||
154 | |||
155 | enum loop_type { | ||
156 | CLOSE_LOOP, | ||
157 | OPEN_LOOP | ||
158 | }; | ||
159 | |||
160 | struct actuator_data { | ||
161 | unsigned char mnActuatorType; | ||
162 | unsigned char mnEffectLib; | ||
163 | unsigned char mnRatedVoltage; | ||
164 | unsigned char mnOverDriveClampVoltage; | ||
165 | unsigned char mnERMLib; | ||
166 | unsigned char mnLRAFreq; | ||
167 | }; | ||
168 | |||
169 | struct drv2605_waveform { | ||
170 | unsigned char mnEffect; | ||
171 | }; | ||
172 | |||
173 | struct drv2605_waveform_sequencer { | ||
174 | struct drv2605_waveform msWaveform[DRV2605_SEQUENCER_SIZE]; | ||
175 | }; | ||
176 | |||
177 | struct drv2605_autocal_result { | ||
178 | int mnFinished; | ||
179 | unsigned char mnResult; | ||
180 | unsigned char mnCalComp; | ||
181 | unsigned char mnCalBemf; | ||
182 | unsigned char mnCalGain; | ||
183 | }; | ||
184 | |||
185 | struct drv2605_diag_result { | ||
186 | int mnFinished; | ||
187 | unsigned char mnResult; | ||
188 | }; | ||
189 | |||
190 | struct drv2605_platform_data { | ||
191 | int mnGpioEN; | ||
192 | unsigned char mnLoop; | ||
193 | struct actuator_data msActuator; | ||
194 | }; | ||
195 | |||
196 | struct drv2605_data { | ||
197 | struct drv2605_platform_data msPlatData; | ||
198 | struct mutex dev_lock; | ||
199 | unsigned char mnDeviceID; | ||
200 | struct device *dev; | ||
201 | struct regmap *mpRegmap; | ||
202 | struct drv2605_waveform_sequencer msWaveformSequencer; | ||
203 | unsigned char mnFileCmd; | ||
204 | volatile int mnVibratorPlaying; | ||
205 | enum dev_mode mnDevMode; | ||
206 | enum work_mode mnWorkMode; | ||
207 | unsigned char mnRTPStrength; | ||
208 | unsigned char mnCurrentReg; | ||
209 | struct wake_lock wklock; | ||
210 | struct hrtimer timer; | ||
211 | struct mutex lock; | ||
212 | struct work_struct vibrator_work; | ||
213 | struct timed_output_dev to_dev; | ||
214 | |||
215 | struct drv2605_autocal_result mAutoCalResult; | ||
216 | struct drv2605_diag_result mDiagResult; | ||
217 | |||
218 | }; | ||
219 | |||
220 | #define DRV2605_MAGIC_NUMBER 'T' | ||
221 | |||
222 | #define DRV2605_WAVSEQ_PLAY _IOWR(DRV2605_MAGIC_NUMBER, 4, unsigned long) | ||
223 | #define DRV2605_STOP _IOWR(DRV2605_MAGIC_NUMBER, 5, unsigned long) | ||
224 | #define DRV2605_RUN_DIAGNOSTIC _IOWR(DRV2605_MAGIC_NUMBER, 6, unsigned long) | ||
225 | #define DRV2605_GET_DIAGRESULT _IOWR(DRV2605_MAGIC_NUMBER, 7, struct drv2605_diag_result *) | ||
226 | #define DRV2605_RUN_AUTOCAL _IOWR(DRV2605_MAGIC_NUMBER, 8, unsigned long) | ||
227 | #define DRV2605_GET_CALRESULT _IOWR(DRV2605_MAGIC_NUMBER, 9, struct drv2605_autocal_result *) | ||
228 | |||
229 | #endif | ||
diff --git a/dts.readme b/dts.readme new file mode 100755 index 0000000..1469bf7 --- /dev/null +++ b/dts.readme | |||
@@ -0,0 +1,12 @@ | |||
1 | drv2605@5a { | ||
2 | compatible = "ti,drv2605"; | ||
3 | reg = <0x5a>; | ||
4 | ti,enable-gpio = <&msmgpio 13 0>; | ||
5 | ti,smart-loop = <0>; /* 0-closeloop, 1-openloop */ | ||
6 | ti,actuator = <1>; /* 0-ERM, 1-LRA */ | ||
7 | ti,rated-voltage = <0x53>; | ||
8 | ti,odclamp-voltage = <0x9b>; | ||
9 | ti,lra-frequency = <175>; /* DON'T Care if ERM */ | ||
10 | ti,erm-lib = <1>; /* DON'T Care if LRA */ | ||
11 | status = "ok"; | ||
12 | }; \ No newline at end of file | ||
diff --git a/include_linux_haptics_drv2605.h b/include_linux_haptics_drv2605.h deleted file mode 100755 index c6f430d..0000000 --- a/include_linux_haptics_drv2605.h +++ /dev/null | |||
@@ -1,462 +0,0 @@ | |||
1 | #ifndef __DRV2605_H__ | ||
2 | #define __DRV2605_H__ | ||
3 | /* | ||
4 | ** ============================================================================= | ||
5 | ** Copyright (c)2014 Texas Instruments Inc. | ||
6 | ** | ||
7 | ** This program is free software; you can redistribute it and/or | ||
8 | ** modify it under the terms of the GNU General Public License | ||
9 | ** as published by the Free Software Foundation; either version 2 | ||
10 | ** of the License, or (at your option) any later version. | ||
11 | ** | ||
12 | ** This program is distributed in the hope that it will be useful, | ||
13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | ** GNU General Public License for more details. | ||
16 | ** | ||
17 | ** You should have received a copy of the GNU General Public License | ||
18 | ** along with this program; if not, write to the Free Software | ||
19 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | ** | ||
21 | ** File: | ||
22 | ** drv2605.h | ||
23 | ** | ||
24 | ** Description: | ||
25 | ** Header file for drv2605.c | ||
26 | ** | ||
27 | ** ============================================================================= | ||
28 | */ | ||
29 | |||
30 | #include <linux/switch.h> | ||
31 | #include <linux/earlysuspend.h> | ||
32 | #include <linux/regmap.h> | ||
33 | #include <linux/timer.h> | ||
34 | #include <linux/workqueue.h> | ||
35 | #include <../../../drivers/staging/android/timed_output.h> | ||
36 | #include <linux/hrtimer.h> | ||
37 | #include <linux/wakelock.h> | ||
38 | #include <linux/mutex.h> | ||
39 | #include <linux/cdev.h> | ||
40 | #include <linux/earlysuspend.h> | ||
41 | |||
42 | #define HAPTICS_DEVICE_NAME "drv2605" | ||
43 | |||
44 | #define LIBRARY_A 0x01 | ||
45 | #define LIBRARY_B 0x02 | ||
46 | #define LIBRARY_C 0x03 | ||
47 | #define LIBRARY_D 0x04 | ||
48 | #define LIBRARY_E 0x05 | ||
49 | #define LIBRARY_F 0x06 | ||
50 | |||
51 | #define GO_BIT_POLL_INTERVAL 15 | ||
52 | #define STANDBY_WAKE_DELAY 1 | ||
53 | #define WAKE_STANDBY_DELAY 3 | ||
54 | |||
55 | /* Commands */ | ||
56 | #define HAPTIC_CMDID_PLAY_SINGLE_EFFECT 0x01 | ||
57 | #define HAPTIC_CMDID_PLAY_EFFECT_SEQUENCE 0x02 | ||
58 | #define HAPTIC_CMDID_PLAY_TIMED_EFFECT 0x03 | ||
59 | #define HAPTIC_CMDID_GET_DEV_ID 0x04 | ||
60 | #define HAPTIC_CMDID_RUN_DIAG 0x05 | ||
61 | #define HAPTIC_CMDID_AUDIOHAPTIC_ENABLE 0x06 | ||
62 | #define HAPTIC_CMDID_AUDIOHAPTIC_DISABLE 0x07 | ||
63 | #define HAPTIC_CMDID_AUDIOHAPTIC_GETSTATUS 0x08 | ||
64 | |||
65 | #define HAPTIC_CMDID_REG_WRITE 0x09 | ||
66 | #define HAPTIC_CMDID_REG_READ 0x0a | ||
67 | #define HAPTIC_CMDID_REG_SETBIT 0x0b | ||
68 | |||
69 | #define HAPTIC_CMDID_PATTERN_RTP 0x0c | ||
70 | #define HAPTIC_CMDID_RTP_SEQUENCE 0x0d | ||
71 | #define HAPTIC_CMDID_GET_EFFECT_COUNT 0x10 | ||
72 | #define HAPTIC_CMDID_UPDATE_FIRMWARE 0x11 | ||
73 | #define HAPTIC_CMDID_READ_FIRMWARE 0x12 | ||
74 | #define HAPTIC_CMDID_STOP 0xFF | ||
75 | |||
76 | /* | ||
77 | ** Go | ||
78 | */ | ||
79 | #define GO_REG 0x0C | ||
80 | #define GO_MASK 0x01 | ||
81 | #define GO 0x01 | ||
82 | #define STOP 0x00 | ||
83 | |||
84 | /* | ||
85 | ** Status | ||
86 | */ | ||
87 | #define STATUS_REG 0x00 | ||
88 | #define STATUS_DEFAULT 0x00 | ||
89 | |||
90 | #define DIAG_RESULT_MASK (1 << 3) | ||
91 | #define AUTO_CAL_PASSED (0 << 3) | ||
92 | #define AUTO_CAL_FAILED (1 << 3) | ||
93 | #define DIAG_GOOD (0 << 3) | ||
94 | #define DIAG_BAD (1 << 3) | ||
95 | |||
96 | #define DEV_ID_MASK (7 << 5) | ||
97 | |||
98 | #define DRV2605_VER_1DOT1 (3 << 5) | ||
99 | #define DRV2605_VER_1DOT0 (5 << 5) | ||
100 | #define DRV2604 (4 << 5) | ||
101 | #define DRV2604L (6 << 5) | ||
102 | #define DRV2605L (7 << 5) | ||
103 | |||
104 | /* | ||
105 | ** Mode | ||
106 | */ | ||
107 | #define MODE_REG 0x01 | ||
108 | #define MODE_STANDBY_MASK 0x40 | ||
109 | #define MODE_STANDBY 0x40 | ||
110 | #define MODE_RESET 0x80 | ||
111 | #define DRV2605_MODE_MASK 0x07 | ||
112 | #define MODE_INTERNAL_TRIGGER 0 | ||
113 | #define MODE_EXTERNAL_TRIGGER_EDGE 1 | ||
114 | #define MODE_EXTERNAL_TRIGGER_LEVEL 2 | ||
115 | #define MODE_PWM_OR_ANALOG_INPUT 3 | ||
116 | #define MODE_AUDIOHAPTIC 4 | ||
117 | #define MODE_REAL_TIME_PLAYBACK 5 | ||
118 | #define MODE_DIAGNOSTICS 6 | ||
119 | #define AUTO_CALIBRATION 7 | ||
120 | |||
121 | /* | ||
122 | ** Real Time Playback | ||
123 | */ | ||
124 | #define REAL_TIME_PLAYBACK_REG 0x02 | ||
125 | |||
126 | /* | ||
127 | ** Library Selection | ||
128 | */ | ||
129 | #define LIBRARY_SELECTION_REG 0x03 | ||
130 | #define LIBRARY_SELECTION_DEFAULT 0x00 | ||
131 | #define LIBRARY_SELECTION_HIZ_MASK 0x10 | ||
132 | #define LIBRARY_SELECTION_HIZ_EN 1 | ||
133 | #define LIBRARY_SELECTION_HIZ_DIS 0 | ||
134 | |||
135 | /* | ||
136 | ** Waveform Sequencer | ||
137 | */ | ||
138 | #define WAVEFORM_SEQUENCER_REG 0x04 | ||
139 | #define WAVEFORM_SEQUENCER_REG2 0x05 | ||
140 | #define WAVEFORM_SEQUENCER_REG3 0x06 | ||
141 | #define WAVEFORM_SEQUENCER_REG4 0x07 | ||
142 | #define WAVEFORM_SEQUENCER_REG5 0x08 | ||
143 | #define WAVEFORM_SEQUENCER_REG6 0x09 | ||
144 | #define WAVEFORM_SEQUENCER_REG7 0x0A | ||
145 | #define WAVEFORM_SEQUENCER_REG8 0x0B | ||
146 | #define WAVEFORM_SEQUENCER_MAX 8 | ||
147 | #define WAVEFORM_SEQUENCER_DEFAULT 0x00 | ||
148 | |||
149 | /* | ||
150 | ** OverDrive Time Offset | ||
151 | */ | ||
152 | #define OVERDRIVE_TIME_OFFSET_REG 0x0D | ||
153 | |||
154 | /* | ||
155 | ** Sustain Time Offset, postive | ||
156 | */ | ||
157 | #define SUSTAIN_TIME_OFFSET_POS_REG 0x0E | ||
158 | |||
159 | /* | ||
160 | ** Sustain Time Offset, negative | ||
161 | */ | ||
162 | #define SUSTAIN_TIME_OFFSET_NEG_REG 0x0F | ||
163 | |||
164 | /* | ||
165 | ** Brake Time Offset | ||
166 | */ | ||
167 | #define BRAKE_TIME_OFFSET_REG 0x10 | ||
168 | |||
169 | /* | ||
170 | ** Audio to Haptics Control | ||
171 | */ | ||
172 | #define AUDIO_HAPTICS_CONTROL_REG 0x11 | ||
173 | |||
174 | #define AUDIO_HAPTICS_RECT_10MS (0 << 2) | ||
175 | #define AUDIO_HAPTICS_RECT_20MS (1 << 2) | ||
176 | #define AUDIO_HAPTICS_RECT_30MS (2 << 2) | ||
177 | #define AUDIO_HAPTICS_RECT_40MS (3 << 2) | ||
178 | |||
179 | #define AUDIO_HAPTICS_FILTER_100HZ 0 | ||
180 | #define AUDIO_HAPTICS_FILTER_125HZ 1 | ||
181 | #define AUDIO_HAPTICS_FILTER_150HZ 2 | ||
182 | #define AUDIO_HAPTICS_FILTER_200HZ 3 | ||
183 | |||
184 | /* | ||
185 | ** Audio to Haptics Minimum Input Level | ||
186 | */ | ||
187 | #define AUDIO_HAPTICS_MIN_INPUT_REG 0x12 | ||
188 | |||
189 | /* | ||
190 | ** Audio to Haptics Maximum Input Level | ||
191 | */ | ||
192 | #define AUDIO_HAPTICS_MAX_INPUT_REG 0x13 | ||
193 | |||
194 | /* | ||
195 | ** Audio to Haptics Minimum Output Drive | ||
196 | */ | ||
197 | #define AUDIO_HAPTICS_MIN_OUTPUT_REG 0x14 | ||
198 | |||
199 | /* | ||
200 | ** Audio to Haptics Maximum Output Drive | ||
201 | */ | ||
202 | #define AUDIO_HAPTICS_MAX_OUTPUT_REG 0x15 | ||
203 | |||
204 | /* | ||
205 | ** Rated Voltage | ||
206 | */ | ||
207 | #define RATED_VOLTAGE_REG 0x16 | ||
208 | |||
209 | /* | ||
210 | ** Overdrive Clamp Voltage | ||
211 | */ | ||
212 | #define OVERDRIVE_CLAMP_VOLTAGE_REG 0x17 | ||
213 | |||
214 | /* | ||
215 | ** Auto Calibrationi Compensation Result | ||
216 | */ | ||
217 | #define AUTO_CALI_RESULT_REG 0x18 | ||
218 | |||
219 | /* | ||
220 | ** Auto Calibration Back-EMF Result | ||
221 | */ | ||
222 | #define AUTO_CALI_BACK_EMF_RESULT_REG 0x19 | ||
223 | |||
224 | /* | ||
225 | ** Feedback Control | ||
226 | */ | ||
227 | #define FEEDBACK_CONTROL_REG 0x1A | ||
228 | #define FEEDBACK_CONTROL_DEVICE_TYPE_MASK 0x80 | ||
229 | #define FEEDBACK_CONTROL_BEMF_ERM_GAIN0 0 // 0.33x | ||
230 | #define FEEDBACK_CONTROL_BEMF_ERM_GAIN1 1 // 1.0x | ||
231 | #define FEEDBACK_CONTROL_BEMF_ERM_GAIN2 2 // 1.8x | ||
232 | #define FEEDBACK_CONTROL_BEMF_ERM_GAIN3 3 // 4.0x | ||
233 | |||
234 | #define FEEDBACK_CONTROL_BEMF_LRA_GAIN0 0 // 5x | ||
235 | #define FEEDBACK_CONTROL_BEMF_LRA_GAIN1 1 // 10x | ||
236 | #define FEEDBACK_CONTROL_BEMF_LRA_GAIN2 2 // 20x | ||
237 | #define FEEDBACK_CONTROL_BEMF_LRA_GAIN3 3 // 30x | ||
238 | |||
239 | #define LOOP_RESPONSE_SLOW (0 << 2) | ||
240 | #define LOOP_RESPONSE_MEDIUM (1 << 2) // default | ||
241 | #define LOOP_RESPONSE_FAST (2 << 2) | ||
242 | #define LOOP_RESPONSE_VERY_FAST (3 << 2) | ||
243 | |||
244 | #define FB_BRAKE_FACTOR_1X (0 << 4) // 1x | ||
245 | #define FB_BRAKE_FACTOR_2X (1 << 4) // 2x | ||
246 | #define FB_BRAKE_FACTOR_3X (2 << 4) // 3x (default) | ||
247 | #define FB_BRAKE_FACTOR_4X (3 << 4) // 4x | ||
248 | #define FB_BRAKE_FACTOR_6X (4 << 4) // 6x | ||
249 | #define FB_BRAKE_FACTOR_8X (5 << 4) // 8x | ||
250 | #define FB_BRAKE_FACTOR_16X (6 << 4) // 16x | ||
251 | #define FB_BRAKE_DISABLED (7 << 4) | ||
252 | |||
253 | #define FEEDBACK_CONTROL_MODE_ERM 0 // default | ||
254 | #define FEEDBACK_CONTROL_MODE_LRA (1 << 7) | ||
255 | |||
256 | /* | ||
257 | ** Control1 | ||
258 | */ | ||
259 | #define Control1_REG 0x1B | ||
260 | #define Control1_REG_AC_COUPLE_MASK 0x20 | ||
261 | #define Control1_REG_DRIVE_TIME_MASK 0x1f | ||
262 | |||
263 | #define STARTUP_BOOST_ENABLED (1 << 7) | ||
264 | #define STARTUP_BOOST_DISABLED (0 << 7) // default | ||
265 | #define AC_COUPLE_ENABLED (1 << 5) | ||
266 | #define AC_COUPLE_DISABLED (0 << 5) // default | ||
267 | |||
268 | #define DEFAULT_DRIVE_TIME 0x13 | ||
269 | #define AUDIOHAPTIC_DRIVE_TIME 0x13 | ||
270 | |||
271 | /* | ||
272 | ** Control2 | ||
273 | */ | ||
274 | #define Control2_REG 0x1C | ||
275 | #define Control2_REG_BIDIR_INPUT_MASK 0x80 | ||
276 | |||
277 | #define BIDIR_INPUT_UNIDIRECTIONAL (0<<7) | ||
278 | #define BIDIR_INPUT_BIDIRECTIONAL (1<<7) | ||
279 | #define IDISS_TIME_MASK 0x03 | ||
280 | #define IDISS_TIME_VERY_SHORT 0 | ||
281 | #define IDISS_TIME_SHORT 1 | ||
282 | #define IDISS_TIME_MEDIUM 2 // default | ||
283 | #define IDISS_TIME_LONG 3 | ||
284 | |||
285 | #define BLANKING_TIME_MASK 0x0C | ||
286 | #define BLANKING_TIME_VERY_SHORT (0 << 2) | ||
287 | #define BLANKING_TIME_SHORT (1 << 2) | ||
288 | #define BLANKING_TIME_MEDIUM (2 << 2) // default | ||
289 | #define BLANKING_TIME_VERY_LONG (3 << 2) | ||
290 | |||
291 | #define AUTO_RES_GAIN_MASK 0x30 | ||
292 | #define AUTO_RES_GAIN_VERY_LOW (0 << 4) | ||
293 | #define AUTO_RES_GAIN_LOW (1 << 4) | ||
294 | #define AUTO_RES_GAIN_MEDIUM (2 << 4) // default | ||
295 | #define AUTO_RES_GAIN_HIGH (3 << 4) | ||
296 | |||
297 | #define SOFT_BRAKE_MASK 0x40 | ||
298 | |||
299 | #define BIDIR_INPUT_MASK 0x80 | ||
300 | #define UNIDIRECT_INPUT (0 << 7) | ||
301 | #define BRAKE_STABLIZER (1<<6) | ||
302 | #define BIDIRECT_INPUT (1 << 7) // default | ||
303 | |||
304 | /* | ||
305 | ** Control3 | ||
306 | */ | ||
307 | #define Control3_REG 0x1D | ||
308 | #define Control3_REG_LOOP_MASK 0x21 | ||
309 | #define Control3_REG_PWMANALOG_MASK 0x02 | ||
310 | #define Control3_REG_FORMAT_MASK 0x08 | ||
311 | #define INPUT_PWM (0 << 1) // default | ||
312 | #define INPUT_ANALOG (1 << 1) | ||
313 | #define ERM_OpenLoop_Enabled (1 << 5) | ||
314 | #define ERM_OpenLoop_Disable (0 << 5) | ||
315 | #define LRA_OpenLoop_Enabled (1 << 0) | ||
316 | #define LRA_OpenLoop_Disable (0 << 0) | ||
317 | #define RTP_FORMAT_SIGNED (0 << 3) | ||
318 | #define RTP_FORMAT_UNSIGNED (1 << 3) | ||
319 | #define NG_Thresh_DISABLED (0 << 6) | ||
320 | #define NG_Thresh_1 (1 << 6) | ||
321 | #define NG_Thresh_2 (2 << 6) | ||
322 | #define NG_Thresh_3 (3 << 6) | ||
323 | |||
324 | /* | ||
325 | ** Auto Calibration Memory Interface | ||
326 | */ | ||
327 | #define AUTOCAL_MEM_INTERFACE_REG 0x1E | ||
328 | #define AUTOCAL_MEM_INTERFACE_REG_OTP_MASK 0x04 | ||
329 | |||
330 | #define AUTOCAL_TIME_150MS (0 << 4) | ||
331 | #define AUTOCAL_TIME_250MS (1 << 4) | ||
332 | #define AUTOCAL_TIME_500MS (2 << 4) | ||
333 | #define AUTOCAL_TIME_1000MS (3 << 4) | ||
334 | |||
335 | #define SILICON_REVISION_REG 0x3B | ||
336 | #define SILICON_REVISION_MASK 0x07 | ||
337 | |||
338 | //reset values | ||
339 | #define AUDIO_HAPTICS_MIN_INPUT_VOLTAGE 0x19 | ||
340 | #define AUDIO_HAPTICS_MAX_INPUT_VOLTAGE 0xff | ||
341 | #define AUDIO_HAPTICS_MIN_OUTPUT_VOLTAGE 0x19 | ||
342 | #define AUDIO_HAPTICS_MAX_OUTPUT_VOLTAGE 0xFF | ||
343 | |||
344 | #define MAX_TIMEOUT 10000 /* 10s */ | ||
345 | #define MAX_READ_BYTES 0xff | ||
346 | |||
347 | #define SW_STATE_IDLE 0x00 | ||
348 | #define SW_STATE_AUDIO2HAPTIC 0x01 | ||
349 | #define SW_STATE_SEQUENCE_PLAYBACK 0x02 | ||
350 | #define SW_STATE_RTP_PLAYBACK 0x04 | ||
351 | |||
352 | #define DEV_IDLE 0 // default | ||
353 | #define DEV_STANDBY 1 | ||
354 | #define DEV_READY 2 | ||
355 | |||
356 | #define WORK_IDLE 0x00 | ||
357 | #define WORK_AUDIO2HAPTIC 0x05 | ||
358 | #define WORK_RTP 0x06 | ||
359 | #define WORK_CALIBRATION 0x07 | ||
360 | #define WORK_VIBRATOR 0x08 | ||
361 | #define WORK_PATTERN_RTP_ON 0x09 | ||
362 | #define WORK_PATTERN_RTP_OFF 0x0a | ||
363 | #define WORK_SEQ_RTP_ON 0x0b | ||
364 | #define WORK_SEQ_RTP_OFF 0x0c | ||
365 | #define WORK_SEQ_PLAYBACK 0x0d | ||
366 | |||
367 | #define YES 1 | ||
368 | #define NO 0 | ||
369 | |||
370 | enum actuator_type { | ||
371 | ERM, | ||
372 | LRA | ||
373 | }; | ||
374 | |||
375 | enum loop_type { | ||
376 | OPEN_LOOP, | ||
377 | CLOSE_LOOP | ||
378 | }; | ||
379 | |||
380 | enum RTP_Format { | ||
381 | Signed, | ||
382 | Unsigned | ||
383 | }; | ||
384 | |||
385 | enum BIDIR_Input { | ||
386 | UniDirectional, | ||
387 | BiDirectional | ||
388 | }; | ||
389 | |||
390 | struct actuator_data { | ||
391 | enum actuator_type device_type; | ||
392 | unsigned char g_effect_bank; | ||
393 | unsigned char rated_vol; | ||
394 | unsigned char over_drive_vol; | ||
395 | unsigned char LRAFreq; | ||
396 | }; | ||
397 | |||
398 | struct audio2haptics_data { | ||
399 | unsigned char a2h_min_input; | ||
400 | unsigned char a2h_max_input; | ||
401 | unsigned char a2h_min_output; | ||
402 | unsigned char a2h_max_output; | ||
403 | }; | ||
404 | |||
405 | struct drv2605_platform_data { | ||
406 | int GpioEnable; | ||
407 | int GpioTrigger; | ||
408 | enum loop_type loop; | ||
409 | enum RTP_Format RTPFormat; | ||
410 | enum BIDIR_Input BIDIRInput; | ||
411 | struct actuator_data actuator; | ||
412 | struct audio2haptics_data a2h; | ||
413 | }; | ||
414 | |||
415 | #define MAX_RTP_SEQ 16 | ||
416 | |||
417 | struct RTP_Seq{ | ||
418 | unsigned short RTPData[MAX_RTP_SEQ]; //RTPTime<<8||RTPAmp | ||
419 | int RTPCounts; | ||
420 | int RTPindex; | ||
421 | }; | ||
422 | |||
423 | struct drv2605_data { | ||
424 | struct drv2605_platform_data PlatData; | ||
425 | int device_id; | ||
426 | |||
427 | struct regmap *regmap; | ||
428 | |||
429 | struct class* class; | ||
430 | struct device* device; | ||
431 | dev_t version; | ||
432 | struct semaphore sem; | ||
433 | struct cdev cdev; | ||
434 | struct switch_dev sw_dev; | ||
435 | volatile int audio_haptics_enabled; | ||
436 | volatile int vibrator_is_playing; | ||
437 | char ReadBuff[MAX_READ_BYTES]; | ||
438 | int ReadLen; | ||
439 | |||
440 | int vibration_time; | ||
441 | int silience_time; | ||
442 | char repeat_times; | ||
443 | volatile char work_mode; | ||
444 | char dev_mode; | ||
445 | |||
446 | struct RTP_Seq RTPSeq; | ||
447 | |||
448 | int OTP; | ||
449 | |||
450 | struct wake_lock wklock; | ||
451 | struct hrtimer timer; | ||
452 | struct mutex lock; | ||
453 | struct work_struct vibrator_work; | ||
454 | unsigned char sequence[WAVEFORM_SEQUENCER_MAX]; | ||
455 | volatile int should_stop; | ||
456 | struct timed_output_dev to_dev; | ||
457 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
458 | struct early_suspend early_suspend; | ||
459 | #endif | ||
460 | }; | ||
461 | |||
462 | #endif | ||