Commit e7ec014a47e4d68fc01561d0541a50650646317c
Committed by
Dmitry Torokhov
1 parent
32edbf562c
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
Input: twl6040-vibra - update for device tree support
The twl6040 DT support implementation has been changed from the originally planned. None of the child devices going to have compatible_of property which means that the child devices of twl6040 will be created as traditional MFD devices. The mfd core driver will decide (based on the DT blob) to create a device for the twl6040-vibra or not. If the DT blob has 'vibra' section the device will be created without pdata. In this case the vibra driver will reach up to the parent node to get the needed properties. With DT booted kernel we no longer be able to link the regulators to the vibra driver, they can be only linked to the MFD device (probed via DT). From the vibra driver we ned to use pdev->dev.parent to get the regulators. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Showing 2 changed files with 24 additions and 55 deletions Inline Diff
Documentation/devicetree/bindings/input/twl6040-vibra.txt
1 | Vibra driver for the twl6040 family | File was deleted | |
2 | |||
3 | The vibra driver is a child of the twl6040 MFD dirver. | ||
4 | Documentation/devicetree/bindings/mfd/twl6040.txt | ||
5 | |||
6 | Required properties: | ||
7 | - compatible : Must be "ti,twl6040-vibra"; | ||
8 | - interrupts: 4, Vibra overcurrent interrupt | ||
9 | - vddvibl-supply: Regulator supplying the left vibra motor | ||
10 | - vddvibr-supply: Regulator supplying the right vibra motor | ||
11 | - vibldrv_res: Board specific left driver resistance | ||
12 | - vibrdrv_res: Board specific right driver resistance | ||
13 | - viblmotor_res: Board specific left motor resistance | ||
14 | - vibrmotor_res: Board specific right motor resistance | ||
15 | |||
16 | Optional properties: | ||
17 | - vddvibl_uV: If the vddvibl default voltage need to be changed | ||
18 | - vddvibr_uV: If the vddvibr default voltage need to be changed | ||
19 | |||
20 | Example: | ||
21 | /* | ||
22 | * 8-channel high quality low-power audio codec | ||
23 | * http://www.ti.com/lit/ds/symlink/twl6040.pdf | ||
24 | */ | ||
25 | twl6040: twl6040@4b { | ||
26 | ... | ||
27 | twl6040_vibra: twl6040@1 { | ||
28 | compatible = "ti,twl6040-vibra"; | ||
29 | interrupts = <4>; | ||
30 | vddvibl-supply = <&vbat>; | ||
31 | vddvibr-supply = <&vbat>; | ||
32 | vibldrv_res = <8>; | ||
33 | vibrdrv_res = <3>; | ||
34 | viblmotor_res = <10>; | ||
35 | vibrmotor_res = <10>; | ||
36 | }; | ||
37 | }; | ||
38 | 1 | Vibra driver for the twl6040 family |
drivers/input/misc/twl6040-vibra.c
1 | /* | 1 | /* |
2 | * twl6040-vibra.c - TWL6040 Vibrator driver | 2 | * twl6040-vibra.c - TWL6040 Vibrator driver |
3 | * | 3 | * |
4 | * Author: Jorge Eduardo Candelaria <jorge.candelaria@ti.com> | 4 | * Author: Jorge Eduardo Candelaria <jorge.candelaria@ti.com> |
5 | * Author: Misael Lopez Cruz <misael.lopez@ti.com> | 5 | * Author: Misael Lopez Cruz <misael.lopez@ti.com> |
6 | * | 6 | * |
7 | * Copyright: (C) 2011 Texas Instruments, Inc. | 7 | * Copyright: (C) 2011 Texas Instruments, Inc. |
8 | * | 8 | * |
9 | * Based on twl4030-vibra.c by Henrik Saari <henrik.saari@nokia.com> | 9 | * Based on twl4030-vibra.c by Henrik Saari <henrik.saari@nokia.com> |
10 | * Felipe Balbi <felipe.balbi@nokia.com> | 10 | * Felipe Balbi <felipe.balbi@nokia.com> |
11 | * Jari Vanhala <ext-javi.vanhala@nokia.com> | 11 | * Jari Vanhala <ext-javi.vanhala@nokia.com> |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License version 2 as | 14 | * it under the terms of the GNU General Public License version 2 as |
15 | * published by the Free Software Foundation. | 15 | * published by the Free Software Foundation. |
16 | * | 16 | * |
17 | * This program is distributed in the hope that it will be useful, but | 17 | * This program is distributed in the hope that it will be useful, but |
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
20 | * General Public License for more details. | 20 | * General Public License for more details. |
21 | * | 21 | * |
22 | * You should have received a copy of the GNU General Public License | 22 | * You should have received a copy of the GNU General Public License |
23 | * along with this program; if not, write to the Free Software | 23 | * along with this program; if not, write to the Free Software |
24 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | 24 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
25 | * 02110-1301 USA | 25 | * 02110-1301 USA |
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
30 | #include <linux/of.h> | 30 | #include <linux/of.h> |
31 | #include <linux/workqueue.h> | 31 | #include <linux/workqueue.h> |
32 | #include <linux/input.h> | 32 | #include <linux/input.h> |
33 | #include <linux/mfd/twl6040.h> | 33 | #include <linux/mfd/twl6040.h> |
34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
35 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
36 | #include <linux/regulator/consumer.h> | 36 | #include <linux/regulator/consumer.h> |
37 | 37 | ||
38 | #define EFFECT_DIR_180_DEG 0x8000 | 38 | #define EFFECT_DIR_180_DEG 0x8000 |
39 | 39 | ||
40 | /* Recommended modulation index 85% */ | 40 | /* Recommended modulation index 85% */ |
41 | #define TWL6040_VIBRA_MOD 85 | 41 | #define TWL6040_VIBRA_MOD 85 |
42 | 42 | ||
43 | #define TWL6040_NUM_SUPPLIES 2 | 43 | #define TWL6040_NUM_SUPPLIES 2 |
44 | 44 | ||
45 | struct vibra_info { | 45 | struct vibra_info { |
46 | struct device *dev; | 46 | struct device *dev; |
47 | struct input_dev *input_dev; | 47 | struct input_dev *input_dev; |
48 | struct workqueue_struct *workqueue; | 48 | struct workqueue_struct *workqueue; |
49 | struct work_struct play_work; | 49 | struct work_struct play_work; |
50 | struct mutex mutex; | 50 | struct mutex mutex; |
51 | int irq; | 51 | int irq; |
52 | 52 | ||
53 | bool enabled; | 53 | bool enabled; |
54 | int weak_speed; | 54 | int weak_speed; |
55 | int strong_speed; | 55 | int strong_speed; |
56 | int direction; | 56 | int direction; |
57 | 57 | ||
58 | unsigned int vibldrv_res; | 58 | unsigned int vibldrv_res; |
59 | unsigned int vibrdrv_res; | 59 | unsigned int vibrdrv_res; |
60 | unsigned int viblmotor_res; | 60 | unsigned int viblmotor_res; |
61 | unsigned int vibrmotor_res; | 61 | unsigned int vibrmotor_res; |
62 | 62 | ||
63 | struct regulator_bulk_data supplies[TWL6040_NUM_SUPPLIES]; | 63 | struct regulator_bulk_data supplies[TWL6040_NUM_SUPPLIES]; |
64 | 64 | ||
65 | struct twl6040 *twl6040; | 65 | struct twl6040 *twl6040; |
66 | }; | 66 | }; |
67 | 67 | ||
68 | static irqreturn_t twl6040_vib_irq_handler(int irq, void *data) | 68 | static irqreturn_t twl6040_vib_irq_handler(int irq, void *data) |
69 | { | 69 | { |
70 | struct vibra_info *info = data; | 70 | struct vibra_info *info = data; |
71 | struct twl6040 *twl6040 = info->twl6040; | 71 | struct twl6040 *twl6040 = info->twl6040; |
72 | u8 status; | 72 | u8 status; |
73 | 73 | ||
74 | status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS); | 74 | status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS); |
75 | if (status & TWL6040_VIBLOCDET) { | 75 | if (status & TWL6040_VIBLOCDET) { |
76 | dev_warn(info->dev, "Left Vibrator overcurrent detected\n"); | 76 | dev_warn(info->dev, "Left Vibrator overcurrent detected\n"); |
77 | twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL, | 77 | twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL, |
78 | TWL6040_VIBENA); | 78 | TWL6040_VIBENA); |
79 | } | 79 | } |
80 | if (status & TWL6040_VIBROCDET) { | 80 | if (status & TWL6040_VIBROCDET) { |
81 | dev_warn(info->dev, "Right Vibrator overcurrent detected\n"); | 81 | dev_warn(info->dev, "Right Vibrator overcurrent detected\n"); |
82 | twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR, | 82 | twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR, |
83 | TWL6040_VIBENA); | 83 | TWL6040_VIBENA); |
84 | } | 84 | } |
85 | 85 | ||
86 | return IRQ_HANDLED; | 86 | return IRQ_HANDLED; |
87 | } | 87 | } |
88 | 88 | ||
89 | static void twl6040_vibra_enable(struct vibra_info *info) | 89 | static void twl6040_vibra_enable(struct vibra_info *info) |
90 | { | 90 | { |
91 | struct twl6040 *twl6040 = info->twl6040; | 91 | struct twl6040 *twl6040 = info->twl6040; |
92 | int ret; | 92 | int ret; |
93 | 93 | ||
94 | ret = regulator_bulk_enable(ARRAY_SIZE(info->supplies), info->supplies); | 94 | ret = regulator_bulk_enable(ARRAY_SIZE(info->supplies), info->supplies); |
95 | if (ret) { | 95 | if (ret) { |
96 | dev_err(info->dev, "failed to enable regulators %d\n", ret); | 96 | dev_err(info->dev, "failed to enable regulators %d\n", ret); |
97 | return; | 97 | return; |
98 | } | 98 | } |
99 | 99 | ||
100 | twl6040_power(info->twl6040, 1); | 100 | twl6040_power(info->twl6040, 1); |
101 | if (twl6040_get_revid(twl6040) <= TWL6040_REV_ES1_1) { | 101 | if (twl6040_get_revid(twl6040) <= TWL6040_REV_ES1_1) { |
102 | /* | 102 | /* |
103 | * ERRATA: Disable overcurrent protection for at least | 103 | * ERRATA: Disable overcurrent protection for at least |
104 | * 3ms when enabling vibrator drivers to avoid false | 104 | * 3ms when enabling vibrator drivers to avoid false |
105 | * overcurrent detection | 105 | * overcurrent detection |
106 | */ | 106 | */ |
107 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, | 107 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, |
108 | TWL6040_VIBENA | TWL6040_VIBCTRL); | 108 | TWL6040_VIBENA | TWL6040_VIBCTRL); |
109 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, | 109 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, |
110 | TWL6040_VIBENA | TWL6040_VIBCTRL); | 110 | TWL6040_VIBENA | TWL6040_VIBCTRL); |
111 | usleep_range(3000, 3500); | 111 | usleep_range(3000, 3500); |
112 | } | 112 | } |
113 | 113 | ||
114 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, | 114 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, |
115 | TWL6040_VIBENA); | 115 | TWL6040_VIBENA); |
116 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, | 116 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, |
117 | TWL6040_VIBENA); | 117 | TWL6040_VIBENA); |
118 | 118 | ||
119 | info->enabled = true; | 119 | info->enabled = true; |
120 | } | 120 | } |
121 | 121 | ||
122 | static void twl6040_vibra_disable(struct vibra_info *info) | 122 | static void twl6040_vibra_disable(struct vibra_info *info) |
123 | { | 123 | { |
124 | struct twl6040 *twl6040 = info->twl6040; | 124 | struct twl6040 *twl6040 = info->twl6040; |
125 | 125 | ||
126 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, 0x00); | 126 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, 0x00); |
127 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, 0x00); | 127 | twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, 0x00); |
128 | twl6040_power(info->twl6040, 0); | 128 | twl6040_power(info->twl6040, 0); |
129 | 129 | ||
130 | regulator_bulk_disable(ARRAY_SIZE(info->supplies), info->supplies); | 130 | regulator_bulk_disable(ARRAY_SIZE(info->supplies), info->supplies); |
131 | 131 | ||
132 | info->enabled = false; | 132 | info->enabled = false; |
133 | } | 133 | } |
134 | 134 | ||
135 | static u8 twl6040_vibra_code(int vddvib, int vibdrv_res, int motor_res, | 135 | static u8 twl6040_vibra_code(int vddvib, int vibdrv_res, int motor_res, |
136 | int speed, int direction) | 136 | int speed, int direction) |
137 | { | 137 | { |
138 | int vpk, max_code; | 138 | int vpk, max_code; |
139 | u8 vibdat; | 139 | u8 vibdat; |
140 | 140 | ||
141 | /* output swing */ | 141 | /* output swing */ |
142 | vpk = (vddvib * motor_res * TWL6040_VIBRA_MOD) / | 142 | vpk = (vddvib * motor_res * TWL6040_VIBRA_MOD) / |
143 | (100 * (vibdrv_res + motor_res)); | 143 | (100 * (vibdrv_res + motor_res)); |
144 | 144 | ||
145 | /* 50mV per VIBDAT code step */ | 145 | /* 50mV per VIBDAT code step */ |
146 | max_code = vpk / 50; | 146 | max_code = vpk / 50; |
147 | if (max_code > TWL6040_VIBDAT_MAX) | 147 | if (max_code > TWL6040_VIBDAT_MAX) |
148 | max_code = TWL6040_VIBDAT_MAX; | 148 | max_code = TWL6040_VIBDAT_MAX; |
149 | 149 | ||
150 | /* scale speed to max allowed code */ | 150 | /* scale speed to max allowed code */ |
151 | vibdat = (u8)((speed * max_code) / USHRT_MAX); | 151 | vibdat = (u8)((speed * max_code) / USHRT_MAX); |
152 | 152 | ||
153 | /* 2's complement for direction > 180 degrees */ | 153 | /* 2's complement for direction > 180 degrees */ |
154 | vibdat *= direction; | 154 | vibdat *= direction; |
155 | 155 | ||
156 | return vibdat; | 156 | return vibdat; |
157 | } | 157 | } |
158 | 158 | ||
159 | static void twl6040_vibra_set_effect(struct vibra_info *info) | 159 | static void twl6040_vibra_set_effect(struct vibra_info *info) |
160 | { | 160 | { |
161 | struct twl6040 *twl6040 = info->twl6040; | 161 | struct twl6040 *twl6040 = info->twl6040; |
162 | u8 vibdatl, vibdatr; | 162 | u8 vibdatl, vibdatr; |
163 | int volt; | 163 | int volt; |
164 | 164 | ||
165 | /* weak motor */ | 165 | /* weak motor */ |
166 | volt = regulator_get_voltage(info->supplies[0].consumer) / 1000; | 166 | volt = regulator_get_voltage(info->supplies[0].consumer) / 1000; |
167 | vibdatl = twl6040_vibra_code(volt, info->vibldrv_res, | 167 | vibdatl = twl6040_vibra_code(volt, info->vibldrv_res, |
168 | info->viblmotor_res, | 168 | info->viblmotor_res, |
169 | info->weak_speed, info->direction); | 169 | info->weak_speed, info->direction); |
170 | 170 | ||
171 | /* strong motor */ | 171 | /* strong motor */ |
172 | volt = regulator_get_voltage(info->supplies[1].consumer) / 1000; | 172 | volt = regulator_get_voltage(info->supplies[1].consumer) / 1000; |
173 | vibdatr = twl6040_vibra_code(volt, info->vibrdrv_res, | 173 | vibdatr = twl6040_vibra_code(volt, info->vibrdrv_res, |
174 | info->vibrmotor_res, | 174 | info->vibrmotor_res, |
175 | info->strong_speed, info->direction); | 175 | info->strong_speed, info->direction); |
176 | 176 | ||
177 | twl6040_reg_write(twl6040, TWL6040_REG_VIBDATL, vibdatl); | 177 | twl6040_reg_write(twl6040, TWL6040_REG_VIBDATL, vibdatl); |
178 | twl6040_reg_write(twl6040, TWL6040_REG_VIBDATR, vibdatr); | 178 | twl6040_reg_write(twl6040, TWL6040_REG_VIBDATR, vibdatr); |
179 | } | 179 | } |
180 | 180 | ||
181 | static void vibra_play_work(struct work_struct *work) | 181 | static void vibra_play_work(struct work_struct *work) |
182 | { | 182 | { |
183 | struct vibra_info *info = container_of(work, | 183 | struct vibra_info *info = container_of(work, |
184 | struct vibra_info, play_work); | 184 | struct vibra_info, play_work); |
185 | 185 | ||
186 | mutex_lock(&info->mutex); | 186 | mutex_lock(&info->mutex); |
187 | 187 | ||
188 | if (info->weak_speed || info->strong_speed) { | 188 | if (info->weak_speed || info->strong_speed) { |
189 | if (!info->enabled) | 189 | if (!info->enabled) |
190 | twl6040_vibra_enable(info); | 190 | twl6040_vibra_enable(info); |
191 | 191 | ||
192 | twl6040_vibra_set_effect(info); | 192 | twl6040_vibra_set_effect(info); |
193 | } else if (info->enabled) | 193 | } else if (info->enabled) |
194 | twl6040_vibra_disable(info); | 194 | twl6040_vibra_disable(info); |
195 | 195 | ||
196 | mutex_unlock(&info->mutex); | 196 | mutex_unlock(&info->mutex); |
197 | } | 197 | } |
198 | 198 | ||
199 | static int vibra_play(struct input_dev *input, void *data, | 199 | static int vibra_play(struct input_dev *input, void *data, |
200 | struct ff_effect *effect) | 200 | struct ff_effect *effect) |
201 | { | 201 | { |
202 | struct vibra_info *info = input_get_drvdata(input); | 202 | struct vibra_info *info = input_get_drvdata(input); |
203 | int ret; | 203 | int ret; |
204 | 204 | ||
205 | /* Do not allow effect, while the routing is set to use audio */ | 205 | /* Do not allow effect, while the routing is set to use audio */ |
206 | ret = twl6040_get_vibralr_status(info->twl6040); | 206 | ret = twl6040_get_vibralr_status(info->twl6040); |
207 | if (ret & TWL6040_VIBSEL) { | 207 | if (ret & TWL6040_VIBSEL) { |
208 | dev_info(&input->dev, "Vibra is configured for audio\n"); | 208 | dev_info(&input->dev, "Vibra is configured for audio\n"); |
209 | return -EBUSY; | 209 | return -EBUSY; |
210 | } | 210 | } |
211 | 211 | ||
212 | info->weak_speed = effect->u.rumble.weak_magnitude; | 212 | info->weak_speed = effect->u.rumble.weak_magnitude; |
213 | info->strong_speed = effect->u.rumble.strong_magnitude; | 213 | info->strong_speed = effect->u.rumble.strong_magnitude; |
214 | info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1; | 214 | info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1; |
215 | 215 | ||
216 | ret = queue_work(info->workqueue, &info->play_work); | 216 | ret = queue_work(info->workqueue, &info->play_work); |
217 | if (!ret) { | 217 | if (!ret) { |
218 | dev_info(&input->dev, "work is already on queue\n"); | 218 | dev_info(&input->dev, "work is already on queue\n"); |
219 | return ret; | 219 | return ret; |
220 | } | 220 | } |
221 | 221 | ||
222 | return 0; | 222 | return 0; |
223 | } | 223 | } |
224 | 224 | ||
225 | static void twl6040_vibra_close(struct input_dev *input) | 225 | static void twl6040_vibra_close(struct input_dev *input) |
226 | { | 226 | { |
227 | struct vibra_info *info = input_get_drvdata(input); | 227 | struct vibra_info *info = input_get_drvdata(input); |
228 | 228 | ||
229 | cancel_work_sync(&info->play_work); | 229 | cancel_work_sync(&info->play_work); |
230 | 230 | ||
231 | mutex_lock(&info->mutex); | 231 | mutex_lock(&info->mutex); |
232 | 232 | ||
233 | if (info->enabled) | 233 | if (info->enabled) |
234 | twl6040_vibra_disable(info); | 234 | twl6040_vibra_disable(info); |
235 | 235 | ||
236 | mutex_unlock(&info->mutex); | 236 | mutex_unlock(&info->mutex); |
237 | } | 237 | } |
238 | 238 | ||
239 | #ifdef CONFIG_PM_SLEEP | 239 | #ifdef CONFIG_PM_SLEEP |
240 | static int twl6040_vibra_suspend(struct device *dev) | 240 | static int twl6040_vibra_suspend(struct device *dev) |
241 | { | 241 | { |
242 | struct platform_device *pdev = to_platform_device(dev); | 242 | struct platform_device *pdev = to_platform_device(dev); |
243 | struct vibra_info *info = platform_get_drvdata(pdev); | 243 | struct vibra_info *info = platform_get_drvdata(pdev); |
244 | 244 | ||
245 | mutex_lock(&info->mutex); | 245 | mutex_lock(&info->mutex); |
246 | 246 | ||
247 | if (info->enabled) | 247 | if (info->enabled) |
248 | twl6040_vibra_disable(info); | 248 | twl6040_vibra_disable(info); |
249 | 249 | ||
250 | mutex_unlock(&info->mutex); | 250 | mutex_unlock(&info->mutex); |
251 | 251 | ||
252 | return 0; | 252 | return 0; |
253 | } | 253 | } |
254 | |||
255 | #endif | 254 | #endif |
256 | 255 | ||
257 | static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL); | 256 | static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL); |
258 | 257 | ||
259 | static int __devinit twl6040_vibra_probe(struct platform_device *pdev) | 258 | static int __devinit twl6040_vibra_probe(struct platform_device *pdev) |
260 | { | 259 | { |
261 | struct twl6040_vibra_data *pdata = pdev->dev.platform_data; | 260 | struct twl6040_vibra_data *pdata = pdev->dev.platform_data; |
262 | struct device_node *node = pdev->dev.of_node; | 261 | struct device *twl6040_core_dev = pdev->dev.parent; |
262 | struct device_node *twl6040_core_node = NULL; | ||
263 | struct vibra_info *info; | 263 | struct vibra_info *info; |
264 | int vddvibl_uV = 0; | 264 | int vddvibl_uV = 0; |
265 | int vddvibr_uV = 0; | 265 | int vddvibr_uV = 0; |
266 | int ret; | 266 | int ret; |
267 | 267 | ||
268 | if (!pdata && !node) { | 268 | #ifdef CONFIG_OF |
269 | twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node, | ||
270 | "vibra"); | ||
271 | #endif | ||
272 | |||
273 | if (!pdata && !twl6040_core_node) { | ||
269 | dev_err(&pdev->dev, "platform_data not available\n"); | 274 | dev_err(&pdev->dev, "platform_data not available\n"); |
270 | return -EINVAL; | 275 | return -EINVAL; |
271 | } | 276 | } |
272 | 277 | ||
273 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 278 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
274 | if (!info) { | 279 | if (!info) { |
275 | dev_err(&pdev->dev, "couldn't allocate memory\n"); | 280 | dev_err(&pdev->dev, "couldn't allocate memory\n"); |
276 | return -ENOMEM; | 281 | return -ENOMEM; |
277 | } | 282 | } |
278 | 283 | ||
279 | info->dev = &pdev->dev; | 284 | info->dev = &pdev->dev; |
280 | 285 | ||
281 | info->twl6040 = dev_get_drvdata(pdev->dev.parent); | 286 | info->twl6040 = dev_get_drvdata(pdev->dev.parent); |
282 | if (pdata) { | 287 | if (pdata) { |
283 | info->vibldrv_res = pdata->vibldrv_res; | 288 | info->vibldrv_res = pdata->vibldrv_res; |
284 | info->vibrdrv_res = pdata->vibrdrv_res; | 289 | info->vibrdrv_res = pdata->vibrdrv_res; |
285 | info->viblmotor_res = pdata->viblmotor_res; | 290 | info->viblmotor_res = pdata->viblmotor_res; |
286 | info->vibrmotor_res = pdata->vibrmotor_res; | 291 | info->vibrmotor_res = pdata->vibrmotor_res; |
287 | vddvibl_uV = pdata->vddvibl_uV; | 292 | vddvibl_uV = pdata->vddvibl_uV; |
288 | vddvibr_uV = pdata->vddvibr_uV; | 293 | vddvibr_uV = pdata->vddvibr_uV; |
289 | } else { | 294 | } else { |
290 | of_property_read_u32(node, "vibldrv_res", &info->vibldrv_res); | 295 | of_property_read_u32(twl6040_core_node, "ti,vibldrv-res", |
291 | of_property_read_u32(node, "vibrdrv_res", &info->vibrdrv_res); | 296 | &info->vibldrv_res); |
292 | of_property_read_u32(node, "viblmotor_res", | 297 | of_property_read_u32(twl6040_core_node, "ti,vibrdrv-res", |
298 | &info->vibrdrv_res); | ||
299 | of_property_read_u32(twl6040_core_node, "ti,viblmotor-res", | ||
293 | &info->viblmotor_res); | 300 | &info->viblmotor_res); |
294 | of_property_read_u32(node, "vibrmotor_res", | 301 | of_property_read_u32(twl6040_core_node, "ti,vibrmotor-res", |
295 | &info->vibrmotor_res); | 302 | &info->vibrmotor_res); |
296 | of_property_read_u32(node, "vddvibl_uV", &vddvibl_uV); | 303 | of_property_read_u32(twl6040_core_node, "ti,vddvibl-uV", |
297 | of_property_read_u32(node, "vddvibr_uV", &vddvibr_uV); | 304 | &vddvibl_uV); |
305 | of_property_read_u32(twl6040_core_node, "ti,vddvibr-uV", | ||
306 | &vddvibr_uV); | ||
298 | } | 307 | } |
299 | 308 | ||
300 | if ((!info->vibldrv_res && !info->viblmotor_res) || | 309 | if ((!info->vibldrv_res && !info->viblmotor_res) || |
301 | (!info->vibrdrv_res && !info->vibrmotor_res)) { | 310 | (!info->vibrdrv_res && !info->vibrmotor_res)) { |
302 | dev_err(info->dev, "invalid vibra driver/motor resistance\n"); | 311 | dev_err(info->dev, "invalid vibra driver/motor resistance\n"); |
303 | ret = -EINVAL; | 312 | ret = -EINVAL; |
304 | goto err_kzalloc; | 313 | goto err_kzalloc; |
305 | } | 314 | } |
306 | 315 | ||
307 | info->irq = platform_get_irq(pdev, 0); | 316 | info->irq = platform_get_irq(pdev, 0); |
308 | if (info->irq < 0) { | 317 | if (info->irq < 0) { |
309 | dev_err(info->dev, "invalid irq\n"); | 318 | dev_err(info->dev, "invalid irq\n"); |
310 | ret = -EINVAL; | 319 | ret = -EINVAL; |
311 | goto err_kzalloc; | 320 | goto err_kzalloc; |
312 | } | 321 | } |
313 | 322 | ||
314 | mutex_init(&info->mutex); | 323 | mutex_init(&info->mutex); |
315 | 324 | ||
316 | info->input_dev = input_allocate_device(); | 325 | info->input_dev = input_allocate_device(); |
317 | if (info->input_dev == NULL) { | 326 | if (info->input_dev == NULL) { |
318 | dev_err(info->dev, "couldn't allocate input device\n"); | 327 | dev_err(info->dev, "couldn't allocate input device\n"); |
319 | ret = -ENOMEM; | 328 | ret = -ENOMEM; |
320 | goto err_kzalloc; | 329 | goto err_kzalloc; |
321 | } | 330 | } |
322 | 331 | ||
323 | input_set_drvdata(info->input_dev, info); | 332 | input_set_drvdata(info->input_dev, info); |
324 | 333 | ||
325 | info->input_dev->name = "twl6040:vibrator"; | 334 | info->input_dev->name = "twl6040:vibrator"; |
326 | info->input_dev->id.version = 1; | 335 | info->input_dev->id.version = 1; |
327 | info->input_dev->dev.parent = pdev->dev.parent; | 336 | info->input_dev->dev.parent = pdev->dev.parent; |
328 | info->input_dev->close = twl6040_vibra_close; | 337 | info->input_dev->close = twl6040_vibra_close; |
329 | __set_bit(FF_RUMBLE, info->input_dev->ffbit); | 338 | __set_bit(FF_RUMBLE, info->input_dev->ffbit); |
330 | 339 | ||
331 | ret = input_ff_create_memless(info->input_dev, NULL, vibra_play); | 340 | ret = input_ff_create_memless(info->input_dev, NULL, vibra_play); |
332 | if (ret < 0) { | 341 | if (ret < 0) { |
333 | dev_err(info->dev, "couldn't register vibrator to FF\n"); | 342 | dev_err(info->dev, "couldn't register vibrator to FF\n"); |
334 | goto err_ialloc; | 343 | goto err_ialloc; |
335 | } | 344 | } |
336 | 345 | ||
337 | ret = input_register_device(info->input_dev); | 346 | ret = input_register_device(info->input_dev); |
338 | if (ret < 0) { | 347 | if (ret < 0) { |
339 | dev_err(info->dev, "couldn't register input device\n"); | 348 | dev_err(info->dev, "couldn't register input device\n"); |
340 | goto err_iff; | 349 | goto err_iff; |
341 | } | 350 | } |
342 | 351 | ||
343 | platform_set_drvdata(pdev, info); | 352 | platform_set_drvdata(pdev, info); |
344 | 353 | ||
345 | ret = request_threaded_irq(info->irq, NULL, twl6040_vib_irq_handler, 0, | 354 | ret = request_threaded_irq(info->irq, NULL, twl6040_vib_irq_handler, 0, |
346 | "twl6040_irq_vib", info); | 355 | "twl6040_irq_vib", info); |
347 | if (ret) { | 356 | if (ret) { |
348 | dev_err(info->dev, "VIB IRQ request failed: %d\n", ret); | 357 | dev_err(info->dev, "VIB IRQ request failed: %d\n", ret); |
349 | goto err_irq; | 358 | goto err_irq; |
350 | } | 359 | } |
351 | 360 | ||
352 | info->supplies[0].supply = "vddvibl"; | 361 | info->supplies[0].supply = "vddvibl"; |
353 | info->supplies[1].supply = "vddvibr"; | 362 | info->supplies[1].supply = "vddvibr"; |
354 | ret = regulator_bulk_get(info->dev, ARRAY_SIZE(info->supplies), | 363 | /* |
355 | info->supplies); | 364 | * When booted with Device tree the regulators are attached to the |
365 | * parent device (twl6040 MFD core) | ||
366 | */ | ||
367 | ret = regulator_bulk_get(pdata ? info->dev : twl6040_core_dev, | ||
368 | ARRAY_SIZE(info->supplies), info->supplies); | ||
356 | if (ret) { | 369 | if (ret) { |
357 | dev_err(info->dev, "couldn't get regulators %d\n", ret); | 370 | dev_err(info->dev, "couldn't get regulators %d\n", ret); |
358 | goto err_regulator; | 371 | goto err_regulator; |
359 | } | 372 | } |
360 | 373 | ||
361 | if (vddvibl_uV) { | 374 | if (vddvibl_uV) { |
362 | ret = regulator_set_voltage(info->supplies[0].consumer, | 375 | ret = regulator_set_voltage(info->supplies[0].consumer, |
363 | vddvibl_uV, vddvibl_uV); | 376 | vddvibl_uV, vddvibl_uV); |
364 | if (ret) { | 377 | if (ret) { |
365 | dev_err(info->dev, "failed to set VDDVIBL volt %d\n", | 378 | dev_err(info->dev, "failed to set VDDVIBL volt %d\n", |
366 | ret); | 379 | ret); |
367 | goto err_voltage; | 380 | goto err_voltage; |
368 | } | 381 | } |
369 | } | 382 | } |
370 | 383 | ||
371 | if (vddvibr_uV) { | 384 | if (vddvibr_uV) { |
372 | ret = regulator_set_voltage(info->supplies[1].consumer, | 385 | ret = regulator_set_voltage(info->supplies[1].consumer, |
373 | vddvibr_uV, vddvibr_uV); | 386 | vddvibr_uV, vddvibr_uV); |
374 | if (ret) { | 387 | if (ret) { |
375 | dev_err(info->dev, "failed to set VDDVIBR volt %d\n", | 388 | dev_err(info->dev, "failed to set VDDVIBR volt %d\n", |
376 | ret); | 389 | ret); |
377 | goto err_voltage; | 390 | goto err_voltage; |
378 | } | 391 | } |
379 | } | 392 | } |
380 | 393 | ||
381 | info->workqueue = alloc_workqueue("twl6040-vibra", 0, 0); | 394 | info->workqueue = alloc_workqueue("twl6040-vibra", 0, 0); |
382 | if (info->workqueue == NULL) { | 395 | if (info->workqueue == NULL) { |
383 | dev_err(info->dev, "couldn't create workqueue\n"); | 396 | dev_err(info->dev, "couldn't create workqueue\n"); |
384 | ret = -ENOMEM; | 397 | ret = -ENOMEM; |
385 | goto err_voltage; | 398 | goto err_voltage; |
386 | } | 399 | } |
387 | INIT_WORK(&info->play_work, vibra_play_work); | 400 | INIT_WORK(&info->play_work, vibra_play_work); |
388 | 401 | ||
389 | return 0; | 402 | return 0; |
390 | 403 | ||
391 | err_voltage: | 404 | err_voltage: |
392 | regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); | 405 | regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); |
393 | err_regulator: | 406 | err_regulator: |
394 | free_irq(info->irq, info); | 407 | free_irq(info->irq, info); |
395 | err_irq: | 408 | err_irq: |
396 | input_unregister_device(info->input_dev); | 409 | input_unregister_device(info->input_dev); |
397 | info->input_dev = NULL; | 410 | info->input_dev = NULL; |
398 | err_iff: | 411 | err_iff: |
399 | if (info->input_dev) | 412 | if (info->input_dev) |
400 | input_ff_destroy(info->input_dev); | 413 | input_ff_destroy(info->input_dev); |
401 | err_ialloc: | 414 | err_ialloc: |
402 | input_free_device(info->input_dev); | 415 | input_free_device(info->input_dev); |
403 | err_kzalloc: | 416 | err_kzalloc: |
404 | kfree(info); | 417 | kfree(info); |
405 | return ret; | 418 | return ret; |
406 | } | 419 | } |
407 | 420 | ||
408 | static int __devexit twl6040_vibra_remove(struct platform_device *pdev) | 421 | static int __devexit twl6040_vibra_remove(struct platform_device *pdev) |
409 | { | 422 | { |
410 | struct vibra_info *info = platform_get_drvdata(pdev); | 423 | struct vibra_info *info = platform_get_drvdata(pdev); |
411 | 424 | ||
412 | input_unregister_device(info->input_dev); | 425 | input_unregister_device(info->input_dev); |
413 | free_irq(info->irq, info); | 426 | free_irq(info->irq, info); |
414 | regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); | 427 | regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); |
415 | destroy_workqueue(info->workqueue); | 428 | destroy_workqueue(info->workqueue); |
416 | kfree(info); | 429 | kfree(info); |
417 | 430 | ||
418 | return 0; | 431 | return 0; |
419 | } | 432 | } |
420 | 433 | ||
421 | static const struct of_device_id twl6040_vibra_of_match[] = { | ||
422 | {.compatible = "ti,twl6040-vibra", }, | ||
423 | { }, | ||
424 | }; | ||
425 | MODULE_DEVICE_TABLE(of, twl6040_vibra_of_match); | ||
426 | |||
427 | static struct platform_driver twl6040_vibra_driver = { | 434 | static struct platform_driver twl6040_vibra_driver = { |
428 | .probe = twl6040_vibra_probe, | 435 | .probe = twl6040_vibra_probe, |
429 | .remove = __devexit_p(twl6040_vibra_remove), | 436 | .remove = __devexit_p(twl6040_vibra_remove), |
430 | .driver = { | 437 | .driver = { |
431 | .name = "twl6040-vibra", | 438 | .name = "twl6040-vibra", |
432 | .owner = THIS_MODULE, | 439 | .owner = THIS_MODULE, |
433 | .pm = &twl6040_vibra_pm_ops, | 440 | .pm = &twl6040_vibra_pm_ops, |
434 | .of_match_table = twl6040_vibra_of_match, | ||
435 | }, | 441 | }, |
436 | }; | 442 | }; |