diff options
Diffstat (limited to 'drivers/mfd')
79 files changed, 14748 insertions, 2962 deletions
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 07933f3f7e4c..17dfe9bb6d27 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c | |||
@@ -17,193 +17,141 @@ | |||
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/mfd/core.h> | 18 | #include <linux/mfd/core.h> |
19 | #include <linux/mfd/88pm860x.h> | 19 | #include <linux/mfd/88pm860x.h> |
20 | #include <linux/regulator/machine.h> | ||
20 | 21 | ||
21 | #define INT_STATUS_NUM 3 | 22 | #define INT_STATUS_NUM 3 |
22 | 23 | ||
23 | char pm860x_backlight_name[][MFD_NAME_SIZE] = { | 24 | static struct resource bk_resources[] __devinitdata = { |
24 | "backlight-0", | 25 | {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,}, |
25 | "backlight-1", | 26 | {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,}, |
26 | "backlight-2", | 27 | {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,}, |
27 | }; | 28 | }; |
28 | EXPORT_SYMBOL(pm860x_backlight_name); | ||
29 | |||
30 | char pm860x_led_name[][MFD_NAME_SIZE] = { | ||
31 | "led0-red", | ||
32 | "led0-green", | ||
33 | "led0-blue", | ||
34 | "led1-red", | ||
35 | "led1-green", | ||
36 | "led1-blue", | ||
37 | }; | ||
38 | EXPORT_SYMBOL(pm860x_led_name); | ||
39 | |||
40 | #define PM8606_BACKLIGHT_RESOURCE(_i, _x) \ | ||
41 | { \ | ||
42 | .name = pm860x_backlight_name[_i], \ | ||
43 | .start = PM8606_##_x, \ | ||
44 | .end = PM8606_##_x, \ | ||
45 | .flags = IORESOURCE_IO, \ | ||
46 | } | ||
47 | 29 | ||
48 | static struct resource backlight_resources[] = { | 30 | static struct resource led_resources[] __devinitdata = { |
49 | PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT1, WLED1A), | 31 | {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO,}, |
50 | PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT2, WLED2A), | 32 | {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,}, |
51 | PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT3, WLED3A), | 33 | {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO,}, |
34 | {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO,}, | ||
35 | {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,}, | ||
36 | {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,}, | ||
52 | }; | 37 | }; |
53 | 38 | ||
54 | #define PM8606_BACKLIGHT_DEVS(_i) \ | 39 | static struct resource regulator_resources[] __devinitdata = { |
55 | { \ | 40 | {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,}, |
56 | .name = "88pm860x-backlight", \ | 41 | {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,}, |
57 | .num_resources = 1, \ | 42 | {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,}, |
58 | .resources = &backlight_resources[_i], \ | 43 | {PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_IO,}, |
59 | .id = _i, \ | 44 | {PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_IO,}, |
60 | } | 45 | {PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_IO,}, |
61 | 46 | {PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_IO,}, | |
62 | static struct mfd_cell backlight_devs[] = { | 47 | {PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_IO,}, |
63 | PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT1), | 48 | {PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_IO,}, |
64 | PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT2), | 49 | {PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_IO,}, |
65 | PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT3), | 50 | {PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_IO,}, |
51 | {PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_IO,}, | ||
52 | {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,}, | ||
53 | {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,}, | ||
54 | {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,}, | ||
55 | {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,}, | ||
56 | {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,}, | ||
57 | {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,}, | ||
66 | }; | 58 | }; |
67 | 59 | ||
68 | #define PM8606_LED_RESOURCE(_i, _x) \ | 60 | static struct resource touch_resources[] __devinitdata = { |
69 | { \ | 61 | {PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,}, |
70 | .name = pm860x_led_name[_i], \ | 62 | }; |
71 | .start = PM8606_##_x, \ | ||
72 | .end = PM8606_##_x, \ | ||
73 | .flags = IORESOURCE_IO, \ | ||
74 | } | ||
75 | 63 | ||
76 | static struct resource led_resources[] = { | 64 | static struct resource onkey_resources[] __devinitdata = { |
77 | PM8606_LED_RESOURCE(PM8606_LED1_RED, RGB1B), | 65 | {PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,}, |
78 | PM8606_LED_RESOURCE(PM8606_LED1_GREEN, RGB1C), | ||
79 | PM8606_LED_RESOURCE(PM8606_LED1_BLUE, RGB1D), | ||
80 | PM8606_LED_RESOURCE(PM8606_LED2_RED, RGB2B), | ||
81 | PM8606_LED_RESOURCE(PM8606_LED2_GREEN, RGB2C), | ||
82 | PM8606_LED_RESOURCE(PM8606_LED2_BLUE, RGB2D), | ||
83 | }; | 66 | }; |
84 | 67 | ||
85 | #define PM8606_LED_DEVS(_i) \ | 68 | static struct resource codec_resources[] __devinitdata = { |
86 | { \ | 69 | /* Headset microphone insertion or removal */ |
87 | .name = "88pm860x-led", \ | 70 | {PM8607_IRQ_MICIN, PM8607_IRQ_MICIN, "micin", IORESOURCE_IRQ,}, |
88 | .num_resources = 1, \ | 71 | /* Hook-switch press or release */ |
89 | .resources = &led_resources[_i], \ | 72 | {PM8607_IRQ_HOOK, PM8607_IRQ_HOOK, "hook", IORESOURCE_IRQ,}, |
90 | .id = _i, \ | 73 | /* Headset insertion or removal */ |
91 | } | 74 | {PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,}, |
75 | /* Audio short */ | ||
76 | {PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,}, | ||
77 | }; | ||
92 | 78 | ||
93 | static struct mfd_cell led_devs[] = { | 79 | static struct resource battery_resources[] __devinitdata = { |
94 | PM8606_LED_DEVS(PM8606_LED1_RED), | 80 | {PM8607_IRQ_CC, PM8607_IRQ_CC, "columb counter", IORESOURCE_IRQ,}, |
95 | PM8606_LED_DEVS(PM8606_LED1_GREEN), | 81 | {PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery", IORESOURCE_IRQ,}, |
96 | PM8606_LED_DEVS(PM8606_LED1_BLUE), | ||
97 | PM8606_LED_DEVS(PM8606_LED2_RED), | ||
98 | PM8606_LED_DEVS(PM8606_LED2_GREEN), | ||
99 | PM8606_LED_DEVS(PM8606_LED2_BLUE), | ||
100 | }; | 82 | }; |
101 | 83 | ||
102 | static struct resource touch_resources[] = { | 84 | static struct resource charger_resources[] __devinitdata = { |
103 | { | 85 | {PM8607_IRQ_CHG, PM8607_IRQ_CHG, "charger detect", IORESOURCE_IRQ,}, |
104 | .start = PM8607_IRQ_PEN, | 86 | {PM8607_IRQ_CHG_DONE, PM8607_IRQ_CHG_DONE, "charging done", IORESOURCE_IRQ,}, |
105 | .end = PM8607_IRQ_PEN, | 87 | {PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout", IORESOURCE_IRQ,}, |
106 | .flags = IORESOURCE_IRQ, | 88 | {PM8607_IRQ_GPADC1, PM8607_IRQ_GPADC1, "battery temperature", IORESOURCE_IRQ,}, |
107 | }, | 89 | {PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,}, |
90 | {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,}, | ||
108 | }; | 91 | }; |
109 | 92 | ||
110 | static struct mfd_cell touch_devs[] = { | 93 | static struct resource rtc_resources[] __devinitdata = { |
111 | { | 94 | {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,}, |
112 | .name = "88pm860x-touch", | ||
113 | .num_resources = 1, | ||
114 | .resources = &touch_resources[0], | ||
115 | }, | ||
116 | }; | 95 | }; |
117 | 96 | ||
118 | #define PM8607_REG_RESOURCE(_start, _end) \ | 97 | static struct mfd_cell bk_devs[] = { |
119 | { \ | 98 | {"88pm860x-backlight", 0,}, |
120 | .start = PM8607_##_start, \ | 99 | {"88pm860x-backlight", 1,}, |
121 | .end = PM8607_##_end, \ | 100 | {"88pm860x-backlight", 2,}, |
122 | .flags = IORESOURCE_IO, \ | 101 | }; |
123 | } | ||
124 | 102 | ||
125 | static struct resource power_supply_resources[] = { | 103 | static struct mfd_cell led_devs[] = { |
126 | { | 104 | {"88pm860x-led", 0,}, |
127 | .name = "88pm860x-power", | 105 | {"88pm860x-led", 1,}, |
128 | .start = PM8607_IRQ_CHG, | 106 | {"88pm860x-led", 2,}, |
129 | .end = PM8607_IRQ_CHG, | 107 | {"88pm860x-led", 3,}, |
130 | .flags = IORESOURCE_IRQ, | 108 | {"88pm860x-led", 4,}, |
131 | }, | 109 | {"88pm860x-led", 5,}, |
132 | }; | 110 | }; |
133 | 111 | ||
134 | static struct mfd_cell power_devs[] = { | 112 | static struct mfd_cell regulator_devs[] = { |
135 | { | 113 | {"88pm860x-regulator", 0,}, |
136 | .name = "88pm860x-power", | 114 | {"88pm860x-regulator", 1,}, |
137 | .num_resources = 1, | 115 | {"88pm860x-regulator", 2,}, |
138 | .resources = &power_supply_resources[0], | 116 | {"88pm860x-regulator", 3,}, |
139 | .id = -1, | 117 | {"88pm860x-regulator", 4,}, |
140 | }, | 118 | {"88pm860x-regulator", 5,}, |
119 | {"88pm860x-regulator", 6,}, | ||
120 | {"88pm860x-regulator", 7,}, | ||
121 | {"88pm860x-regulator", 8,}, | ||
122 | {"88pm860x-regulator", 9,}, | ||
123 | {"88pm860x-regulator", 10,}, | ||
124 | {"88pm860x-regulator", 11,}, | ||
125 | {"88pm860x-regulator", 12,}, | ||
126 | {"88pm860x-regulator", 13,}, | ||
127 | {"88pm860x-regulator", 14,}, | ||
128 | {"88pm860x-regulator", 15,}, | ||
129 | {"88pm860x-regulator", 16,}, | ||
130 | {"88pm860x-regulator", 17,}, | ||
141 | }; | 131 | }; |
142 | 132 | ||
143 | static struct resource onkey_resources[] = { | 133 | static struct mfd_cell touch_devs[] = { |
144 | { | 134 | {"88pm860x-touch", -1,}, |
145 | .name = "88pm860x-onkey", | ||
146 | .start = PM8607_IRQ_ONKEY, | ||
147 | .end = PM8607_IRQ_ONKEY, | ||
148 | .flags = IORESOURCE_IRQ, | ||
149 | }, | ||
150 | }; | 135 | }; |
151 | 136 | ||
152 | static struct mfd_cell onkey_devs[] = { | 137 | static struct mfd_cell onkey_devs[] = { |
153 | { | 138 | {"88pm860x-onkey", -1,}, |
154 | .name = "88pm860x-onkey", | ||
155 | .num_resources = 1, | ||
156 | .resources = &onkey_resources[0], | ||
157 | .id = -1, | ||
158 | }, | ||
159 | }; | 139 | }; |
160 | 140 | ||
161 | static struct resource regulator_resources[] = { | 141 | static struct mfd_cell codec_devs[] = { |
162 | PM8607_REG_RESOURCE(BUCK1, BUCK1), | 142 | {"88pm860x-codec", -1,}, |
163 | PM8607_REG_RESOURCE(BUCK2, BUCK2), | ||
164 | PM8607_REG_RESOURCE(BUCK3, BUCK3), | ||
165 | PM8607_REG_RESOURCE(LDO1, LDO1), | ||
166 | PM8607_REG_RESOURCE(LDO2, LDO2), | ||
167 | PM8607_REG_RESOURCE(LDO3, LDO3), | ||
168 | PM8607_REG_RESOURCE(LDO4, LDO4), | ||
169 | PM8607_REG_RESOURCE(LDO5, LDO5), | ||
170 | PM8607_REG_RESOURCE(LDO6, LDO6), | ||
171 | PM8607_REG_RESOURCE(LDO7, LDO7), | ||
172 | PM8607_REG_RESOURCE(LDO8, LDO8), | ||
173 | PM8607_REG_RESOURCE(LDO9, LDO9), | ||
174 | PM8607_REG_RESOURCE(LDO10, LDO10), | ||
175 | PM8607_REG_RESOURCE(LDO12, LDO12), | ||
176 | PM8607_REG_RESOURCE(VIBRATOR_SET, VIBRATOR_SET), | ||
177 | PM8607_REG_RESOURCE(LDO14, LDO14), | ||
178 | }; | 143 | }; |
179 | 144 | ||
180 | #define PM8607_REG_DEVS(_id) \ | 145 | static struct mfd_cell power_devs[] = { |
181 | { \ | 146 | {"88pm860x-battery", -1,}, |
182 | .name = "88pm860x-regulator", \ | 147 | {"88pm860x-charger", -1,}, |
183 | .num_resources = 1, \ | 148 | }; |
184 | .resources = ®ulator_resources[PM8607_ID_##_id], \ | ||
185 | .id = PM8607_ID_##_id, \ | ||
186 | } | ||
187 | 149 | ||
188 | static struct mfd_cell regulator_devs[] = { | 150 | static struct mfd_cell rtc_devs[] = { |
189 | PM8607_REG_DEVS(BUCK1), | 151 | {"88pm860x-rtc", -1,}, |
190 | PM8607_REG_DEVS(BUCK2), | ||
191 | PM8607_REG_DEVS(BUCK3), | ||
192 | PM8607_REG_DEVS(LDO1), | ||
193 | PM8607_REG_DEVS(LDO2), | ||
194 | PM8607_REG_DEVS(LDO3), | ||
195 | PM8607_REG_DEVS(LDO4), | ||
196 | PM8607_REG_DEVS(LDO5), | ||
197 | PM8607_REG_DEVS(LDO6), | ||
198 | PM8607_REG_DEVS(LDO7), | ||
199 | PM8607_REG_DEVS(LDO8), | ||
200 | PM8607_REG_DEVS(LDO9), | ||
201 | PM8607_REG_DEVS(LDO10), | ||
202 | PM8607_REG_DEVS(LDO12), | ||
203 | PM8607_REG_DEVS(LDO13), | ||
204 | PM8607_REG_DEVS(LDO14), | ||
205 | }; | 152 | }; |
206 | 153 | ||
154 | |||
207 | struct pm860x_irq_data { | 155 | struct pm860x_irq_data { |
208 | int reg; | 156 | int reg; |
209 | int mask_reg; | 157 | int mask_reg; |
@@ -324,12 +272,6 @@ static struct pm860x_irq_data pm860x_irqs[] = { | |||
324 | }, | 272 | }, |
325 | }; | 273 | }; |
326 | 274 | ||
327 | static inline struct pm860x_irq_data *irq_to_pm860x(struct pm860x_chip *chip, | ||
328 | int irq) | ||
329 | { | ||
330 | return &pm860x_irqs[irq - chip->irq_base]; | ||
331 | } | ||
332 | |||
333 | static irqreturn_t pm860x_irq(int irq, void *data) | 275 | static irqreturn_t pm860x_irq(int irq, void *data) |
334 | { | 276 | { |
335 | struct pm860x_chip *chip = data; | 277 | struct pm860x_chip *chip = data; |
@@ -351,16 +293,16 @@ static irqreturn_t pm860x_irq(int irq, void *data) | |||
351 | return IRQ_HANDLED; | 293 | return IRQ_HANDLED; |
352 | } | 294 | } |
353 | 295 | ||
354 | static void pm860x_irq_lock(unsigned int irq) | 296 | static void pm860x_irq_lock(struct irq_data *data) |
355 | { | 297 | { |
356 | struct pm860x_chip *chip = get_irq_chip_data(irq); | 298 | struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); |
357 | 299 | ||
358 | mutex_lock(&chip->irq_lock); | 300 | mutex_lock(&chip->irq_lock); |
359 | } | 301 | } |
360 | 302 | ||
361 | static void pm860x_irq_sync_unlock(unsigned int irq) | 303 | static void pm860x_irq_sync_unlock(struct irq_data *data) |
362 | { | 304 | { |
363 | struct pm860x_chip *chip = get_irq_chip_data(irq); | 305 | struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); |
364 | struct pm860x_irq_data *irq_data; | 306 | struct pm860x_irq_data *irq_data; |
365 | struct i2c_client *i2c; | 307 | struct i2c_client *i2c; |
366 | static unsigned char cached[3] = {0x0, 0x0, 0x0}; | 308 | static unsigned char cached[3] = {0x0, 0x0, 0x0}; |
@@ -402,25 +344,25 @@ static void pm860x_irq_sync_unlock(unsigned int irq) | |||
402 | mutex_unlock(&chip->irq_lock); | 344 | mutex_unlock(&chip->irq_lock); |
403 | } | 345 | } |
404 | 346 | ||
405 | static void pm860x_irq_enable(unsigned int irq) | 347 | static void pm860x_irq_enable(struct irq_data *data) |
406 | { | 348 | { |
407 | struct pm860x_chip *chip = get_irq_chip_data(irq); | 349 | struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); |
408 | pm860x_irqs[irq - chip->irq_base].enable | 350 | pm860x_irqs[data->irq - chip->irq_base].enable |
409 | = pm860x_irqs[irq - chip->irq_base].offs; | 351 | = pm860x_irqs[data->irq - chip->irq_base].offs; |
410 | } | 352 | } |
411 | 353 | ||
412 | static void pm860x_irq_disable(unsigned int irq) | 354 | static void pm860x_irq_disable(struct irq_data *data) |
413 | { | 355 | { |
414 | struct pm860x_chip *chip = get_irq_chip_data(irq); | 356 | struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); |
415 | pm860x_irqs[irq - chip->irq_base].enable = 0; | 357 | pm860x_irqs[data->irq - chip->irq_base].enable = 0; |
416 | } | 358 | } |
417 | 359 | ||
418 | static struct irq_chip pm860x_irq_chip = { | 360 | static struct irq_chip pm860x_irq_chip = { |
419 | .name = "88pm860x", | 361 | .name = "88pm860x", |
420 | .bus_lock = pm860x_irq_lock, | 362 | .irq_bus_lock = pm860x_irq_lock, |
421 | .bus_sync_unlock = pm860x_irq_sync_unlock, | 363 | .irq_bus_sync_unlock = pm860x_irq_sync_unlock, |
422 | .enable = pm860x_irq_enable, | 364 | .irq_enable = pm860x_irq_enable, |
423 | .disable = pm860x_irq_disable, | 365 | .irq_disable = pm860x_irq_disable, |
424 | }; | 366 | }; |
425 | 367 | ||
426 | static int __devinit device_gpadc_init(struct pm860x_chip *chip, | 368 | static int __devinit device_gpadc_init(struct pm860x_chip *chip, |
@@ -477,7 +419,6 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, | |||
477 | : chip->companion; | 419 | : chip->companion; |
478 | unsigned char status_buf[INT_STATUS_NUM]; | 420 | unsigned char status_buf[INT_STATUS_NUM]; |
479 | unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; | 421 | unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; |
480 | struct irq_desc *desc; | ||
481 | int i, data, mask, ret = -EINVAL; | 422 | int i, data, mask, ret = -EINVAL; |
482 | int __irq; | 423 | int __irq; |
483 | 424 | ||
@@ -529,19 +470,17 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, | |||
529 | if (!chip->core_irq) | 470 | if (!chip->core_irq) |
530 | goto out; | 471 | goto out; |
531 | 472 | ||
532 | desc = irq_to_desc(chip->core_irq); | ||
533 | |||
534 | /* register IRQ by genirq */ | 473 | /* register IRQ by genirq */ |
535 | for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { | 474 | for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { |
536 | __irq = i + chip->irq_base; | 475 | __irq = i + chip->irq_base; |
537 | set_irq_chip_data(__irq, chip); | 476 | irq_set_chip_data(__irq, chip); |
538 | set_irq_chip_and_handler(__irq, &pm860x_irq_chip, | 477 | irq_set_chip_and_handler(__irq, &pm860x_irq_chip, |
539 | handle_edge_irq); | 478 | handle_edge_irq); |
540 | set_irq_nested_thread(__irq, 1); | 479 | irq_set_nested_thread(__irq, 1); |
541 | #ifdef CONFIG_ARM | 480 | #ifdef CONFIG_ARM |
542 | set_irq_flags(__irq, IRQF_VALID); | 481 | set_irq_flags(__irq, IRQF_VALID); |
543 | #else | 482 | #else |
544 | set_irq_noprobe(__irq); | 483 | irq_set_noprobe(__irq); |
545 | #endif | 484 | #endif |
546 | } | 485 | } |
547 | 486 | ||
@@ -564,37 +503,203 @@ static void device_irq_exit(struct pm860x_chip *chip) | |||
564 | free_irq(chip->core_irq, chip); | 503 | free_irq(chip->core_irq, chip); |
565 | } | 504 | } |
566 | 505 | ||
567 | static void __devinit device_8606_init(struct pm860x_chip *chip, | 506 | static void __devinit device_bk_init(struct pm860x_chip *chip, |
568 | struct i2c_client *i2c, | 507 | struct pm860x_platform_data *pdata) |
569 | struct pm860x_platform_data *pdata) | ||
570 | { | 508 | { |
571 | int ret; | 509 | int ret; |
510 | int i, j, id; | ||
511 | |||
512 | if ((pdata == NULL) || (pdata->backlight == NULL)) | ||
513 | return; | ||
514 | |||
515 | if (pdata->num_backlights > ARRAY_SIZE(bk_devs)) | ||
516 | pdata->num_backlights = ARRAY_SIZE(bk_devs); | ||
517 | |||
518 | for (i = 0; i < pdata->num_backlights; i++) { | ||
519 | bk_devs[i].platform_data = &pdata->backlight[i]; | ||
520 | bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata); | ||
521 | |||
522 | for (j = 0; j < ARRAY_SIZE(bk_devs); j++) { | ||
523 | id = bk_resources[j].start; | ||
524 | if (pdata->backlight[i].flags != id) | ||
525 | continue; | ||
526 | |||
527 | bk_devs[i].num_resources = 1; | ||
528 | bk_devs[i].resources = &bk_resources[j]; | ||
529 | ret = mfd_add_devices(chip->dev, 0, | ||
530 | &bk_devs[i], 1, | ||
531 | &bk_resources[j], 0); | ||
532 | if (ret < 0) { | ||
533 | dev_err(chip->dev, "Failed to add " | ||
534 | "backlight subdev\n"); | ||
535 | return; | ||
536 | } | ||
537 | } | ||
538 | } | ||
539 | } | ||
572 | 540 | ||
573 | if (pdata && pdata->backlight) { | 541 | static void __devinit device_led_init(struct pm860x_chip *chip, |
574 | ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], | 542 | struct pm860x_platform_data *pdata) |
575 | ARRAY_SIZE(backlight_devs), | 543 | { |
576 | &backlight_resources[0], 0); | 544 | int ret; |
577 | if (ret < 0) { | 545 | int i, j, id; |
578 | dev_err(chip->dev, "Failed to add backlight " | 546 | |
579 | "subdev\n"); | 547 | if ((pdata == NULL) || (pdata->led == NULL)) |
580 | goto out_dev; | 548 | return; |
549 | |||
550 | if (pdata->num_leds > ARRAY_SIZE(led_devs)) | ||
551 | pdata->num_leds = ARRAY_SIZE(led_devs); | ||
552 | |||
553 | for (i = 0; i < pdata->num_leds; i++) { | ||
554 | led_devs[i].platform_data = &pdata->led[i]; | ||
555 | led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata); | ||
556 | |||
557 | for (j = 0; j < ARRAY_SIZE(led_devs); j++) { | ||
558 | id = led_resources[j].start; | ||
559 | if (pdata->led[i].flags != id) | ||
560 | continue; | ||
561 | |||
562 | led_devs[i].num_resources = 1; | ||
563 | led_devs[i].resources = &led_resources[j], | ||
564 | ret = mfd_add_devices(chip->dev, 0, | ||
565 | &led_devs[i], 1, | ||
566 | &led_resources[j], 0); | ||
567 | if (ret < 0) { | ||
568 | dev_err(chip->dev, "Failed to add " | ||
569 | "led subdev\n"); | ||
570 | return; | ||
571 | } | ||
581 | } | 572 | } |
582 | } | 573 | } |
574 | } | ||
583 | 575 | ||
584 | if (pdata && pdata->led) { | 576 | static void __devinit device_regulator_init(struct pm860x_chip *chip, |
585 | ret = mfd_add_devices(chip->dev, 0, &led_devs[0], | 577 | struct pm860x_platform_data *pdata) |
586 | ARRAY_SIZE(led_devs), | 578 | { |
587 | &led_resources[0], 0); | 579 | struct regulator_init_data *initdata; |
580 | int ret; | ||
581 | int i, seq; | ||
582 | |||
583 | if ((pdata == NULL) || (pdata->regulator == NULL)) | ||
584 | return; | ||
585 | |||
586 | if (pdata->num_regulators > ARRAY_SIZE(regulator_devs)) | ||
587 | pdata->num_regulators = ARRAY_SIZE(regulator_devs); | ||
588 | |||
589 | for (i = 0, seq = -1; i < pdata->num_regulators; i++) { | ||
590 | initdata = &pdata->regulator[i]; | ||
591 | seq = *(unsigned int *)initdata->driver_data; | ||
592 | if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) { | ||
593 | dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n", | ||
594 | seq, initdata->constraints.name); | ||
595 | goto out; | ||
596 | } | ||
597 | regulator_devs[i].platform_data = &pdata->regulator[i]; | ||
598 | regulator_devs[i].pdata_size = sizeof(struct regulator_init_data); | ||
599 | regulator_devs[i].num_resources = 1; | ||
600 | regulator_devs[i].resources = ®ulator_resources[seq]; | ||
601 | |||
602 | ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1, | ||
603 | ®ulator_resources[seq], 0); | ||
588 | if (ret < 0) { | 604 | if (ret < 0) { |
589 | dev_err(chip->dev, "Failed to add led " | 605 | dev_err(chip->dev, "Failed to add regulator subdev\n"); |
590 | "subdev\n"); | 606 | goto out; |
591 | goto out_dev; | ||
592 | } | 607 | } |
593 | } | 608 | } |
609 | out: | ||
594 | return; | 610 | return; |
595 | out_dev: | 611 | } |
596 | mfd_remove_devices(chip->dev); | 612 | |
597 | device_irq_exit(chip); | 613 | static void __devinit device_rtc_init(struct pm860x_chip *chip, |
614 | struct pm860x_platform_data *pdata) | ||
615 | { | ||
616 | int ret; | ||
617 | |||
618 | if ((pdata == NULL)) | ||
619 | return; | ||
620 | |||
621 | rtc_devs[0].platform_data = pdata->rtc; | ||
622 | rtc_devs[0].pdata_size = sizeof(struct pm860x_rtc_pdata); | ||
623 | rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources); | ||
624 | rtc_devs[0].resources = &rtc_resources[0]; | ||
625 | ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], | ||
626 | ARRAY_SIZE(rtc_devs), &rtc_resources[0], | ||
627 | chip->irq_base); | ||
628 | if (ret < 0) | ||
629 | dev_err(chip->dev, "Failed to add rtc subdev\n"); | ||
630 | } | ||
631 | |||
632 | static void __devinit device_touch_init(struct pm860x_chip *chip, | ||
633 | struct pm860x_platform_data *pdata) | ||
634 | { | ||
635 | int ret; | ||
636 | |||
637 | if (pdata == NULL) | ||
638 | return; | ||
639 | |||
640 | touch_devs[0].platform_data = pdata->touch; | ||
641 | touch_devs[0].pdata_size = sizeof(struct pm860x_touch_pdata); | ||
642 | touch_devs[0].num_resources = ARRAY_SIZE(touch_resources); | ||
643 | touch_devs[0].resources = &touch_resources[0]; | ||
644 | ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], | ||
645 | ARRAY_SIZE(touch_devs), &touch_resources[0], | ||
646 | chip->irq_base); | ||
647 | if (ret < 0) | ||
648 | dev_err(chip->dev, "Failed to add touch subdev\n"); | ||
649 | } | ||
650 | |||
651 | static void __devinit device_power_init(struct pm860x_chip *chip, | ||
652 | struct pm860x_platform_data *pdata) | ||
653 | { | ||
654 | int ret; | ||
655 | |||
656 | if (pdata == NULL) | ||
657 | return; | ||
658 | |||
659 | power_devs[0].platform_data = pdata->power; | ||
660 | power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata); | ||
661 | power_devs[0].num_resources = ARRAY_SIZE(battery_resources); | ||
662 | power_devs[0].resources = &battery_resources[0], | ||
663 | ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1, | ||
664 | &battery_resources[0], chip->irq_base); | ||
665 | if (ret < 0) | ||
666 | dev_err(chip->dev, "Failed to add battery subdev\n"); | ||
667 | |||
668 | power_devs[1].platform_data = pdata->power; | ||
669 | power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata); | ||
670 | power_devs[1].num_resources = ARRAY_SIZE(charger_resources); | ||
671 | power_devs[1].resources = &charger_resources[0], | ||
672 | ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1, | ||
673 | &charger_resources[0], chip->irq_base); | ||
674 | if (ret < 0) | ||
675 | dev_err(chip->dev, "Failed to add charger subdev\n"); | ||
676 | } | ||
677 | |||
678 | static void __devinit device_onkey_init(struct pm860x_chip *chip, | ||
679 | struct pm860x_platform_data *pdata) | ||
680 | { | ||
681 | int ret; | ||
682 | |||
683 | onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources); | ||
684 | onkey_devs[0].resources = &onkey_resources[0], | ||
685 | ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], | ||
686 | ARRAY_SIZE(onkey_devs), &onkey_resources[0], | ||
687 | chip->irq_base); | ||
688 | if (ret < 0) | ||
689 | dev_err(chip->dev, "Failed to add onkey subdev\n"); | ||
690 | } | ||
691 | |||
692 | static void __devinit device_codec_init(struct pm860x_chip *chip, | ||
693 | struct pm860x_platform_data *pdata) | ||
694 | { | ||
695 | int ret; | ||
696 | |||
697 | codec_devs[0].num_resources = ARRAY_SIZE(codec_resources); | ||
698 | codec_devs[0].resources = &codec_resources[0], | ||
699 | ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], | ||
700 | ARRAY_SIZE(codec_devs), &codec_resources[0], 0); | ||
701 | if (ret < 0) | ||
702 | dev_err(chip->dev, "Failed to add codec subdev\n"); | ||
598 | } | 703 | } |
599 | 704 | ||
600 | static void __devinit device_8607_init(struct pm860x_chip *chip, | 705 | static void __devinit device_8607_init(struct pm860x_chip *chip, |
@@ -608,10 +713,13 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, | |||
608 | dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret); | 713 | dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret); |
609 | goto out; | 714 | goto out; |
610 | } | 715 | } |
611 | if ((ret & PM8607_VERSION_MASK) == PM8607_VERSION) | 716 | switch (ret & PM8607_VERSION_MASK) { |
717 | case 0x40: | ||
718 | case 0x50: | ||
612 | dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n", | 719 | dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n", |
613 | ret); | 720 | ret); |
614 | else { | 721 | break; |
722 | default: | ||
615 | dev_err(chip->dev, "Failed to detect Marvell 88PM8607. " | 723 | dev_err(chip->dev, "Failed to detect Marvell 88PM8607. " |
616 | "Chip ID: %02x\n", ret); | 724 | "Chip ID: %02x\n", ret); |
617 | goto out; | 725 | goto out; |
@@ -649,48 +757,12 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, | |||
649 | if (ret < 0) | 757 | if (ret < 0) |
650 | goto out; | 758 | goto out; |
651 | 759 | ||
652 | ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], | 760 | device_regulator_init(chip, pdata); |
653 | ARRAY_SIZE(regulator_devs), | 761 | device_rtc_init(chip, pdata); |
654 | ®ulator_resources[0], 0); | 762 | device_onkey_init(chip, pdata); |
655 | if (ret < 0) { | 763 | device_touch_init(chip, pdata); |
656 | dev_err(chip->dev, "Failed to add regulator subdev\n"); | 764 | device_power_init(chip, pdata); |
657 | goto out_dev; | 765 | device_codec_init(chip, pdata); |
658 | } | ||
659 | |||
660 | if (pdata && pdata->touch) { | ||
661 | ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], | ||
662 | ARRAY_SIZE(touch_devs), | ||
663 | &touch_resources[0], 0); | ||
664 | if (ret < 0) { | ||
665 | dev_err(chip->dev, "Failed to add touch " | ||
666 | "subdev\n"); | ||
667 | goto out_dev; | ||
668 | } | ||
669 | } | ||
670 | |||
671 | if (pdata && pdata->power) { | ||
672 | ret = mfd_add_devices(chip->dev, 0, &power_devs[0], | ||
673 | ARRAY_SIZE(power_devs), | ||
674 | &power_supply_resources[0], 0); | ||
675 | if (ret < 0) { | ||
676 | dev_err(chip->dev, "Failed to add power supply " | ||
677 | "subdev\n"); | ||
678 | goto out_dev; | ||
679 | } | ||
680 | } | ||
681 | |||
682 | ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], | ||
683 | ARRAY_SIZE(onkey_devs), | ||
684 | &onkey_resources[0], 0); | ||
685 | if (ret < 0) { | ||
686 | dev_err(chip->dev, "Failed to add onkey subdev\n"); | ||
687 | goto out_dev; | ||
688 | } | ||
689 | |||
690 | return; | ||
691 | out_dev: | ||
692 | mfd_remove_devices(chip->dev); | ||
693 | device_irq_exit(chip); | ||
694 | out: | 766 | out: |
695 | return; | 767 | return; |
696 | } | 768 | } |
@@ -702,7 +774,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, | |||
702 | 774 | ||
703 | switch (chip->id) { | 775 | switch (chip->id) { |
704 | case CHIP_PM8606: | 776 | case CHIP_PM8606: |
705 | device_8606_init(chip, chip->client, pdata); | 777 | device_bk_init(chip, pdata); |
778 | device_led_init(chip, pdata); | ||
706 | break; | 779 | break; |
707 | case CHIP_PM8607: | 780 | case CHIP_PM8607: |
708 | device_8607_init(chip, chip->client, pdata); | 781 | device_8607_init(chip, chip->client, pdata); |
@@ -712,7 +785,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, | |||
712 | if (chip->companion) { | 785 | if (chip->companion) { |
713 | switch (chip->id) { | 786 | switch (chip->id) { |
714 | case CHIP_PM8607: | 787 | case CHIP_PM8607: |
715 | device_8606_init(chip, chip->companion, pdata); | 788 | device_bk_init(chip, pdata); |
789 | device_led_init(chip, pdata); | ||
716 | break; | 790 | break; |
717 | case CHIP_PM8606: | 791 | case CHIP_PM8606: |
718 | device_8607_init(chip, chip->companion, pdata); | 792 | device_8607_init(chip, chip->companion, pdata); |
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index bc02e6b21608..e017dc88622a 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c | |||
@@ -126,6 +126,109 @@ out: | |||
126 | } | 126 | } |
127 | EXPORT_SYMBOL(pm860x_set_bits); | 127 | EXPORT_SYMBOL(pm860x_set_bits); |
128 | 128 | ||
129 | int pm860x_page_reg_read(struct i2c_client *i2c, int reg) | ||
130 | { | ||
131 | struct pm860x_chip *chip = i2c_get_clientdata(i2c); | ||
132 | unsigned char zero = 0; | ||
133 | unsigned char data; | ||
134 | int ret; | ||
135 | |||
136 | mutex_lock(&chip->io_lock); | ||
137 | pm860x_write_device(i2c, 0xFA, 0, &zero); | ||
138 | pm860x_write_device(i2c, 0xFB, 0, &zero); | ||
139 | pm860x_write_device(i2c, 0xFF, 0, &zero); | ||
140 | ret = pm860x_read_device(i2c, reg, 1, &data); | ||
141 | if (ret >= 0) | ||
142 | ret = (int)data; | ||
143 | pm860x_write_device(i2c, 0xFE, 0, &zero); | ||
144 | pm860x_write_device(i2c, 0xFC, 0, &zero); | ||
145 | mutex_unlock(&chip->io_lock); | ||
146 | return ret; | ||
147 | } | ||
148 | EXPORT_SYMBOL(pm860x_page_reg_read); | ||
149 | |||
150 | int pm860x_page_reg_write(struct i2c_client *i2c, int reg, | ||
151 | unsigned char data) | ||
152 | { | ||
153 | struct pm860x_chip *chip = i2c_get_clientdata(i2c); | ||
154 | unsigned char zero; | ||
155 | int ret; | ||
156 | |||
157 | mutex_lock(&chip->io_lock); | ||
158 | pm860x_write_device(i2c, 0xFA, 0, &zero); | ||
159 | pm860x_write_device(i2c, 0xFB, 0, &zero); | ||
160 | pm860x_write_device(i2c, 0xFF, 0, &zero); | ||
161 | ret = pm860x_write_device(i2c, reg, 1, &data); | ||
162 | pm860x_write_device(i2c, 0xFE, 0, &zero); | ||
163 | pm860x_write_device(i2c, 0xFC, 0, &zero); | ||
164 | mutex_unlock(&chip->io_lock); | ||
165 | return ret; | ||
166 | } | ||
167 | EXPORT_SYMBOL(pm860x_page_reg_write); | ||
168 | |||
169 | int pm860x_page_bulk_read(struct i2c_client *i2c, int reg, | ||
170 | int count, unsigned char *buf) | ||
171 | { | ||
172 | struct pm860x_chip *chip = i2c_get_clientdata(i2c); | ||
173 | unsigned char zero = 0; | ||
174 | int ret; | ||
175 | |||
176 | mutex_lock(&chip->io_lock); | ||
177 | pm860x_write_device(i2c, 0xFA, 0, &zero); | ||
178 | pm860x_write_device(i2c, 0xFB, 0, &zero); | ||
179 | pm860x_write_device(i2c, 0xFF, 0, &zero); | ||
180 | ret = pm860x_read_device(i2c, reg, count, buf); | ||
181 | pm860x_write_device(i2c, 0xFE, 0, &zero); | ||
182 | pm860x_write_device(i2c, 0xFC, 0, &zero); | ||
183 | mutex_unlock(&chip->io_lock); | ||
184 | return ret; | ||
185 | } | ||
186 | EXPORT_SYMBOL(pm860x_page_bulk_read); | ||
187 | |||
188 | int pm860x_page_bulk_write(struct i2c_client *i2c, int reg, | ||
189 | int count, unsigned char *buf) | ||
190 | { | ||
191 | struct pm860x_chip *chip = i2c_get_clientdata(i2c); | ||
192 | unsigned char zero = 0; | ||
193 | int ret; | ||
194 | |||
195 | mutex_lock(&chip->io_lock); | ||
196 | pm860x_write_device(i2c, 0xFA, 0, &zero); | ||
197 | pm860x_write_device(i2c, 0xFB, 0, &zero); | ||
198 | pm860x_write_device(i2c, 0xFF, 0, &zero); | ||
199 | ret = pm860x_write_device(i2c, reg, count, buf); | ||
200 | pm860x_write_device(i2c, 0xFE, 0, &zero); | ||
201 | pm860x_write_device(i2c, 0xFC, 0, &zero); | ||
202 | mutex_unlock(&chip->io_lock); | ||
203 | return ret; | ||
204 | } | ||
205 | EXPORT_SYMBOL(pm860x_page_bulk_write); | ||
206 | |||
207 | int pm860x_page_set_bits(struct i2c_client *i2c, int reg, | ||
208 | unsigned char mask, unsigned char data) | ||
209 | { | ||
210 | struct pm860x_chip *chip = i2c_get_clientdata(i2c); | ||
211 | unsigned char zero; | ||
212 | unsigned char value; | ||
213 | int ret; | ||
214 | |||
215 | mutex_lock(&chip->io_lock); | ||
216 | pm860x_write_device(i2c, 0xFA, 0, &zero); | ||
217 | pm860x_write_device(i2c, 0xFB, 0, &zero); | ||
218 | pm860x_write_device(i2c, 0xFF, 0, &zero); | ||
219 | ret = pm860x_read_device(i2c, reg, 1, &value); | ||
220 | if (ret < 0) | ||
221 | goto out; | ||
222 | value &= ~mask; | ||
223 | value |= data; | ||
224 | ret = pm860x_write_device(i2c, reg, 1, &value); | ||
225 | out: | ||
226 | pm860x_write_device(i2c, 0xFE, 0, &zero); | ||
227 | pm860x_write_device(i2c, 0xFC, 0, &zero); | ||
228 | mutex_unlock(&chip->io_lock); | ||
229 | return ret; | ||
230 | } | ||
231 | EXPORT_SYMBOL(pm860x_page_set_bits); | ||
129 | 232 | ||
130 | static const struct i2c_device_id pm860x_id_table[] = { | 233 | static const struct i2c_device_id pm860x_id_table[] = { |
131 | { "88PM860x", 0 }, | 234 | { "88PM860x", 0 }, |
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index db51ea1c6082..6ca938a6bf94 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -60,27 +60,29 @@ config MFD_ASIC3 | |||
60 | This driver supports the ASIC3 multifunction chip found on many | 60 | This driver supports the ASIC3 multifunction chip found on many |
61 | PDAs (mainly iPAQ and HTC based ones) | 61 | PDAs (mainly iPAQ and HTC based ones) |
62 | 62 | ||
63 | config MFD_SH_MOBILE_SDHI | ||
64 | bool "Support for SuperH Mobile SDHI" | ||
65 | depends on SUPERH || ARCH_SHMOBILE | ||
66 | select MFD_CORE | ||
67 | select TMIO_MMC_DMA | ||
68 | ---help--- | ||
69 | This driver supports the SDHI hardware block found in many | ||
70 | SuperH Mobile SoCs. | ||
71 | |||
72 | config MFD_DAVINCI_VOICECODEC | 63 | config MFD_DAVINCI_VOICECODEC |
73 | tristate | 64 | tristate |
74 | select MFD_CORE | 65 | select MFD_CORE |
75 | 66 | ||
76 | config MFD_DM355EVM_MSP | 67 | config MFD_DM355EVM_MSP |
77 | bool "DaVinci DM355 EVM microcontroller" | 68 | bool "DaVinci DM355 EVM microcontroller" |
78 | depends on I2C && MACH_DAVINCI_DM355_EVM | 69 | depends on I2C=y && MACH_DAVINCI_DM355_EVM |
79 | help | 70 | help |
80 | This driver supports the MSP430 microcontroller used on these | 71 | This driver supports the MSP430 microcontroller used on these |
81 | boards. MSP430 firmware manages resets and power sequencing, | 72 | boards. MSP430 firmware manages resets and power sequencing, |
82 | inputs from buttons and the IR remote, LEDs, an RTC, and more. | 73 | inputs from buttons and the IR remote, LEDs, an RTC, and more. |
83 | 74 | ||
75 | config MFD_TI_SSP | ||
76 | tristate "TI Sequencer Serial Port support" | ||
77 | depends on ARCH_DAVINCI_TNETV107X | ||
78 | select MFD_CORE | ||
79 | ---help--- | ||
80 | Say Y here if you want support for the Sequencer Serial Port | ||
81 | in a Texas Instruments TNETV107X SoC. | ||
82 | |||
83 | To compile this driver as a module, choose M here: the | ||
84 | module will be called ti-ssp. | ||
85 | |||
84 | config HTC_EGPIO | 86 | config HTC_EGPIO |
85 | bool "HTC EGPIO support" | 87 | bool "HTC EGPIO support" |
86 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM | 88 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM |
@@ -118,6 +120,18 @@ config UCB1400_CORE | |||
118 | To compile this driver as a module, choose M here: the | 120 | To compile this driver as a module, choose M here: the |
119 | module will be called ucb1400_core. | 121 | module will be called ucb1400_core. |
120 | 122 | ||
123 | config TPS6105X | ||
124 | tristate "TPS61050/61052 Boost Converters" | ||
125 | depends on I2C | ||
126 | select REGULATOR | ||
127 | select MFD_CORE | ||
128 | select REGULATOR_FIXED_VOLTAGE | ||
129 | help | ||
130 | This option enables a driver for the TP61050/TPS61052 | ||
131 | high-power "white LED driver". This boost converter is | ||
132 | sometimes used for other things than white LEDs, and | ||
133 | also contains a GPIO pin. | ||
134 | |||
121 | config TPS65010 | 135 | config TPS65010 |
122 | tristate "TPS6501x Power Management chips" | 136 | tristate "TPS6501x Power Management chips" |
123 | depends on I2C && GPIOLIB | 137 | depends on I2C && GPIOLIB |
@@ -143,6 +157,20 @@ config TPS6507X | |||
143 | This driver can also be built as a module. If so, the module | 157 | This driver can also be built as a module. If so, the module |
144 | will be called tps6507x. | 158 | will be called tps6507x. |
145 | 159 | ||
160 | config MFD_TPS6586X | ||
161 | bool "TPS6586x Power Management chips" | ||
162 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS | ||
163 | select MFD_CORE | ||
164 | help | ||
165 | If you say yes here you get support for the TPS6586X series of | ||
166 | Power Management chips. | ||
167 | This driver provides common support for accessing the device, | ||
168 | additional drivers must be enabled in order to use the | ||
169 | functionality of the device. | ||
170 | |||
171 | This driver can also be built as a module. If so, the module | ||
172 | will be called tps6586x. | ||
173 | |||
146 | config MENELAUS | 174 | config MENELAUS |
147 | bool "Texas Instruments TWL92330/Menelaus PM chip" | 175 | bool "Texas Instruments TWL92330/Menelaus PM chip" |
148 | depends on I2C=y && ARCH_OMAP2 | 176 | depends on I2C=y && ARCH_OMAP2 |
@@ -167,6 +195,16 @@ config TWL4030_CORE | |||
167 | high speed USB OTG transceiver, an audio codec (on most | 195 | high speed USB OTG transceiver, an audio codec (on most |
168 | versions) and many other features. | 196 | versions) and many other features. |
169 | 197 | ||
198 | config TWL4030_MADC | ||
199 | tristate "Texas Instruments TWL4030 MADC" | ||
200 | depends on TWL4030_CORE | ||
201 | help | ||
202 | This driver provides support for triton TWL4030-MADC. The | ||
203 | driver supports both RT and SW conversion methods. | ||
204 | |||
205 | This driver can be built as a module. If so it will be | ||
206 | named twl4030-madc | ||
207 | |||
170 | config TWL4030_POWER | 208 | config TWL4030_POWER |
171 | bool "Support power resources on TWL4030 family chips" | 209 | bool "Support power resources on TWL4030 family chips" |
172 | depends on TWL4030_CORE && ARM | 210 | depends on TWL4030_CORE && ARM |
@@ -177,7 +215,7 @@ config TWL4030_POWER | |||
177 | as clock request handshaking. | 215 | as clock request handshaking. |
178 | 216 | ||
179 | This driver uses board-specific data to initialize the resources | 217 | This driver uses board-specific data to initialize the resources |
180 | and load scripts controling which resources are switched off/on | 218 | and load scripts controlling which resources are switched off/on |
181 | or reset when a sleep, wakeup or warm reset event occurs. | 219 | or reset when a sleep, wakeup or warm reset event occurs. |
182 | 220 | ||
183 | config TWL4030_CODEC | 221 | config TWL4030_CODEC |
@@ -218,12 +256,12 @@ config MFD_STMPE | |||
218 | Keypad: stmpe-keypad | 256 | Keypad: stmpe-keypad |
219 | Touchscreen: stmpe-ts | 257 | Touchscreen: stmpe-ts |
220 | 258 | ||
221 | config MFD_TC35892 | 259 | config MFD_TC3589X |
222 | bool "Support Toshiba TC35892" | 260 | bool "Support Toshiba TC35892 and variants" |
223 | depends on I2C=y && GENERIC_HARDIRQS | 261 | depends on I2C=y && GENERIC_HARDIRQS |
224 | select MFD_CORE | 262 | select MFD_CORE |
225 | help | 263 | help |
226 | Support for the Toshiba TC35892 I/O Expander. | 264 | Support for the Toshiba TC35892 and variants I/O Expander. |
227 | 265 | ||
228 | This driver provides common support for accessing the device, | 266 | This driver provides common support for accessing the device, |
229 | additional drivers must be enabled in order to use the | 267 | additional drivers must be enabled in order to use the |
@@ -233,11 +271,6 @@ config MFD_TMIO | |||
233 | bool | 271 | bool |
234 | default n | 272 | default n |
235 | 273 | ||
236 | config TMIO_MMC_DMA | ||
237 | bool | ||
238 | select DMA_ENGINE | ||
239 | select DMADEVICES | ||
240 | |||
241 | config MFD_T7L66XB | 274 | config MFD_T7L66XB |
242 | bool "Support Toshiba T7L66XB" | 275 | bool "Support Toshiba T7L66XB" |
243 | depends on ARM && HAVE_CLK | 276 | depends on ARM && HAVE_CLK |
@@ -293,15 +326,28 @@ config MFD_MAX8925 | |||
293 | accessing the device, additional drivers must be enabled in order | 326 | accessing the device, additional drivers must be enabled in order |
294 | to use the functionality of the device. | 327 | to use the functionality of the device. |
295 | 328 | ||
329 | config MFD_MAX8997 | ||
330 | bool "Maxim Semiconductor MAX8997/8966 PMIC Support" | ||
331 | depends on I2C=y && GENERIC_HARDIRQS | ||
332 | select MFD_CORE | ||
333 | help | ||
334 | Say yes here to support for Maxim Semiconductor MAX8998/8966. | ||
335 | This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic, | ||
336 | MUIC controls on chip. | ||
337 | This driver provides common support for accessing the device; | ||
338 | additional drivers must be enabled in order to use the functionality | ||
339 | of the device. | ||
340 | |||
296 | config MFD_MAX8998 | 341 | config MFD_MAX8998 |
297 | bool "Maxim Semiconductor MAX8998 PMIC Support" | 342 | bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" |
298 | depends on I2C=y | 343 | depends on I2C=y && GENERIC_HARDIRQS |
299 | select MFD_CORE | 344 | select MFD_CORE |
300 | help | 345 | help |
301 | Say yes here to support for Maxim Semiconductor MAX8998. This is | 346 | Say yes here to support for Maxim Semiconductor MAX8998 and |
302 | a Power Management IC. This driver provies common support for | 347 | National Semiconductor LP3974. This is a Power Management IC. |
303 | accessing the device, additional drivers must be enabled in order | 348 | This driver provies common support for accessing the device, |
304 | to use the functionality of the device. | 349 | additional drivers must be enabled in order to use the functionality |
350 | of the device. | ||
305 | 351 | ||
306 | config MFD_WM8400 | 352 | config MFD_WM8400 |
307 | tristate "Support Wolfson Microelectronics WM8400" | 353 | tristate "Support Wolfson Microelectronics WM8400" |
@@ -314,14 +360,30 @@ config MFD_WM8400 | |||
314 | the functionality of the device. | 360 | the functionality of the device. |
315 | 361 | ||
316 | config MFD_WM831X | 362 | config MFD_WM831X |
317 | bool "Support Wolfson Microelectronics WM831x/2x PMICs" | 363 | bool |
364 | depends on GENERIC_HARDIRQS | ||
365 | |||
366 | config MFD_WM831X_I2C | ||
367 | bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C" | ||
318 | select MFD_CORE | 368 | select MFD_CORE |
369 | select MFD_WM831X | ||
319 | depends on I2C=y && GENERIC_HARDIRQS | 370 | depends on I2C=y && GENERIC_HARDIRQS |
320 | help | 371 | help |
321 | Support for the Wolfson Microelecronics WM831x and WM832x PMICs. | 372 | Support for the Wolfson Microelecronics WM831x and WM832x PMICs |
322 | This driver provides common support for accessing the device, | 373 | when controlled using I2C. This driver provides common support |
323 | additional drivers must be enabled in order to use the | 374 | for accessing the device, additional drivers must be enabled in |
324 | functionality of the device. | 375 | order to use the functionality of the device. |
376 | |||
377 | config MFD_WM831X_SPI | ||
378 | bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI" | ||
379 | select MFD_CORE | ||
380 | select MFD_WM831X | ||
381 | depends on SPI_MASTER && GENERIC_HARDIRQS | ||
382 | help | ||
383 | Support for the Wolfson Microelecronics WM831x and WM832x PMICs | ||
384 | when controlled using SPI. This driver provides common support | ||
385 | for accessing the device, additional drivers must be enabled in | ||
386 | order to use the functionality of the device. | ||
325 | 387 | ||
326 | config MFD_WM8350 | 388 | config MFD_WM8350 |
327 | bool | 389 | bool |
@@ -407,16 +469,6 @@ config MFD_PCF50633 | |||
407 | facilities, and registers devices for the various functions | 469 | facilities, and registers devices for the various functions |
408 | so that function-specific drivers can bind to them. | 470 | so that function-specific drivers can bind to them. |
409 | 471 | ||
410 | config MFD_MC13783 | ||
411 | tristate "Support Freescale MC13783" | ||
412 | depends on SPI_MASTER | ||
413 | select MFD_CORE | ||
414 | help | ||
415 | Support for the Freescale (Atlas) MC13783 PMIC and audio CODEC. | ||
416 | This driver provides common support for accessing the device, | ||
417 | additional drivers must be enabled in order to use the | ||
418 | functionality of the device. | ||
419 | |||
420 | config PCF50633_ADC | 472 | config PCF50633_ADC |
421 | tristate "Support for NXP PCF50633 ADC" | 473 | tristate "Support for NXP PCF50633 ADC" |
422 | depends on MFD_PCF50633 | 474 | depends on MFD_PCF50633 |
@@ -431,9 +483,24 @@ config PCF50633_GPIO | |||
431 | Say yes here if you want to include support GPIO for pins on | 483 | Say yes here if you want to include support GPIO for pins on |
432 | the PCF50633 chip. | 484 | the PCF50633 chip. |
433 | 485 | ||
486 | config MFD_MC13783 | ||
487 | tristate | ||
488 | |||
489 | config MFD_MC13XXX | ||
490 | tristate "Support Freescale MC13783 and MC13892" | ||
491 | depends on SPI_MASTER | ||
492 | select MFD_CORE | ||
493 | select MFD_MC13783 | ||
494 | help | ||
495 | Support for the Freescale (Atlas) PMIC and audio CODECs | ||
496 | MC13783 and MC13892. | ||
497 | This driver provides common support for accessing the device, | ||
498 | additional drivers must be enabled in order to use the | ||
499 | functionality of the device. | ||
500 | |||
434 | config ABX500_CORE | 501 | config ABX500_CORE |
435 | bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" | 502 | bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" |
436 | default y if ARCH_U300 | 503 | default y if ARCH_U300 || ARCH_U8500 |
437 | help | 504 | help |
438 | Say yes here if you have the ABX500 Mixed Signal IC family | 505 | Say yes here if you have the ABX500 Mixed Signal IC family |
439 | chips. This core driver expose register access functions. | 506 | chips. This core driver expose register access functions. |
@@ -444,6 +511,7 @@ config ABX500_CORE | |||
444 | config AB3100_CORE | 511 | config AB3100_CORE |
445 | bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" | 512 | bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" |
446 | depends on I2C=y && ABX500_CORE | 513 | depends on I2C=y && ABX500_CORE |
514 | select MFD_CORE | ||
447 | default y if ARCH_U300 | 515 | default y if ARCH_U300 |
448 | help | 516 | help |
449 | Select this to enable the AB3100 Mixed Signal IC core | 517 | Select this to enable the AB3100 Mixed Signal IC core |
@@ -473,14 +541,40 @@ config EZX_PCAP | |||
473 | 541 | ||
474 | config AB8500_CORE | 542 | config AB8500_CORE |
475 | bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" | 543 | bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" |
476 | depends on SPI=y && GENERIC_HARDIRQS | 544 | depends on GENERIC_HARDIRQS && ABX500_CORE |
477 | select MFD_CORE | 545 | select MFD_CORE |
478 | help | 546 | help |
479 | Select this option to enable access to AB8500 power management | 547 | Select this option to enable access to AB8500 power management |
480 | chip. This connects to U8500 on the SSP/SPI bus and exports | 548 | chip. This connects to U8500 either on the SSP/SPI bus (deprecated |
481 | read/write functions for the devices to get access to this chip. | 549 | since hardware version v1.0) or the I2C bus via PRCMU. It also adds |
550 | the irq_chip parts for handling the Mixed Signal chip events. | ||
482 | This chip embeds various other multimedia funtionalities as well. | 551 | This chip embeds various other multimedia funtionalities as well. |
483 | 552 | ||
553 | config AB8500_I2C_CORE | ||
554 | bool "AB8500 register access via PRCMU I2C" | ||
555 | depends on AB8500_CORE && MFD_DB8500_PRCMU | ||
556 | default y | ||
557 | help | ||
558 | This enables register access to the AB8500 chip via PRCMU I2C. | ||
559 | The AB8500 chip can be accessed via SPI or I2C. On DB8500 hardware | ||
560 | the I2C bus is connected to the Power Reset | ||
561 | and Mangagement Unit, PRCMU. | ||
562 | |||
563 | config AB8500_DEBUG | ||
564 | bool "Enable debug info via debugfs" | ||
565 | depends on AB8500_CORE && DEBUG_FS | ||
566 | default y if DEBUG_FS | ||
567 | help | ||
568 | Select this option if you want debug information using the debug | ||
569 | filesystem, debugfs. | ||
570 | |||
571 | config AB8500_GPADC | ||
572 | bool "AB8500 GPADC driver" | ||
573 | depends on AB8500_CORE && REGULATOR_AB8500 | ||
574 | default y | ||
575 | help | ||
576 | AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage | ||
577 | |||
484 | config AB3550_CORE | 578 | config AB3550_CORE |
485 | bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions" | 579 | bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions" |
486 | select MFD_CORE | 580 | select MFD_CORE |
@@ -495,6 +589,34 @@ config AB3550_CORE | |||
495 | LEDs, vibrator, system power and temperature, power management | 589 | LEDs, vibrator, system power and temperature, power management |
496 | and ALSA sound. | 590 | and ALSA sound. |
497 | 591 | ||
592 | config MFD_DB8500_PRCMU | ||
593 | bool "ST-Ericsson DB8500 Power Reset Control Management Unit" | ||
594 | depends on UX500_SOC_DB8500 | ||
595 | select MFD_CORE | ||
596 | help | ||
597 | Select this option to enable support for the DB8500 Power Reset | ||
598 | and Control Management Unit. This is basically an autonomous | ||
599 | system controller running an XP70 microprocessor, which is accessed | ||
600 | through a register map. | ||
601 | |||
602 | config MFD_DB5500_PRCMU | ||
603 | bool "ST-Ericsson DB5500 Power Reset Control Management Unit" | ||
604 | depends on UX500_SOC_DB5500 | ||
605 | select MFD_CORE | ||
606 | help | ||
607 | Select this option to enable support for the DB5500 Power Reset | ||
608 | and Control Management Unit. This is basically an autonomous | ||
609 | system controller running an XP70 microprocessor, which is accessed | ||
610 | through a register map. | ||
611 | |||
612 | config MFD_CS5535 | ||
613 | tristate "Support for CS5535 and CS5536 southbridge core functions" | ||
614 | select MFD_CORE | ||
615 | depends on PCI && X86 | ||
616 | ---help--- | ||
617 | This is the core driver for CS5535/CS5536 MFD functions. This is | ||
618 | necessary for using the board's GPIO and MFGPT functionality. | ||
619 | |||
498 | config MFD_TIMBERDALE | 620 | config MFD_TIMBERDALE |
499 | tristate "Support for the Timberdale FPGA" | 621 | tristate "Support for the Timberdale FPGA" |
500 | select MFD_CORE | 622 | select MFD_CORE |
@@ -541,19 +663,73 @@ config MFD_JZ4740_ADC | |||
541 | Say yes here if you want support for the ADC unit in the JZ4740 SoC. | 663 | Say yes here if you want support for the ADC unit in the JZ4740 SoC. |
542 | This driver is necessary for jz4740-battery and jz4740-hwmon driver. | 664 | This driver is necessary for jz4740-battery and jz4740-hwmon driver. |
543 | 665 | ||
544 | config MFD_TPS6586X | 666 | config MFD_VX855 |
545 | tristate "TPS6586x Power Management chips" | 667 | tristate "Support for VIA VX855/VX875 integrated south bridge" |
546 | depends on I2C && GPIOLIB | 668 | depends on PCI |
547 | select MFD_CORE | 669 | select MFD_CORE |
548 | help | 670 | help |
549 | If you say yes here you get support for the TPS6586X series of | 671 | Say yes here to enable support for various functions of the |
672 | VIA VX855/VX875 south bridge. You will need to enable the vx855_spi | ||
673 | and/or vx855_gpio drivers for this to do anything useful. | ||
674 | |||
675 | config MFD_WL1273_CORE | ||
676 | tristate "Support for TI WL1273 FM radio." | ||
677 | depends on I2C | ||
678 | select MFD_CORE | ||
679 | default n | ||
680 | help | ||
681 | This is the core driver for the TI WL1273 FM radio. This MFD | ||
682 | driver connects the radio-wl1273 V4L2 module and the wl1273 | ||
683 | audio codec. | ||
684 | |||
685 | config MFD_OMAP_USB_HOST | ||
686 | bool "Support OMAP USBHS core driver" | ||
687 | depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 | ||
688 | default y | ||
689 | help | ||
690 | This is the core driver for the OAMP EHCI and OHCI drivers. | ||
691 | This MFD driver does the required setup functionalities for | ||
692 | OMAP USB Host drivers. | ||
693 | |||
694 | config MFD_PM8XXX | ||
695 | tristate | ||
696 | |||
697 | config MFD_PM8921_CORE | ||
698 | tristate "Qualcomm PM8921 PMIC chip" | ||
699 | depends on MSM_SSBI | ||
700 | select MFD_CORE | ||
701 | select MFD_PM8XXX | ||
702 | help | ||
703 | If you say yes to this option, support will be included for the | ||
704 | built-in PM8921 PMIC chip. | ||
705 | |||
706 | This is required if your board has a PM8921 and uses its features, | ||
707 | such as: MPPs, GPIOs, regulators, interrupts, and PWM. | ||
708 | |||
709 | Say M here if you want to include support for PM8921 chip as a module. | ||
710 | This will build a module called "pm8921-core". | ||
711 | |||
712 | config MFD_PM8XXX_IRQ | ||
713 | bool "Support for Qualcomm PM8xxx IRQ features" | ||
714 | depends on MFD_PM8XXX | ||
715 | default y if MFD_PM8XXX | ||
716 | help | ||
717 | This is the IRQ driver for Qualcomm PM 8xxx PMIC chips. | ||
718 | |||
719 | This is required to use certain other PM 8xxx features, such as GPIO | ||
720 | and MPP. | ||
721 | |||
722 | config MFD_TPS65910 | ||
723 | bool "TPS65910 Power Management chip" | ||
724 | depends on I2C=y && GPIOLIB | ||
725 | select MFD_CORE | ||
726 | select GPIO_TPS65910 | ||
727 | help | ||
728 | if you say yes here you get support for the TPS65910 series of | ||
550 | Power Management chips. | 729 | Power Management chips. |
551 | This driver provides common support for accessing the device, | ||
552 | additional drivers must be enabled in order to use the | ||
553 | functionality of the device. | ||
554 | 730 | ||
555 | This driver can also be built as a module. If so, the module | 731 | config TPS65911_COMPARATOR |
556 | will be called tps6586x. | 732 | tristate |
557 | 733 | ||
558 | endif # MFD_SUPPORT | 734 | endif # MFD_SUPPORT |
559 | 735 | ||
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index feaeeaeeddb7..d7d47d2a4c76 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -6,7 +6,6 @@ | |||
6 | obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o | 6 | obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o |
7 | obj-$(CONFIG_MFD_SM501) += sm501.o | 7 | obj-$(CONFIG_MFD_SM501) += sm501.o |
8 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o | 8 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o |
9 | obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o | ||
10 | 9 | ||
11 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o | 10 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o |
12 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o | 11 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o |
@@ -14,9 +13,10 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o | |||
14 | 13 | ||
15 | obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o | 14 | obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o |
16 | obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o | 15 | obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o |
16 | obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o | ||
17 | 17 | ||
18 | obj-$(CONFIG_MFD_STMPE) += stmpe.o | 18 | obj-$(CONFIG_MFD_STMPE) += stmpe.o |
19 | obj-$(CONFIG_MFD_TC35892) += tc35892.o | 19 | obj-$(CONFIG_MFD_TC3589X) += tc3589x.o |
20 | obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o | 20 | obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o |
21 | obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o | 21 | obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o |
22 | obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o | 22 | obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o |
@@ -24,22 +24,26 @@ obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o | |||
24 | obj-$(CONFIG_MFD_WM8400) += wm8400-core.o | 24 | obj-$(CONFIG_MFD_WM8400) += wm8400-core.o |
25 | wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o | 25 | wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o |
26 | obj-$(CONFIG_MFD_WM831X) += wm831x.o | 26 | obj-$(CONFIG_MFD_WM831X) += wm831x.o |
27 | obj-$(CONFIG_MFD_WM831X_I2C) += wm831x-i2c.o | ||
28 | obj-$(CONFIG_MFD_WM831X_SPI) += wm831x-spi.o | ||
27 | wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o | 29 | wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o |
28 | wm8350-objs += wm8350-irq.o | 30 | wm8350-objs += wm8350-irq.o |
29 | obj-$(CONFIG_MFD_WM8350) += wm8350.o | 31 | obj-$(CONFIG_MFD_WM8350) += wm8350.o |
30 | obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o | 32 | obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o |
31 | obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o | 33 | obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o |
32 | 34 | ||
35 | obj-$(CONFIG_TPS6105X) += tps6105x.o | ||
33 | obj-$(CONFIG_TPS65010) += tps65010.o | 36 | obj-$(CONFIG_TPS65010) += tps65010.o |
34 | obj-$(CONFIG_TPS6507X) += tps6507x.o | 37 | obj-$(CONFIG_TPS6507X) += tps6507x.o |
35 | obj-$(CONFIG_MENELAUS) += menelaus.o | 38 | obj-$(CONFIG_MENELAUS) += menelaus.o |
36 | 39 | ||
37 | obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o | 40 | obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o |
41 | obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o | ||
38 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o | 42 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o |
39 | obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o | 43 | obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o |
40 | obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o | 44 | obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o |
41 | 45 | ||
42 | obj-$(CONFIG_MFD_MC13783) += mc13783-core.o | 46 | obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o |
43 | 47 | ||
44 | obj-$(CONFIG_MFD_CORE) += mfd-core.o | 48 | obj-$(CONFIG_MFD_CORE) += mfd-core.o |
45 | 49 | ||
@@ -58,7 +62,8 @@ obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o | |||
58 | obj-$(CONFIG_PMIC_DA903X) += da903x.o | 62 | obj-$(CONFIG_PMIC_DA903X) += da903x.o |
59 | max8925-objs := max8925-core.o max8925-i2c.o | 63 | max8925-objs := max8925-core.o max8925-i2c.o |
60 | obj-$(CONFIG_MFD_MAX8925) += max8925.o | 64 | obj-$(CONFIG_MFD_MAX8925) += max8925.o |
61 | obj-$(CONFIG_MFD_MAX8998) += max8998.o | 65 | obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o |
66 | obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o | ||
62 | 67 | ||
63 | pcf50633-objs := pcf50633-core.o pcf50633-irq.o | 68 | pcf50633-objs := pcf50633-core.o pcf50633-irq.o |
64 | obj-$(CONFIG_MFD_PCF50633) += pcf50633.o | 69 | obj-$(CONFIG_MFD_PCF50633) += pcf50633.o |
@@ -68,7 +73,13 @@ obj-$(CONFIG_ABX500_CORE) += abx500-core.o | |||
68 | obj-$(CONFIG_AB3100_CORE) += ab3100-core.o | 73 | obj-$(CONFIG_AB3100_CORE) += ab3100-core.o |
69 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o | 74 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o |
70 | obj-$(CONFIG_AB3550_CORE) += ab3550-core.o | 75 | obj-$(CONFIG_AB3550_CORE) += ab3550-core.o |
71 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o | 76 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o |
77 | obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o | ||
78 | obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o | ||
79 | obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o | ||
80 | # ab8500-i2c need to come after db8500-prcmu (which provides the channel) | ||
81 | obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o | ||
82 | obj-$(CONFIG_MFD_DB5500_PRCMU) += db5500-prcmu.o | ||
72 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o | 83 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o |
73 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o | 84 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o |
74 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o | 85 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o |
@@ -76,3 +87,11 @@ obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o | |||
76 | obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o | 87 | obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o |
77 | obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o | 88 | obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o |
78 | obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o | 89 | obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o |
90 | obj-$(CONFIG_MFD_VX855) += vx855.o | ||
91 | obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o | ||
92 | obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o | ||
93 | obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o | ||
94 | obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o | ||
95 | obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o | ||
96 | obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o | ||
97 | obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o | ||
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 66379b413906..a20e1c41bed2 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/debugfs.h> | 19 | #include <linux/debugfs.h> |
20 | #include <linux/seq_file.h> | 20 | #include <linux/seq_file.h> |
21 | #include <linux/uaccess.h> | 21 | #include <linux/uaccess.h> |
22 | #include <linux/mfd/core.h> | ||
22 | #include <linux/mfd/abx500.h> | 23 | #include <linux/mfd/abx500.h> |
23 | 24 | ||
24 | /* These are the only registers inside AB3100 used in this main file */ | 25 | /* These are the only registers inside AB3100 used in this main file */ |
@@ -146,7 +147,7 @@ static int ab3100_set_test_register_interruptible(struct ab3100 *ab3100, | |||
146 | } | 147 | } |
147 | 148 | ||
148 | static int ab3100_get_register_interruptible(struct ab3100 *ab3100, | 149 | static int ab3100_get_register_interruptible(struct ab3100 *ab3100, |
149 | u8 reg, u8 *regval) | 150 | u8 reg, u8 *regval) |
150 | { | 151 | { |
151 | int err; | 152 | int err; |
152 | 153 | ||
@@ -202,7 +203,7 @@ static int ab3100_get_register_interruptible(struct ab3100 *ab3100, | |||
202 | } | 203 | } |
203 | 204 | ||
204 | static int get_register_interruptible(struct device *dev, u8 bank, u8 reg, | 205 | static int get_register_interruptible(struct device *dev, u8 bank, u8 reg, |
205 | u8 *value) | 206 | u8 *value) |
206 | { | 207 | { |
207 | struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); | 208 | struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); |
208 | 209 | ||
@@ -583,6 +584,7 @@ static ssize_t ab3100_get_set_reg(struct file *file, | |||
583 | static const struct file_operations ab3100_get_set_reg_fops = { | 584 | static const struct file_operations ab3100_get_set_reg_fops = { |
584 | .open = ab3100_get_set_reg_open_file, | 585 | .open = ab3100_get_set_reg_open_file, |
585 | .write = ab3100_get_set_reg, | 586 | .write = ab3100_get_set_reg, |
587 | .llseek = noop_llseek, | ||
586 | }; | 588 | }; |
587 | 589 | ||
588 | static struct dentry *ab3100_dir; | 590 | static struct dentry *ab3100_dir; |
@@ -611,7 +613,7 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100) | |||
611 | ab3100_get_priv.ab3100 = ab3100; | 613 | ab3100_get_priv.ab3100 = ab3100; |
612 | ab3100_get_priv.mode = false; | 614 | ab3100_get_priv.mode = false; |
613 | ab3100_get_reg_file = debugfs_create_file("get_reg", | 615 | ab3100_get_reg_file = debugfs_create_file("get_reg", |
614 | S_IWUGO, ab3100_dir, &ab3100_get_priv, | 616 | S_IWUSR, ab3100_dir, &ab3100_get_priv, |
615 | &ab3100_get_set_reg_fops); | 617 | &ab3100_get_set_reg_fops); |
616 | if (!ab3100_get_reg_file) { | 618 | if (!ab3100_get_reg_file) { |
617 | err = -ENOMEM; | 619 | err = -ENOMEM; |
@@ -621,7 +623,7 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100) | |||
621 | ab3100_set_priv.ab3100 = ab3100; | 623 | ab3100_set_priv.ab3100 = ab3100; |
622 | ab3100_set_priv.mode = true; | 624 | ab3100_set_priv.mode = true; |
623 | ab3100_set_reg_file = debugfs_create_file("set_reg", | 625 | ab3100_set_reg_file = debugfs_create_file("set_reg", |
624 | S_IWUGO, ab3100_dir, &ab3100_set_priv, | 626 | S_IWUSR, ab3100_dir, &ab3100_set_priv, |
625 | &ab3100_get_set_reg_fops); | 627 | &ab3100_get_set_reg_fops); |
626 | if (!ab3100_set_reg_file) { | 628 | if (!ab3100_set_reg_file) { |
627 | err = -ENOMEM; | 629 | err = -ENOMEM; |
@@ -665,7 +667,7 @@ struct ab3100_init_setting { | |||
665 | u8 setting; | 667 | u8 setting; |
666 | }; | 668 | }; |
667 | 669 | ||
668 | static const struct ab3100_init_setting __initconst | 670 | static const struct ab3100_init_setting __devinitconst |
669 | ab3100_init_settings[] = { | 671 | ab3100_init_settings[] = { |
670 | { | 672 | { |
671 | .abreg = AB3100_MCA, | 673 | .abreg = AB3100_MCA, |
@@ -712,7 +714,7 @@ ab3100_init_settings[] = { | |||
712 | }, | 714 | }, |
713 | }; | 715 | }; |
714 | 716 | ||
715 | static int __init ab3100_setup(struct ab3100 *ab3100) | 717 | static int __devinit ab3100_setup(struct ab3100 *ab3100) |
716 | { | 718 | { |
717 | int err = 0; | 719 | int err = 0; |
718 | int i; | 720 | int i; |
@@ -742,52 +744,64 @@ static int __init ab3100_setup(struct ab3100 *ab3100) | |||
742 | return err; | 744 | return err; |
743 | } | 745 | } |
744 | 746 | ||
745 | /* | 747 | /* The subdevices of the AB3100 */ |
746 | * Here we define all the platform devices that appear | 748 | static struct mfd_cell ab3100_devs[] = { |
747 | * as children of the AB3100. These are regular platform | 749 | { |
748 | * devices with the IORESOURCE_IO .start and .end set | 750 | .name = "ab3100-dac", |
749 | * to correspond to the internal AB3100 register range | 751 | .id = -1, |
750 | * mapping to the corresponding subdevice. | 752 | }, |
751 | */ | 753 | { |
752 | 754 | .name = "ab3100-leds", | |
753 | #define AB3100_DEVICE(devname, devid) \ | 755 | .id = -1, |
754 | static struct platform_device ab3100_##devname##_device = { \ | 756 | }, |
755 | .name = devid, \ | 757 | { |
756 | .id = -1, \ | 758 | .name = "ab3100-power", |
757 | } | 759 | .id = -1, |
758 | 760 | }, | |
759 | /* This lists all the subdevices */ | 761 | { |
760 | AB3100_DEVICE(dac, "ab3100-dac"); | 762 | .name = "ab3100-regulators", |
761 | AB3100_DEVICE(leds, "ab3100-leds"); | 763 | .id = -1, |
762 | AB3100_DEVICE(power, "ab3100-power"); | 764 | }, |
763 | AB3100_DEVICE(regulators, "ab3100-regulators"); | 765 | { |
764 | AB3100_DEVICE(sim, "ab3100-sim"); | 766 | .name = "ab3100-sim", |
765 | AB3100_DEVICE(uart, "ab3100-uart"); | 767 | .id = -1, |
766 | AB3100_DEVICE(rtc, "ab3100-rtc"); | 768 | }, |
767 | AB3100_DEVICE(charger, "ab3100-charger"); | 769 | { |
768 | AB3100_DEVICE(boost, "ab3100-boost"); | 770 | .name = "ab3100-uart", |
769 | AB3100_DEVICE(adc, "ab3100-adc"); | 771 | .id = -1, |
770 | AB3100_DEVICE(fuelgauge, "ab3100-fuelgauge"); | 772 | }, |
771 | AB3100_DEVICE(vibrator, "ab3100-vibrator"); | 773 | { |
772 | AB3100_DEVICE(otp, "ab3100-otp"); | 774 | .name = "ab3100-rtc", |
773 | AB3100_DEVICE(codec, "ab3100-codec"); | 775 | .id = -1, |
774 | 776 | }, | |
775 | static struct platform_device * | 777 | { |
776 | ab3100_platform_devs[] = { | 778 | .name = "ab3100-charger", |
777 | &ab3100_dac_device, | 779 | .id = -1, |
778 | &ab3100_leds_device, | 780 | }, |
779 | &ab3100_power_device, | 781 | { |
780 | &ab3100_regulators_device, | 782 | .name = "ab3100-boost", |
781 | &ab3100_sim_device, | 783 | .id = -1, |
782 | &ab3100_uart_device, | 784 | }, |
783 | &ab3100_rtc_device, | 785 | { |
784 | &ab3100_charger_device, | 786 | .name = "ab3100-adc", |
785 | &ab3100_boost_device, | 787 | .id = -1, |
786 | &ab3100_adc_device, | 788 | }, |
787 | &ab3100_fuelgauge_device, | 789 | { |
788 | &ab3100_vibrator_device, | 790 | .name = "ab3100-fuelgauge", |
789 | &ab3100_otp_device, | 791 | .id = -1, |
790 | &ab3100_codec_device, | 792 | }, |
793 | { | ||
794 | .name = "ab3100-vibrator", | ||
795 | .id = -1, | ||
796 | }, | ||
797 | { | ||
798 | .name = "ab3100-otp", | ||
799 | .id = -1, | ||
800 | }, | ||
801 | { | ||
802 | .name = "ab3100-codec", | ||
803 | .id = -1, | ||
804 | }, | ||
791 | }; | 805 | }; |
792 | 806 | ||
793 | struct ab_family_id { | 807 | struct ab_family_id { |
@@ -795,7 +809,7 @@ struct ab_family_id { | |||
795 | char *name; | 809 | char *name; |
796 | }; | 810 | }; |
797 | 811 | ||
798 | static const struct ab_family_id ids[] __initdata = { | 812 | static const struct ab_family_id ids[] __devinitdata = { |
799 | /* AB3100 */ | 813 | /* AB3100 */ |
800 | { | 814 | { |
801 | .id = 0xc0, | 815 | .id = 0xc0, |
@@ -849,8 +863,8 @@ static const struct ab_family_id ids[] __initdata = { | |||
849 | }, | 863 | }, |
850 | }; | 864 | }; |
851 | 865 | ||
852 | static int __init ab3100_probe(struct i2c_client *client, | 866 | static int __devinit ab3100_probe(struct i2c_client *client, |
853 | const struct i2c_device_id *id) | 867 | const struct i2c_device_id *id) |
854 | { | 868 | { |
855 | struct ab3100 *ab3100; | 869 | struct ab3100 *ab3100; |
856 | struct ab3100_platform_data *ab3100_plf_data = | 870 | struct ab3100_platform_data *ab3100_plf_data = |
@@ -934,18 +948,14 @@ static int __init ab3100_probe(struct i2c_client *client, | |||
934 | if (err) | 948 | if (err) |
935 | goto exit_no_ops; | 949 | goto exit_no_ops; |
936 | 950 | ||
937 | /* Set parent and a pointer back to the container in device data */ | 951 | /* Set up and register the platform devices. */ |
938 | for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++) { | 952 | for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) { |
939 | ab3100_platform_devs[i]->dev.parent = | 953 | ab3100_devs[i].platform_data = ab3100_plf_data; |
940 | &client->dev; | 954 | ab3100_devs[i].pdata_size = sizeof(struct ab3100_platform_data); |
941 | ab3100_platform_devs[i]->dev.platform_data = | ||
942 | ab3100_plf_data; | ||
943 | platform_set_drvdata(ab3100_platform_devs[i], ab3100); | ||
944 | } | 955 | } |
945 | 956 | ||
946 | /* Register the platform devices */ | 957 | err = mfd_add_devices(&client->dev, 0, ab3100_devs, |
947 | platform_add_devices(ab3100_platform_devs, | 958 | ARRAY_SIZE(ab3100_devs), NULL, 0); |
948 | ARRAY_SIZE(ab3100_platform_devs)); | ||
949 | 959 | ||
950 | ab3100_setup_debugfs(ab3100); | 960 | ab3100_setup_debugfs(ab3100); |
951 | 961 | ||
@@ -961,14 +971,12 @@ static int __init ab3100_probe(struct i2c_client *client, | |||
961 | return err; | 971 | return err; |
962 | } | 972 | } |
963 | 973 | ||
964 | static int __exit ab3100_remove(struct i2c_client *client) | 974 | static int __devexit ab3100_remove(struct i2c_client *client) |
965 | { | 975 | { |
966 | struct ab3100 *ab3100 = i2c_get_clientdata(client); | 976 | struct ab3100 *ab3100 = i2c_get_clientdata(client); |
967 | int i; | ||
968 | 977 | ||
969 | /* Unregister subdevices */ | 978 | /* Unregister subdevices */ |
970 | for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++) | 979 | mfd_remove_devices(&client->dev); |
971 | platform_device_unregister(ab3100_platform_devs[i]); | ||
972 | 980 | ||
973 | ab3100_remove_debugfs(); | 981 | ab3100_remove_debugfs(); |
974 | i2c_unregister_device(ab3100->testreg_client); | 982 | i2c_unregister_device(ab3100->testreg_client); |
@@ -995,7 +1003,7 @@ static struct i2c_driver ab3100_driver = { | |||
995 | }, | 1003 | }, |
996 | .id_table = ab3100_id, | 1004 | .id_table = ab3100_id, |
997 | .probe = ab3100_probe, | 1005 | .probe = ab3100_probe, |
998 | .remove = __exit_p(ab3100_remove), | 1006 | .remove = __devexit_p(ab3100_remove), |
999 | }; | 1007 | }; |
1000 | 1008 | ||
1001 | static int __init ab3100_i2c_init(void) | 1009 | static int __init ab3100_i2c_init(void) |
diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c index 8a98739e6d9c..3d7dce671b93 100644 --- a/drivers/mfd/ab3550-core.c +++ b/drivers/mfd/ab3550-core.c | |||
@@ -668,7 +668,7 @@ static int ab3550_startup_irq_enabled(struct device *dev, unsigned int irq) | |||
668 | struct ab3550_platform_data *plf_data; | 668 | struct ab3550_platform_data *plf_data; |
669 | bool val; | 669 | bool val; |
670 | 670 | ||
671 | ab = get_irq_chip_data(irq); | 671 | ab = irq_get_chip_data(irq); |
672 | plf_data = ab->i2c_client[0]->dev.platform_data; | 672 | plf_data = ab->i2c_client[0]->dev.platform_data; |
673 | irq -= plf_data->irq.base; | 673 | irq -= plf_data->irq.base; |
674 | val = ((ab->startup_events[irq / 8] & BIT(irq % 8)) != 0); | 674 | val = ((ab->startup_events[irq / 8] & BIT(irq % 8)) != 0); |
@@ -1053,17 +1053,17 @@ static inline void ab3550_setup_debugfs(struct ab3550 *ab) | |||
1053 | goto exit_destroy_dir; | 1053 | goto exit_destroy_dir; |
1054 | 1054 | ||
1055 | ab3550_bank_file = debugfs_create_file("register-bank", | 1055 | ab3550_bank_file = debugfs_create_file("register-bank", |
1056 | (S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_bank_fops); | 1056 | (S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_bank_fops); |
1057 | if (!ab3550_bank_file) | 1057 | if (!ab3550_bank_file) |
1058 | goto exit_destroy_reg; | 1058 | goto exit_destroy_reg; |
1059 | 1059 | ||
1060 | ab3550_address_file = debugfs_create_file("register-address", | 1060 | ab3550_address_file = debugfs_create_file("register-address", |
1061 | (S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_address_fops); | 1061 | (S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_address_fops); |
1062 | if (!ab3550_address_file) | 1062 | if (!ab3550_address_file) |
1063 | goto exit_destroy_bank; | 1063 | goto exit_destroy_bank; |
1064 | 1064 | ||
1065 | ab3550_val_file = debugfs_create_file("register-value", | 1065 | ab3550_val_file = debugfs_create_file("register-value", |
1066 | (S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_val_fops); | 1066 | (S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_val_fops); |
1067 | if (!ab3550_val_file) | 1067 | if (!ab3550_val_file) |
1068 | goto exit_destroy_address; | 1068 | goto exit_destroy_address; |
1069 | 1069 | ||
@@ -1159,15 +1159,16 @@ static void ab3550_mask_work(struct work_struct *work) | |||
1159 | } | 1159 | } |
1160 | } | 1160 | } |
1161 | 1161 | ||
1162 | static void ab3550_mask(unsigned int irq) | 1162 | static void ab3550_mask(struct irq_data *data) |
1163 | { | 1163 | { |
1164 | unsigned long flags; | 1164 | unsigned long flags; |
1165 | struct ab3550 *ab; | 1165 | struct ab3550 *ab; |
1166 | struct ab3550_platform_data *plf_data; | 1166 | struct ab3550_platform_data *plf_data; |
1167 | int irq; | ||
1167 | 1168 | ||
1168 | ab = get_irq_chip_data(irq); | 1169 | ab = irq_data_get_irq_chip_data(data); |
1169 | plf_data = ab->i2c_client[0]->dev.platform_data; | 1170 | plf_data = ab->i2c_client[0]->dev.platform_data; |
1170 | irq -= plf_data->irq.base; | 1171 | irq = data->irq - plf_data->irq.base; |
1171 | 1172 | ||
1172 | spin_lock_irqsave(&ab->event_lock, flags); | 1173 | spin_lock_irqsave(&ab->event_lock, flags); |
1173 | ab->event_mask[irq / 8] |= BIT(irq % 8); | 1174 | ab->event_mask[irq / 8] |= BIT(irq % 8); |
@@ -1176,15 +1177,16 @@ static void ab3550_mask(unsigned int irq) | |||
1176 | schedule_work(&ab->mask_work); | 1177 | schedule_work(&ab->mask_work); |
1177 | } | 1178 | } |
1178 | 1179 | ||
1179 | static void ab3550_unmask(unsigned int irq) | 1180 | static void ab3550_unmask(struct irq_data *data) |
1180 | { | 1181 | { |
1181 | unsigned long flags; | 1182 | unsigned long flags; |
1182 | struct ab3550 *ab; | 1183 | struct ab3550 *ab; |
1183 | struct ab3550_platform_data *plf_data; | 1184 | struct ab3550_platform_data *plf_data; |
1185 | int irq; | ||
1184 | 1186 | ||
1185 | ab = get_irq_chip_data(irq); | 1187 | ab = irq_data_get_irq_chip_data(data); |
1186 | plf_data = ab->i2c_client[0]->dev.platform_data; | 1188 | plf_data = ab->i2c_client[0]->dev.platform_data; |
1187 | irq -= plf_data->irq.base; | 1189 | irq = data->irq - plf_data->irq.base; |
1188 | 1190 | ||
1189 | spin_lock_irqsave(&ab->event_lock, flags); | 1191 | spin_lock_irqsave(&ab->event_lock, flags); |
1190 | ab->event_mask[irq / 8] &= ~BIT(irq % 8); | 1192 | ab->event_mask[irq / 8] &= ~BIT(irq % 8); |
@@ -1193,20 +1195,16 @@ static void ab3550_unmask(unsigned int irq) | |||
1193 | schedule_work(&ab->mask_work); | 1195 | schedule_work(&ab->mask_work); |
1194 | } | 1196 | } |
1195 | 1197 | ||
1196 | static void noop(unsigned int irq) | 1198 | static void noop(struct irq_data *data) |
1197 | { | 1199 | { |
1198 | } | 1200 | } |
1199 | 1201 | ||
1200 | static struct irq_chip ab3550_irq_chip = { | 1202 | static struct irq_chip ab3550_irq_chip = { |
1201 | .name = "ab3550-core", /* Keep the same name as the request */ | 1203 | .name = "ab3550-core", /* Keep the same name as the request */ |
1202 | .startup = NULL, /* defaults to enable */ | 1204 | .irq_disable = ab3550_mask, /* No default to mask in chip.c */ |
1203 | .shutdown = NULL, /* defaults to disable */ | 1205 | .irq_ack = noop, |
1204 | .enable = NULL, /* defaults to unmask */ | 1206 | .irq_mask = ab3550_mask, |
1205 | .disable = ab3550_mask, /* No default to mask in chip.c */ | 1207 | .irq_unmask = ab3550_unmask, |
1206 | .ack = noop, | ||
1207 | .mask = ab3550_mask, | ||
1208 | .unmask = ab3550_unmask, | ||
1209 | .end = NULL, | ||
1210 | }; | 1208 | }; |
1211 | 1209 | ||
1212 | struct ab_family_id { | 1210 | struct ab_family_id { |
@@ -1298,14 +1296,14 @@ static int __init ab3550_probe(struct i2c_client *client, | |||
1298 | unsigned int irq; | 1296 | unsigned int irq; |
1299 | 1297 | ||
1300 | irq = ab3550_plf_data->irq.base + i; | 1298 | irq = ab3550_plf_data->irq.base + i; |
1301 | set_irq_chip_data(irq, ab); | 1299 | irq_set_chip_data(irq, ab); |
1302 | set_irq_chip_and_handler(irq, &ab3550_irq_chip, | 1300 | irq_set_chip_and_handler(irq, &ab3550_irq_chip, |
1303 | handle_simple_irq); | 1301 | handle_simple_irq); |
1304 | set_irq_nested_thread(irq, 1); | 1302 | irq_set_nested_thread(irq, 1); |
1305 | #ifdef CONFIG_ARM | 1303 | #ifdef CONFIG_ARM |
1306 | set_irq_flags(irq, IRQF_VALID); | 1304 | set_irq_flags(irq, IRQF_VALID); |
1307 | #else | 1305 | #else |
1308 | set_irq_noprobe(irq); | 1306 | irq_set_noprobe(irq); |
1309 | #endif | 1307 | #endif |
1310 | } | 1308 | } |
1311 | 1309 | ||
@@ -1324,7 +1322,7 @@ static int __init ab3550_probe(struct i2c_client *client, | |||
1324 | /* Set up and register the platform devices. */ | 1322 | /* Set up and register the platform devices. */ |
1325 | for (i = 0; i < AB3550_NUM_DEVICES; i++) { | 1323 | for (i = 0; i < AB3550_NUM_DEVICES; i++) { |
1326 | ab3550_devs[i].platform_data = ab3550_plf_data->dev_data[i]; | 1324 | ab3550_devs[i].platform_data = ab3550_plf_data->dev_data[i]; |
1327 | ab3550_devs[i].data_size = ab3550_plf_data->dev_data_sz[i]; | 1325 | ab3550_devs[i].pdata_size = ab3550_plf_data->dev_data_sz[i]; |
1328 | } | 1326 | } |
1329 | 1327 | ||
1330 | err = mfd_add_devices(&client->dev, 0, ab3550_devs, | 1328 | err = mfd_add_devices(&client->dev, 0, ab3550_devs, |
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index defa786dee34..fc0c1af1566e 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * License Terms: GNU General Public License v2 | 4 | * License Terms: GNU General Public License v2 |
5 | * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> | 5 | * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> |
6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> | 6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> |
7 | * Author: Mattias Wallin <mattias.wallin@stericsson.com> | ||
7 | */ | 8 | */ |
8 | 9 | ||
9 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
@@ -15,6 +16,7 @@ | |||
15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
16 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
17 | #include <linux/mfd/core.h> | 18 | #include <linux/mfd/core.h> |
19 | #include <linux/mfd/abx500.h> | ||
18 | #include <linux/mfd/ab8500.h> | 20 | #include <linux/mfd/ab8500.h> |
19 | #include <linux/regulator/ab8500.h> | 21 | #include <linux/regulator/ab8500.h> |
20 | 22 | ||
@@ -22,71 +24,73 @@ | |||
22 | * Interrupt register offsets | 24 | * Interrupt register offsets |
23 | * Bank : 0x0E | 25 | * Bank : 0x0E |
24 | */ | 26 | */ |
25 | #define AB8500_IT_SOURCE1_REG 0x0E00 | 27 | #define AB8500_IT_SOURCE1_REG 0x00 |
26 | #define AB8500_IT_SOURCE2_REG 0x0E01 | 28 | #define AB8500_IT_SOURCE2_REG 0x01 |
27 | #define AB8500_IT_SOURCE3_REG 0x0E02 | 29 | #define AB8500_IT_SOURCE3_REG 0x02 |
28 | #define AB8500_IT_SOURCE4_REG 0x0E03 | 30 | #define AB8500_IT_SOURCE4_REG 0x03 |
29 | #define AB8500_IT_SOURCE5_REG 0x0E04 | 31 | #define AB8500_IT_SOURCE5_REG 0x04 |
30 | #define AB8500_IT_SOURCE6_REG 0x0E05 | 32 | #define AB8500_IT_SOURCE6_REG 0x05 |
31 | #define AB8500_IT_SOURCE7_REG 0x0E06 | 33 | #define AB8500_IT_SOURCE7_REG 0x06 |
32 | #define AB8500_IT_SOURCE8_REG 0x0E07 | 34 | #define AB8500_IT_SOURCE8_REG 0x07 |
33 | #define AB8500_IT_SOURCE19_REG 0x0E12 | 35 | #define AB8500_IT_SOURCE19_REG 0x12 |
34 | #define AB8500_IT_SOURCE20_REG 0x0E13 | 36 | #define AB8500_IT_SOURCE20_REG 0x13 |
35 | #define AB8500_IT_SOURCE21_REG 0x0E14 | 37 | #define AB8500_IT_SOURCE21_REG 0x14 |
36 | #define AB8500_IT_SOURCE22_REG 0x0E15 | 38 | #define AB8500_IT_SOURCE22_REG 0x15 |
37 | #define AB8500_IT_SOURCE23_REG 0x0E16 | 39 | #define AB8500_IT_SOURCE23_REG 0x16 |
38 | #define AB8500_IT_SOURCE24_REG 0x0E17 | 40 | #define AB8500_IT_SOURCE24_REG 0x17 |
39 | 41 | ||
40 | /* | 42 | /* |
41 | * latch registers | 43 | * latch registers |
42 | */ | 44 | */ |
43 | #define AB8500_IT_LATCH1_REG 0x0E20 | 45 | #define AB8500_IT_LATCH1_REG 0x20 |
44 | #define AB8500_IT_LATCH2_REG 0x0E21 | 46 | #define AB8500_IT_LATCH2_REG 0x21 |
45 | #define AB8500_IT_LATCH3_REG 0x0E22 | 47 | #define AB8500_IT_LATCH3_REG 0x22 |
46 | #define AB8500_IT_LATCH4_REG 0x0E23 | 48 | #define AB8500_IT_LATCH4_REG 0x23 |
47 | #define AB8500_IT_LATCH5_REG 0x0E24 | 49 | #define AB8500_IT_LATCH5_REG 0x24 |
48 | #define AB8500_IT_LATCH6_REG 0x0E25 | 50 | #define AB8500_IT_LATCH6_REG 0x25 |
49 | #define AB8500_IT_LATCH7_REG 0x0E26 | 51 | #define AB8500_IT_LATCH7_REG 0x26 |
50 | #define AB8500_IT_LATCH8_REG 0x0E27 | 52 | #define AB8500_IT_LATCH8_REG 0x27 |
51 | #define AB8500_IT_LATCH9_REG 0x0E28 | 53 | #define AB8500_IT_LATCH9_REG 0x28 |
52 | #define AB8500_IT_LATCH10_REG 0x0E29 | 54 | #define AB8500_IT_LATCH10_REG 0x29 |
53 | #define AB8500_IT_LATCH19_REG 0x0E32 | 55 | #define AB8500_IT_LATCH12_REG 0x2B |
54 | #define AB8500_IT_LATCH20_REG 0x0E33 | 56 | #define AB8500_IT_LATCH19_REG 0x32 |
55 | #define AB8500_IT_LATCH21_REG 0x0E34 | 57 | #define AB8500_IT_LATCH20_REG 0x33 |
56 | #define AB8500_IT_LATCH22_REG 0x0E35 | 58 | #define AB8500_IT_LATCH21_REG 0x34 |
57 | #define AB8500_IT_LATCH23_REG 0x0E36 | 59 | #define AB8500_IT_LATCH22_REG 0x35 |
58 | #define AB8500_IT_LATCH24_REG 0x0E37 | 60 | #define AB8500_IT_LATCH23_REG 0x36 |
61 | #define AB8500_IT_LATCH24_REG 0x37 | ||
59 | 62 | ||
60 | /* | 63 | /* |
61 | * mask registers | 64 | * mask registers |
62 | */ | 65 | */ |
63 | 66 | ||
64 | #define AB8500_IT_MASK1_REG 0x0E40 | 67 | #define AB8500_IT_MASK1_REG 0x40 |
65 | #define AB8500_IT_MASK2_REG 0x0E41 | 68 | #define AB8500_IT_MASK2_REG 0x41 |
66 | #define AB8500_IT_MASK3_REG 0x0E42 | 69 | #define AB8500_IT_MASK3_REG 0x42 |
67 | #define AB8500_IT_MASK4_REG 0x0E43 | 70 | #define AB8500_IT_MASK4_REG 0x43 |
68 | #define AB8500_IT_MASK5_REG 0x0E44 | 71 | #define AB8500_IT_MASK5_REG 0x44 |
69 | #define AB8500_IT_MASK6_REG 0x0E45 | 72 | #define AB8500_IT_MASK6_REG 0x45 |
70 | #define AB8500_IT_MASK7_REG 0x0E46 | 73 | #define AB8500_IT_MASK7_REG 0x46 |
71 | #define AB8500_IT_MASK8_REG 0x0E47 | 74 | #define AB8500_IT_MASK8_REG 0x47 |
72 | #define AB8500_IT_MASK9_REG 0x0E48 | 75 | #define AB8500_IT_MASK9_REG 0x48 |
73 | #define AB8500_IT_MASK10_REG 0x0E49 | 76 | #define AB8500_IT_MASK10_REG 0x49 |
74 | #define AB8500_IT_MASK11_REG 0x0E4A | 77 | #define AB8500_IT_MASK11_REG 0x4A |
75 | #define AB8500_IT_MASK12_REG 0x0E4B | 78 | #define AB8500_IT_MASK12_REG 0x4B |
76 | #define AB8500_IT_MASK13_REG 0x0E4C | 79 | #define AB8500_IT_MASK13_REG 0x4C |
77 | #define AB8500_IT_MASK14_REG 0x0E4D | 80 | #define AB8500_IT_MASK14_REG 0x4D |
78 | #define AB8500_IT_MASK15_REG 0x0E4E | 81 | #define AB8500_IT_MASK15_REG 0x4E |
79 | #define AB8500_IT_MASK16_REG 0x0E4F | 82 | #define AB8500_IT_MASK16_REG 0x4F |
80 | #define AB8500_IT_MASK17_REG 0x0E50 | 83 | #define AB8500_IT_MASK17_REG 0x50 |
81 | #define AB8500_IT_MASK18_REG 0x0E51 | 84 | #define AB8500_IT_MASK18_REG 0x51 |
82 | #define AB8500_IT_MASK19_REG 0x0E52 | 85 | #define AB8500_IT_MASK19_REG 0x52 |
83 | #define AB8500_IT_MASK20_REG 0x0E53 | 86 | #define AB8500_IT_MASK20_REG 0x53 |
84 | #define AB8500_IT_MASK21_REG 0x0E54 | 87 | #define AB8500_IT_MASK21_REG 0x54 |
85 | #define AB8500_IT_MASK22_REG 0x0E55 | 88 | #define AB8500_IT_MASK22_REG 0x55 |
86 | #define AB8500_IT_MASK23_REG 0x0E56 | 89 | #define AB8500_IT_MASK23_REG 0x56 |
87 | #define AB8500_IT_MASK24_REG 0x0E57 | 90 | #define AB8500_IT_MASK24_REG 0x57 |
88 | 91 | ||
89 | #define AB8500_REV_REG 0x1080 | 92 | #define AB8500_REV_REG 0x80 |
93 | #define AB8500_SWITCH_OFF_STATUS 0x00 | ||
90 | 94 | ||
91 | /* | 95 | /* |
92 | * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt | 96 | * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt |
@@ -96,110 +100,150 @@ | |||
96 | * offset 0. | 100 | * offset 0. |
97 | */ | 101 | */ |
98 | static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { | 102 | static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { |
99 | 0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21, | 103 | 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, |
100 | }; | 104 | }; |
101 | 105 | ||
102 | static int __ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data) | 106 | static int ab8500_get_chip_id(struct device *dev) |
107 | { | ||
108 | struct ab8500 *ab8500; | ||
109 | |||
110 | if (!dev) | ||
111 | return -EINVAL; | ||
112 | ab8500 = dev_get_drvdata(dev->parent); | ||
113 | return ab8500 ? (int)ab8500->chip_id : -EINVAL; | ||
114 | } | ||
115 | |||
116 | static int set_register_interruptible(struct ab8500 *ab8500, u8 bank, | ||
117 | u8 reg, u8 data) | ||
103 | { | 118 | { |
104 | int ret; | 119 | int ret; |
120 | /* | ||
121 | * Put the u8 bank and u8 register together into a an u16. | ||
122 | * The bank on higher 8 bits and register in lower 8 bits. | ||
123 | * */ | ||
124 | u16 addr = ((u16)bank) << 8 | reg; | ||
105 | 125 | ||
106 | dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); | 126 | dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); |
107 | 127 | ||
128 | ret = mutex_lock_interruptible(&ab8500->lock); | ||
129 | if (ret) | ||
130 | return ret; | ||
131 | |||
108 | ret = ab8500->write(ab8500, addr, data); | 132 | ret = ab8500->write(ab8500, addr, data); |
109 | if (ret < 0) | 133 | if (ret < 0) |
110 | dev_err(ab8500->dev, "failed to write reg %#x: %d\n", | 134 | dev_err(ab8500->dev, "failed to write reg %#x: %d\n", |
111 | addr, ret); | 135 | addr, ret); |
136 | mutex_unlock(&ab8500->lock); | ||
112 | 137 | ||
113 | return ret; | 138 | return ret; |
114 | } | 139 | } |
115 | 140 | ||
116 | /** | 141 | static int ab8500_set_register(struct device *dev, u8 bank, |
117 | * ab8500_write() - write an AB8500 register | 142 | u8 reg, u8 value) |
118 | * @ab8500: device to write to | ||
119 | * @addr: address of the register | ||
120 | * @data: value to write | ||
121 | */ | ||
122 | int ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data) | ||
123 | { | 143 | { |
124 | int ret; | 144 | struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); |
125 | 145 | ||
126 | mutex_lock(&ab8500->lock); | 146 | return set_register_interruptible(ab8500, bank, reg, value); |
127 | ret = __ab8500_write(ab8500, addr, data); | ||
128 | mutex_unlock(&ab8500->lock); | ||
129 | |||
130 | return ret; | ||
131 | } | 147 | } |
132 | EXPORT_SYMBOL_GPL(ab8500_write); | ||
133 | 148 | ||
134 | static int __ab8500_read(struct ab8500 *ab8500, u16 addr) | 149 | static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, |
150 | u8 reg, u8 *value) | ||
135 | { | 151 | { |
136 | int ret; | 152 | int ret; |
153 | /* put the u8 bank and u8 reg together into a an u16. | ||
154 | * bank on higher 8 bits and reg in lower */ | ||
155 | u16 addr = ((u16)bank) << 8 | reg; | ||
156 | |||
157 | ret = mutex_lock_interruptible(&ab8500->lock); | ||
158 | if (ret) | ||
159 | return ret; | ||
137 | 160 | ||
138 | ret = ab8500->read(ab8500, addr); | 161 | ret = ab8500->read(ab8500, addr); |
139 | if (ret < 0) | 162 | if (ret < 0) |
140 | dev_err(ab8500->dev, "failed to read reg %#x: %d\n", | 163 | dev_err(ab8500->dev, "failed to read reg %#x: %d\n", |
141 | addr, ret); | 164 | addr, ret); |
165 | else | ||
166 | *value = ret; | ||
142 | 167 | ||
168 | mutex_unlock(&ab8500->lock); | ||
143 | dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); | 169 | dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); |
144 | 170 | ||
145 | return ret; | 171 | return ret; |
146 | } | 172 | } |
147 | 173 | ||
148 | /** | 174 | static int ab8500_get_register(struct device *dev, u8 bank, |
149 | * ab8500_read() - read an AB8500 register | 175 | u8 reg, u8 *value) |
150 | * @ab8500: device to read from | ||
151 | * @addr: address of the register | ||
152 | */ | ||
153 | int ab8500_read(struct ab8500 *ab8500, u16 addr) | ||
154 | { | 176 | { |
155 | int ret; | 177 | struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); |
156 | |||
157 | mutex_lock(&ab8500->lock); | ||
158 | ret = __ab8500_read(ab8500, addr); | ||
159 | mutex_unlock(&ab8500->lock); | ||
160 | 178 | ||
161 | return ret; | 179 | return get_register_interruptible(ab8500, bank, reg, value); |
162 | } | 180 | } |
163 | EXPORT_SYMBOL_GPL(ab8500_read); | 181 | |
164 | 182 | static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank, | |
165 | /** | 183 | u8 reg, u8 bitmask, u8 bitvalues) |
166 | * ab8500_set_bits() - set a bitfield in an AB8500 register | ||
167 | * @ab8500: device to read from | ||
168 | * @addr: address of the register | ||
169 | * @mask: mask of the bitfield to modify | ||
170 | * @data: value to set to the bitfield | ||
171 | */ | ||
172 | int ab8500_set_bits(struct ab8500 *ab8500, u16 addr, u8 mask, u8 data) | ||
173 | { | 184 | { |
174 | int ret; | 185 | int ret; |
186 | u8 data; | ||
187 | /* put the u8 bank and u8 reg together into a an u16. | ||
188 | * bank on higher 8 bits and reg in lower */ | ||
189 | u16 addr = ((u16)bank) << 8 | reg; | ||
175 | 190 | ||
176 | mutex_lock(&ab8500->lock); | 191 | ret = mutex_lock_interruptible(&ab8500->lock); |
192 | if (ret) | ||
193 | return ret; | ||
177 | 194 | ||
178 | ret = __ab8500_read(ab8500, addr); | 195 | ret = ab8500->read(ab8500, addr); |
179 | if (ret < 0) | 196 | if (ret < 0) { |
197 | dev_err(ab8500->dev, "failed to read reg %#x: %d\n", | ||
198 | addr, ret); | ||
180 | goto out; | 199 | goto out; |
200 | } | ||
181 | 201 | ||
182 | ret &= ~mask; | 202 | data = (u8)ret; |
183 | ret |= data; | 203 | data = (~bitmask & data) | (bitmask & bitvalues); |
184 | 204 | ||
185 | ret = __ab8500_write(ab8500, addr, ret); | 205 | ret = ab8500->write(ab8500, addr, data); |
206 | if (ret < 0) | ||
207 | dev_err(ab8500->dev, "failed to write reg %#x: %d\n", | ||
208 | addr, ret); | ||
186 | 209 | ||
210 | dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, data); | ||
187 | out: | 211 | out: |
188 | mutex_unlock(&ab8500->lock); | 212 | mutex_unlock(&ab8500->lock); |
189 | return ret; | 213 | return ret; |
190 | } | 214 | } |
191 | EXPORT_SYMBOL_GPL(ab8500_set_bits); | ||
192 | 215 | ||
193 | static void ab8500_irq_lock(unsigned int irq) | 216 | static int ab8500_mask_and_set_register(struct device *dev, |
217 | u8 bank, u8 reg, u8 bitmask, u8 bitvalues) | ||
194 | { | 218 | { |
195 | struct ab8500 *ab8500 = get_irq_chip_data(irq); | 219 | struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); |
220 | |||
221 | return mask_and_set_register_interruptible(ab8500, bank, reg, | ||
222 | bitmask, bitvalues); | ||
223 | |||
224 | } | ||
225 | |||
226 | static struct abx500_ops ab8500_ops = { | ||
227 | .get_chip_id = ab8500_get_chip_id, | ||
228 | .get_register = ab8500_get_register, | ||
229 | .set_register = ab8500_set_register, | ||
230 | .get_register_page = NULL, | ||
231 | .set_register_page = NULL, | ||
232 | .mask_and_set_register = ab8500_mask_and_set_register, | ||
233 | .event_registers_startup_state_get = NULL, | ||
234 | .startup_irq_enabled = NULL, | ||
235 | }; | ||
236 | |||
237 | static void ab8500_irq_lock(struct irq_data *data) | ||
238 | { | ||
239 | struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); | ||
196 | 240 | ||
197 | mutex_lock(&ab8500->irq_lock); | 241 | mutex_lock(&ab8500->irq_lock); |
198 | } | 242 | } |
199 | 243 | ||
200 | static void ab8500_irq_sync_unlock(unsigned int irq) | 244 | static void ab8500_irq_sync_unlock(struct irq_data *data) |
201 | { | 245 | { |
202 | struct ab8500 *ab8500 = get_irq_chip_data(irq); | 246 | struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); |
203 | int i; | 247 | int i; |
204 | 248 | ||
205 | for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { | 249 | for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { |
@@ -210,29 +254,34 @@ static void ab8500_irq_sync_unlock(unsigned int irq) | |||
210 | if (new == old) | 254 | if (new == old) |
211 | continue; | 255 | continue; |
212 | 256 | ||
257 | /* Interrupt register 12 doesn't exist prior to version 2.0 */ | ||
258 | if (ab8500_irq_regoffset[i] == 11 && | ||
259 | ab8500->chip_id < AB8500_CUT2P0) | ||
260 | continue; | ||
261 | |||
213 | ab8500->oldmask[i] = new; | 262 | ab8500->oldmask[i] = new; |
214 | 263 | ||
215 | reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i]; | 264 | reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i]; |
216 | ab8500_write(ab8500, reg, new); | 265 | set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new); |
217 | } | 266 | } |
218 | 267 | ||
219 | mutex_unlock(&ab8500->irq_lock); | 268 | mutex_unlock(&ab8500->irq_lock); |
220 | } | 269 | } |
221 | 270 | ||
222 | static void ab8500_irq_mask(unsigned int irq) | 271 | static void ab8500_irq_mask(struct irq_data *data) |
223 | { | 272 | { |
224 | struct ab8500 *ab8500 = get_irq_chip_data(irq); | 273 | struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); |
225 | int offset = irq - ab8500->irq_base; | 274 | int offset = data->irq - ab8500->irq_base; |
226 | int index = offset / 8; | 275 | int index = offset / 8; |
227 | int mask = 1 << (offset % 8); | 276 | int mask = 1 << (offset % 8); |
228 | 277 | ||
229 | ab8500->mask[index] |= mask; | 278 | ab8500->mask[index] |= mask; |
230 | } | 279 | } |
231 | 280 | ||
232 | static void ab8500_irq_unmask(unsigned int irq) | 281 | static void ab8500_irq_unmask(struct irq_data *data) |
233 | { | 282 | { |
234 | struct ab8500 *ab8500 = get_irq_chip_data(irq); | 283 | struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); |
235 | int offset = irq - ab8500->irq_base; | 284 | int offset = data->irq - ab8500->irq_base; |
236 | int index = offset / 8; | 285 | int index = offset / 8; |
237 | int mask = 1 << (offset % 8); | 286 | int mask = 1 << (offset % 8); |
238 | 287 | ||
@@ -241,10 +290,10 @@ static void ab8500_irq_unmask(unsigned int irq) | |||
241 | 290 | ||
242 | static struct irq_chip ab8500_irq_chip = { | 291 | static struct irq_chip ab8500_irq_chip = { |
243 | .name = "ab8500", | 292 | .name = "ab8500", |
244 | .bus_lock = ab8500_irq_lock, | 293 | .irq_bus_lock = ab8500_irq_lock, |
245 | .bus_sync_unlock = ab8500_irq_sync_unlock, | 294 | .irq_bus_sync_unlock = ab8500_irq_sync_unlock, |
246 | .mask = ab8500_irq_mask, | 295 | .irq_mask = ab8500_irq_mask, |
247 | .unmask = ab8500_irq_unmask, | 296 | .irq_unmask = ab8500_irq_unmask, |
248 | }; | 297 | }; |
249 | 298 | ||
250 | static irqreturn_t ab8500_irq(int irq, void *dev) | 299 | static irqreturn_t ab8500_irq(int irq, void *dev) |
@@ -257,18 +306,24 @@ static irqreturn_t ab8500_irq(int irq, void *dev) | |||
257 | for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { | 306 | for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { |
258 | int regoffset = ab8500_irq_regoffset[i]; | 307 | int regoffset = ab8500_irq_regoffset[i]; |
259 | int status; | 308 | int status; |
309 | u8 value; | ||
260 | 310 | ||
261 | status = ab8500_read(ab8500, AB8500_IT_LATCH1_REG + regoffset); | 311 | /* Interrupt register 12 doesn't exist prior to version 2.0 */ |
262 | if (status <= 0) | 312 | if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0) |
313 | continue; | ||
314 | |||
315 | status = get_register_interruptible(ab8500, AB8500_INTERRUPT, | ||
316 | AB8500_IT_LATCH1_REG + regoffset, &value); | ||
317 | if (status < 0 || value == 0) | ||
263 | continue; | 318 | continue; |
264 | 319 | ||
265 | do { | 320 | do { |
266 | int bit = __ffs(status); | 321 | int bit = __ffs(value); |
267 | int line = i * 8 + bit; | 322 | int line = i * 8 + bit; |
268 | 323 | ||
269 | handle_nested_irq(ab8500->irq_base + line); | 324 | handle_nested_irq(ab8500->irq_base + line); |
270 | status &= ~(1 << bit); | 325 | value &= ~(1 << bit); |
271 | } while (status); | 326 | } while (value); |
272 | } | 327 | } |
273 | 328 | ||
274 | return IRQ_HANDLED; | 329 | return IRQ_HANDLED; |
@@ -280,14 +335,14 @@ static int ab8500_irq_init(struct ab8500 *ab8500) | |||
280 | int irq; | 335 | int irq; |
281 | 336 | ||
282 | for (irq = base; irq < base + AB8500_NR_IRQS; irq++) { | 337 | for (irq = base; irq < base + AB8500_NR_IRQS; irq++) { |
283 | set_irq_chip_data(irq, ab8500); | 338 | irq_set_chip_data(irq, ab8500); |
284 | set_irq_chip_and_handler(irq, &ab8500_irq_chip, | 339 | irq_set_chip_and_handler(irq, &ab8500_irq_chip, |
285 | handle_simple_irq); | 340 | handle_simple_irq); |
286 | set_irq_nested_thread(irq, 1); | 341 | irq_set_nested_thread(irq, 1); |
287 | #ifdef CONFIG_ARM | 342 | #ifdef CONFIG_ARM |
288 | set_irq_flags(irq, IRQF_VALID); | 343 | set_irq_flags(irq, IRQF_VALID); |
289 | #else | 344 | #else |
290 | set_irq_noprobe(irq); | 345 | irq_set_noprobe(irq); |
291 | #endif | 346 | #endif |
292 | } | 347 | } |
293 | 348 | ||
@@ -303,11 +358,20 @@ static void ab8500_irq_remove(struct ab8500 *ab8500) | |||
303 | #ifdef CONFIG_ARM | 358 | #ifdef CONFIG_ARM |
304 | set_irq_flags(irq, 0); | 359 | set_irq_flags(irq, 0); |
305 | #endif | 360 | #endif |
306 | set_irq_chip_and_handler(irq, NULL, NULL); | 361 | irq_set_chip_and_handler(irq, NULL, NULL); |
307 | set_irq_chip_data(irq, NULL); | 362 | irq_set_chip_data(irq, NULL); |
308 | } | 363 | } |
309 | } | 364 | } |
310 | 365 | ||
366 | static struct resource ab8500_gpio_resources[] = { | ||
367 | { | ||
368 | .name = "GPIO_INT6", | ||
369 | .start = AB8500_INT_GPIO6R, | ||
370 | .end = AB8500_INT_GPIO41F, | ||
371 | .flags = IORESOURCE_IRQ, | ||
372 | } | ||
373 | }; | ||
374 | |||
311 | static struct resource ab8500_gpadc_resources[] = { | 375 | static struct resource ab8500_gpadc_resources[] = { |
312 | { | 376 | { |
313 | .name = "HW_CONV_END", | 377 | .name = "HW_CONV_END", |
@@ -338,7 +402,214 @@ static struct resource ab8500_rtc_resources[] = { | |||
338 | }, | 402 | }, |
339 | }; | 403 | }; |
340 | 404 | ||
405 | static struct resource ab8500_poweronkey_db_resources[] = { | ||
406 | { | ||
407 | .name = "ONKEY_DBF", | ||
408 | .start = AB8500_INT_PON_KEY1DB_F, | ||
409 | .end = AB8500_INT_PON_KEY1DB_F, | ||
410 | .flags = IORESOURCE_IRQ, | ||
411 | }, | ||
412 | { | ||
413 | .name = "ONKEY_DBR", | ||
414 | .start = AB8500_INT_PON_KEY1DB_R, | ||
415 | .end = AB8500_INT_PON_KEY1DB_R, | ||
416 | .flags = IORESOURCE_IRQ, | ||
417 | }, | ||
418 | }; | ||
419 | |||
420 | static struct resource ab8500_bm_resources[] = { | ||
421 | { | ||
422 | .name = "MAIN_EXT_CH_NOT_OK", | ||
423 | .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, | ||
424 | .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, | ||
425 | .flags = IORESOURCE_IRQ, | ||
426 | }, | ||
427 | { | ||
428 | .name = "BATT_OVV", | ||
429 | .start = AB8500_INT_BATT_OVV, | ||
430 | .end = AB8500_INT_BATT_OVV, | ||
431 | .flags = IORESOURCE_IRQ, | ||
432 | }, | ||
433 | { | ||
434 | .name = "MAIN_CH_UNPLUG_DET", | ||
435 | .start = AB8500_INT_MAIN_CH_UNPLUG_DET, | ||
436 | .end = AB8500_INT_MAIN_CH_UNPLUG_DET, | ||
437 | .flags = IORESOURCE_IRQ, | ||
438 | }, | ||
439 | { | ||
440 | .name = "MAIN_CHARGE_PLUG_DET", | ||
441 | .start = AB8500_INT_MAIN_CH_PLUG_DET, | ||
442 | .end = AB8500_INT_MAIN_CH_PLUG_DET, | ||
443 | .flags = IORESOURCE_IRQ, | ||
444 | }, | ||
445 | { | ||
446 | .name = "VBUS_DET_F", | ||
447 | .start = AB8500_INT_VBUS_DET_F, | ||
448 | .end = AB8500_INT_VBUS_DET_F, | ||
449 | .flags = IORESOURCE_IRQ, | ||
450 | }, | ||
451 | { | ||
452 | .name = "VBUS_DET_R", | ||
453 | .start = AB8500_INT_VBUS_DET_R, | ||
454 | .end = AB8500_INT_VBUS_DET_R, | ||
455 | .flags = IORESOURCE_IRQ, | ||
456 | }, | ||
457 | { | ||
458 | .name = "BAT_CTRL_INDB", | ||
459 | .start = AB8500_INT_BAT_CTRL_INDB, | ||
460 | .end = AB8500_INT_BAT_CTRL_INDB, | ||
461 | .flags = IORESOURCE_IRQ, | ||
462 | }, | ||
463 | { | ||
464 | .name = "CH_WD_EXP", | ||
465 | .start = AB8500_INT_CH_WD_EXP, | ||
466 | .end = AB8500_INT_CH_WD_EXP, | ||
467 | .flags = IORESOURCE_IRQ, | ||
468 | }, | ||
469 | { | ||
470 | .name = "VBUS_OVV", | ||
471 | .start = AB8500_INT_VBUS_OVV, | ||
472 | .end = AB8500_INT_VBUS_OVV, | ||
473 | .flags = IORESOURCE_IRQ, | ||
474 | }, | ||
475 | { | ||
476 | .name = "NCONV_ACCU", | ||
477 | .start = AB8500_INT_CCN_CONV_ACC, | ||
478 | .end = AB8500_INT_CCN_CONV_ACC, | ||
479 | .flags = IORESOURCE_IRQ, | ||
480 | }, | ||
481 | { | ||
482 | .name = "LOW_BAT_F", | ||
483 | .start = AB8500_INT_LOW_BAT_F, | ||
484 | .end = AB8500_INT_LOW_BAT_F, | ||
485 | .flags = IORESOURCE_IRQ, | ||
486 | }, | ||
487 | { | ||
488 | .name = "LOW_BAT_R", | ||
489 | .start = AB8500_INT_LOW_BAT_R, | ||
490 | .end = AB8500_INT_LOW_BAT_R, | ||
491 | .flags = IORESOURCE_IRQ, | ||
492 | }, | ||
493 | { | ||
494 | .name = "BTEMP_LOW", | ||
495 | .start = AB8500_INT_BTEMP_LOW, | ||
496 | .end = AB8500_INT_BTEMP_LOW, | ||
497 | .flags = IORESOURCE_IRQ, | ||
498 | }, | ||
499 | { | ||
500 | .name = "BTEMP_HIGH", | ||
501 | .start = AB8500_INT_BTEMP_HIGH, | ||
502 | .end = AB8500_INT_BTEMP_HIGH, | ||
503 | .flags = IORESOURCE_IRQ, | ||
504 | }, | ||
505 | { | ||
506 | .name = "USB_CHARGER_NOT_OKR", | ||
507 | .start = AB8500_INT_USB_CHARGER_NOT_OK, | ||
508 | .end = AB8500_INT_USB_CHARGER_NOT_OK, | ||
509 | .flags = IORESOURCE_IRQ, | ||
510 | }, | ||
511 | { | ||
512 | .name = "USB_CHARGE_DET_DONE", | ||
513 | .start = AB8500_INT_USB_CHG_DET_DONE, | ||
514 | .end = AB8500_INT_USB_CHG_DET_DONE, | ||
515 | .flags = IORESOURCE_IRQ, | ||
516 | }, | ||
517 | { | ||
518 | .name = "USB_CH_TH_PROT_R", | ||
519 | .start = AB8500_INT_USB_CH_TH_PROT_R, | ||
520 | .end = AB8500_INT_USB_CH_TH_PROT_R, | ||
521 | .flags = IORESOURCE_IRQ, | ||
522 | }, | ||
523 | { | ||
524 | .name = "MAIN_CH_TH_PROT_R", | ||
525 | .start = AB8500_INT_MAIN_CH_TH_PROT_R, | ||
526 | .end = AB8500_INT_MAIN_CH_TH_PROT_R, | ||
527 | .flags = IORESOURCE_IRQ, | ||
528 | }, | ||
529 | { | ||
530 | .name = "USB_CHARGER_NOT_OKF", | ||
531 | .start = AB8500_INT_USB_CHARGER_NOT_OKF, | ||
532 | .end = AB8500_INT_USB_CHARGER_NOT_OKF, | ||
533 | .flags = IORESOURCE_IRQ, | ||
534 | }, | ||
535 | }; | ||
536 | |||
537 | static struct resource ab8500_debug_resources[] = { | ||
538 | { | ||
539 | .name = "IRQ_FIRST", | ||
540 | .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, | ||
541 | .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, | ||
542 | .flags = IORESOURCE_IRQ, | ||
543 | }, | ||
544 | { | ||
545 | .name = "IRQ_LAST", | ||
546 | .start = AB8500_INT_USB_CHARGER_NOT_OKF, | ||
547 | .end = AB8500_INT_USB_CHARGER_NOT_OKF, | ||
548 | .flags = IORESOURCE_IRQ, | ||
549 | }, | ||
550 | }; | ||
551 | |||
552 | static struct resource ab8500_usb_resources[] = { | ||
553 | { | ||
554 | .name = "ID_WAKEUP_R", | ||
555 | .start = AB8500_INT_ID_WAKEUP_R, | ||
556 | .end = AB8500_INT_ID_WAKEUP_R, | ||
557 | .flags = IORESOURCE_IRQ, | ||
558 | }, | ||
559 | { | ||
560 | .name = "ID_WAKEUP_F", | ||
561 | .start = AB8500_INT_ID_WAKEUP_F, | ||
562 | .end = AB8500_INT_ID_WAKEUP_F, | ||
563 | .flags = IORESOURCE_IRQ, | ||
564 | }, | ||
565 | { | ||
566 | .name = "VBUS_DET_F", | ||
567 | .start = AB8500_INT_VBUS_DET_F, | ||
568 | .end = AB8500_INT_VBUS_DET_F, | ||
569 | .flags = IORESOURCE_IRQ, | ||
570 | }, | ||
571 | { | ||
572 | .name = "VBUS_DET_R", | ||
573 | .start = AB8500_INT_VBUS_DET_R, | ||
574 | .end = AB8500_INT_VBUS_DET_R, | ||
575 | .flags = IORESOURCE_IRQ, | ||
576 | }, | ||
577 | { | ||
578 | .name = "USB_LINK_STATUS", | ||
579 | .start = AB8500_INT_USB_LINK_STATUS, | ||
580 | .end = AB8500_INT_USB_LINK_STATUS, | ||
581 | .flags = IORESOURCE_IRQ, | ||
582 | }, | ||
583 | }; | ||
584 | |||
585 | static struct resource ab8500_temp_resources[] = { | ||
586 | { | ||
587 | .name = "AB8500_TEMP_WARM", | ||
588 | .start = AB8500_INT_TEMP_WARM, | ||
589 | .end = AB8500_INT_TEMP_WARM, | ||
590 | .flags = IORESOURCE_IRQ, | ||
591 | }, | ||
592 | }; | ||
593 | |||
341 | static struct mfd_cell ab8500_devs[] = { | 594 | static struct mfd_cell ab8500_devs[] = { |
595 | #ifdef CONFIG_DEBUG_FS | ||
596 | { | ||
597 | .name = "ab8500-debug", | ||
598 | .num_resources = ARRAY_SIZE(ab8500_debug_resources), | ||
599 | .resources = ab8500_debug_resources, | ||
600 | }, | ||
601 | #endif | ||
602 | { | ||
603 | .name = "ab8500-sysctrl", | ||
604 | }, | ||
605 | { | ||
606 | .name = "ab8500-regulator", | ||
607 | }, | ||
608 | { | ||
609 | .name = "ab8500-gpio", | ||
610 | .num_resources = ARRAY_SIZE(ab8500_gpio_resources), | ||
611 | .resources = ab8500_gpio_resources, | ||
612 | }, | ||
342 | { | 613 | { |
343 | .name = "ab8500-gpadc", | 614 | .name = "ab8500-gpadc", |
344 | .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), | 615 | .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), |
@@ -349,11 +620,91 @@ static struct mfd_cell ab8500_devs[] = { | |||
349 | .num_resources = ARRAY_SIZE(ab8500_rtc_resources), | 620 | .num_resources = ARRAY_SIZE(ab8500_rtc_resources), |
350 | .resources = ab8500_rtc_resources, | 621 | .resources = ab8500_rtc_resources, |
351 | }, | 622 | }, |
352 | { .name = "ab8500-charger", }, | 623 | { |
353 | { .name = "ab8500-audio", }, | 624 | .name = "ab8500-bm", |
354 | { .name = "ab8500-usb", }, | 625 | .num_resources = ARRAY_SIZE(ab8500_bm_resources), |
355 | { .name = "ab8500-pwm", }, | 626 | .resources = ab8500_bm_resources, |
356 | { .name = "ab8500-regulator", }, | 627 | }, |
628 | { .name = "ab8500-codec", }, | ||
629 | { | ||
630 | .name = "ab8500-usb", | ||
631 | .num_resources = ARRAY_SIZE(ab8500_usb_resources), | ||
632 | .resources = ab8500_usb_resources, | ||
633 | }, | ||
634 | { | ||
635 | .name = "ab8500-poweron-key", | ||
636 | .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), | ||
637 | .resources = ab8500_poweronkey_db_resources, | ||
638 | }, | ||
639 | { | ||
640 | .name = "ab8500-pwm", | ||
641 | .id = 1, | ||
642 | }, | ||
643 | { | ||
644 | .name = "ab8500-pwm", | ||
645 | .id = 2, | ||
646 | }, | ||
647 | { | ||
648 | .name = "ab8500-pwm", | ||
649 | .id = 3, | ||
650 | }, | ||
651 | { .name = "ab8500-leds", }, | ||
652 | { | ||
653 | .name = "ab8500-denc", | ||
654 | }, | ||
655 | { | ||
656 | .name = "ab8500-temp", | ||
657 | .num_resources = ARRAY_SIZE(ab8500_temp_resources), | ||
658 | .resources = ab8500_temp_resources, | ||
659 | }, | ||
660 | }; | ||
661 | |||
662 | static ssize_t show_chip_id(struct device *dev, | ||
663 | struct device_attribute *attr, char *buf) | ||
664 | { | ||
665 | struct ab8500 *ab8500; | ||
666 | |||
667 | ab8500 = dev_get_drvdata(dev); | ||
668 | return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); | ||
669 | } | ||
670 | |||
671 | /* | ||
672 | * ab8500 has switched off due to (SWITCH_OFF_STATUS): | ||
673 | * 0x01 Swoff bit programming | ||
674 | * 0x02 Thermal protection activation | ||
675 | * 0x04 Vbat lower then BattOk falling threshold | ||
676 | * 0x08 Watchdog expired | ||
677 | * 0x10 Non presence of 32kHz clock | ||
678 | * 0x20 Battery level lower than power on reset threshold | ||
679 | * 0x40 Power on key 1 pressed longer than 10 seconds | ||
680 | * 0x80 DB8500 thermal shutdown | ||
681 | */ | ||
682 | static ssize_t show_switch_off_status(struct device *dev, | ||
683 | struct device_attribute *attr, char *buf) | ||
684 | { | ||
685 | int ret; | ||
686 | u8 value; | ||
687 | struct ab8500 *ab8500; | ||
688 | |||
689 | ab8500 = dev_get_drvdata(dev); | ||
690 | ret = get_register_interruptible(ab8500, AB8500_RTC, | ||
691 | AB8500_SWITCH_OFF_STATUS, &value); | ||
692 | if (ret < 0) | ||
693 | return ret; | ||
694 | return sprintf(buf, "%#x\n", value); | ||
695 | } | ||
696 | |||
697 | static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); | ||
698 | static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); | ||
699 | |||
700 | static struct attribute *ab8500_sysfs_entries[] = { | ||
701 | &dev_attr_chip_id.attr, | ||
702 | &dev_attr_switch_off_status.attr, | ||
703 | NULL, | ||
704 | }; | ||
705 | |||
706 | static struct attribute_group ab8500_attr_group = { | ||
707 | .attrs = ab8500_sysfs_entries, | ||
357 | }; | 708 | }; |
358 | 709 | ||
359 | int __devinit ab8500_init(struct ab8500 *ab8500) | 710 | int __devinit ab8500_init(struct ab8500 *ab8500) |
@@ -361,6 +712,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500) | |||
361 | struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev); | 712 | struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev); |
362 | int ret; | 713 | int ret; |
363 | int i; | 714 | int i; |
715 | u8 value; | ||
364 | 716 | ||
365 | if (plat) | 717 | if (plat) |
366 | ab8500->irq_base = plat->irq_base; | 718 | ab8500->irq_base = plat->irq_base; |
@@ -368,37 +720,64 @@ int __devinit ab8500_init(struct ab8500 *ab8500) | |||
368 | mutex_init(&ab8500->lock); | 720 | mutex_init(&ab8500->lock); |
369 | mutex_init(&ab8500->irq_lock); | 721 | mutex_init(&ab8500->irq_lock); |
370 | 722 | ||
371 | ret = ab8500_read(ab8500, AB8500_REV_REG); | 723 | ret = get_register_interruptible(ab8500, AB8500_MISC, |
724 | AB8500_REV_REG, &value); | ||
372 | if (ret < 0) | 725 | if (ret < 0) |
373 | return ret; | 726 | return ret; |
374 | 727 | ||
375 | /* | 728 | switch (value) { |
376 | * 0x0 - Early Drop | 729 | case AB8500_CUTEARLY: |
377 | * 0x10 - Cut 1.0 | 730 | case AB8500_CUT1P0: |
378 | * 0x11 - Cut 1.1 | 731 | case AB8500_CUT1P1: |
379 | */ | 732 | case AB8500_CUT2P0: |
380 | if (ret == 0x0 || ret == 0x10 || ret == 0x11) { | 733 | case AB8500_CUT3P0: |
381 | ab8500->revision = ret; | 734 | dev_info(ab8500->dev, "detected chip, revision: %#x\n", value); |
382 | dev_info(ab8500->dev, "detected chip, revision: %#x\n", ret); | 735 | break; |
383 | } else { | 736 | default: |
384 | dev_err(ab8500->dev, "unknown chip, revision: %#x\n", ret); | 737 | dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value); |
385 | return -EINVAL; | 738 | return -EINVAL; |
386 | } | 739 | } |
740 | ab8500->chip_id = value; | ||
741 | |||
742 | /* | ||
743 | * ab8500 has switched off due to (SWITCH_OFF_STATUS): | ||
744 | * 0x01 Swoff bit programming | ||
745 | * 0x02 Thermal protection activation | ||
746 | * 0x04 Vbat lower then BattOk falling threshold | ||
747 | * 0x08 Watchdog expired | ||
748 | * 0x10 Non presence of 32kHz clock | ||
749 | * 0x20 Battery level lower than power on reset threshold | ||
750 | * 0x40 Power on key 1 pressed longer than 10 seconds | ||
751 | * 0x80 DB8500 thermal shutdown | ||
752 | */ | ||
753 | |||
754 | ret = get_register_interruptible(ab8500, AB8500_RTC, | ||
755 | AB8500_SWITCH_OFF_STATUS, &value); | ||
756 | if (ret < 0) | ||
757 | return ret; | ||
758 | dev_info(ab8500->dev, "switch off status: %#x", value); | ||
387 | 759 | ||
388 | if (plat && plat->init) | 760 | if (plat && plat->init) |
389 | plat->init(ab8500); | 761 | plat->init(ab8500); |
390 | 762 | ||
391 | /* Clear and mask all interrupts */ | 763 | /* Clear and mask all interrupts */ |
392 | for (i = 0; i < 10; i++) { | 764 | for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { |
393 | ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i); | 765 | /* Interrupt register 12 doesn't exist prior to version 2.0 */ |
394 | ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff); | 766 | if (ab8500_irq_regoffset[i] == 11 && |
395 | } | 767 | ab8500->chip_id < AB8500_CUT2P0) |
768 | continue; | ||
396 | 769 | ||
397 | for (i = 18; i < 24; i++) { | 770 | get_register_interruptible(ab8500, AB8500_INTERRUPT, |
398 | ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i); | 771 | AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i], |
399 | ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff); | 772 | &value); |
773 | set_register_interruptible(ab8500, AB8500_INTERRUPT, | ||
774 | AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff); | ||
400 | } | 775 | } |
401 | 776 | ||
777 | ret = abx500_register_ops(ab8500->dev, &ab8500_ops); | ||
778 | if (ret) | ||
779 | return ret; | ||
780 | |||
402 | for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) | 781 | for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) |
403 | ab8500->mask[i] = ab8500->oldmask[i] = 0xff; | 782 | ab8500->mask[i] = ab8500->oldmask[i] = 0xff; |
404 | 783 | ||
@@ -408,7 +787,8 @@ int __devinit ab8500_init(struct ab8500 *ab8500) | |||
408 | return ret; | 787 | return ret; |
409 | 788 | ||
410 | ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq, | 789 | ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq, |
411 | IRQF_ONESHOT, "ab8500", ab8500); | 790 | IRQF_ONESHOT | IRQF_NO_SUSPEND, |
791 | "ab8500", ab8500); | ||
412 | if (ret) | 792 | if (ret) |
413 | goto out_removeirq; | 793 | goto out_removeirq; |
414 | } | 794 | } |
@@ -419,6 +799,10 @@ int __devinit ab8500_init(struct ab8500 *ab8500) | |||
419 | if (ret) | 799 | if (ret) |
420 | goto out_freeirq; | 800 | goto out_freeirq; |
421 | 801 | ||
802 | ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group); | ||
803 | if (ret) | ||
804 | dev_err(ab8500->dev, "error creating sysfs entries\n"); | ||
805 | |||
422 | return ret; | 806 | return ret; |
423 | 807 | ||
424 | out_freeirq: | 808 | out_freeirq: |
@@ -432,6 +816,7 @@ out_removeirq: | |||
432 | 816 | ||
433 | int __devexit ab8500_exit(struct ab8500 *ab8500) | 817 | int __devexit ab8500_exit(struct ab8500 *ab8500) |
434 | { | 818 | { |
819 | sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); | ||
435 | mfd_remove_devices(ab8500->dev); | 820 | mfd_remove_devices(ab8500->dev); |
436 | if (ab8500->irq_base) { | 821 | if (ab8500->irq_base) { |
437 | free_irq(ab8500->irq, ab8500); | 822 | free_irq(ab8500->irq, ab8500); |
@@ -441,6 +826,6 @@ int __devexit ab8500_exit(struct ab8500 *ab8500) | |||
441 | return 0; | 826 | return 0; |
442 | } | 827 | } |
443 | 828 | ||
444 | MODULE_AUTHOR("Srinidhi Kasagar, Rabin Vincent"); | 829 | MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent"); |
445 | MODULE_DESCRIPTION("AB8500 MFD core"); | 830 | MODULE_DESCRIPTION("AB8500 MFD core"); |
446 | MODULE_LICENSE("GPL v2"); | 831 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c new file mode 100644 index 000000000000..64748e42ac03 --- /dev/null +++ b/drivers/mfd/ab8500-debugfs.c | |||
@@ -0,0 +1,652 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson. | ||
5 | * License Terms: GNU General Public License v2 | ||
6 | */ | ||
7 | |||
8 | #include <linux/seq_file.h> | ||
9 | #include <linux/uaccess.h> | ||
10 | #include <linux/fs.h> | ||
11 | #include <linux/debugfs.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | |||
14 | #include <linux/mfd/abx500.h> | ||
15 | #include <linux/mfd/ab8500.h> | ||
16 | |||
17 | static u32 debug_bank; | ||
18 | static u32 debug_address; | ||
19 | |||
20 | /** | ||
21 | * struct ab8500_reg_range | ||
22 | * @first: the first address of the range | ||
23 | * @last: the last address of the range | ||
24 | * @perm: access permissions for the range | ||
25 | */ | ||
26 | struct ab8500_reg_range { | ||
27 | u8 first; | ||
28 | u8 last; | ||
29 | u8 perm; | ||
30 | }; | ||
31 | |||
32 | /** | ||
33 | * struct ab8500_i2c_ranges | ||
34 | * @num_ranges: the number of ranges in the list | ||
35 | * @bankid: bank identifier | ||
36 | * @range: the list of register ranges | ||
37 | */ | ||
38 | struct ab8500_i2c_ranges { | ||
39 | u8 num_ranges; | ||
40 | u8 bankid; | ||
41 | const struct ab8500_reg_range *range; | ||
42 | }; | ||
43 | |||
44 | #define AB8500_NAME_STRING "ab8500" | ||
45 | #define AB8500_NUM_BANKS 22 | ||
46 | |||
47 | #define AB8500_REV_REG 0x80 | ||
48 | |||
49 | static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = { | ||
50 | [0x0] = { | ||
51 | .num_ranges = 0, | ||
52 | .range = 0, | ||
53 | }, | ||
54 | [AB8500_SYS_CTRL1_BLOCK] = { | ||
55 | .num_ranges = 3, | ||
56 | .range = (struct ab8500_reg_range[]) { | ||
57 | { | ||
58 | .first = 0x00, | ||
59 | .last = 0x02, | ||
60 | }, | ||
61 | { | ||
62 | .first = 0x42, | ||
63 | .last = 0x42, | ||
64 | }, | ||
65 | { | ||
66 | .first = 0x80, | ||
67 | .last = 0x81, | ||
68 | }, | ||
69 | }, | ||
70 | }, | ||
71 | [AB8500_SYS_CTRL2_BLOCK] = { | ||
72 | .num_ranges = 4, | ||
73 | .range = (struct ab8500_reg_range[]) { | ||
74 | { | ||
75 | .first = 0x00, | ||
76 | .last = 0x0D, | ||
77 | }, | ||
78 | { | ||
79 | .first = 0x0F, | ||
80 | .last = 0x17, | ||
81 | }, | ||
82 | { | ||
83 | .first = 0x30, | ||
84 | .last = 0x30, | ||
85 | }, | ||
86 | { | ||
87 | .first = 0x32, | ||
88 | .last = 0x33, | ||
89 | }, | ||
90 | }, | ||
91 | }, | ||
92 | [AB8500_REGU_CTRL1] = { | ||
93 | .num_ranges = 3, | ||
94 | .range = (struct ab8500_reg_range[]) { | ||
95 | { | ||
96 | .first = 0x00, | ||
97 | .last = 0x00, | ||
98 | }, | ||
99 | { | ||
100 | .first = 0x03, | ||
101 | .last = 0x10, | ||
102 | }, | ||
103 | { | ||
104 | .first = 0x80, | ||
105 | .last = 0x84, | ||
106 | }, | ||
107 | }, | ||
108 | }, | ||
109 | [AB8500_REGU_CTRL2] = { | ||
110 | .num_ranges = 5, | ||
111 | .range = (struct ab8500_reg_range[]) { | ||
112 | { | ||
113 | .first = 0x00, | ||
114 | .last = 0x15, | ||
115 | }, | ||
116 | { | ||
117 | .first = 0x17, | ||
118 | .last = 0x19, | ||
119 | }, | ||
120 | { | ||
121 | .first = 0x1B, | ||
122 | .last = 0x1D, | ||
123 | }, | ||
124 | { | ||
125 | .first = 0x1F, | ||
126 | .last = 0x22, | ||
127 | }, | ||
128 | { | ||
129 | .first = 0x40, | ||
130 | .last = 0x44, | ||
131 | }, | ||
132 | /* 0x80-0x8B is SIM registers and should | ||
133 | * not be accessed from here */ | ||
134 | }, | ||
135 | }, | ||
136 | [AB8500_USB] = { | ||
137 | .num_ranges = 2, | ||
138 | .range = (struct ab8500_reg_range[]) { | ||
139 | { | ||
140 | .first = 0x80, | ||
141 | .last = 0x83, | ||
142 | }, | ||
143 | { | ||
144 | .first = 0x87, | ||
145 | .last = 0x8A, | ||
146 | }, | ||
147 | }, | ||
148 | }, | ||
149 | [AB8500_TVOUT] = { | ||
150 | .num_ranges = 9, | ||
151 | .range = (struct ab8500_reg_range[]) { | ||
152 | { | ||
153 | .first = 0x00, | ||
154 | .last = 0x12, | ||
155 | }, | ||
156 | { | ||
157 | .first = 0x15, | ||
158 | .last = 0x17, | ||
159 | }, | ||
160 | { | ||
161 | .first = 0x19, | ||
162 | .last = 0x21, | ||
163 | }, | ||
164 | { | ||
165 | .first = 0x27, | ||
166 | .last = 0x2C, | ||
167 | }, | ||
168 | { | ||
169 | .first = 0x41, | ||
170 | .last = 0x41, | ||
171 | }, | ||
172 | { | ||
173 | .first = 0x45, | ||
174 | .last = 0x5B, | ||
175 | }, | ||
176 | { | ||
177 | .first = 0x5D, | ||
178 | .last = 0x5D, | ||
179 | }, | ||
180 | { | ||
181 | .first = 0x69, | ||
182 | .last = 0x69, | ||
183 | }, | ||
184 | { | ||
185 | .first = 0x80, | ||
186 | .last = 0x81, | ||
187 | }, | ||
188 | }, | ||
189 | }, | ||
190 | [AB8500_DBI] = { | ||
191 | .num_ranges = 0, | ||
192 | .range = NULL, | ||
193 | }, | ||
194 | [AB8500_ECI_AV_ACC] = { | ||
195 | .num_ranges = 1, | ||
196 | .range = (struct ab8500_reg_range[]) { | ||
197 | { | ||
198 | .first = 0x80, | ||
199 | .last = 0x82, | ||
200 | }, | ||
201 | }, | ||
202 | }, | ||
203 | [0x9] = { | ||
204 | .num_ranges = 0, | ||
205 | .range = NULL, | ||
206 | }, | ||
207 | [AB8500_GPADC] = { | ||
208 | .num_ranges = 1, | ||
209 | .range = (struct ab8500_reg_range[]) { | ||
210 | { | ||
211 | .first = 0x00, | ||
212 | .last = 0x08, | ||
213 | }, | ||
214 | }, | ||
215 | }, | ||
216 | [AB8500_CHARGER] = { | ||
217 | .num_ranges = 8, | ||
218 | .range = (struct ab8500_reg_range[]) { | ||
219 | { | ||
220 | .first = 0x00, | ||
221 | .last = 0x03, | ||
222 | }, | ||
223 | { | ||
224 | .first = 0x05, | ||
225 | .last = 0x05, | ||
226 | }, | ||
227 | { | ||
228 | .first = 0x40, | ||
229 | .last = 0x40, | ||
230 | }, | ||
231 | { | ||
232 | .first = 0x42, | ||
233 | .last = 0x42, | ||
234 | }, | ||
235 | { | ||
236 | .first = 0x44, | ||
237 | .last = 0x44, | ||
238 | }, | ||
239 | { | ||
240 | .first = 0x50, | ||
241 | .last = 0x55, | ||
242 | }, | ||
243 | { | ||
244 | .first = 0x80, | ||
245 | .last = 0x82, | ||
246 | }, | ||
247 | { | ||
248 | .first = 0xC0, | ||
249 | .last = 0xC2, | ||
250 | }, | ||
251 | }, | ||
252 | }, | ||
253 | [AB8500_GAS_GAUGE] = { | ||
254 | .num_ranges = 3, | ||
255 | .range = (struct ab8500_reg_range[]) { | ||
256 | { | ||
257 | .first = 0x00, | ||
258 | .last = 0x00, | ||
259 | }, | ||
260 | { | ||
261 | .first = 0x07, | ||
262 | .last = 0x0A, | ||
263 | }, | ||
264 | { | ||
265 | .first = 0x10, | ||
266 | .last = 0x14, | ||
267 | }, | ||
268 | }, | ||
269 | }, | ||
270 | [AB8500_AUDIO] = { | ||
271 | .num_ranges = 1, | ||
272 | .range = (struct ab8500_reg_range[]) { | ||
273 | { | ||
274 | .first = 0x00, | ||
275 | .last = 0x6F, | ||
276 | }, | ||
277 | }, | ||
278 | }, | ||
279 | [AB8500_INTERRUPT] = { | ||
280 | .num_ranges = 0, | ||
281 | .range = NULL, | ||
282 | }, | ||
283 | [AB8500_RTC] = { | ||
284 | .num_ranges = 1, | ||
285 | .range = (struct ab8500_reg_range[]) { | ||
286 | { | ||
287 | .first = 0x00, | ||
288 | .last = 0x0F, | ||
289 | }, | ||
290 | }, | ||
291 | }, | ||
292 | [AB8500_MISC] = { | ||
293 | .num_ranges = 8, | ||
294 | .range = (struct ab8500_reg_range[]) { | ||
295 | { | ||
296 | .first = 0x00, | ||
297 | .last = 0x05, | ||
298 | }, | ||
299 | { | ||
300 | .first = 0x10, | ||
301 | .last = 0x15, | ||
302 | }, | ||
303 | { | ||
304 | .first = 0x20, | ||
305 | .last = 0x25, | ||
306 | }, | ||
307 | { | ||
308 | .first = 0x30, | ||
309 | .last = 0x35, | ||
310 | }, | ||
311 | { | ||
312 | .first = 0x40, | ||
313 | .last = 0x45, | ||
314 | }, | ||
315 | { | ||
316 | .first = 0x50, | ||
317 | .last = 0x50, | ||
318 | }, | ||
319 | { | ||
320 | .first = 0x60, | ||
321 | .last = 0x67, | ||
322 | }, | ||
323 | { | ||
324 | .first = 0x80, | ||
325 | .last = 0x80, | ||
326 | }, | ||
327 | }, | ||
328 | }, | ||
329 | [0x11] = { | ||
330 | .num_ranges = 0, | ||
331 | .range = NULL, | ||
332 | }, | ||
333 | [0x12] = { | ||
334 | .num_ranges = 0, | ||
335 | .range = NULL, | ||
336 | }, | ||
337 | [0x13] = { | ||
338 | .num_ranges = 0, | ||
339 | .range = NULL, | ||
340 | }, | ||
341 | [0x14] = { | ||
342 | .num_ranges = 0, | ||
343 | .range = NULL, | ||
344 | }, | ||
345 | [AB8500_OTP_EMUL] = { | ||
346 | .num_ranges = 1, | ||
347 | .range = (struct ab8500_reg_range[]) { | ||
348 | { | ||
349 | .first = 0x01, | ||
350 | .last = 0x0F, | ||
351 | }, | ||
352 | }, | ||
353 | }, | ||
354 | }; | ||
355 | |||
356 | static int ab8500_registers_print(struct seq_file *s, void *p) | ||
357 | { | ||
358 | struct device *dev = s->private; | ||
359 | unsigned int i; | ||
360 | u32 bank = debug_bank; | ||
361 | |||
362 | seq_printf(s, AB8500_NAME_STRING " register values:\n"); | ||
363 | |||
364 | seq_printf(s, " bank %u:\n", bank); | ||
365 | for (i = 0; i < debug_ranges[bank].num_ranges; i++) { | ||
366 | u32 reg; | ||
367 | |||
368 | for (reg = debug_ranges[bank].range[i].first; | ||
369 | reg <= debug_ranges[bank].range[i].last; | ||
370 | reg++) { | ||
371 | u8 value; | ||
372 | int err; | ||
373 | |||
374 | err = abx500_get_register_interruptible(dev, | ||
375 | (u8)bank, (u8)reg, &value); | ||
376 | if (err < 0) { | ||
377 | dev_err(dev, "ab->read fail %d\n", err); | ||
378 | return err; | ||
379 | } | ||
380 | |||
381 | err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank, | ||
382 | reg, value); | ||
383 | if (err < 0) { | ||
384 | dev_err(dev, "seq_printf overflow\n"); | ||
385 | /* Error is not returned here since | ||
386 | * the output is wanted in any case */ | ||
387 | return 0; | ||
388 | } | ||
389 | } | ||
390 | } | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int ab8500_registers_open(struct inode *inode, struct file *file) | ||
395 | { | ||
396 | return single_open(file, ab8500_registers_print, inode->i_private); | ||
397 | } | ||
398 | |||
399 | static const struct file_operations ab8500_registers_fops = { | ||
400 | .open = ab8500_registers_open, | ||
401 | .read = seq_read, | ||
402 | .llseek = seq_lseek, | ||
403 | .release = single_release, | ||
404 | .owner = THIS_MODULE, | ||
405 | }; | ||
406 | |||
407 | static int ab8500_bank_print(struct seq_file *s, void *p) | ||
408 | { | ||
409 | return seq_printf(s, "%d\n", debug_bank); | ||
410 | } | ||
411 | |||
412 | static int ab8500_bank_open(struct inode *inode, struct file *file) | ||
413 | { | ||
414 | return single_open(file, ab8500_bank_print, inode->i_private); | ||
415 | } | ||
416 | |||
417 | static ssize_t ab8500_bank_write(struct file *file, | ||
418 | const char __user *user_buf, | ||
419 | size_t count, loff_t *ppos) | ||
420 | { | ||
421 | struct device *dev = ((struct seq_file *)(file->private_data))->private; | ||
422 | char buf[32]; | ||
423 | int buf_size; | ||
424 | unsigned long user_bank; | ||
425 | int err; | ||
426 | |||
427 | /* Get userspace string and assure termination */ | ||
428 | buf_size = min(count, (sizeof(buf) - 1)); | ||
429 | if (copy_from_user(buf, user_buf, buf_size)) | ||
430 | return -EFAULT; | ||
431 | buf[buf_size] = 0; | ||
432 | |||
433 | err = strict_strtoul(buf, 0, &user_bank); | ||
434 | if (err) | ||
435 | return -EINVAL; | ||
436 | |||
437 | if (user_bank >= AB8500_NUM_BANKS) { | ||
438 | dev_err(dev, "debugfs error input > number of banks\n"); | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | |||
442 | debug_bank = user_bank; | ||
443 | |||
444 | return buf_size; | ||
445 | } | ||
446 | |||
447 | static int ab8500_address_print(struct seq_file *s, void *p) | ||
448 | { | ||
449 | return seq_printf(s, "0x%02X\n", debug_address); | ||
450 | } | ||
451 | |||
452 | static int ab8500_address_open(struct inode *inode, struct file *file) | ||
453 | { | ||
454 | return single_open(file, ab8500_address_print, inode->i_private); | ||
455 | } | ||
456 | |||
457 | static ssize_t ab8500_address_write(struct file *file, | ||
458 | const char __user *user_buf, | ||
459 | size_t count, loff_t *ppos) | ||
460 | { | ||
461 | struct device *dev = ((struct seq_file *)(file->private_data))->private; | ||
462 | char buf[32]; | ||
463 | int buf_size; | ||
464 | unsigned long user_address; | ||
465 | int err; | ||
466 | |||
467 | /* Get userspace string and assure termination */ | ||
468 | buf_size = min(count, (sizeof(buf) - 1)); | ||
469 | if (copy_from_user(buf, user_buf, buf_size)) | ||
470 | return -EFAULT; | ||
471 | buf[buf_size] = 0; | ||
472 | |||
473 | err = strict_strtoul(buf, 0, &user_address); | ||
474 | if (err) | ||
475 | return -EINVAL; | ||
476 | if (user_address > 0xff) { | ||
477 | dev_err(dev, "debugfs error input > 0xff\n"); | ||
478 | return -EINVAL; | ||
479 | } | ||
480 | debug_address = user_address; | ||
481 | return buf_size; | ||
482 | } | ||
483 | |||
484 | static int ab8500_val_print(struct seq_file *s, void *p) | ||
485 | { | ||
486 | struct device *dev = s->private; | ||
487 | int ret; | ||
488 | u8 regvalue; | ||
489 | |||
490 | ret = abx500_get_register_interruptible(dev, | ||
491 | (u8)debug_bank, (u8)debug_address, ®value); | ||
492 | if (ret < 0) { | ||
493 | dev_err(dev, "abx500_get_reg fail %d, %d\n", | ||
494 | ret, __LINE__); | ||
495 | return -EINVAL; | ||
496 | } | ||
497 | seq_printf(s, "0x%02X\n", regvalue); | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int ab8500_val_open(struct inode *inode, struct file *file) | ||
503 | { | ||
504 | return single_open(file, ab8500_val_print, inode->i_private); | ||
505 | } | ||
506 | |||
507 | static ssize_t ab8500_val_write(struct file *file, | ||
508 | const char __user *user_buf, | ||
509 | size_t count, loff_t *ppos) | ||
510 | { | ||
511 | struct device *dev = ((struct seq_file *)(file->private_data))->private; | ||
512 | char buf[32]; | ||
513 | int buf_size; | ||
514 | unsigned long user_val; | ||
515 | int err; | ||
516 | |||
517 | /* Get userspace string and assure termination */ | ||
518 | buf_size = min(count, (sizeof(buf)-1)); | ||
519 | if (copy_from_user(buf, user_buf, buf_size)) | ||
520 | return -EFAULT; | ||
521 | buf[buf_size] = 0; | ||
522 | |||
523 | err = strict_strtoul(buf, 0, &user_val); | ||
524 | if (err) | ||
525 | return -EINVAL; | ||
526 | if (user_val > 0xff) { | ||
527 | dev_err(dev, "debugfs error input > 0xff\n"); | ||
528 | return -EINVAL; | ||
529 | } | ||
530 | err = abx500_set_register_interruptible(dev, | ||
531 | (u8)debug_bank, debug_address, (u8)user_val); | ||
532 | if (err < 0) { | ||
533 | printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__); | ||
534 | return -EINVAL; | ||
535 | } | ||
536 | |||
537 | return buf_size; | ||
538 | } | ||
539 | |||
540 | static const struct file_operations ab8500_bank_fops = { | ||
541 | .open = ab8500_bank_open, | ||
542 | .write = ab8500_bank_write, | ||
543 | .read = seq_read, | ||
544 | .llseek = seq_lseek, | ||
545 | .release = single_release, | ||
546 | .owner = THIS_MODULE, | ||
547 | }; | ||
548 | |||
549 | static const struct file_operations ab8500_address_fops = { | ||
550 | .open = ab8500_address_open, | ||
551 | .write = ab8500_address_write, | ||
552 | .read = seq_read, | ||
553 | .llseek = seq_lseek, | ||
554 | .release = single_release, | ||
555 | .owner = THIS_MODULE, | ||
556 | }; | ||
557 | |||
558 | static const struct file_operations ab8500_val_fops = { | ||
559 | .open = ab8500_val_open, | ||
560 | .write = ab8500_val_write, | ||
561 | .read = seq_read, | ||
562 | .llseek = seq_lseek, | ||
563 | .release = single_release, | ||
564 | .owner = THIS_MODULE, | ||
565 | }; | ||
566 | |||
567 | static struct dentry *ab8500_dir; | ||
568 | static struct dentry *ab8500_reg_file; | ||
569 | static struct dentry *ab8500_bank_file; | ||
570 | static struct dentry *ab8500_address_file; | ||
571 | static struct dentry *ab8500_val_file; | ||
572 | |||
573 | static int __devinit ab8500_debug_probe(struct platform_device *plf) | ||
574 | { | ||
575 | debug_bank = AB8500_MISC; | ||
576 | debug_address = AB8500_REV_REG & 0x00FF; | ||
577 | |||
578 | ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL); | ||
579 | if (!ab8500_dir) | ||
580 | goto exit_no_debugfs; | ||
581 | |||
582 | ab8500_reg_file = debugfs_create_file("all-bank-registers", | ||
583 | S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops); | ||
584 | if (!ab8500_reg_file) | ||
585 | goto exit_destroy_dir; | ||
586 | |||
587 | ab8500_bank_file = debugfs_create_file("register-bank", | ||
588 | (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_bank_fops); | ||
589 | if (!ab8500_bank_file) | ||
590 | goto exit_destroy_reg; | ||
591 | |||
592 | ab8500_address_file = debugfs_create_file("register-address", | ||
593 | (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, | ||
594 | &ab8500_address_fops); | ||
595 | if (!ab8500_address_file) | ||
596 | goto exit_destroy_bank; | ||
597 | |||
598 | ab8500_val_file = debugfs_create_file("register-value", | ||
599 | (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_val_fops); | ||
600 | if (!ab8500_val_file) | ||
601 | goto exit_destroy_address; | ||
602 | |||
603 | return 0; | ||
604 | |||
605 | exit_destroy_address: | ||
606 | debugfs_remove(ab8500_address_file); | ||
607 | exit_destroy_bank: | ||
608 | debugfs_remove(ab8500_bank_file); | ||
609 | exit_destroy_reg: | ||
610 | debugfs_remove(ab8500_reg_file); | ||
611 | exit_destroy_dir: | ||
612 | debugfs_remove(ab8500_dir); | ||
613 | exit_no_debugfs: | ||
614 | dev_err(&plf->dev, "failed to create debugfs entries.\n"); | ||
615 | return -ENOMEM; | ||
616 | } | ||
617 | |||
618 | static int __devexit ab8500_debug_remove(struct platform_device *plf) | ||
619 | { | ||
620 | debugfs_remove(ab8500_val_file); | ||
621 | debugfs_remove(ab8500_address_file); | ||
622 | debugfs_remove(ab8500_bank_file); | ||
623 | debugfs_remove(ab8500_reg_file); | ||
624 | debugfs_remove(ab8500_dir); | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | static struct platform_driver ab8500_debug_driver = { | ||
630 | .driver = { | ||
631 | .name = "ab8500-debug", | ||
632 | .owner = THIS_MODULE, | ||
633 | }, | ||
634 | .probe = ab8500_debug_probe, | ||
635 | .remove = __devexit_p(ab8500_debug_remove) | ||
636 | }; | ||
637 | |||
638 | static int __init ab8500_debug_init(void) | ||
639 | { | ||
640 | return platform_driver_register(&ab8500_debug_driver); | ||
641 | } | ||
642 | |||
643 | static void __exit ab8500_debug_exit(void) | ||
644 | { | ||
645 | platform_driver_unregister(&ab8500_debug_driver); | ||
646 | } | ||
647 | subsys_initcall(ab8500_debug_init); | ||
648 | module_exit(ab8500_debug_exit); | ||
649 | |||
650 | MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com"); | ||
651 | MODULE_DESCRIPTION("AB8500 DEBUG"); | ||
652 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c new file mode 100644 index 000000000000..f16afb234ff9 --- /dev/null +++ b/drivers/mfd/ab8500-gpadc.c | |||
@@ -0,0 +1,646 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * License Terms: GNU General Public License v2 | ||
5 | * Author: Arun R Murthy <arun.murthy@stericsson.com> | ||
6 | * Author: Daniel Willerud <daniel.willerud@stericsson.com> | ||
7 | * Author: Johan Palsson <johan.palsson@stericsson.com> | ||
8 | */ | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/device.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/completion.h> | ||
17 | #include <linux/regulator/consumer.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/list.h> | ||
21 | #include <linux/mfd/ab8500.h> | ||
22 | #include <linux/mfd/abx500.h> | ||
23 | #include <linux/mfd/ab8500/gpadc.h> | ||
24 | |||
25 | /* | ||
26 | * GPADC register offsets | ||
27 | * Bank : 0x0A | ||
28 | */ | ||
29 | #define AB8500_GPADC_CTRL1_REG 0x00 | ||
30 | #define AB8500_GPADC_CTRL2_REG 0x01 | ||
31 | #define AB8500_GPADC_CTRL3_REG 0x02 | ||
32 | #define AB8500_GPADC_AUTO_TIMER_REG 0x03 | ||
33 | #define AB8500_GPADC_STAT_REG 0x04 | ||
34 | #define AB8500_GPADC_MANDATAL_REG 0x05 | ||
35 | #define AB8500_GPADC_MANDATAH_REG 0x06 | ||
36 | #define AB8500_GPADC_AUTODATAL_REG 0x07 | ||
37 | #define AB8500_GPADC_AUTODATAH_REG 0x08 | ||
38 | #define AB8500_GPADC_MUX_CTRL_REG 0x09 | ||
39 | |||
40 | /* | ||
41 | * OTP register offsets | ||
42 | * Bank : 0x15 | ||
43 | */ | ||
44 | #define AB8500_GPADC_CAL_1 0x0F | ||
45 | #define AB8500_GPADC_CAL_2 0x10 | ||
46 | #define AB8500_GPADC_CAL_3 0x11 | ||
47 | #define AB8500_GPADC_CAL_4 0x12 | ||
48 | #define AB8500_GPADC_CAL_5 0x13 | ||
49 | #define AB8500_GPADC_CAL_6 0x14 | ||
50 | #define AB8500_GPADC_CAL_7 0x15 | ||
51 | |||
52 | /* gpadc constants */ | ||
53 | #define EN_VINTCORE12 0x04 | ||
54 | #define EN_VTVOUT 0x02 | ||
55 | #define EN_GPADC 0x01 | ||
56 | #define DIS_GPADC 0x00 | ||
57 | #define SW_AVG_16 0x60 | ||
58 | #define ADC_SW_CONV 0x04 | ||
59 | #define EN_ICHAR 0x80 | ||
60 | #define BTEMP_PULL_UP 0x08 | ||
61 | #define EN_BUF 0x40 | ||
62 | #define DIS_ZERO 0x00 | ||
63 | #define GPADC_BUSY 0x01 | ||
64 | |||
65 | /* GPADC constants from AB8500 spec, UM0836 */ | ||
66 | #define ADC_RESOLUTION 1024 | ||
67 | #define ADC_CH_BTEMP_MIN 0 | ||
68 | #define ADC_CH_BTEMP_MAX 1350 | ||
69 | #define ADC_CH_DIETEMP_MIN 0 | ||
70 | #define ADC_CH_DIETEMP_MAX 1350 | ||
71 | #define ADC_CH_CHG_V_MIN 0 | ||
72 | #define ADC_CH_CHG_V_MAX 20030 | ||
73 | #define ADC_CH_ACCDET2_MIN 0 | ||
74 | #define ADC_CH_ACCDET2_MAX 2500 | ||
75 | #define ADC_CH_VBAT_MIN 2300 | ||
76 | #define ADC_CH_VBAT_MAX 4800 | ||
77 | #define ADC_CH_CHG_I_MIN 0 | ||
78 | #define ADC_CH_CHG_I_MAX 1500 | ||
79 | #define ADC_CH_BKBAT_MIN 0 | ||
80 | #define ADC_CH_BKBAT_MAX 3200 | ||
81 | |||
82 | /* This is used to not lose precision when dividing to get gain and offset */ | ||
83 | #define CALIB_SCALE 1000 | ||
84 | |||
85 | enum cal_channels { | ||
86 | ADC_INPUT_VMAIN = 0, | ||
87 | ADC_INPUT_BTEMP, | ||
88 | ADC_INPUT_VBAT, | ||
89 | NBR_CAL_INPUTS, | ||
90 | }; | ||
91 | |||
92 | /** | ||
93 | * struct adc_cal_data - Table for storing gain and offset for the calibrated | ||
94 | * ADC channels | ||
95 | * @gain: Gain of the ADC channel | ||
96 | * @offset: Offset of the ADC channel | ||
97 | */ | ||
98 | struct adc_cal_data { | ||
99 | u64 gain; | ||
100 | u64 offset; | ||
101 | }; | ||
102 | |||
103 | /** | ||
104 | * struct ab8500_gpadc - AB8500 GPADC device information | ||
105 | * @chip_id ABB chip id | ||
106 | * @dev: pointer to the struct device | ||
107 | * @node: a list of AB8500 GPADCs, hence prepared for | ||
108 | reentrance | ||
109 | * @ab8500_gpadc_complete: pointer to the struct completion, to indicate | ||
110 | * the completion of gpadc conversion | ||
111 | * @ab8500_gpadc_lock: structure of type mutex | ||
112 | * @regu: pointer to the struct regulator | ||
113 | * @irq: interrupt number that is used by gpadc | ||
114 | * @cal_data array of ADC calibration data structs | ||
115 | */ | ||
116 | struct ab8500_gpadc { | ||
117 | u8 chip_id; | ||
118 | struct device *dev; | ||
119 | struct list_head node; | ||
120 | struct completion ab8500_gpadc_complete; | ||
121 | struct mutex ab8500_gpadc_lock; | ||
122 | struct regulator *regu; | ||
123 | int irq; | ||
124 | struct adc_cal_data cal_data[NBR_CAL_INPUTS]; | ||
125 | }; | ||
126 | |||
127 | static LIST_HEAD(ab8500_gpadc_list); | ||
128 | |||
129 | /** | ||
130 | * ab8500_gpadc_get() - returns a reference to the primary AB8500 GPADC | ||
131 | * (i.e. the first GPADC in the instance list) | ||
132 | */ | ||
133 | struct ab8500_gpadc *ab8500_gpadc_get(char *name) | ||
134 | { | ||
135 | struct ab8500_gpadc *gpadc; | ||
136 | |||
137 | list_for_each_entry(gpadc, &ab8500_gpadc_list, node) { | ||
138 | if (!strcmp(name, dev_name(gpadc->dev))) | ||
139 | return gpadc; | ||
140 | } | ||
141 | |||
142 | return ERR_PTR(-ENOENT); | ||
143 | } | ||
144 | EXPORT_SYMBOL(ab8500_gpadc_get); | ||
145 | |||
146 | static int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 input, | ||
147 | int ad_value) | ||
148 | { | ||
149 | int res; | ||
150 | |||
151 | switch (input) { | ||
152 | case MAIN_CHARGER_V: | ||
153 | /* For some reason we don't have calibrated data */ | ||
154 | if (!gpadc->cal_data[ADC_INPUT_VMAIN].gain) { | ||
155 | res = ADC_CH_CHG_V_MIN + (ADC_CH_CHG_V_MAX - | ||
156 | ADC_CH_CHG_V_MIN) * ad_value / | ||
157 | ADC_RESOLUTION; | ||
158 | break; | ||
159 | } | ||
160 | /* Here we can use the calibrated data */ | ||
161 | res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VMAIN].gain + | ||
162 | gpadc->cal_data[ADC_INPUT_VMAIN].offset) / CALIB_SCALE; | ||
163 | break; | ||
164 | |||
165 | case BAT_CTRL: | ||
166 | case BTEMP_BALL: | ||
167 | case ACC_DETECT1: | ||
168 | case ADC_AUX1: | ||
169 | case ADC_AUX2: | ||
170 | /* For some reason we don't have calibrated data */ | ||
171 | if (!gpadc->cal_data[ADC_INPUT_BTEMP].gain) { | ||
172 | res = ADC_CH_BTEMP_MIN + (ADC_CH_BTEMP_MAX - | ||
173 | ADC_CH_BTEMP_MIN) * ad_value / | ||
174 | ADC_RESOLUTION; | ||
175 | break; | ||
176 | } | ||
177 | /* Here we can use the calibrated data */ | ||
178 | res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_BTEMP].gain + | ||
179 | gpadc->cal_data[ADC_INPUT_BTEMP].offset) / CALIB_SCALE; | ||
180 | break; | ||
181 | |||
182 | case MAIN_BAT_V: | ||
183 | /* For some reason we don't have calibrated data */ | ||
184 | if (!gpadc->cal_data[ADC_INPUT_VBAT].gain) { | ||
185 | res = ADC_CH_VBAT_MIN + (ADC_CH_VBAT_MAX - | ||
186 | ADC_CH_VBAT_MIN) * ad_value / | ||
187 | ADC_RESOLUTION; | ||
188 | break; | ||
189 | } | ||
190 | /* Here we can use the calibrated data */ | ||
191 | res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VBAT].gain + | ||
192 | gpadc->cal_data[ADC_INPUT_VBAT].offset) / CALIB_SCALE; | ||
193 | break; | ||
194 | |||
195 | case DIE_TEMP: | ||
196 | res = ADC_CH_DIETEMP_MIN + | ||
197 | (ADC_CH_DIETEMP_MAX - ADC_CH_DIETEMP_MIN) * ad_value / | ||
198 | ADC_RESOLUTION; | ||
199 | break; | ||
200 | |||
201 | case ACC_DETECT2: | ||
202 | res = ADC_CH_ACCDET2_MIN + | ||
203 | (ADC_CH_ACCDET2_MAX - ADC_CH_ACCDET2_MIN) * ad_value / | ||
204 | ADC_RESOLUTION; | ||
205 | break; | ||
206 | |||
207 | case VBUS_V: | ||
208 | res = ADC_CH_CHG_V_MIN + | ||
209 | (ADC_CH_CHG_V_MAX - ADC_CH_CHG_V_MIN) * ad_value / | ||
210 | ADC_RESOLUTION; | ||
211 | break; | ||
212 | |||
213 | case MAIN_CHARGER_C: | ||
214 | case USB_CHARGER_C: | ||
215 | res = ADC_CH_CHG_I_MIN + | ||
216 | (ADC_CH_CHG_I_MAX - ADC_CH_CHG_I_MIN) * ad_value / | ||
217 | ADC_RESOLUTION; | ||
218 | break; | ||
219 | |||
220 | case BK_BAT_V: | ||
221 | res = ADC_CH_BKBAT_MIN + | ||
222 | (ADC_CH_BKBAT_MAX - ADC_CH_BKBAT_MIN) * ad_value / | ||
223 | ADC_RESOLUTION; | ||
224 | break; | ||
225 | |||
226 | default: | ||
227 | dev_err(gpadc->dev, | ||
228 | "unknown channel, not possible to convert\n"); | ||
229 | res = -EINVAL; | ||
230 | break; | ||
231 | |||
232 | } | ||
233 | return res; | ||
234 | } | ||
235 | |||
236 | /** | ||
237 | * ab8500_gpadc_convert() - gpadc conversion | ||
238 | * @input: analog input to be converted to digital data | ||
239 | * | ||
240 | * This function converts the selected analog i/p to digital | ||
241 | * data. | ||
242 | */ | ||
243 | int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) | ||
244 | { | ||
245 | int ret; | ||
246 | u16 data = 0; | ||
247 | int looplimit = 0; | ||
248 | u8 val, low_data, high_data; | ||
249 | |||
250 | if (!gpadc) | ||
251 | return -ENODEV; | ||
252 | |||
253 | mutex_lock(&gpadc->ab8500_gpadc_lock); | ||
254 | /* Enable VTVout LDO this is required for GPADC */ | ||
255 | regulator_enable(gpadc->regu); | ||
256 | |||
257 | /* Check if ADC is not busy, lock and proceed */ | ||
258 | do { | ||
259 | ret = abx500_get_register_interruptible(gpadc->dev, | ||
260 | AB8500_GPADC, AB8500_GPADC_STAT_REG, &val); | ||
261 | if (ret < 0) | ||
262 | goto out; | ||
263 | if (!(val & GPADC_BUSY)) | ||
264 | break; | ||
265 | msleep(10); | ||
266 | } while (++looplimit < 10); | ||
267 | if (looplimit >= 10 && (val & GPADC_BUSY)) { | ||
268 | dev_err(gpadc->dev, "gpadc_conversion: GPADC busy"); | ||
269 | ret = -EINVAL; | ||
270 | goto out; | ||
271 | } | ||
272 | |||
273 | /* Enable GPADC */ | ||
274 | ret = abx500_mask_and_set_register_interruptible(gpadc->dev, | ||
275 | AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC); | ||
276 | if (ret < 0) { | ||
277 | dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n"); | ||
278 | goto out; | ||
279 | } | ||
280 | |||
281 | /* Select the input source and set average samples to 16 */ | ||
282 | ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, | ||
283 | AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16)); | ||
284 | if (ret < 0) { | ||
285 | dev_err(gpadc->dev, | ||
286 | "gpadc_conversion: set avg samples failed\n"); | ||
287 | goto out; | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * Enable ADC, buffering, select rising edge and enable ADC path | ||
292 | * charging current sense if it needed, ABB 3.0 needs some special | ||
293 | * treatment too. | ||
294 | */ | ||
295 | switch (input) { | ||
296 | case MAIN_CHARGER_C: | ||
297 | case USB_CHARGER_C: | ||
298 | ret = abx500_mask_and_set_register_interruptible(gpadc->dev, | ||
299 | AB8500_GPADC, AB8500_GPADC_CTRL1_REG, | ||
300 | EN_BUF | EN_ICHAR, | ||
301 | EN_BUF | EN_ICHAR); | ||
302 | break; | ||
303 | case BTEMP_BALL: | ||
304 | if (gpadc->chip_id >= AB8500_CUT3P0) { | ||
305 | /* Turn on btemp pull-up on ABB 3.0 */ | ||
306 | ret = abx500_mask_and_set_register_interruptible( | ||
307 | gpadc->dev, | ||
308 | AB8500_GPADC, AB8500_GPADC_CTRL1_REG, | ||
309 | EN_BUF | BTEMP_PULL_UP, | ||
310 | EN_BUF | BTEMP_PULL_UP); | ||
311 | |||
312 | /* | ||
313 | * Delay might be needed for ABB8500 cut 3.0, if not, remove | ||
314 | * when hardware will be availible | ||
315 | */ | ||
316 | msleep(1); | ||
317 | break; | ||
318 | } | ||
319 | /* Intentional fallthrough */ | ||
320 | default: | ||
321 | ret = abx500_mask_and_set_register_interruptible(gpadc->dev, | ||
322 | AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF); | ||
323 | break; | ||
324 | } | ||
325 | if (ret < 0) { | ||
326 | dev_err(gpadc->dev, | ||
327 | "gpadc_conversion: select falling edge failed\n"); | ||
328 | goto out; | ||
329 | } | ||
330 | |||
331 | ret = abx500_mask_and_set_register_interruptible(gpadc->dev, | ||
332 | AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV); | ||
333 | if (ret < 0) { | ||
334 | dev_err(gpadc->dev, | ||
335 | "gpadc_conversion: start s/w conversion failed\n"); | ||
336 | goto out; | ||
337 | } | ||
338 | /* wait for completion of conversion */ | ||
339 | if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, 2*HZ)) { | ||
340 | dev_err(gpadc->dev, | ||
341 | "timeout: didn't receive GPADC conversion interrupt\n"); | ||
342 | ret = -EINVAL; | ||
343 | goto out; | ||
344 | } | ||
345 | |||
346 | /* Read the converted RAW data */ | ||
347 | ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC, | ||
348 | AB8500_GPADC_MANDATAL_REG, &low_data); | ||
349 | if (ret < 0) { | ||
350 | dev_err(gpadc->dev, "gpadc_conversion: read low data failed\n"); | ||
351 | goto out; | ||
352 | } | ||
353 | |||
354 | ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC, | ||
355 | AB8500_GPADC_MANDATAH_REG, &high_data); | ||
356 | if (ret < 0) { | ||
357 | dev_err(gpadc->dev, | ||
358 | "gpadc_conversion: read high data failed\n"); | ||
359 | goto out; | ||
360 | } | ||
361 | |||
362 | data = (high_data << 8) | low_data; | ||
363 | /* Disable GPADC */ | ||
364 | ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, | ||
365 | AB8500_GPADC_CTRL1_REG, DIS_GPADC); | ||
366 | if (ret < 0) { | ||
367 | dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n"); | ||
368 | goto out; | ||
369 | } | ||
370 | /* Disable VTVout LDO this is required for GPADC */ | ||
371 | regulator_disable(gpadc->regu); | ||
372 | mutex_unlock(&gpadc->ab8500_gpadc_lock); | ||
373 | ret = ab8500_gpadc_ad_to_voltage(gpadc, input, data); | ||
374 | return ret; | ||
375 | |||
376 | out: | ||
377 | /* | ||
378 | * It has shown to be needed to turn off the GPADC if an error occurs, | ||
379 | * otherwise we might have problem when waiting for the busy bit in the | ||
380 | * GPADC status register to go low. In V1.1 there wait_for_completion | ||
381 | * seems to timeout when waiting for an interrupt.. Not seen in V2.0 | ||
382 | */ | ||
383 | (void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, | ||
384 | AB8500_GPADC_CTRL1_REG, DIS_GPADC); | ||
385 | regulator_disable(gpadc->regu); | ||
386 | mutex_unlock(&gpadc->ab8500_gpadc_lock); | ||
387 | dev_err(gpadc->dev, | ||
388 | "gpadc_conversion: Failed to AD convert channel %d\n", input); | ||
389 | return ret; | ||
390 | } | ||
391 | EXPORT_SYMBOL(ab8500_gpadc_convert); | ||
392 | |||
393 | /** | ||
394 | * ab8500_bm_gpswadcconvend_handler() - isr for s/w gpadc conversion completion | ||
395 | * @irq: irq number | ||
396 | * @data: pointer to the data passed during request irq | ||
397 | * | ||
398 | * This is a interrupt service routine for s/w gpadc conversion completion. | ||
399 | * Notifies the gpadc completion is completed and the converted raw value | ||
400 | * can be read from the registers. | ||
401 | * Returns IRQ status(IRQ_HANDLED) | ||
402 | */ | ||
403 | static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_gpadc) | ||
404 | { | ||
405 | struct ab8500_gpadc *gpadc = _gpadc; | ||
406 | |||
407 | complete(&gpadc->ab8500_gpadc_complete); | ||
408 | |||
409 | return IRQ_HANDLED; | ||
410 | } | ||
411 | |||
412 | static int otp_cal_regs[] = { | ||
413 | AB8500_GPADC_CAL_1, | ||
414 | AB8500_GPADC_CAL_2, | ||
415 | AB8500_GPADC_CAL_3, | ||
416 | AB8500_GPADC_CAL_4, | ||
417 | AB8500_GPADC_CAL_5, | ||
418 | AB8500_GPADC_CAL_6, | ||
419 | AB8500_GPADC_CAL_7, | ||
420 | }; | ||
421 | |||
422 | static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc) | ||
423 | { | ||
424 | int i; | ||
425 | int ret[ARRAY_SIZE(otp_cal_regs)]; | ||
426 | u8 gpadc_cal[ARRAY_SIZE(otp_cal_regs)]; | ||
427 | |||
428 | int vmain_high, vmain_low; | ||
429 | int btemp_high, btemp_low; | ||
430 | int vbat_high, vbat_low; | ||
431 | |||
432 | /* First we read all OTP registers and store the error code */ | ||
433 | for (i = 0; i < ARRAY_SIZE(otp_cal_regs); i++) { | ||
434 | ret[i] = abx500_get_register_interruptible(gpadc->dev, | ||
435 | AB8500_OTP_EMUL, otp_cal_regs[i], &gpadc_cal[i]); | ||
436 | if (ret[i] < 0) | ||
437 | dev_err(gpadc->dev, "%s: read otp reg 0x%02x failed\n", | ||
438 | __func__, otp_cal_regs[i]); | ||
439 | } | ||
440 | |||
441 | /* | ||
442 | * The ADC calibration data is stored in OTP registers. | ||
443 | * The layout of the calibration data is outlined below and a more | ||
444 | * detailed description can be found in UM0836 | ||
445 | * | ||
446 | * vm_h/l = vmain_high/low | ||
447 | * bt_h/l = btemp_high/low | ||
448 | * vb_h/l = vbat_high/low | ||
449 | * | ||
450 | * Data bits: | ||
451 | * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ||
452 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
453 | * | | vm_h9 | vm_h8 | ||
454 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
455 | * | | vm_h7 | vm_h6 | vm_h5 | vm_h4 | vm_h3 | vm_h2 | ||
456 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
457 | * | vm_h1 | vm_h0 | vm_l4 | vm_l3 | vm_l2 | vm_l1 | vm_l0 | bt_h9 | ||
458 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
459 | * | bt_h8 | bt_h7 | bt_h6 | bt_h5 | bt_h4 | bt_h3 | bt_h2 | bt_h1 | ||
460 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
461 | * | bt_h0 | bt_l4 | bt_l3 | bt_l2 | bt_l1 | bt_l0 | vb_h9 | vb_h8 | ||
462 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
463 | * | vb_h7 | vb_h6 | vb_h5 | vb_h4 | vb_h3 | vb_h2 | vb_h1 | vb_h0 | ||
464 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
465 | * | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 | | ||
466 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
467 | * | ||
468 | * | ||
469 | * Ideal output ADC codes corresponding to injected input voltages | ||
470 | * during manufacturing is: | ||
471 | * | ||
472 | * vmain_high: Vin = 19500mV / ADC ideal code = 997 | ||
473 | * vmain_low: Vin = 315mV / ADC ideal code = 16 | ||
474 | * btemp_high: Vin = 1300mV / ADC ideal code = 985 | ||
475 | * btemp_low: Vin = 21mV / ADC ideal code = 16 | ||
476 | * vbat_high: Vin = 4700mV / ADC ideal code = 982 | ||
477 | * vbat_low: Vin = 2380mV / ADC ideal code = 33 | ||
478 | */ | ||
479 | |||
480 | /* Calculate gain and offset for VMAIN if all reads succeeded */ | ||
481 | if (!(ret[0] < 0 || ret[1] < 0 || ret[2] < 0)) { | ||
482 | vmain_high = (((gpadc_cal[0] & 0x03) << 8) | | ||
483 | ((gpadc_cal[1] & 0x3F) << 2) | | ||
484 | ((gpadc_cal[2] & 0xC0) >> 6)); | ||
485 | |||
486 | vmain_low = ((gpadc_cal[2] & 0x3E) >> 1); | ||
487 | |||
488 | gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE * | ||
489 | (19500 - 315) / (vmain_high - vmain_low); | ||
490 | |||
491 | gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE * 19500 - | ||
492 | (CALIB_SCALE * (19500 - 315) / | ||
493 | (vmain_high - vmain_low)) * vmain_high; | ||
494 | } else { | ||
495 | gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0; | ||
496 | } | ||
497 | |||
498 | /* Calculate gain and offset for BTEMP if all reads succeeded */ | ||
499 | if (!(ret[2] < 0 || ret[3] < 0 || ret[4] < 0)) { | ||
500 | btemp_high = (((gpadc_cal[2] & 0x01) << 9) | | ||
501 | (gpadc_cal[3] << 1) | | ||
502 | ((gpadc_cal[4] & 0x80) >> 7)); | ||
503 | |||
504 | btemp_low = ((gpadc_cal[4] & 0x7C) >> 2); | ||
505 | |||
506 | gpadc->cal_data[ADC_INPUT_BTEMP].gain = | ||
507 | CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low); | ||
508 | |||
509 | gpadc->cal_data[ADC_INPUT_BTEMP].offset = CALIB_SCALE * 1300 - | ||
510 | (CALIB_SCALE * (1300 - 21) / | ||
511 | (btemp_high - btemp_low)) * btemp_high; | ||
512 | } else { | ||
513 | gpadc->cal_data[ADC_INPUT_BTEMP].gain = 0; | ||
514 | } | ||
515 | |||
516 | /* Calculate gain and offset for VBAT if all reads succeeded */ | ||
517 | if (!(ret[4] < 0 || ret[5] < 0 || ret[6] < 0)) { | ||
518 | vbat_high = (((gpadc_cal[4] & 0x03) << 8) | gpadc_cal[5]); | ||
519 | vbat_low = ((gpadc_cal[6] & 0xFC) >> 2); | ||
520 | |||
521 | gpadc->cal_data[ADC_INPUT_VBAT].gain = CALIB_SCALE * | ||
522 | (4700 - 2380) / (vbat_high - vbat_low); | ||
523 | |||
524 | gpadc->cal_data[ADC_INPUT_VBAT].offset = CALIB_SCALE * 4700 - | ||
525 | (CALIB_SCALE * (4700 - 2380) / | ||
526 | (vbat_high - vbat_low)) * vbat_high; | ||
527 | } else { | ||
528 | gpadc->cal_data[ADC_INPUT_VBAT].gain = 0; | ||
529 | } | ||
530 | |||
531 | dev_dbg(gpadc->dev, "VMAIN gain %llu offset %llu\n", | ||
532 | gpadc->cal_data[ADC_INPUT_VMAIN].gain, | ||
533 | gpadc->cal_data[ADC_INPUT_VMAIN].offset); | ||
534 | |||
535 | dev_dbg(gpadc->dev, "BTEMP gain %llu offset %llu\n", | ||
536 | gpadc->cal_data[ADC_INPUT_BTEMP].gain, | ||
537 | gpadc->cal_data[ADC_INPUT_BTEMP].offset); | ||
538 | |||
539 | dev_dbg(gpadc->dev, "VBAT gain %llu offset %llu\n", | ||
540 | gpadc->cal_data[ADC_INPUT_VBAT].gain, | ||
541 | gpadc->cal_data[ADC_INPUT_VBAT].offset); | ||
542 | } | ||
543 | |||
544 | static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) | ||
545 | { | ||
546 | int ret = 0; | ||
547 | struct ab8500_gpadc *gpadc; | ||
548 | |||
549 | gpadc = kzalloc(sizeof(struct ab8500_gpadc), GFP_KERNEL); | ||
550 | if (!gpadc) { | ||
551 | dev_err(&pdev->dev, "Error: No memory\n"); | ||
552 | return -ENOMEM; | ||
553 | } | ||
554 | |||
555 | gpadc->irq = platform_get_irq_byname(pdev, "SW_CONV_END"); | ||
556 | if (gpadc->irq < 0) { | ||
557 | dev_err(gpadc->dev, "failed to get platform irq-%d\n", | ||
558 | gpadc->irq); | ||
559 | ret = gpadc->irq; | ||
560 | goto fail; | ||
561 | } | ||
562 | |||
563 | gpadc->dev = &pdev->dev; | ||
564 | mutex_init(&gpadc->ab8500_gpadc_lock); | ||
565 | |||
566 | /* Initialize completion used to notify completion of conversion */ | ||
567 | init_completion(&gpadc->ab8500_gpadc_complete); | ||
568 | |||
569 | /* Register interrupt - SwAdcComplete */ | ||
570 | ret = request_threaded_irq(gpadc->irq, NULL, | ||
571 | ab8500_bm_gpswadcconvend_handler, | ||
572 | IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc", gpadc); | ||
573 | if (ret < 0) { | ||
574 | dev_err(gpadc->dev, "Failed to register interrupt, irq: %d\n", | ||
575 | gpadc->irq); | ||
576 | goto fail; | ||
577 | } | ||
578 | |||
579 | /* Get Chip ID of the ABB ASIC */ | ||
580 | ret = abx500_get_chip_id(gpadc->dev); | ||
581 | if (ret < 0) { | ||
582 | dev_err(gpadc->dev, "failed to get chip ID\n"); | ||
583 | goto fail_irq; | ||
584 | } | ||
585 | gpadc->chip_id = (u8) ret; | ||
586 | |||
587 | /* VTVout LDO used to power up ab8500-GPADC */ | ||
588 | gpadc->regu = regulator_get(&pdev->dev, "vddadc"); | ||
589 | if (IS_ERR(gpadc->regu)) { | ||
590 | ret = PTR_ERR(gpadc->regu); | ||
591 | dev_err(gpadc->dev, "failed to get vtvout LDO\n"); | ||
592 | goto fail_irq; | ||
593 | } | ||
594 | ab8500_gpadc_read_calibration_data(gpadc); | ||
595 | list_add_tail(&gpadc->node, &ab8500_gpadc_list); | ||
596 | dev_dbg(gpadc->dev, "probe success\n"); | ||
597 | return 0; | ||
598 | fail_irq: | ||
599 | free_irq(gpadc->irq, gpadc); | ||
600 | fail: | ||
601 | kfree(gpadc); | ||
602 | gpadc = NULL; | ||
603 | return ret; | ||
604 | } | ||
605 | |||
606 | static int __devexit ab8500_gpadc_remove(struct platform_device *pdev) | ||
607 | { | ||
608 | struct ab8500_gpadc *gpadc = platform_get_drvdata(pdev); | ||
609 | |||
610 | /* remove this gpadc entry from the list */ | ||
611 | list_del(&gpadc->node); | ||
612 | /* remove interrupt - completion of Sw ADC conversion */ | ||
613 | free_irq(gpadc->irq, gpadc); | ||
614 | /* disable VTVout LDO that is being used by GPADC */ | ||
615 | regulator_put(gpadc->regu); | ||
616 | kfree(gpadc); | ||
617 | gpadc = NULL; | ||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | static struct platform_driver ab8500_gpadc_driver = { | ||
622 | .probe = ab8500_gpadc_probe, | ||
623 | .remove = __devexit_p(ab8500_gpadc_remove), | ||
624 | .driver = { | ||
625 | .name = "ab8500-gpadc", | ||
626 | .owner = THIS_MODULE, | ||
627 | }, | ||
628 | }; | ||
629 | |||
630 | static int __init ab8500_gpadc_init(void) | ||
631 | { | ||
632 | return platform_driver_register(&ab8500_gpadc_driver); | ||
633 | } | ||
634 | |||
635 | static void __exit ab8500_gpadc_exit(void) | ||
636 | { | ||
637 | platform_driver_unregister(&ab8500_gpadc_driver); | ||
638 | } | ||
639 | |||
640 | subsys_initcall_sync(ab8500_gpadc_init); | ||
641 | module_exit(ab8500_gpadc_exit); | ||
642 | |||
643 | MODULE_LICENSE("GPL v2"); | ||
644 | MODULE_AUTHOR("Arun R Murthy, Daniel Willerud, Johan Palsson"); | ||
645 | MODULE_ALIAS("platform:ab8500_gpadc"); | ||
646 | MODULE_DESCRIPTION("AB8500 GPADC driver"); | ||
diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c new file mode 100644 index 000000000000..9be541c6b004 --- /dev/null +++ b/drivers/mfd/ab8500-i2c.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson. | ||
4 | * License Terms: GNU General Public License v2 | ||
5 | * This file was based on drivers/mfd/ab8500-spi.c | ||
6 | */ | ||
7 | |||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/slab.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/mfd/ab8500.h> | ||
14 | #include <linux/mfd/db8500-prcmu.h> | ||
15 | |||
16 | static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data) | ||
17 | { | ||
18 | int ret; | ||
19 | |||
20 | ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); | ||
21 | if (ret < 0) | ||
22 | dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); | ||
23 | return ret; | ||
24 | } | ||
25 | |||
26 | static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr) | ||
27 | { | ||
28 | int ret; | ||
29 | u8 data; | ||
30 | |||
31 | ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1); | ||
32 | if (ret < 0) { | ||
33 | dev_err(ab8500->dev, "prcmu i2c error %d\n", ret); | ||
34 | return ret; | ||
35 | } | ||
36 | return (int)data; | ||
37 | } | ||
38 | |||
39 | static int __devinit ab8500_i2c_probe(struct platform_device *plf) | ||
40 | { | ||
41 | struct ab8500 *ab8500; | ||
42 | struct resource *resource; | ||
43 | int ret; | ||
44 | |||
45 | ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL); | ||
46 | if (!ab8500) | ||
47 | return -ENOMEM; | ||
48 | |||
49 | ab8500->dev = &plf->dev; | ||
50 | |||
51 | resource = platform_get_resource(plf, IORESOURCE_IRQ, 0); | ||
52 | if (!resource) { | ||
53 | kfree(ab8500); | ||
54 | return -ENODEV; | ||
55 | } | ||
56 | |||
57 | ab8500->irq = resource->start; | ||
58 | |||
59 | ab8500->read = ab8500_i2c_read; | ||
60 | ab8500->write = ab8500_i2c_write; | ||
61 | |||
62 | platform_set_drvdata(plf, ab8500); | ||
63 | |||
64 | ret = ab8500_init(ab8500); | ||
65 | if (ret) | ||
66 | kfree(ab8500); | ||
67 | |||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | static int __devexit ab8500_i2c_remove(struct platform_device *plf) | ||
72 | { | ||
73 | struct ab8500 *ab8500 = platform_get_drvdata(plf); | ||
74 | |||
75 | ab8500_exit(ab8500); | ||
76 | kfree(ab8500); | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static struct platform_driver ab8500_i2c_driver = { | ||
82 | .driver = { | ||
83 | .name = "ab8500-i2c", | ||
84 | .owner = THIS_MODULE, | ||
85 | }, | ||
86 | .probe = ab8500_i2c_probe, | ||
87 | .remove = __devexit_p(ab8500_i2c_remove) | ||
88 | }; | ||
89 | |||
90 | static int __init ab8500_i2c_init(void) | ||
91 | { | ||
92 | return platform_driver_register(&ab8500_i2c_driver); | ||
93 | } | ||
94 | |||
95 | static void __exit ab8500_i2c_exit(void) | ||
96 | { | ||
97 | platform_driver_unregister(&ab8500_i2c_driver); | ||
98 | } | ||
99 | arch_initcall(ab8500_i2c_init); | ||
100 | module_exit(ab8500_i2c_exit); | ||
101 | |||
102 | MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com"); | ||
103 | MODULE_DESCRIPTION("AB8500 Core access via PRCMU I2C"); | ||
104 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/ab8500-spi.c b/drivers/mfd/ab8500-spi.c deleted file mode 100644 index e1c8b62b086d..000000000000 --- a/drivers/mfd/ab8500-spi.c +++ /dev/null | |||
@@ -1,138 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * License Terms: GNU General Public License v2 | ||
5 | * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/slab.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/spi/spi.h> | ||
14 | #include <linux/mfd/ab8500.h> | ||
15 | |||
16 | /* | ||
17 | * This funtion writes to any AB8500 registers using | ||
18 | * SPI protocol & before it writes it packs the data | ||
19 | * in the below 24 bit frame format | ||
20 | * | ||
21 | * *|------------------------------------| | ||
22 | * *| 23|22...18|17.......10|9|8|7......0| | ||
23 | * *| r/w bank adr data | | ||
24 | * * ------------------------------------ | ||
25 | * | ||
26 | * This function shouldn't be called from interrupt | ||
27 | * context | ||
28 | */ | ||
29 | static int ab8500_spi_write(struct ab8500 *ab8500, u16 addr, u8 data) | ||
30 | { | ||
31 | struct spi_device *spi = container_of(ab8500->dev, struct spi_device, | ||
32 | dev); | ||
33 | unsigned long spi_data = addr << 10 | data; | ||
34 | struct spi_transfer xfer; | ||
35 | struct spi_message msg; | ||
36 | |||
37 | ab8500->tx_buf[0] = spi_data; | ||
38 | ab8500->rx_buf[0] = 0; | ||
39 | |||
40 | xfer.tx_buf = ab8500->tx_buf; | ||
41 | xfer.rx_buf = NULL; | ||
42 | xfer.len = sizeof(unsigned long); | ||
43 | |||
44 | spi_message_init(&msg); | ||
45 | spi_message_add_tail(&xfer, &msg); | ||
46 | |||
47 | return spi_sync(spi, &msg); | ||
48 | } | ||
49 | |||
50 | static int ab8500_spi_read(struct ab8500 *ab8500, u16 addr) | ||
51 | { | ||
52 | struct spi_device *spi = container_of(ab8500->dev, struct spi_device, | ||
53 | dev); | ||
54 | unsigned long spi_data = 1 << 23 | addr << 10; | ||
55 | struct spi_transfer xfer; | ||
56 | struct spi_message msg; | ||
57 | int ret; | ||
58 | |||
59 | ab8500->tx_buf[0] = spi_data; | ||
60 | ab8500->rx_buf[0] = 0; | ||
61 | |||
62 | xfer.tx_buf = ab8500->tx_buf; | ||
63 | xfer.rx_buf = ab8500->rx_buf; | ||
64 | xfer.len = sizeof(unsigned long); | ||
65 | |||
66 | spi_message_init(&msg); | ||
67 | spi_message_add_tail(&xfer, &msg); | ||
68 | |||
69 | ret = spi_sync(spi, &msg); | ||
70 | if (!ret) | ||
71 | /* | ||
72 | * Only the 8 lowermost bytes are | ||
73 | * defined with value, the rest may | ||
74 | * vary depending on chip/board noise. | ||
75 | */ | ||
76 | ret = ab8500->rx_buf[0] & 0xFFU; | ||
77 | |||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | static int __devinit ab8500_spi_probe(struct spi_device *spi) | ||
82 | { | ||
83 | struct ab8500 *ab8500; | ||
84 | int ret; | ||
85 | |||
86 | ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL); | ||
87 | if (!ab8500) | ||
88 | return -ENOMEM; | ||
89 | |||
90 | ab8500->dev = &spi->dev; | ||
91 | ab8500->irq = spi->irq; | ||
92 | |||
93 | ab8500->read = ab8500_spi_read; | ||
94 | ab8500->write = ab8500_spi_write; | ||
95 | |||
96 | spi_set_drvdata(spi, ab8500); | ||
97 | |||
98 | ret = ab8500_init(ab8500); | ||
99 | if (ret) | ||
100 | kfree(ab8500); | ||
101 | |||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | static int __devexit ab8500_spi_remove(struct spi_device *spi) | ||
106 | { | ||
107 | struct ab8500 *ab8500 = spi_get_drvdata(spi); | ||
108 | |||
109 | ab8500_exit(ab8500); | ||
110 | kfree(ab8500); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static struct spi_driver ab8500_spi_driver = { | ||
116 | .driver = { | ||
117 | .name = "ab8500", | ||
118 | .owner = THIS_MODULE, | ||
119 | }, | ||
120 | .probe = ab8500_spi_probe, | ||
121 | .remove = __devexit_p(ab8500_spi_remove) | ||
122 | }; | ||
123 | |||
124 | static int __init ab8500_spi_init(void) | ||
125 | { | ||
126 | return spi_register_driver(&ab8500_spi_driver); | ||
127 | } | ||
128 | subsys_initcall(ab8500_spi_init); | ||
129 | |||
130 | static void __exit ab8500_spi_exit(void) | ||
131 | { | ||
132 | spi_unregister_driver(&ab8500_spi_driver); | ||
133 | } | ||
134 | module_exit(ab8500_spi_exit); | ||
135 | |||
136 | MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com"); | ||
137 | MODULE_DESCRIPTION("AB8500 SPI"); | ||
138 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c new file mode 100644 index 000000000000..392185965b39 --- /dev/null +++ b/drivers/mfd/ab8500-sysctrl.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson. | ||
4 | * License terms: GNU General Public License (GPL) version 2 | ||
5 | */ | ||
6 | |||
7 | #include <linux/err.h> | ||
8 | #include <linux/platform_device.h> | ||
9 | #include <linux/mfd/ab8500.h> | ||
10 | #include <linux/mfd/abx500.h> | ||
11 | #include <linux/mfd/ab8500/sysctrl.h> | ||
12 | |||
13 | static struct device *sysctrl_dev; | ||
14 | |||
15 | static inline bool valid_bank(u8 bank) | ||
16 | { | ||
17 | return ((bank == AB8500_SYS_CTRL1_BLOCK) || | ||
18 | (bank == AB8500_SYS_CTRL2_BLOCK)); | ||
19 | } | ||
20 | |||
21 | int ab8500_sysctrl_read(u16 reg, u8 *value) | ||
22 | { | ||
23 | u8 bank; | ||
24 | |||
25 | if (sysctrl_dev == NULL) | ||
26 | return -EAGAIN; | ||
27 | |||
28 | bank = (reg >> 8); | ||
29 | if (!valid_bank(bank)) | ||
30 | return -EINVAL; | ||
31 | |||
32 | return abx500_get_register_interruptible(sysctrl_dev, bank, | ||
33 | (u8)(reg & 0xFF), value); | ||
34 | } | ||
35 | |||
36 | int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value) | ||
37 | { | ||
38 | u8 bank; | ||
39 | |||
40 | if (sysctrl_dev == NULL) | ||
41 | return -EAGAIN; | ||
42 | |||
43 | bank = (reg >> 8); | ||
44 | if (!valid_bank(bank)) | ||
45 | return -EINVAL; | ||
46 | |||
47 | return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank, | ||
48 | (u8)(reg & 0xFF), mask, value); | ||
49 | } | ||
50 | |||
51 | static int __devinit ab8500_sysctrl_probe(struct platform_device *pdev) | ||
52 | { | ||
53 | sysctrl_dev = &pdev->dev; | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int __devexit ab8500_sysctrl_remove(struct platform_device *pdev) | ||
58 | { | ||
59 | sysctrl_dev = NULL; | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static struct platform_driver ab8500_sysctrl_driver = { | ||
64 | .driver = { | ||
65 | .name = "ab8500-sysctrl", | ||
66 | .owner = THIS_MODULE, | ||
67 | }, | ||
68 | .probe = ab8500_sysctrl_probe, | ||
69 | .remove = __devexit_p(ab8500_sysctrl_remove), | ||
70 | }; | ||
71 | |||
72 | static int __init ab8500_sysctrl_init(void) | ||
73 | { | ||
74 | return platform_driver_register(&ab8500_sysctrl_driver); | ||
75 | } | ||
76 | subsys_initcall(ab8500_sysctrl_init); | ||
77 | |||
78 | MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com"); | ||
79 | MODULE_DESCRIPTION("AB8500 system control driver"); | ||
80 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index 3122139b4300..f1d88483112c 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c | |||
@@ -321,27 +321,27 @@ static int __devexit adp5520_remove(struct i2c_client *client) | |||
321 | } | 321 | } |
322 | 322 | ||
323 | #ifdef CONFIG_PM | 323 | #ifdef CONFIG_PM |
324 | static int adp5520_suspend(struct i2c_client *client, | 324 | static int adp5520_suspend(struct device *dev) |
325 | pm_message_t state) | ||
326 | { | 325 | { |
326 | struct i2c_client *client = to_i2c_client(dev); | ||
327 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | 327 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); |
328 | 328 | ||
329 | adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | 329 | adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); |
330 | return 0; | 330 | return 0; |
331 | } | 331 | } |
332 | 332 | ||
333 | static int adp5520_resume(struct i2c_client *client) | 333 | static int adp5520_resume(struct device *dev) |
334 | { | 334 | { |
335 | struct i2c_client *client = to_i2c_client(dev); | ||
335 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | 336 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); |
336 | 337 | ||
337 | adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | 338 | adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); |
338 | return 0; | 339 | return 0; |
339 | } | 340 | } |
340 | #else | ||
341 | #define adp5520_suspend NULL | ||
342 | #define adp5520_resume NULL | ||
343 | #endif | 341 | #endif |
344 | 342 | ||
343 | static SIMPLE_DEV_PM_OPS(adp5520_pm, adp5520_suspend, adp5520_resume); | ||
344 | |||
345 | static const struct i2c_device_id adp5520_id[] = { | 345 | static const struct i2c_device_id adp5520_id[] = { |
346 | { "pmic-adp5520", ID_ADP5520 }, | 346 | { "pmic-adp5520", ID_ADP5520 }, |
347 | { "pmic-adp5501", ID_ADP5501 }, | 347 | { "pmic-adp5501", ID_ADP5501 }, |
@@ -353,11 +353,10 @@ static struct i2c_driver adp5520_driver = { | |||
353 | .driver = { | 353 | .driver = { |
354 | .name = "adp5520", | 354 | .name = "adp5520", |
355 | .owner = THIS_MODULE, | 355 | .owner = THIS_MODULE, |
356 | .pm = &adp5520_pm, | ||
356 | }, | 357 | }, |
357 | .probe = adp5520_probe, | 358 | .probe = adp5520_probe, |
358 | .remove = __devexit_p(adp5520_remove), | 359 | .remove = __devexit_p(adp5520_remove), |
359 | .suspend = adp5520_suspend, | ||
360 | .resume = adp5520_resume, | ||
361 | .id_table = adp5520_id, | 360 | .id_table = adp5520_id, |
362 | }; | 361 | }; |
363 | 362 | ||
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 7de708d15d72..c71ae09430c5 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c | |||
@@ -57,7 +57,7 @@ struct asic3_clk { | |||
57 | .rate = _rate, \ | 57 | .rate = _rate, \ |
58 | } | 58 | } |
59 | 59 | ||
60 | struct asic3_clk asic3_clk_init[] __initdata = { | 60 | static struct asic3_clk asic3_clk_init[] __initdata = { |
61 | INIT_CDEX(SPI, 0), | 61 | INIT_CDEX(SPI, 0), |
62 | INIT_CDEX(OWM, 5000000), | 62 | INIT_CDEX(OWM, 5000000), |
63 | INIT_CDEX(PWM0, 0), | 63 | INIT_CDEX(PWM0, 0), |
@@ -88,21 +88,21 @@ struct asic3 { | |||
88 | 88 | ||
89 | static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset); | 89 | static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset); |
90 | 90 | ||
91 | static inline void asic3_write_register(struct asic3 *asic, | 91 | void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 value) |
92 | unsigned int reg, u32 value) | ||
93 | { | 92 | { |
94 | iowrite16(value, asic->mapping + | 93 | iowrite16(value, asic->mapping + |
95 | (reg >> asic->bus_shift)); | 94 | (reg >> asic->bus_shift)); |
96 | } | 95 | } |
96 | EXPORT_SYMBOL_GPL(asic3_write_register); | ||
97 | 97 | ||
98 | static inline u32 asic3_read_register(struct asic3 *asic, | 98 | u32 asic3_read_register(struct asic3 *asic, unsigned int reg) |
99 | unsigned int reg) | ||
100 | { | 99 | { |
101 | return ioread16(asic->mapping + | 100 | return ioread16(asic->mapping + |
102 | (reg >> asic->bus_shift)); | 101 | (reg >> asic->bus_shift)); |
103 | } | 102 | } |
103 | EXPORT_SYMBOL_GPL(asic3_read_register); | ||
104 | 104 | ||
105 | void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set) | 105 | static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set) |
106 | { | 106 | { |
107 | unsigned long flags; | 107 | unsigned long flags; |
108 | u32 val; | 108 | u32 val; |
@@ -139,13 +139,12 @@ static void asic3_irq_flip_edge(struct asic3 *asic, | |||
139 | 139 | ||
140 | static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) | 140 | static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) |
141 | { | 141 | { |
142 | struct asic3 *asic = irq_desc_get_handler_data(desc); | ||
143 | struct irq_data *data = irq_desc_get_irq_data(desc); | ||
142 | int iter, i; | 144 | int iter, i; |
143 | unsigned long flags; | 145 | unsigned long flags; |
144 | struct asic3 *asic; | ||
145 | |||
146 | desc->chip->ack(irq); | ||
147 | 146 | ||
148 | asic = desc->handler_data; | 147 | data->chip->irq_ack(data); |
149 | 148 | ||
150 | for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) { | 149 | for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) { |
151 | u32 status; | 150 | u32 status; |
@@ -188,8 +187,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) | |||
188 | irqnr = asic->irq_base + | 187 | irqnr = asic->irq_base + |
189 | (ASIC3_GPIOS_PER_BANK * bank) | 188 | (ASIC3_GPIOS_PER_BANK * bank) |
190 | + i; | 189 | + i; |
191 | desc = irq_to_desc(irqnr); | 190 | generic_handle_irq(irqnr); |
192 | desc->handle_irq(irqnr, desc); | ||
193 | if (asic->irq_bothedge[bank] & bit) | 191 | if (asic->irq_bothedge[bank] & bit) |
194 | asic3_irq_flip_edge(asic, base, | 192 | asic3_irq_flip_edge(asic, base, |
195 | bit); | 193 | bit); |
@@ -200,11 +198,8 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) | |||
200 | /* Handle remaining IRQs in the status register */ | 198 | /* Handle remaining IRQs in the status register */ |
201 | for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) { | 199 | for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) { |
202 | /* They start at bit 4 and go up */ | 200 | /* They start at bit 4 and go up */ |
203 | if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) { | 201 | if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) |
204 | desc = irq_to_desc(asic->irq_base + i); | 202 | generic_handle_irq(asic->irq_base + i); |
205 | desc->handle_irq(asic->irq_base + i, | ||
206 | desc); | ||
207 | } | ||
208 | } | 203 | } |
209 | } | 204 | } |
210 | 205 | ||
@@ -226,14 +221,14 @@ static inline int asic3_irq_to_index(struct asic3 *asic, int irq) | |||
226 | return (irq - asic->irq_base) & 0xf; | 221 | return (irq - asic->irq_base) & 0xf; |
227 | } | 222 | } |
228 | 223 | ||
229 | static void asic3_mask_gpio_irq(unsigned int irq) | 224 | static void asic3_mask_gpio_irq(struct irq_data *data) |
230 | { | 225 | { |
231 | struct asic3 *asic = get_irq_chip_data(irq); | 226 | struct asic3 *asic = irq_data_get_irq_chip_data(data); |
232 | u32 val, bank, index; | 227 | u32 val, bank, index; |
233 | unsigned long flags; | 228 | unsigned long flags; |
234 | 229 | ||
235 | bank = asic3_irq_to_bank(asic, irq); | 230 | bank = asic3_irq_to_bank(asic, data->irq); |
236 | index = asic3_irq_to_index(asic, irq); | 231 | index = asic3_irq_to_index(asic, data->irq); |
237 | 232 | ||
238 | spin_lock_irqsave(&asic->lock, flags); | 233 | spin_lock_irqsave(&asic->lock, flags); |
239 | val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); | 234 | val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); |
@@ -242,9 +237,9 @@ static void asic3_mask_gpio_irq(unsigned int irq) | |||
242 | spin_unlock_irqrestore(&asic->lock, flags); | 237 | spin_unlock_irqrestore(&asic->lock, flags); |
243 | } | 238 | } |
244 | 239 | ||
245 | static void asic3_mask_irq(unsigned int irq) | 240 | static void asic3_mask_irq(struct irq_data *data) |
246 | { | 241 | { |
247 | struct asic3 *asic = get_irq_chip_data(irq); | 242 | struct asic3 *asic = irq_data_get_irq_chip_data(data); |
248 | int regval; | 243 | int regval; |
249 | unsigned long flags; | 244 | unsigned long flags; |
250 | 245 | ||
@@ -254,7 +249,7 @@ static void asic3_mask_irq(unsigned int irq) | |||
254 | ASIC3_INTR_INT_MASK); | 249 | ASIC3_INTR_INT_MASK); |
255 | 250 | ||
256 | regval &= ~(ASIC3_INTMASK_MASK0 << | 251 | regval &= ~(ASIC3_INTMASK_MASK0 << |
257 | (irq - (asic->irq_base + ASIC3_NUM_GPIOS))); | 252 | (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS))); |
258 | 253 | ||
259 | asic3_write_register(asic, | 254 | asic3_write_register(asic, |
260 | ASIC3_INTR_BASE + | 255 | ASIC3_INTR_BASE + |
@@ -263,14 +258,14 @@ static void asic3_mask_irq(unsigned int irq) | |||
263 | spin_unlock_irqrestore(&asic->lock, flags); | 258 | spin_unlock_irqrestore(&asic->lock, flags); |
264 | } | 259 | } |
265 | 260 | ||
266 | static void asic3_unmask_gpio_irq(unsigned int irq) | 261 | static void asic3_unmask_gpio_irq(struct irq_data *data) |
267 | { | 262 | { |
268 | struct asic3 *asic = get_irq_chip_data(irq); | 263 | struct asic3 *asic = irq_data_get_irq_chip_data(data); |
269 | u32 val, bank, index; | 264 | u32 val, bank, index; |
270 | unsigned long flags; | 265 | unsigned long flags; |
271 | 266 | ||
272 | bank = asic3_irq_to_bank(asic, irq); | 267 | bank = asic3_irq_to_bank(asic, data->irq); |
273 | index = asic3_irq_to_index(asic, irq); | 268 | index = asic3_irq_to_index(asic, data->irq); |
274 | 269 | ||
275 | spin_lock_irqsave(&asic->lock, flags); | 270 | spin_lock_irqsave(&asic->lock, flags); |
276 | val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); | 271 | val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); |
@@ -279,9 +274,9 @@ static void asic3_unmask_gpio_irq(unsigned int irq) | |||
279 | spin_unlock_irqrestore(&asic->lock, flags); | 274 | spin_unlock_irqrestore(&asic->lock, flags); |
280 | } | 275 | } |
281 | 276 | ||
282 | static void asic3_unmask_irq(unsigned int irq) | 277 | static void asic3_unmask_irq(struct irq_data *data) |
283 | { | 278 | { |
284 | struct asic3 *asic = get_irq_chip_data(irq); | 279 | struct asic3 *asic = irq_data_get_irq_chip_data(data); |
285 | int regval; | 280 | int regval; |
286 | unsigned long flags; | 281 | unsigned long flags; |
287 | 282 | ||
@@ -291,7 +286,7 @@ static void asic3_unmask_irq(unsigned int irq) | |||
291 | ASIC3_INTR_INT_MASK); | 286 | ASIC3_INTR_INT_MASK); |
292 | 287 | ||
293 | regval |= (ASIC3_INTMASK_MASK0 << | 288 | regval |= (ASIC3_INTMASK_MASK0 << |
294 | (irq - (asic->irq_base + ASIC3_NUM_GPIOS))); | 289 | (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS))); |
295 | 290 | ||
296 | asic3_write_register(asic, | 291 | asic3_write_register(asic, |
297 | ASIC3_INTR_BASE + | 292 | ASIC3_INTR_BASE + |
@@ -300,15 +295,15 @@ static void asic3_unmask_irq(unsigned int irq) | |||
300 | spin_unlock_irqrestore(&asic->lock, flags); | 295 | spin_unlock_irqrestore(&asic->lock, flags); |
301 | } | 296 | } |
302 | 297 | ||
303 | static int asic3_gpio_irq_type(unsigned int irq, unsigned int type) | 298 | static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type) |
304 | { | 299 | { |
305 | struct asic3 *asic = get_irq_chip_data(irq); | 300 | struct asic3 *asic = irq_data_get_irq_chip_data(data); |
306 | u32 bank, index; | 301 | u32 bank, index; |
307 | u16 trigger, level, edge, bit; | 302 | u16 trigger, level, edge, bit; |
308 | unsigned long flags; | 303 | unsigned long flags; |
309 | 304 | ||
310 | bank = asic3_irq_to_bank(asic, irq); | 305 | bank = asic3_irq_to_bank(asic, data->irq); |
311 | index = asic3_irq_to_index(asic, irq); | 306 | index = asic3_irq_to_index(asic, data->irq); |
312 | bit = 1<<index; | 307 | bit = 1<<index; |
313 | 308 | ||
314 | spin_lock_irqsave(&asic->lock, flags); | 309 | spin_lock_irqsave(&asic->lock, flags); |
@@ -318,7 +313,7 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type) | |||
318 | bank + ASIC3_GPIO_EDGE_TRIGGER); | 313 | bank + ASIC3_GPIO_EDGE_TRIGGER); |
319 | trigger = asic3_read_register(asic, | 314 | trigger = asic3_read_register(asic, |
320 | bank + ASIC3_GPIO_TRIGGER_TYPE); | 315 | bank + ASIC3_GPIO_TRIGGER_TYPE); |
321 | asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit; | 316 | asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] &= ~bit; |
322 | 317 | ||
323 | if (type == IRQ_TYPE_EDGE_RISING) { | 318 | if (type == IRQ_TYPE_EDGE_RISING) { |
324 | trigger |= bit; | 319 | trigger |= bit; |
@@ -328,11 +323,11 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type) | |||
328 | edge &= ~bit; | 323 | edge &= ~bit; |
329 | } else if (type == IRQ_TYPE_EDGE_BOTH) { | 324 | } else if (type == IRQ_TYPE_EDGE_BOTH) { |
330 | trigger |= bit; | 325 | trigger |= bit; |
331 | if (asic3_gpio_get(&asic->gpio, irq - asic->irq_base)) | 326 | if (asic3_gpio_get(&asic->gpio, data->irq - asic->irq_base)) |
332 | edge &= ~bit; | 327 | edge &= ~bit; |
333 | else | 328 | else |
334 | edge |= bit; | 329 | edge |= bit; |
335 | asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit; | 330 | asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] |= bit; |
336 | } else if (type == IRQ_TYPE_LEVEL_LOW) { | 331 | } else if (type == IRQ_TYPE_LEVEL_LOW) { |
337 | trigger &= ~bit; | 332 | trigger &= ~bit; |
338 | level &= ~bit; | 333 | level &= ~bit; |
@@ -359,17 +354,17 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type) | |||
359 | 354 | ||
360 | static struct irq_chip asic3_gpio_irq_chip = { | 355 | static struct irq_chip asic3_gpio_irq_chip = { |
361 | .name = "ASIC3-GPIO", | 356 | .name = "ASIC3-GPIO", |
362 | .ack = asic3_mask_gpio_irq, | 357 | .irq_ack = asic3_mask_gpio_irq, |
363 | .mask = asic3_mask_gpio_irq, | 358 | .irq_mask = asic3_mask_gpio_irq, |
364 | .unmask = asic3_unmask_gpio_irq, | 359 | .irq_unmask = asic3_unmask_gpio_irq, |
365 | .set_type = asic3_gpio_irq_type, | 360 | .irq_set_type = asic3_gpio_irq_type, |
366 | }; | 361 | }; |
367 | 362 | ||
368 | static struct irq_chip asic3_irq_chip = { | 363 | static struct irq_chip asic3_irq_chip = { |
369 | .name = "ASIC3", | 364 | .name = "ASIC3", |
370 | .ack = asic3_mask_irq, | 365 | .irq_ack = asic3_mask_irq, |
371 | .mask = asic3_mask_irq, | 366 | .irq_mask = asic3_mask_irq, |
372 | .unmask = asic3_unmask_irq, | 367 | .irq_unmask = asic3_unmask_irq, |
373 | }; | 368 | }; |
374 | 369 | ||
375 | static int __init asic3_irq_probe(struct platform_device *pdev) | 370 | static int __init asic3_irq_probe(struct platform_device *pdev) |
@@ -393,21 +388,21 @@ static int __init asic3_irq_probe(struct platform_device *pdev) | |||
393 | 388 | ||
394 | for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { | 389 | for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { |
395 | if (irq < asic->irq_base + ASIC3_NUM_GPIOS) | 390 | if (irq < asic->irq_base + ASIC3_NUM_GPIOS) |
396 | set_irq_chip(irq, &asic3_gpio_irq_chip); | 391 | irq_set_chip(irq, &asic3_gpio_irq_chip); |
397 | else | 392 | else |
398 | set_irq_chip(irq, &asic3_irq_chip); | 393 | irq_set_chip(irq, &asic3_irq_chip); |
399 | 394 | ||
400 | set_irq_chip_data(irq, asic); | 395 | irq_set_chip_data(irq, asic); |
401 | set_irq_handler(irq, handle_level_irq); | 396 | irq_set_handler(irq, handle_level_irq); |
402 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 397 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
403 | } | 398 | } |
404 | 399 | ||
405 | asic3_write_register(asic, ASIC3_OFFSET(INTR, INT_MASK), | 400 | asic3_write_register(asic, ASIC3_OFFSET(INTR, INT_MASK), |
406 | ASIC3_INTMASK_GINTMASK); | 401 | ASIC3_INTMASK_GINTMASK); |
407 | 402 | ||
408 | set_irq_chained_handler(asic->irq_nr, asic3_irq_demux); | 403 | irq_set_chained_handler(asic->irq_nr, asic3_irq_demux); |
409 | set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING); | 404 | irq_set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING); |
410 | set_irq_data(asic->irq_nr, asic); | 405 | irq_set_handler_data(asic->irq_nr, asic); |
411 | 406 | ||
412 | return 0; | 407 | return 0; |
413 | } | 408 | } |
@@ -421,11 +416,10 @@ static void asic3_irq_remove(struct platform_device *pdev) | |||
421 | 416 | ||
422 | for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { | 417 | for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { |
423 | set_irq_flags(irq, 0); | 418 | set_irq_flags(irq, 0); |
424 | set_irq_handler(irq, NULL); | 419 | irq_set_chip_and_handler(irq, NULL, NULL); |
425 | set_irq_chip(irq, NULL); | 420 | irq_set_chip_data(irq, NULL); |
426 | set_irq_chip_data(irq, NULL); | ||
427 | } | 421 | } |
428 | set_irq_chained_handler(asic->irq_nr, NULL); | 422 | irq_set_chained_handler(asic->irq_nr, NULL); |
429 | } | 423 | } |
430 | 424 | ||
431 | /* GPIOs */ | 425 | /* GPIOs */ |
@@ -625,6 +619,7 @@ static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk) | |||
625 | /* MFD cells (SPI, PWM, LED, DS1WM, MMC) */ | 619 | /* MFD cells (SPI, PWM, LED, DS1WM, MMC) */ |
626 | static struct ds1wm_driver_data ds1wm_pdata = { | 620 | static struct ds1wm_driver_data ds1wm_pdata = { |
627 | .active_high = 1, | 621 | .active_high = 1, |
622 | .reset_recover_delay = 1, | ||
628 | }; | 623 | }; |
629 | 624 | ||
630 | static struct resource ds1wm_resources[] = { | 625 | static struct resource ds1wm_resources[] = { |
@@ -635,7 +630,7 @@ static struct resource ds1wm_resources[] = { | |||
635 | }, | 630 | }, |
636 | { | 631 | { |
637 | .start = ASIC3_IRQ_OWM, | 632 | .start = ASIC3_IRQ_OWM, |
638 | .start = ASIC3_IRQ_OWM, | 633 | .end = ASIC3_IRQ_OWM, |
639 | .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, | 634 | .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, |
640 | }, | 635 | }, |
641 | }; | 636 | }; |
@@ -682,7 +677,8 @@ static struct mfd_cell asic3_cell_ds1wm = { | |||
682 | .name = "ds1wm", | 677 | .name = "ds1wm", |
683 | .enable = ds1wm_enable, | 678 | .enable = ds1wm_enable, |
684 | .disable = ds1wm_disable, | 679 | .disable = ds1wm_disable, |
685 | .driver_data = &ds1wm_pdata, | 680 | .platform_data = &ds1wm_pdata, |
681 | .pdata_size = sizeof(ds1wm_pdata), | ||
686 | .num_resources = ARRAY_SIZE(ds1wm_resources), | 682 | .num_resources = ARRAY_SIZE(ds1wm_resources), |
687 | .resources = ds1wm_resources, | 683 | .resources = ds1wm_resources, |
688 | }; | 684 | }; |
@@ -783,12 +779,61 @@ static struct mfd_cell asic3_cell_mmc = { | |||
783 | .name = "tmio-mmc", | 779 | .name = "tmio-mmc", |
784 | .enable = asic3_mmc_enable, | 780 | .enable = asic3_mmc_enable, |
785 | .disable = asic3_mmc_disable, | 781 | .disable = asic3_mmc_disable, |
786 | .driver_data = &asic3_mmc_data, | 782 | .platform_data = &asic3_mmc_data, |
783 | .pdata_size = sizeof(asic3_mmc_data), | ||
787 | .num_resources = ARRAY_SIZE(asic3_mmc_resources), | 784 | .num_resources = ARRAY_SIZE(asic3_mmc_resources), |
788 | .resources = asic3_mmc_resources, | 785 | .resources = asic3_mmc_resources, |
789 | }; | 786 | }; |
790 | 787 | ||
788 | static const int clock_ledn[ASIC3_NUM_LEDS] = { | ||
789 | [0] = ASIC3_CLOCK_LED0, | ||
790 | [1] = ASIC3_CLOCK_LED1, | ||
791 | [2] = ASIC3_CLOCK_LED2, | ||
792 | }; | ||
793 | |||
794 | static int asic3_leds_enable(struct platform_device *pdev) | ||
795 | { | ||
796 | const struct mfd_cell *cell = mfd_get_cell(pdev); | ||
797 | struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); | ||
798 | |||
799 | asic3_clk_enable(asic, &asic->clocks[clock_ledn[cell->id]]); | ||
800 | |||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | static int asic3_leds_disable(struct platform_device *pdev) | ||
805 | { | ||
806 | const struct mfd_cell *cell = mfd_get_cell(pdev); | ||
807 | struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); | ||
808 | |||
809 | asic3_clk_disable(asic, &asic->clocks[clock_ledn[cell->id]]); | ||
810 | |||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | static struct mfd_cell asic3_cell_leds[ASIC3_NUM_LEDS] = { | ||
815 | [0] = { | ||
816 | .name = "leds-asic3", | ||
817 | .id = 0, | ||
818 | .enable = asic3_leds_enable, | ||
819 | .disable = asic3_leds_disable, | ||
820 | }, | ||
821 | [1] = { | ||
822 | .name = "leds-asic3", | ||
823 | .id = 1, | ||
824 | .enable = asic3_leds_enable, | ||
825 | .disable = asic3_leds_disable, | ||
826 | }, | ||
827 | [2] = { | ||
828 | .name = "leds-asic3", | ||
829 | .id = 2, | ||
830 | .enable = asic3_leds_enable, | ||
831 | .disable = asic3_leds_disable, | ||
832 | }, | ||
833 | }; | ||
834 | |||
791 | static int __init asic3_mfd_probe(struct platform_device *pdev, | 835 | static int __init asic3_mfd_probe(struct platform_device *pdev, |
836 | struct asic3_platform_data *pdata, | ||
792 | struct resource *mem) | 837 | struct resource *mem) |
793 | { | 838 | { |
794 | struct asic3 *asic = platform_get_drvdata(pdev); | 839 | struct asic3 *asic = platform_get_drvdata(pdev); |
@@ -810,12 +855,10 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, | |||
810 | ds1wm_resources[0].start >>= asic->bus_shift; | 855 | ds1wm_resources[0].start >>= asic->bus_shift; |
811 | ds1wm_resources[0].end >>= asic->bus_shift; | 856 | ds1wm_resources[0].end >>= asic->bus_shift; |
812 | 857 | ||
813 | asic3_cell_ds1wm.platform_data = &asic3_cell_ds1wm; | ||
814 | asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm); | ||
815 | |||
816 | /* MMC */ | 858 | /* MMC */ |
817 | asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) + | 859 | asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) + |
818 | mem_sdio->start, 0x400 >> asic->bus_shift); | 860 | mem_sdio->start, |
861 | ASIC3_SD_CONFIG_SIZE >> asic->bus_shift); | ||
819 | if (!asic->tmio_cnf) { | 862 | if (!asic->tmio_cnf) { |
820 | ret = -ENOMEM; | 863 | ret = -ENOMEM; |
821 | dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n"); | 864 | dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n"); |
@@ -824,17 +867,28 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, | |||
824 | asic3_mmc_resources[0].start >>= asic->bus_shift; | 867 | asic3_mmc_resources[0].start >>= asic->bus_shift; |
825 | asic3_mmc_resources[0].end >>= asic->bus_shift; | 868 | asic3_mmc_resources[0].end >>= asic->bus_shift; |
826 | 869 | ||
827 | asic3_cell_mmc.platform_data = &asic3_cell_mmc; | ||
828 | asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc); | ||
829 | |||
830 | ret = mfd_add_devices(&pdev->dev, pdev->id, | 870 | ret = mfd_add_devices(&pdev->dev, pdev->id, |
831 | &asic3_cell_ds1wm, 1, mem, asic->irq_base); | 871 | &asic3_cell_ds1wm, 1, mem, asic->irq_base); |
832 | if (ret < 0) | 872 | if (ret < 0) |
833 | goto out; | 873 | goto out; |
834 | 874 | ||
835 | if (mem_sdio && (irq >= 0)) | 875 | if (mem_sdio && (irq >= 0)) { |
836 | ret = mfd_add_devices(&pdev->dev, pdev->id, | 876 | ret = mfd_add_devices(&pdev->dev, pdev->id, |
837 | &asic3_cell_mmc, 1, mem_sdio, irq); | 877 | &asic3_cell_mmc, 1, mem_sdio, irq); |
878 | if (ret < 0) | ||
879 | goto out; | ||
880 | } | ||
881 | |||
882 | if (pdata->leds) { | ||
883 | int i; | ||
884 | |||
885 | for (i = 0; i < ASIC3_NUM_LEDS; ++i) { | ||
886 | asic3_cell_leds[i].platform_data = &pdata->leds[i]; | ||
887 | asic3_cell_leds[i].pdata_size = sizeof(pdata->leds[i]); | ||
888 | } | ||
889 | ret = mfd_add_devices(&pdev->dev, 0, | ||
890 | asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0); | ||
891 | } | ||
838 | 892 | ||
839 | out: | 893 | out: |
840 | return ret; | 894 | return ret; |
@@ -915,7 +969,7 @@ static int __init asic3_probe(struct platform_device *pdev) | |||
915 | */ | 969 | */ |
916 | memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init)); | 970 | memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init)); |
917 | 971 | ||
918 | asic3_mfd_probe(pdev, mem); | 972 | asic3_mfd_probe(pdev, pdata, mem); |
919 | 973 | ||
920 | dev_info(asic->dev, "ASIC3 Core driver\n"); | 974 | dev_info(asic->dev, "ASIC3 Core driver\n"); |
921 | 975 | ||
diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c new file mode 100644 index 000000000000..155fa0407882 --- /dev/null +++ b/drivers/mfd/cs5535-mfd.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* | ||
2 | * cs5535-mfd.c - core MFD driver for CS5535/CS5536 southbridges | ||
3 | * | ||
4 | * The CS5535 and CS5536 has an ISA bridge on the PCI bus that is | ||
5 | * used for accessing GPIOs, MFGPTs, ACPI, etc. Each subdevice has | ||
6 | * an IO range that's specified in a single BAR. The BAR order is | ||
7 | * hardcoded in the CS553x specifications. | ||
8 | * | ||
9 | * Copyright (c) 2010 Andres Salomon <dilinger@queued.net> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | */ | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/mfd/core.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <asm/olpc.h> | ||
31 | |||
32 | #define DRV_NAME "cs5535-mfd" | ||
33 | |||
34 | enum cs5535_mfd_bars { | ||
35 | SMB_BAR = 0, | ||
36 | GPIO_BAR = 1, | ||
37 | MFGPT_BAR = 2, | ||
38 | PMS_BAR = 4, | ||
39 | ACPI_BAR = 5, | ||
40 | NR_BARS, | ||
41 | }; | ||
42 | |||
43 | static int cs5535_mfd_res_enable(struct platform_device *pdev) | ||
44 | { | ||
45 | struct resource *res; | ||
46 | |||
47 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
48 | if (!res) { | ||
49 | dev_err(&pdev->dev, "can't fetch device resource info\n"); | ||
50 | return -EIO; | ||
51 | } | ||
52 | |||
53 | if (!request_region(res->start, resource_size(res), DRV_NAME)) { | ||
54 | dev_err(&pdev->dev, "can't request region\n"); | ||
55 | return -EIO; | ||
56 | } | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int cs5535_mfd_res_disable(struct platform_device *pdev) | ||
62 | { | ||
63 | struct resource *res; | ||
64 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
65 | if (!res) { | ||
66 | dev_err(&pdev->dev, "can't fetch device resource info\n"); | ||
67 | return -EIO; | ||
68 | } | ||
69 | |||
70 | release_region(res->start, resource_size(res)); | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static __devinitdata struct resource cs5535_mfd_resources[NR_BARS]; | ||
75 | |||
76 | static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { | ||
77 | { | ||
78 | .id = SMB_BAR, | ||
79 | .name = "cs5535-smb", | ||
80 | .num_resources = 1, | ||
81 | .resources = &cs5535_mfd_resources[SMB_BAR], | ||
82 | }, | ||
83 | { | ||
84 | .id = GPIO_BAR, | ||
85 | .name = "cs5535-gpio", | ||
86 | .num_resources = 1, | ||
87 | .resources = &cs5535_mfd_resources[GPIO_BAR], | ||
88 | }, | ||
89 | { | ||
90 | .id = MFGPT_BAR, | ||
91 | .name = "cs5535-mfgpt", | ||
92 | .num_resources = 1, | ||
93 | .resources = &cs5535_mfd_resources[MFGPT_BAR], | ||
94 | }, | ||
95 | { | ||
96 | .id = PMS_BAR, | ||
97 | .name = "cs5535-pms", | ||
98 | .num_resources = 1, | ||
99 | .resources = &cs5535_mfd_resources[PMS_BAR], | ||
100 | |||
101 | .enable = cs5535_mfd_res_enable, | ||
102 | .disable = cs5535_mfd_res_disable, | ||
103 | }, | ||
104 | { | ||
105 | .id = ACPI_BAR, | ||
106 | .name = "cs5535-acpi", | ||
107 | .num_resources = 1, | ||
108 | .resources = &cs5535_mfd_resources[ACPI_BAR], | ||
109 | |||
110 | .enable = cs5535_mfd_res_enable, | ||
111 | .disable = cs5535_mfd_res_disable, | ||
112 | }, | ||
113 | }; | ||
114 | |||
115 | #ifdef CONFIG_OLPC | ||
116 | static void __devinit cs5535_clone_olpc_cells(void) | ||
117 | { | ||
118 | const char *acpi_clones[] = { "olpc-xo1-pm-acpi", "olpc-xo1-sci-acpi" }; | ||
119 | |||
120 | if (!machine_is_olpc()) | ||
121 | return; | ||
122 | |||
123 | mfd_clone_cell("cs5535-acpi", acpi_clones, ARRAY_SIZE(acpi_clones)); | ||
124 | } | ||
125 | #else | ||
126 | static void cs5535_clone_olpc_cells(void) { } | ||
127 | #endif | ||
128 | |||
129 | static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, | ||
130 | const struct pci_device_id *id) | ||
131 | { | ||
132 | int err, i; | ||
133 | |||
134 | err = pci_enable_device(pdev); | ||
135 | if (err) | ||
136 | return err; | ||
137 | |||
138 | /* fill in IO range for each cell; subdrivers handle the region */ | ||
139 | for (i = 0; i < ARRAY_SIZE(cs5535_mfd_cells); i++) { | ||
140 | int bar = cs5535_mfd_cells[i].id; | ||
141 | struct resource *r = &cs5535_mfd_resources[bar]; | ||
142 | |||
143 | r->flags = IORESOURCE_IO; | ||
144 | r->start = pci_resource_start(pdev, bar); | ||
145 | r->end = pci_resource_end(pdev, bar); | ||
146 | |||
147 | /* id is used for temporarily storing BAR; unset it now */ | ||
148 | cs5535_mfd_cells[i].id = 0; | ||
149 | } | ||
150 | |||
151 | err = mfd_add_devices(&pdev->dev, -1, cs5535_mfd_cells, | ||
152 | ARRAY_SIZE(cs5535_mfd_cells), NULL, 0); | ||
153 | if (err) { | ||
154 | dev_err(&pdev->dev, "MFD add devices failed: %d\n", err); | ||
155 | goto err_disable; | ||
156 | } | ||
157 | cs5535_clone_olpc_cells(); | ||
158 | |||
159 | dev_info(&pdev->dev, "%zu devices registered.\n", | ||
160 | ARRAY_SIZE(cs5535_mfd_cells)); | ||
161 | |||
162 | return 0; | ||
163 | |||
164 | err_disable: | ||
165 | pci_disable_device(pdev); | ||
166 | return err; | ||
167 | } | ||
168 | |||
169 | static void __devexit cs5535_mfd_remove(struct pci_dev *pdev) | ||
170 | { | ||
171 | mfd_remove_devices(&pdev->dev); | ||
172 | pci_disable_device(pdev); | ||
173 | } | ||
174 | |||
175 | static struct pci_device_id cs5535_mfd_pci_tbl[] = { | ||
176 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, | ||
177 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, | ||
178 | { 0, } | ||
179 | }; | ||
180 | MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl); | ||
181 | |||
182 | static struct pci_driver cs5535_mfd_drv = { | ||
183 | .name = DRV_NAME, | ||
184 | .id_table = cs5535_mfd_pci_tbl, | ||
185 | .probe = cs5535_mfd_probe, | ||
186 | .remove = __devexit_p(cs5535_mfd_remove), | ||
187 | }; | ||
188 | |||
189 | static int __init cs5535_mfd_init(void) | ||
190 | { | ||
191 | return pci_register_driver(&cs5535_mfd_drv); | ||
192 | } | ||
193 | |||
194 | static void __exit cs5535_mfd_exit(void) | ||
195 | { | ||
196 | pci_unregister_driver(&cs5535_mfd_drv); | ||
197 | } | ||
198 | |||
199 | module_init(cs5535_mfd_init); | ||
200 | module_exit(cs5535_mfd_exit); | ||
201 | |||
202 | MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>"); | ||
203 | MODULE_DESCRIPTION("MFD driver for CS5535/CS5536 southbridge's ISA PCI device"); | ||
204 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index c07aece900fb..2fadbaeb1cb1 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c | |||
@@ -470,13 +470,19 @@ static int __devinit da903x_add_subdevs(struct da903x_chip *chip, | |||
470 | subdev = &pdata->subdevs[i]; | 470 | subdev = &pdata->subdevs[i]; |
471 | 471 | ||
472 | pdev = platform_device_alloc(subdev->name, subdev->id); | 472 | pdev = platform_device_alloc(subdev->name, subdev->id); |
473 | if (!pdev) { | ||
474 | ret = -ENOMEM; | ||
475 | goto failed; | ||
476 | } | ||
473 | 477 | ||
474 | pdev->dev.parent = chip->dev; | 478 | pdev->dev.parent = chip->dev; |
475 | pdev->dev.platform_data = subdev->platform_data; | 479 | pdev->dev.platform_data = subdev->platform_data; |
476 | 480 | ||
477 | ret = platform_device_add(pdev); | 481 | ret = platform_device_add(pdev); |
478 | if (ret) | 482 | if (ret) { |
483 | platform_device_put(pdev); | ||
479 | goto failed; | 484 | goto failed; |
485 | } | ||
480 | } | 486 | } |
481 | return 0; | 487 | return 0; |
482 | 488 | ||
diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index 33c923d215c7..4e2af2cb2d26 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c | |||
@@ -118,13 +118,15 @@ static int __init davinci_vc_probe(struct platform_device *pdev) | |||
118 | 118 | ||
119 | /* Voice codec interface client */ | 119 | /* Voice codec interface client */ |
120 | cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL]; | 120 | cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL]; |
121 | cell->name = "davinci_vcif"; | 121 | cell->name = "davinci-vcif"; |
122 | cell->driver_data = davinci_vc; | 122 | cell->platform_data = davinci_vc; |
123 | cell->pdata_size = sizeof(*davinci_vc); | ||
123 | 124 | ||
124 | /* Voice codec CQ93VC client */ | 125 | /* Voice codec CQ93VC client */ |
125 | cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL]; | 126 | cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL]; |
126 | cell->name = "cq93vc"; | 127 | cell->name = "cq93vc-codec"; |
127 | cell->driver_data = davinci_vc; | 128 | cell->platform_data = davinci_vc; |
129 | cell->pdata_size = sizeof(*davinci_vc); | ||
128 | 130 | ||
129 | ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells, | 131 | ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells, |
130 | DAVINCI_VC_CELLS, NULL, 0); | 132 | DAVINCI_VC_CELLS, NULL, 0); |
diff --git a/drivers/mfd/db5500-prcmu-regs.h b/drivers/mfd/db5500-prcmu-regs.h new file mode 100644 index 000000000000..9a8e9e4ddd33 --- /dev/null +++ b/drivers/mfd/db5500-prcmu-regs.h | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics 2009 | ||
3 | * Copyright (C) ST-Ericsson SA 2010 | ||
4 | * | ||
5 | * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> | ||
6 | * Author: Sundar Iyer <sundar.iyer@stericsson.com> | ||
7 | * | ||
8 | * License Terms: GNU General Public License v2 | ||
9 | * | ||
10 | * PRCM Unit registers | ||
11 | */ | ||
12 | |||
13 | #ifndef __MACH_PRCMU_REGS_H | ||
14 | #define __MACH_PRCMU_REGS_H | ||
15 | |||
16 | #include <mach/hardware.h> | ||
17 | |||
18 | #define PRCM_ARM_PLLDIVPS (_PRCMU_BASE + 0x118) | ||
19 | #define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE 0x3f | ||
20 | #define PRCM_ARM_PLLDIVPS_MAX_MASK 0xf | ||
21 | |||
22 | #define PRCM_PLLARM_LOCKP (_PRCMU_BASE + 0x0a8) | ||
23 | #define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 0x2 | ||
24 | |||
25 | #define PRCM_ARM_CHGCLKREQ (_PRCMU_BASE + 0x114) | ||
26 | #define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ 0x1 | ||
27 | |||
28 | #define PRCM_PLLARM_ENABLE (_PRCMU_BASE + 0x98) | ||
29 | #define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE 0x1 | ||
30 | #define PRCM_PLLARM_ENABLE_PRCM_PLLARM_COUNTON 0x100 | ||
31 | |||
32 | #define PRCM_ARMCLKFIX_MGT (_PRCMU_BASE + 0x0) | ||
33 | #define PRCM_A9_RESETN_CLR (_PRCMU_BASE + 0x1f4) | ||
34 | #define PRCM_A9_RESETN_SET (_PRCMU_BASE + 0x1f0) | ||
35 | #define PRCM_ARM_LS_CLAMP (_PRCMU_BASE + 0x30c) | ||
36 | #define PRCM_SRAM_A9 (_PRCMU_BASE + 0x308) | ||
37 | |||
38 | /* ARM WFI Standby signal register */ | ||
39 | #define PRCM_ARM_WFI_STANDBY (_PRCMU_BASE + 0x130) | ||
40 | #define PRCM_IOCR (_PRCMU_BASE + 0x310) | ||
41 | #define PRCM_IOCR_IOFORCE 0x1 | ||
42 | |||
43 | /* CPU mailbox registers */ | ||
44 | #define PRCM_MBOX_CPU_VAL (_PRCMU_BASE + 0x0fc) | ||
45 | #define PRCM_MBOX_CPU_SET (_PRCMU_BASE + 0x100) | ||
46 | #define PRCM_MBOX_CPU_CLR (_PRCMU_BASE + 0x104) | ||
47 | |||
48 | /* Dual A9 core interrupt management unit registers */ | ||
49 | #define PRCM_A9_MASK_REQ (_PRCMU_BASE + 0x328) | ||
50 | #define PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ 0x1 | ||
51 | |||
52 | #define PRCM_A9_MASK_ACK (_PRCMU_BASE + 0x32c) | ||
53 | #define PRCM_ARMITMSK31TO0 (_PRCMU_BASE + 0x11c) | ||
54 | #define PRCM_ARMITMSK63TO32 (_PRCMU_BASE + 0x120) | ||
55 | #define PRCM_ARMITMSK95TO64 (_PRCMU_BASE + 0x124) | ||
56 | #define PRCM_ARMITMSK127TO96 (_PRCMU_BASE + 0x128) | ||
57 | #define PRCM_POWER_STATE_VAL (_PRCMU_BASE + 0x25C) | ||
58 | #define PRCM_ARMITVAL31TO0 (_PRCMU_BASE + 0x260) | ||
59 | #define PRCM_ARMITVAL63TO32 (_PRCMU_BASE + 0x264) | ||
60 | #define PRCM_ARMITVAL95TO64 (_PRCMU_BASE + 0x268) | ||
61 | #define PRCM_ARMITVAL127TO96 (_PRCMU_BASE + 0x26C) | ||
62 | |||
63 | #define PRCM_HOSTACCESS_REQ (_PRCMU_BASE + 0x334) | ||
64 | #define ARM_WAKEUP_MODEM 0x1 | ||
65 | |||
66 | #define PRCM_ARM_IT1_CLEAR (_PRCMU_BASE + 0x48C) | ||
67 | #define PRCM_ARM_IT1_VAL (_PRCMU_BASE + 0x494) | ||
68 | #define PRCM_HOLD_EVT (_PRCMU_BASE + 0x174) | ||
69 | |||
70 | #define PRCM_ITSTATUS0 (_PRCMU_BASE + 0x148) | ||
71 | #define PRCM_ITSTATUS1 (_PRCMU_BASE + 0x150) | ||
72 | #define PRCM_ITSTATUS2 (_PRCMU_BASE + 0x158) | ||
73 | #define PRCM_ITSTATUS3 (_PRCMU_BASE + 0x160) | ||
74 | #define PRCM_ITSTATUS4 (_PRCMU_BASE + 0x168) | ||
75 | #define PRCM_ITSTATUS5 (_PRCMU_BASE + 0x484) | ||
76 | #define PRCM_ITCLEAR5 (_PRCMU_BASE + 0x488) | ||
77 | #define PRCM_ARMIT_MASKXP70_IT (_PRCMU_BASE + 0x1018) | ||
78 | |||
79 | /* System reset register */ | ||
80 | #define PRCM_APE_SOFTRST (_PRCMU_BASE + 0x228) | ||
81 | |||
82 | /* Level shifter and clamp control registers */ | ||
83 | #define PRCM_MMIP_LS_CLAMP_SET (_PRCMU_BASE + 0x420) | ||
84 | #define PRCM_MMIP_LS_CLAMP_CLR (_PRCMU_BASE + 0x424) | ||
85 | |||
86 | /* PRCMU clock/PLL/reset registers */ | ||
87 | #define PRCM_PLLDSI_FREQ (_PRCMU_BASE + 0x500) | ||
88 | #define PRCM_PLLDSI_ENABLE (_PRCMU_BASE + 0x504) | ||
89 | #define PRCM_PLLDSI_LOCKP (_PRCMU_BASE + 0x508) | ||
90 | #define PRCM_LCDCLK_MGT (_PRCMU_BASE + 0x044) | ||
91 | #define PRCM_MCDECLK_MGT (_PRCMU_BASE + 0x064) | ||
92 | #define PRCM_HDMICLK_MGT (_PRCMU_BASE + 0x058) | ||
93 | #define PRCM_TVCLK_MGT (_PRCMU_BASE + 0x07c) | ||
94 | #define PRCM_DSI_PLLOUT_SEL (_PRCMU_BASE + 0x530) | ||
95 | #define PRCM_DSITVCLK_DIV (_PRCMU_BASE + 0x52C) | ||
96 | #define PRCM_PLLDSI_LOCKP (_PRCMU_BASE + 0x508) | ||
97 | #define PRCM_APE_RESETN_SET (_PRCMU_BASE + 0x1E4) | ||
98 | #define PRCM_APE_RESETN_CLR (_PRCMU_BASE + 0x1E8) | ||
99 | #define PRCM_CLKOCR (_PRCMU_BASE + 0x1CC) | ||
100 | |||
101 | /* ePOD and memory power signal control registers */ | ||
102 | #define PRCM_EPOD_C_SET (_PRCMU_BASE + 0x410) | ||
103 | #define PRCM_SRAM_LS_SLEEP (_PRCMU_BASE + 0x304) | ||
104 | |||
105 | /* Debug power control unit registers */ | ||
106 | #define PRCM_POWER_STATE_SET (_PRCMU_BASE + 0x254) | ||
107 | |||
108 | /* Miscellaneous unit registers */ | ||
109 | #define PRCM_DSI_SW_RESET (_PRCMU_BASE + 0x324) | ||
110 | #define PRCM_GPIOCR (_PRCMU_BASE + 0x138) | ||
111 | #define PRCM_GPIOCR_DBG_STM_MOD_CMD1 0x800 | ||
112 | #define PRCM_GPIOCR_DBG_UARTMOD_CMD0 0x1 | ||
113 | |||
114 | |||
115 | #endif /* __MACH_PRCMU__REGS_H */ | ||
diff --git a/drivers/mfd/db5500-prcmu.c b/drivers/mfd/db5500-prcmu.c new file mode 100644 index 000000000000..9dbb3cab4a6f --- /dev/null +++ b/drivers/mfd/db5500-prcmu.c | |||
@@ -0,0 +1,448 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * License Terms: GNU General Public License v2 | ||
5 | * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> | ||
6 | * | ||
7 | * U5500 PRCM Unit interface driver | ||
8 | */ | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/err.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/mutex.h> | ||
18 | #include <linux/completion.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/jiffies.h> | ||
21 | #include <linux/bitops.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/mfd/db5500-prcmu.h> | ||
24 | #include <mach/hardware.h> | ||
25 | #include <mach/irqs.h> | ||
26 | #include <mach/db5500-regs.h> | ||
27 | #include "db5500-prcmu-regs.h" | ||
28 | |||
29 | #define _PRCM_MB_HEADER (tcdm_base + 0xFE8) | ||
30 | #define PRCM_REQ_MB0_HEADER (_PRCM_MB_HEADER + 0x0) | ||
31 | #define PRCM_REQ_MB1_HEADER (_PRCM_MB_HEADER + 0x1) | ||
32 | #define PRCM_REQ_MB2_HEADER (_PRCM_MB_HEADER + 0x2) | ||
33 | #define PRCM_REQ_MB3_HEADER (_PRCM_MB_HEADER + 0x3) | ||
34 | #define PRCM_REQ_MB4_HEADER (_PRCM_MB_HEADER + 0x4) | ||
35 | #define PRCM_REQ_MB5_HEADER (_PRCM_MB_HEADER + 0x5) | ||
36 | #define PRCM_REQ_MB6_HEADER (_PRCM_MB_HEADER + 0x6) | ||
37 | #define PRCM_REQ_MB7_HEADER (_PRCM_MB_HEADER + 0x7) | ||
38 | #define PRCM_ACK_MB0_HEADER (_PRCM_MB_HEADER + 0x8) | ||
39 | #define PRCM_ACK_MB1_HEADER (_PRCM_MB_HEADER + 0x9) | ||
40 | #define PRCM_ACK_MB2_HEADER (_PRCM_MB_HEADER + 0xa) | ||
41 | #define PRCM_ACK_MB3_HEADER (_PRCM_MB_HEADER + 0xb) | ||
42 | #define PRCM_ACK_MB4_HEADER (_PRCM_MB_HEADER + 0xc) | ||
43 | #define PRCM_ACK_MB5_HEADER (_PRCM_MB_HEADER + 0xd) | ||
44 | #define PRCM_ACK_MB6_HEADER (_PRCM_MB_HEADER + 0xe) | ||
45 | #define PRCM_ACK_MB7_HEADER (_PRCM_MB_HEADER + 0xf) | ||
46 | |||
47 | /* Req Mailboxes */ | ||
48 | #define PRCM_REQ_MB0 (tcdm_base + 0xFD8) | ||
49 | #define PRCM_REQ_MB1 (tcdm_base + 0xFCC) | ||
50 | #define PRCM_REQ_MB2 (tcdm_base + 0xFC4) | ||
51 | #define PRCM_REQ_MB3 (tcdm_base + 0xFC0) | ||
52 | #define PRCM_REQ_MB4 (tcdm_base + 0xF98) | ||
53 | #define PRCM_REQ_MB5 (tcdm_base + 0xF90) | ||
54 | #define PRCM_REQ_MB6 (tcdm_base + 0xF8C) | ||
55 | #define PRCM_REQ_MB7 (tcdm_base + 0xF84) | ||
56 | |||
57 | /* Ack Mailboxes */ | ||
58 | #define PRCM_ACK_MB0 (tcdm_base + 0xF38) | ||
59 | #define PRCM_ACK_MB1 (tcdm_base + 0xF30) | ||
60 | #define PRCM_ACK_MB2 (tcdm_base + 0xF24) | ||
61 | #define PRCM_ACK_MB3 (tcdm_base + 0xF20) | ||
62 | #define PRCM_ACK_MB4 (tcdm_base + 0xF1C) | ||
63 | #define PRCM_ACK_MB5 (tcdm_base + 0xF14) | ||
64 | #define PRCM_ACK_MB6 (tcdm_base + 0xF0C) | ||
65 | #define PRCM_ACK_MB7 (tcdm_base + 0xF08) | ||
66 | |||
67 | enum mb_return_code { | ||
68 | RC_SUCCESS, | ||
69 | RC_FAIL, | ||
70 | }; | ||
71 | |||
72 | /* Mailbox 0 headers. */ | ||
73 | enum mb0_header { | ||
74 | /* request */ | ||
75 | RMB0H_PWR_STATE_TRANS = 1, | ||
76 | RMB0H_WAKE_UP_CFG, | ||
77 | RMB0H_RD_WAKE_UP_ACK, | ||
78 | /* acknowledge */ | ||
79 | AMB0H_WAKE_UP = 1, | ||
80 | }; | ||
81 | |||
82 | /* Mailbox 5 headers. */ | ||
83 | enum mb5_header { | ||
84 | MB5H_I2C_WRITE = 1, | ||
85 | MB5H_I2C_READ, | ||
86 | }; | ||
87 | |||
88 | /* Request mailbox 5 fields. */ | ||
89 | #define PRCM_REQ_MB5_I2C_SLAVE (PRCM_REQ_MB5 + 0) | ||
90 | #define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 1) | ||
91 | #define PRCM_REQ_MB5_I2C_SIZE (PRCM_REQ_MB5 + 2) | ||
92 | #define PRCM_REQ_MB5_I2C_DATA (PRCM_REQ_MB5 + 4) | ||
93 | |||
94 | /* Acknowledge mailbox 5 fields. */ | ||
95 | #define PRCM_ACK_MB5_RETURN_CODE (PRCM_ACK_MB5 + 0) | ||
96 | #define PRCM_ACK_MB5_I2C_DATA (PRCM_ACK_MB5 + 4) | ||
97 | |||
98 | #define NUM_MB 8 | ||
99 | #define MBOX_BIT BIT | ||
100 | #define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1) | ||
101 | |||
102 | /* | ||
103 | * Used by MCDE to setup all necessary PRCMU registers | ||
104 | */ | ||
105 | #define PRCMU_RESET_DSIPLL 0x00004000 | ||
106 | #define PRCMU_UNCLAMP_DSIPLL 0x00400800 | ||
107 | |||
108 | /* HDMI CLK MGT PLLSW=001 (PLLSOC0), PLLDIV=0x8, = 50 Mhz*/ | ||
109 | #define PRCMU_DSI_CLOCK_SETTING 0x00000128 | ||
110 | /* TVCLK_MGT PLLSW=001 (PLLSOC0) PLLDIV=0x13, = 19.05 MHZ */ | ||
111 | #define PRCMU_DSI_LP_CLOCK_SETTING 0x00000135 | ||
112 | #define PRCMU_PLLDSI_FREQ_SETTING 0x0004013C | ||
113 | #define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000002 | ||
114 | #define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x03000101 | ||
115 | #define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00000101 | ||
116 | |||
117 | #define PRCMU_ENABLE_PLLDSI 0x00000001 | ||
118 | #define PRCMU_DISABLE_PLLDSI 0x00000000 | ||
119 | |||
120 | #define PRCMU_DSI_RESET_SW 0x00000003 | ||
121 | |||
122 | #define PRCMU_PLLDSI_LOCKP_LOCKED 0x3 | ||
123 | |||
124 | /* | ||
125 | * mb0_transfer - state needed for mailbox 0 communication. | ||
126 | * @lock: The transaction lock. | ||
127 | */ | ||
128 | static struct { | ||
129 | spinlock_t lock; | ||
130 | } mb0_transfer; | ||
131 | |||
132 | /* | ||
133 | * mb5_transfer - state needed for mailbox 5 communication. | ||
134 | * @lock: The transaction lock. | ||
135 | * @work: The transaction completion structure. | ||
136 | * @ack: Reply ("acknowledge") data. | ||
137 | */ | ||
138 | static struct { | ||
139 | struct mutex lock; | ||
140 | struct completion work; | ||
141 | struct { | ||
142 | u8 header; | ||
143 | u8 status; | ||
144 | u8 value[4]; | ||
145 | } ack; | ||
146 | } mb5_transfer; | ||
147 | |||
148 | /* PRCMU TCDM base IO address. */ | ||
149 | static __iomem void *tcdm_base; | ||
150 | |||
151 | /** | ||
152 | * db5500_prcmu_abb_read() - Read register value(s) from the ABB. | ||
153 | * @slave: The I2C slave address. | ||
154 | * @reg: The (start) register address. | ||
155 | * @value: The read out value(s). | ||
156 | * @size: The number of registers to read. | ||
157 | * | ||
158 | * Reads register value(s) from the ABB. | ||
159 | * @size has to be <= 4. | ||
160 | */ | ||
161 | int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size) | ||
162 | { | ||
163 | int r; | ||
164 | |||
165 | if ((size < 1) || (4 < size)) | ||
166 | return -EINVAL; | ||
167 | |||
168 | mutex_lock(&mb5_transfer.lock); | ||
169 | |||
170 | while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5)) | ||
171 | cpu_relax(); | ||
172 | writeb(slave, PRCM_REQ_MB5_I2C_SLAVE); | ||
173 | writeb(reg, PRCM_REQ_MB5_I2C_REG); | ||
174 | writeb(size, PRCM_REQ_MB5_I2C_SIZE); | ||
175 | writeb(MB5H_I2C_READ, PRCM_REQ_MB5_HEADER); | ||
176 | |||
177 | writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET); | ||
178 | wait_for_completion(&mb5_transfer.work); | ||
179 | |||
180 | r = 0; | ||
181 | if ((mb5_transfer.ack.header == MB5H_I2C_READ) && | ||
182 | (mb5_transfer.ack.status == RC_SUCCESS)) | ||
183 | memcpy(value, mb5_transfer.ack.value, (size_t)size); | ||
184 | else | ||
185 | r = -EIO; | ||
186 | |||
187 | mutex_unlock(&mb5_transfer.lock); | ||
188 | |||
189 | return r; | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * db5500_prcmu_abb_write() - Write register value(s) to the ABB. | ||
194 | * @slave: The I2C slave address. | ||
195 | * @reg: The (start) register address. | ||
196 | * @value: The value(s) to write. | ||
197 | * @size: The number of registers to write. | ||
198 | * | ||
199 | * Writes register value(s) to the ABB. | ||
200 | * @size has to be <= 4. | ||
201 | */ | ||
202 | int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size) | ||
203 | { | ||
204 | int r; | ||
205 | |||
206 | if ((size < 1) || (4 < size)) | ||
207 | return -EINVAL; | ||
208 | |||
209 | mutex_lock(&mb5_transfer.lock); | ||
210 | |||
211 | while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5)) | ||
212 | cpu_relax(); | ||
213 | writeb(slave, PRCM_REQ_MB5_I2C_SLAVE); | ||
214 | writeb(reg, PRCM_REQ_MB5_I2C_REG); | ||
215 | writeb(size, PRCM_REQ_MB5_I2C_SIZE); | ||
216 | memcpy_toio(PRCM_REQ_MB5_I2C_DATA, value, size); | ||
217 | writeb(MB5H_I2C_WRITE, PRCM_REQ_MB5_HEADER); | ||
218 | |||
219 | writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET); | ||
220 | wait_for_completion(&mb5_transfer.work); | ||
221 | |||
222 | if ((mb5_transfer.ack.header == MB5H_I2C_WRITE) && | ||
223 | (mb5_transfer.ack.status == RC_SUCCESS)) | ||
224 | r = 0; | ||
225 | else | ||
226 | r = -EIO; | ||
227 | |||
228 | mutex_unlock(&mb5_transfer.lock); | ||
229 | |||
230 | return r; | ||
231 | } | ||
232 | |||
233 | int db5500_prcmu_enable_dsipll(void) | ||
234 | { | ||
235 | int i; | ||
236 | |||
237 | /* Enable DSIPLL_RESETN resets */ | ||
238 | writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR); | ||
239 | /* Unclamp DSIPLL in/out */ | ||
240 | writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR); | ||
241 | /* Set DSI PLL FREQ */ | ||
242 | writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ); | ||
243 | writel(PRCMU_DSI_PLLOUT_SEL_SETTING, | ||
244 | PRCM_DSI_PLLOUT_SEL); | ||
245 | /* Enable Escape clocks */ | ||
246 | writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV); | ||
247 | |||
248 | /* Start DSI PLL */ | ||
249 | writel(PRCMU_ENABLE_PLLDSI, PRCM_PLLDSI_ENABLE); | ||
250 | /* Reset DSI PLL */ | ||
251 | writel(PRCMU_DSI_RESET_SW, PRCM_DSI_SW_RESET); | ||
252 | for (i = 0; i < 10; i++) { | ||
253 | if ((readl(PRCM_PLLDSI_LOCKP) & | ||
254 | PRCMU_PLLDSI_LOCKP_LOCKED) == PRCMU_PLLDSI_LOCKP_LOCKED) | ||
255 | break; | ||
256 | udelay(100); | ||
257 | } | ||
258 | /* Release DSIPLL_RESETN */ | ||
259 | writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_SET); | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | int db5500_prcmu_disable_dsipll(void) | ||
264 | { | ||
265 | /* Disable dsi pll */ | ||
266 | writel(PRCMU_DISABLE_PLLDSI, PRCM_PLLDSI_ENABLE); | ||
267 | /* Disable escapeclock */ | ||
268 | writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV); | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | int db5500_prcmu_set_display_clocks(void) | ||
273 | { | ||
274 | /* HDMI and TVCLK Should be handled somewhere else */ | ||
275 | /* PLLDIV=8, PLLSW=2, CLKEN=1 */ | ||
276 | writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT); | ||
277 | /* PLLDIV=14, PLLSW=2, CLKEN=1 */ | ||
278 | writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT); | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static void ack_dbb_wakeup(void) | ||
283 | { | ||
284 | unsigned long flags; | ||
285 | |||
286 | spin_lock_irqsave(&mb0_transfer.lock, flags); | ||
287 | |||
288 | while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) | ||
289 | cpu_relax(); | ||
290 | |||
291 | writeb(RMB0H_RD_WAKE_UP_ACK, PRCM_REQ_MB0_HEADER); | ||
292 | writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET); | ||
293 | |||
294 | spin_unlock_irqrestore(&mb0_transfer.lock, flags); | ||
295 | } | ||
296 | |||
297 | static inline void print_unknown_header_warning(u8 n, u8 header) | ||
298 | { | ||
299 | pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n", | ||
300 | header, n); | ||
301 | } | ||
302 | |||
303 | static bool read_mailbox_0(void) | ||
304 | { | ||
305 | bool r; | ||
306 | u8 header; | ||
307 | |||
308 | header = readb(PRCM_ACK_MB0_HEADER); | ||
309 | switch (header) { | ||
310 | case AMB0H_WAKE_UP: | ||
311 | r = true; | ||
312 | break; | ||
313 | default: | ||
314 | print_unknown_header_warning(0, header); | ||
315 | r = false; | ||
316 | break; | ||
317 | } | ||
318 | writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR); | ||
319 | return r; | ||
320 | } | ||
321 | |||
322 | static bool read_mailbox_1(void) | ||
323 | { | ||
324 | writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR); | ||
325 | return false; | ||
326 | } | ||
327 | |||
328 | static bool read_mailbox_2(void) | ||
329 | { | ||
330 | writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR); | ||
331 | return false; | ||
332 | } | ||
333 | |||
334 | static bool read_mailbox_3(void) | ||
335 | { | ||
336 | writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR); | ||
337 | return false; | ||
338 | } | ||
339 | |||
340 | static bool read_mailbox_4(void) | ||
341 | { | ||
342 | writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR); | ||
343 | return false; | ||
344 | } | ||
345 | |||
346 | static bool read_mailbox_5(void) | ||
347 | { | ||
348 | u8 header; | ||
349 | |||
350 | header = readb(PRCM_ACK_MB5_HEADER); | ||
351 | switch (header) { | ||
352 | case MB5H_I2C_READ: | ||
353 | memcpy_fromio(mb5_transfer.ack.value, PRCM_ACK_MB5_I2C_DATA, 4); | ||
354 | case MB5H_I2C_WRITE: | ||
355 | mb5_transfer.ack.header = header; | ||
356 | mb5_transfer.ack.status = readb(PRCM_ACK_MB5_RETURN_CODE); | ||
357 | complete(&mb5_transfer.work); | ||
358 | break; | ||
359 | default: | ||
360 | print_unknown_header_warning(5, header); | ||
361 | break; | ||
362 | } | ||
363 | writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR); | ||
364 | return false; | ||
365 | } | ||
366 | |||
367 | static bool read_mailbox_6(void) | ||
368 | { | ||
369 | writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR); | ||
370 | return false; | ||
371 | } | ||
372 | |||
373 | static bool read_mailbox_7(void) | ||
374 | { | ||
375 | writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR); | ||
376 | return false; | ||
377 | } | ||
378 | |||
379 | static bool (* const read_mailbox[NUM_MB])(void) = { | ||
380 | read_mailbox_0, | ||
381 | read_mailbox_1, | ||
382 | read_mailbox_2, | ||
383 | read_mailbox_3, | ||
384 | read_mailbox_4, | ||
385 | read_mailbox_5, | ||
386 | read_mailbox_6, | ||
387 | read_mailbox_7 | ||
388 | }; | ||
389 | |||
390 | static irqreturn_t prcmu_irq_handler(int irq, void *data) | ||
391 | { | ||
392 | u32 bits; | ||
393 | u8 n; | ||
394 | irqreturn_t r; | ||
395 | |||
396 | bits = (readl(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS); | ||
397 | if (unlikely(!bits)) | ||
398 | return IRQ_NONE; | ||
399 | |||
400 | r = IRQ_HANDLED; | ||
401 | for (n = 0; bits; n++) { | ||
402 | if (bits & MBOX_BIT(n)) { | ||
403 | bits -= MBOX_BIT(n); | ||
404 | if (read_mailbox[n]()) | ||
405 | r = IRQ_WAKE_THREAD; | ||
406 | } | ||
407 | } | ||
408 | return r; | ||
409 | } | ||
410 | |||
411 | static irqreturn_t prcmu_irq_thread_fn(int irq, void *data) | ||
412 | { | ||
413 | ack_dbb_wakeup(); | ||
414 | return IRQ_HANDLED; | ||
415 | } | ||
416 | |||
417 | void __init db5500_prcmu_early_init(void) | ||
418 | { | ||
419 | tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE); | ||
420 | spin_lock_init(&mb0_transfer.lock); | ||
421 | mutex_init(&mb5_transfer.lock); | ||
422 | init_completion(&mb5_transfer.work); | ||
423 | } | ||
424 | |||
425 | /** | ||
426 | * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic | ||
427 | * | ||
428 | */ | ||
429 | int __init db5500_prcmu_init(void) | ||
430 | { | ||
431 | int r = 0; | ||
432 | |||
433 | if (ux500_is_svp() || !cpu_is_u5500()) | ||
434 | return -ENODEV; | ||
435 | |||
436 | /* Clean up the mailbox interrupts after pre-kernel code. */ | ||
437 | writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLEAR); | ||
438 | |||
439 | r = request_threaded_irq(IRQ_DB5500_PRCMU1, prcmu_irq_handler, | ||
440 | prcmu_irq_thread_fn, 0, "prcmu", NULL); | ||
441 | if (r < 0) { | ||
442 | pr_err("prcmu: Failed to allocate IRQ_DB5500_PRCMU1.\n"); | ||
443 | return -EBUSY; | ||
444 | } | ||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | arch_initcall(db5500_prcmu_init); | ||
diff --git a/drivers/mfd/db8500-prcmu-regs.h b/drivers/mfd/db8500-prcmu-regs.h new file mode 100644 index 000000000000..3bbf04d58043 --- /dev/null +++ b/drivers/mfd/db8500-prcmu-regs.h | |||
@@ -0,0 +1,166 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics 2009 | ||
3 | * Copyright (C) ST-Ericsson SA 2010 | ||
4 | * | ||
5 | * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> | ||
6 | * Author: Sundar Iyer <sundar.iyer@stericsson.com> | ||
7 | * | ||
8 | * License Terms: GNU General Public License v2 | ||
9 | * | ||
10 | * PRCM Unit registers | ||
11 | */ | ||
12 | #ifndef __DB8500_PRCMU_REGS_H | ||
13 | #define __DB8500_PRCMU_REGS_H | ||
14 | |||
15 | #include <linux/bitops.h> | ||
16 | #include <mach/hardware.h> | ||
17 | |||
18 | #define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end)) | ||
19 | |||
20 | #define PRCM_ARM_PLLDIVPS 0x118 | ||
21 | #define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE BITS(0, 5) | ||
22 | #define PRCM_ARM_PLLDIVPS_MAX_MASK 0xF | ||
23 | |||
24 | #define PRCM_PLLARM_LOCKP 0x0A8 | ||
25 | #define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 BIT(1) | ||
26 | |||
27 | #define PRCM_ARM_CHGCLKREQ 0x114 | ||
28 | #define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ BIT(0) | ||
29 | |||
30 | #define PRCM_PLLARM_ENABLE 0x98 | ||
31 | #define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE BIT(0) | ||
32 | #define PRCM_PLLARM_ENABLE_PRCM_PLLARM_COUNTON BIT(8) | ||
33 | |||
34 | #define PRCM_ARMCLKFIX_MGT 0x0 | ||
35 | #define PRCM_A9_RESETN_CLR 0x1f4 | ||
36 | #define PRCM_A9_RESETN_SET 0x1f0 | ||
37 | #define PRCM_ARM_LS_CLAMP 0x30C | ||
38 | #define PRCM_SRAM_A9 0x308 | ||
39 | |||
40 | /* ARM WFI Standby signal register */ | ||
41 | #define PRCM_ARM_WFI_STANDBY 0x130 | ||
42 | #define PRCM_IOCR 0x310 | ||
43 | #define PRCM_IOCR_IOFORCE BIT(0) | ||
44 | |||
45 | /* CPU mailbox registers */ | ||
46 | #define PRCM_MBOX_CPU_VAL 0x0FC | ||
47 | #define PRCM_MBOX_CPU_SET 0x100 | ||
48 | |||
49 | /* Dual A9 core interrupt management unit registers */ | ||
50 | #define PRCM_A9_MASK_REQ 0x328 | ||
51 | #define PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ BIT(0) | ||
52 | |||
53 | #define PRCM_A9_MASK_ACK 0x32C | ||
54 | #define PRCM_ARMITMSK31TO0 0x11C | ||
55 | #define PRCM_ARMITMSK63TO32 0x120 | ||
56 | #define PRCM_ARMITMSK95TO64 0x124 | ||
57 | #define PRCM_ARMITMSK127TO96 0x128 | ||
58 | #define PRCM_POWER_STATE_VAL 0x25C | ||
59 | #define PRCM_ARMITVAL31TO0 0x260 | ||
60 | #define PRCM_ARMITVAL63TO32 0x264 | ||
61 | #define PRCM_ARMITVAL95TO64 0x268 | ||
62 | #define PRCM_ARMITVAL127TO96 0x26C | ||
63 | |||
64 | #define PRCM_HOSTACCESS_REQ 0x334 | ||
65 | #define PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ BIT(0) | ||
66 | |||
67 | #define PRCM_ARM_IT1_CLR 0x48C | ||
68 | #define PRCM_ARM_IT1_VAL 0x494 | ||
69 | |||
70 | #define PRCM_ITSTATUS0 0x148 | ||
71 | #define PRCM_ITSTATUS1 0x150 | ||
72 | #define PRCM_ITSTATUS2 0x158 | ||
73 | #define PRCM_ITSTATUS3 0x160 | ||
74 | #define PRCM_ITSTATUS4 0x168 | ||
75 | #define PRCM_ITSTATUS5 0x484 | ||
76 | #define PRCM_ITCLEAR5 0x488 | ||
77 | #define PRCM_ARMIT_MASKXP70_IT 0x1018 | ||
78 | |||
79 | /* System reset register */ | ||
80 | #define PRCM_APE_SOFTRST 0x228 | ||
81 | |||
82 | /* Level shifter and clamp control registers */ | ||
83 | #define PRCM_MMIP_LS_CLAMP_SET 0x420 | ||
84 | #define PRCM_MMIP_LS_CLAMP_CLR 0x424 | ||
85 | |||
86 | /* PRCMU HW semaphore */ | ||
87 | #define PRCM_SEM 0x400 | ||
88 | #define PRCM_SEM_PRCM_SEM BIT(0) | ||
89 | |||
90 | /* PRCMU clock/PLL/reset registers */ | ||
91 | #define PRCM_PLLDSI_FREQ 0x500 | ||
92 | #define PRCM_PLLDSI_ENABLE 0x504 | ||
93 | #define PRCM_PLLDSI_LOCKP 0x508 | ||
94 | #define PRCM_DSI_PLLOUT_SEL 0x530 | ||
95 | #define PRCM_DSITVCLK_DIV 0x52C | ||
96 | #define PRCM_APE_RESETN_SET 0x1E4 | ||
97 | #define PRCM_APE_RESETN_CLR 0x1E8 | ||
98 | |||
99 | #define PRCM_TCR 0x1C8 | ||
100 | #define PRCM_TCR_TENSEL_MASK BITS(0, 7) | ||
101 | #define PRCM_TCR_STOP_TIMERS BIT(16) | ||
102 | #define PRCM_TCR_DOZE_MODE BIT(17) | ||
103 | |||
104 | #define PRCM_CLKOCR 0x1CC | ||
105 | #define PRCM_CLKOCR_CLKODIV0_SHIFT 0 | ||
106 | #define PRCM_CLKOCR_CLKODIV0_MASK BITS(0, 5) | ||
107 | #define PRCM_CLKOCR_CLKOSEL0_SHIFT 6 | ||
108 | #define PRCM_CLKOCR_CLKOSEL0_MASK BITS(6, 8) | ||
109 | #define PRCM_CLKOCR_CLKODIV1_SHIFT 16 | ||
110 | #define PRCM_CLKOCR_CLKODIV1_MASK BITS(16, 21) | ||
111 | #define PRCM_CLKOCR_CLKOSEL1_SHIFT 22 | ||
112 | #define PRCM_CLKOCR_CLKOSEL1_MASK BITS(22, 24) | ||
113 | #define PRCM_CLKOCR_CLK1TYPE BIT(28) | ||
114 | |||
115 | #define PRCM_SGACLK_MGT 0x014 | ||
116 | #define PRCM_UARTCLK_MGT 0x018 | ||
117 | #define PRCM_MSP02CLK_MGT 0x01C | ||
118 | #define PRCM_MSP1CLK_MGT 0x288 | ||
119 | #define PRCM_I2CCLK_MGT 0x020 | ||
120 | #define PRCM_SDMMCCLK_MGT 0x024 | ||
121 | #define PRCM_SLIMCLK_MGT 0x028 | ||
122 | #define PRCM_PER1CLK_MGT 0x02C | ||
123 | #define PRCM_PER2CLK_MGT 0x030 | ||
124 | #define PRCM_PER3CLK_MGT 0x034 | ||
125 | #define PRCM_PER5CLK_MGT 0x038 | ||
126 | #define PRCM_PER6CLK_MGT 0x03C | ||
127 | #define PRCM_PER7CLK_MGT 0x040 | ||
128 | #define PRCM_LCDCLK_MGT 0x044 | ||
129 | #define PRCM_BMLCLK_MGT 0x04C | ||
130 | #define PRCM_HSITXCLK_MGT 0x050 | ||
131 | #define PRCM_HSIRXCLK_MGT 0x054 | ||
132 | #define PRCM_HDMICLK_MGT 0x058 | ||
133 | #define PRCM_APEATCLK_MGT 0x05C | ||
134 | #define PRCM_APETRACECLK_MGT 0x060 | ||
135 | #define PRCM_MCDECLK_MGT 0x064 | ||
136 | #define PRCM_IPI2CCLK_MGT 0x068 | ||
137 | #define PRCM_DSIALTCLK_MGT 0x06C | ||
138 | #define PRCM_DMACLK_MGT 0x074 | ||
139 | #define PRCM_B2R2CLK_MGT 0x078 | ||
140 | #define PRCM_TVCLK_MGT 0x07C | ||
141 | #define PRCM_UNIPROCLK_MGT 0x278 | ||
142 | #define PRCM_SSPCLK_MGT 0x280 | ||
143 | #define PRCM_RNGCLK_MGT 0x284 | ||
144 | #define PRCM_UICCCLK_MGT 0x27C | ||
145 | |||
146 | #define PRCM_CLK_MGT_CLKPLLDIV_MASK BITS(0, 4) | ||
147 | #define PRCM_CLK_MGT_CLKPLLSW_MASK BITS(5, 7) | ||
148 | #define PRCM_CLK_MGT_CLKEN BIT(8) | ||
149 | |||
150 | /* ePOD and memory power signal control registers */ | ||
151 | #define PRCM_EPOD_C_SET 0x410 | ||
152 | #define PRCM_SRAM_LS_SLEEP 0x304 | ||
153 | |||
154 | /* Debug power control unit registers */ | ||
155 | #define PRCM_POWER_STATE_SET 0x254 | ||
156 | |||
157 | /* Miscellaneous unit registers */ | ||
158 | #define PRCM_DSI_SW_RESET 0x324 | ||
159 | #define PRCM_GPIOCR 0x138 | ||
160 | |||
161 | /* GPIOCR register */ | ||
162 | #define PRCM_GPIOCR_SPI2_SELECT BIT(23) | ||
163 | |||
164 | #define PRCM_DDR_SUBSYS_APE_MINBW 0x438 | ||
165 | |||
166 | #endif /* __DB8500_PRCMU_REGS_H */ | ||
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c new file mode 100644 index 000000000000..02a15d7cb3b0 --- /dev/null +++ b/drivers/mfd/db8500-prcmu.c | |||
@@ -0,0 +1,2070 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics 2009 | ||
3 | * Copyright (C) ST-Ericsson SA 2010 | ||
4 | * | ||
5 | * License Terms: GNU General Public License v2 | ||
6 | * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> | ||
7 | * Author: Sundar Iyer <sundar.iyer@stericsson.com> | ||
8 | * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> | ||
9 | * | ||
10 | * U8500 PRCM Unit interface driver | ||
11 | * | ||
12 | */ | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/mutex.h> | ||
22 | #include <linux/completion.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/jiffies.h> | ||
25 | #include <linux/bitops.h> | ||
26 | #include <linux/fs.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/uaccess.h> | ||
29 | #include <linux/mfd/core.h> | ||
30 | #include <linux/mfd/db8500-prcmu.h> | ||
31 | #include <linux/regulator/db8500-prcmu.h> | ||
32 | #include <linux/regulator/machine.h> | ||
33 | #include <mach/hardware.h> | ||
34 | #include <mach/irqs.h> | ||
35 | #include <mach/db8500-regs.h> | ||
36 | #include <mach/id.h> | ||
37 | #include "db8500-prcmu-regs.h" | ||
38 | |||
39 | /* Offset for the firmware version within the TCPM */ | ||
40 | #define PRCMU_FW_VERSION_OFFSET 0xA4 | ||
41 | |||
42 | /* PRCMU project numbers, defined by PRCMU FW */ | ||
43 | #define PRCMU_PROJECT_ID_8500V1_0 1 | ||
44 | #define PRCMU_PROJECT_ID_8500V2_0 2 | ||
45 | #define PRCMU_PROJECT_ID_8400V2_0 3 | ||
46 | |||
47 | /* Index of different voltages to be used when accessing AVSData */ | ||
48 | #define PRCM_AVS_BASE 0x2FC | ||
49 | #define PRCM_AVS_VBB_RET (PRCM_AVS_BASE + 0x0) | ||
50 | #define PRCM_AVS_VBB_MAX_OPP (PRCM_AVS_BASE + 0x1) | ||
51 | #define PRCM_AVS_VBB_100_OPP (PRCM_AVS_BASE + 0x2) | ||
52 | #define PRCM_AVS_VBB_50_OPP (PRCM_AVS_BASE + 0x3) | ||
53 | #define PRCM_AVS_VARM_MAX_OPP (PRCM_AVS_BASE + 0x4) | ||
54 | #define PRCM_AVS_VARM_100_OPP (PRCM_AVS_BASE + 0x5) | ||
55 | #define PRCM_AVS_VARM_50_OPP (PRCM_AVS_BASE + 0x6) | ||
56 | #define PRCM_AVS_VARM_RET (PRCM_AVS_BASE + 0x7) | ||
57 | #define PRCM_AVS_VAPE_100_OPP (PRCM_AVS_BASE + 0x8) | ||
58 | #define PRCM_AVS_VAPE_50_OPP (PRCM_AVS_BASE + 0x9) | ||
59 | #define PRCM_AVS_VMOD_100_OPP (PRCM_AVS_BASE + 0xA) | ||
60 | #define PRCM_AVS_VMOD_50_OPP (PRCM_AVS_BASE + 0xB) | ||
61 | #define PRCM_AVS_VSAFE (PRCM_AVS_BASE + 0xC) | ||
62 | |||
63 | #define PRCM_AVS_VOLTAGE 0 | ||
64 | #define PRCM_AVS_VOLTAGE_MASK 0x3f | ||
65 | #define PRCM_AVS_ISSLOWSTARTUP 6 | ||
66 | #define PRCM_AVS_ISSLOWSTARTUP_MASK (1 << PRCM_AVS_ISSLOWSTARTUP) | ||
67 | #define PRCM_AVS_ISMODEENABLE 7 | ||
68 | #define PRCM_AVS_ISMODEENABLE_MASK (1 << PRCM_AVS_ISMODEENABLE) | ||
69 | |||
70 | #define PRCM_BOOT_STATUS 0xFFF | ||
71 | #define PRCM_ROMCODE_A2P 0xFFE | ||
72 | #define PRCM_ROMCODE_P2A 0xFFD | ||
73 | #define PRCM_XP70_CUR_PWR_STATE 0xFFC /* 4 BYTES */ | ||
74 | |||
75 | #define PRCM_SW_RST_REASON 0xFF8 /* 2 bytes */ | ||
76 | |||
77 | #define _PRCM_MBOX_HEADER 0xFE8 /* 16 bytes */ | ||
78 | #define PRCM_MBOX_HEADER_REQ_MB0 (_PRCM_MBOX_HEADER + 0x0) | ||
79 | #define PRCM_MBOX_HEADER_REQ_MB1 (_PRCM_MBOX_HEADER + 0x1) | ||
80 | #define PRCM_MBOX_HEADER_REQ_MB2 (_PRCM_MBOX_HEADER + 0x2) | ||
81 | #define PRCM_MBOX_HEADER_REQ_MB3 (_PRCM_MBOX_HEADER + 0x3) | ||
82 | #define PRCM_MBOX_HEADER_REQ_MB4 (_PRCM_MBOX_HEADER + 0x4) | ||
83 | #define PRCM_MBOX_HEADER_REQ_MB5 (_PRCM_MBOX_HEADER + 0x5) | ||
84 | #define PRCM_MBOX_HEADER_ACK_MB0 (_PRCM_MBOX_HEADER + 0x8) | ||
85 | |||
86 | /* Req Mailboxes */ | ||
87 | #define PRCM_REQ_MB0 0xFDC /* 12 bytes */ | ||
88 | #define PRCM_REQ_MB1 0xFD0 /* 12 bytes */ | ||
89 | #define PRCM_REQ_MB2 0xFC0 /* 16 bytes */ | ||
90 | #define PRCM_REQ_MB3 0xE4C /* 372 bytes */ | ||
91 | #define PRCM_REQ_MB4 0xE48 /* 4 bytes */ | ||
92 | #define PRCM_REQ_MB5 0xE44 /* 4 bytes */ | ||
93 | |||
94 | /* Ack Mailboxes */ | ||
95 | #define PRCM_ACK_MB0 0xE08 /* 52 bytes */ | ||
96 | #define PRCM_ACK_MB1 0xE04 /* 4 bytes */ | ||
97 | #define PRCM_ACK_MB2 0xE00 /* 4 bytes */ | ||
98 | #define PRCM_ACK_MB3 0xDFC /* 4 bytes */ | ||
99 | #define PRCM_ACK_MB4 0xDF8 /* 4 bytes */ | ||
100 | #define PRCM_ACK_MB5 0xDF4 /* 4 bytes */ | ||
101 | |||
102 | /* Mailbox 0 headers */ | ||
103 | #define MB0H_POWER_STATE_TRANS 0 | ||
104 | #define MB0H_CONFIG_WAKEUPS_EXE 1 | ||
105 | #define MB0H_READ_WAKEUP_ACK 3 | ||
106 | #define MB0H_CONFIG_WAKEUPS_SLEEP 4 | ||
107 | |||
108 | #define MB0H_WAKEUP_EXE 2 | ||
109 | #define MB0H_WAKEUP_SLEEP 5 | ||
110 | |||
111 | /* Mailbox 0 REQs */ | ||
112 | #define PRCM_REQ_MB0_AP_POWER_STATE (PRCM_REQ_MB0 + 0x0) | ||
113 | #define PRCM_REQ_MB0_AP_PLL_STATE (PRCM_REQ_MB0 + 0x1) | ||
114 | #define PRCM_REQ_MB0_ULP_CLOCK_STATE (PRCM_REQ_MB0 + 0x2) | ||
115 | #define PRCM_REQ_MB0_DO_NOT_WFI (PRCM_REQ_MB0 + 0x3) | ||
116 | #define PRCM_REQ_MB0_WAKEUP_8500 (PRCM_REQ_MB0 + 0x4) | ||
117 | #define PRCM_REQ_MB0_WAKEUP_4500 (PRCM_REQ_MB0 + 0x8) | ||
118 | |||
119 | /* Mailbox 0 ACKs */ | ||
120 | #define PRCM_ACK_MB0_AP_PWRSTTR_STATUS (PRCM_ACK_MB0 + 0x0) | ||
121 | #define PRCM_ACK_MB0_READ_POINTER (PRCM_ACK_MB0 + 0x1) | ||
122 | #define PRCM_ACK_MB0_WAKEUP_0_8500 (PRCM_ACK_MB0 + 0x4) | ||
123 | #define PRCM_ACK_MB0_WAKEUP_0_4500 (PRCM_ACK_MB0 + 0x8) | ||
124 | #define PRCM_ACK_MB0_WAKEUP_1_8500 (PRCM_ACK_MB0 + 0x1C) | ||
125 | #define PRCM_ACK_MB0_WAKEUP_1_4500 (PRCM_ACK_MB0 + 0x20) | ||
126 | #define PRCM_ACK_MB0_EVENT_4500_NUMBERS 20 | ||
127 | |||
128 | /* Mailbox 1 headers */ | ||
129 | #define MB1H_ARM_APE_OPP 0x0 | ||
130 | #define MB1H_RESET_MODEM 0x2 | ||
131 | #define MB1H_REQUEST_APE_OPP_100_VOLT 0x3 | ||
132 | #define MB1H_RELEASE_APE_OPP_100_VOLT 0x4 | ||
133 | #define MB1H_RELEASE_USB_WAKEUP 0x5 | ||
134 | |||
135 | /* Mailbox 1 Requests */ | ||
136 | #define PRCM_REQ_MB1_ARM_OPP (PRCM_REQ_MB1 + 0x0) | ||
137 | #define PRCM_REQ_MB1_APE_OPP (PRCM_REQ_MB1 + 0x1) | ||
138 | #define PRCM_REQ_MB1_APE_OPP_100_RESTORE (PRCM_REQ_MB1 + 0x4) | ||
139 | #define PRCM_REQ_MB1_ARM_OPP_100_RESTORE (PRCM_REQ_MB1 + 0x8) | ||
140 | |||
141 | /* Mailbox 1 ACKs */ | ||
142 | #define PRCM_ACK_MB1_CURRENT_ARM_OPP (PRCM_ACK_MB1 + 0x0) | ||
143 | #define PRCM_ACK_MB1_CURRENT_APE_OPP (PRCM_ACK_MB1 + 0x1) | ||
144 | #define PRCM_ACK_MB1_APE_VOLTAGE_STATUS (PRCM_ACK_MB1 + 0x2) | ||
145 | #define PRCM_ACK_MB1_DVFS_STATUS (PRCM_ACK_MB1 + 0x3) | ||
146 | |||
147 | /* Mailbox 2 headers */ | ||
148 | #define MB2H_DPS 0x0 | ||
149 | #define MB2H_AUTO_PWR 0x1 | ||
150 | |||
151 | /* Mailbox 2 REQs */ | ||
152 | #define PRCM_REQ_MB2_SVA_MMDSP (PRCM_REQ_MB2 + 0x0) | ||
153 | #define PRCM_REQ_MB2_SVA_PIPE (PRCM_REQ_MB2 + 0x1) | ||
154 | #define PRCM_REQ_MB2_SIA_MMDSP (PRCM_REQ_MB2 + 0x2) | ||
155 | #define PRCM_REQ_MB2_SIA_PIPE (PRCM_REQ_MB2 + 0x3) | ||
156 | #define PRCM_REQ_MB2_SGA (PRCM_REQ_MB2 + 0x4) | ||
157 | #define PRCM_REQ_MB2_B2R2_MCDE (PRCM_REQ_MB2 + 0x5) | ||
158 | #define PRCM_REQ_MB2_ESRAM12 (PRCM_REQ_MB2 + 0x6) | ||
159 | #define PRCM_REQ_MB2_ESRAM34 (PRCM_REQ_MB2 + 0x7) | ||
160 | #define PRCM_REQ_MB2_AUTO_PM_SLEEP (PRCM_REQ_MB2 + 0x8) | ||
161 | #define PRCM_REQ_MB2_AUTO_PM_IDLE (PRCM_REQ_MB2 + 0xC) | ||
162 | |||
163 | /* Mailbox 2 ACKs */ | ||
164 | #define PRCM_ACK_MB2_DPS_STATUS (PRCM_ACK_MB2 + 0x0) | ||
165 | #define HWACC_PWR_ST_OK 0xFE | ||
166 | |||
167 | /* Mailbox 3 headers */ | ||
168 | #define MB3H_ANC 0x0 | ||
169 | #define MB3H_SIDETONE 0x1 | ||
170 | #define MB3H_SYSCLK 0xE | ||
171 | |||
172 | /* Mailbox 3 Requests */ | ||
173 | #define PRCM_REQ_MB3_ANC_FIR_COEFF (PRCM_REQ_MB3 + 0x0) | ||
174 | #define PRCM_REQ_MB3_ANC_IIR_COEFF (PRCM_REQ_MB3 + 0x20) | ||
175 | #define PRCM_REQ_MB3_ANC_SHIFTER (PRCM_REQ_MB3 + 0x60) | ||
176 | #define PRCM_REQ_MB3_ANC_WARP (PRCM_REQ_MB3 + 0x64) | ||
177 | #define PRCM_REQ_MB3_SIDETONE_FIR_GAIN (PRCM_REQ_MB3 + 0x68) | ||
178 | #define PRCM_REQ_MB3_SIDETONE_FIR_COEFF (PRCM_REQ_MB3 + 0x6C) | ||
179 | #define PRCM_REQ_MB3_SYSCLK_MGT (PRCM_REQ_MB3 + 0x16C) | ||
180 | |||
181 | /* Mailbox 4 headers */ | ||
182 | #define MB4H_DDR_INIT 0x0 | ||
183 | #define MB4H_MEM_ST 0x1 | ||
184 | #define MB4H_HOTDOG 0x12 | ||
185 | #define MB4H_HOTMON 0x13 | ||
186 | #define MB4H_HOT_PERIOD 0x14 | ||
187 | |||
188 | /* Mailbox 4 Requests */ | ||
189 | #define PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE (PRCM_REQ_MB4 + 0x0) | ||
190 | #define PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE (PRCM_REQ_MB4 + 0x1) | ||
191 | #define PRCM_REQ_MB4_ESRAM0_ST (PRCM_REQ_MB4 + 0x3) | ||
192 | #define PRCM_REQ_MB4_HOTDOG_THRESHOLD (PRCM_REQ_MB4 + 0x0) | ||
193 | #define PRCM_REQ_MB4_HOTMON_LOW (PRCM_REQ_MB4 + 0x0) | ||
194 | #define PRCM_REQ_MB4_HOTMON_HIGH (PRCM_REQ_MB4 + 0x1) | ||
195 | #define PRCM_REQ_MB4_HOTMON_CONFIG (PRCM_REQ_MB4 + 0x2) | ||
196 | #define PRCM_REQ_MB4_HOT_PERIOD (PRCM_REQ_MB4 + 0x0) | ||
197 | #define HOTMON_CONFIG_LOW BIT(0) | ||
198 | #define HOTMON_CONFIG_HIGH BIT(1) | ||
199 | |||
200 | /* Mailbox 5 Requests */ | ||
201 | #define PRCM_REQ_MB5_I2C_SLAVE_OP (PRCM_REQ_MB5 + 0x0) | ||
202 | #define PRCM_REQ_MB5_I2C_HW_BITS (PRCM_REQ_MB5 + 0x1) | ||
203 | #define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 0x2) | ||
204 | #define PRCM_REQ_MB5_I2C_VAL (PRCM_REQ_MB5 + 0x3) | ||
205 | #define PRCMU_I2C_WRITE(slave) \ | ||
206 | (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0)) | ||
207 | #define PRCMU_I2C_READ(slave) \ | ||
208 | (((slave) << 1) | BIT(0) | (cpu_is_u8500v2() ? BIT(6) : 0)) | ||
209 | #define PRCMU_I2C_STOP_EN BIT(3) | ||
210 | |||
211 | /* Mailbox 5 ACKs */ | ||
212 | #define PRCM_ACK_MB5_I2C_STATUS (PRCM_ACK_MB5 + 0x1) | ||
213 | #define PRCM_ACK_MB5_I2C_VAL (PRCM_ACK_MB5 + 0x3) | ||
214 | #define I2C_WR_OK 0x1 | ||
215 | #define I2C_RD_OK 0x2 | ||
216 | |||
217 | #define NUM_MB 8 | ||
218 | #define MBOX_BIT BIT | ||
219 | #define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1) | ||
220 | |||
221 | /* | ||
222 | * Wakeups/IRQs | ||
223 | */ | ||
224 | |||
225 | #define WAKEUP_BIT_RTC BIT(0) | ||
226 | #define WAKEUP_BIT_RTT0 BIT(1) | ||
227 | #define WAKEUP_BIT_RTT1 BIT(2) | ||
228 | #define WAKEUP_BIT_HSI0 BIT(3) | ||
229 | #define WAKEUP_BIT_HSI1 BIT(4) | ||
230 | #define WAKEUP_BIT_CA_WAKE BIT(5) | ||
231 | #define WAKEUP_BIT_USB BIT(6) | ||
232 | #define WAKEUP_BIT_ABB BIT(7) | ||
233 | #define WAKEUP_BIT_ABB_FIFO BIT(8) | ||
234 | #define WAKEUP_BIT_SYSCLK_OK BIT(9) | ||
235 | #define WAKEUP_BIT_CA_SLEEP BIT(10) | ||
236 | #define WAKEUP_BIT_AC_WAKE_ACK BIT(11) | ||
237 | #define WAKEUP_BIT_SIDE_TONE_OK BIT(12) | ||
238 | #define WAKEUP_BIT_ANC_OK BIT(13) | ||
239 | #define WAKEUP_BIT_SW_ERROR BIT(14) | ||
240 | #define WAKEUP_BIT_AC_SLEEP_ACK BIT(15) | ||
241 | #define WAKEUP_BIT_ARM BIT(17) | ||
242 | #define WAKEUP_BIT_HOTMON_LOW BIT(18) | ||
243 | #define WAKEUP_BIT_HOTMON_HIGH BIT(19) | ||
244 | #define WAKEUP_BIT_MODEM_SW_RESET_REQ BIT(20) | ||
245 | #define WAKEUP_BIT_GPIO0 BIT(23) | ||
246 | #define WAKEUP_BIT_GPIO1 BIT(24) | ||
247 | #define WAKEUP_BIT_GPIO2 BIT(25) | ||
248 | #define WAKEUP_BIT_GPIO3 BIT(26) | ||
249 | #define WAKEUP_BIT_GPIO4 BIT(27) | ||
250 | #define WAKEUP_BIT_GPIO5 BIT(28) | ||
251 | #define WAKEUP_BIT_GPIO6 BIT(29) | ||
252 | #define WAKEUP_BIT_GPIO7 BIT(30) | ||
253 | #define WAKEUP_BIT_GPIO8 BIT(31) | ||
254 | |||
255 | /* | ||
256 | * This vector maps irq numbers to the bits in the bit field used in | ||
257 | * communication with the PRCMU firmware. | ||
258 | * | ||
259 | * The reason for having this is to keep the irq numbers contiguous even though | ||
260 | * the bits in the bit field are not. (The bits also have a tendency to move | ||
261 | * around, to further complicate matters.) | ||
262 | */ | ||
263 | #define IRQ_INDEX(_name) ((IRQ_PRCMU_##_name) - IRQ_PRCMU_BASE) | ||
264 | #define IRQ_ENTRY(_name)[IRQ_INDEX(_name)] = (WAKEUP_BIT_##_name) | ||
265 | static u32 prcmu_irq_bit[NUM_PRCMU_WAKEUPS] = { | ||
266 | IRQ_ENTRY(RTC), | ||
267 | IRQ_ENTRY(RTT0), | ||
268 | IRQ_ENTRY(RTT1), | ||
269 | IRQ_ENTRY(HSI0), | ||
270 | IRQ_ENTRY(HSI1), | ||
271 | IRQ_ENTRY(CA_WAKE), | ||
272 | IRQ_ENTRY(USB), | ||
273 | IRQ_ENTRY(ABB), | ||
274 | IRQ_ENTRY(ABB_FIFO), | ||
275 | IRQ_ENTRY(CA_SLEEP), | ||
276 | IRQ_ENTRY(ARM), | ||
277 | IRQ_ENTRY(HOTMON_LOW), | ||
278 | IRQ_ENTRY(HOTMON_HIGH), | ||
279 | IRQ_ENTRY(MODEM_SW_RESET_REQ), | ||
280 | IRQ_ENTRY(GPIO0), | ||
281 | IRQ_ENTRY(GPIO1), | ||
282 | IRQ_ENTRY(GPIO2), | ||
283 | IRQ_ENTRY(GPIO3), | ||
284 | IRQ_ENTRY(GPIO4), | ||
285 | IRQ_ENTRY(GPIO5), | ||
286 | IRQ_ENTRY(GPIO6), | ||
287 | IRQ_ENTRY(GPIO7), | ||
288 | IRQ_ENTRY(GPIO8) | ||
289 | }; | ||
290 | |||
291 | #define VALID_WAKEUPS (BIT(NUM_PRCMU_WAKEUP_INDICES) - 1) | ||
292 | #define WAKEUP_ENTRY(_name)[PRCMU_WAKEUP_INDEX_##_name] = (WAKEUP_BIT_##_name) | ||
293 | static u32 prcmu_wakeup_bit[NUM_PRCMU_WAKEUP_INDICES] = { | ||
294 | WAKEUP_ENTRY(RTC), | ||
295 | WAKEUP_ENTRY(RTT0), | ||
296 | WAKEUP_ENTRY(RTT1), | ||
297 | WAKEUP_ENTRY(HSI0), | ||
298 | WAKEUP_ENTRY(HSI1), | ||
299 | WAKEUP_ENTRY(USB), | ||
300 | WAKEUP_ENTRY(ABB), | ||
301 | WAKEUP_ENTRY(ABB_FIFO), | ||
302 | WAKEUP_ENTRY(ARM) | ||
303 | }; | ||
304 | |||
305 | /* | ||
306 | * mb0_transfer - state needed for mailbox 0 communication. | ||
307 | * @lock: The transaction lock. | ||
308 | * @dbb_events_lock: A lock used to handle concurrent access to (parts of) | ||
309 | * the request data. | ||
310 | * @mask_work: Work structure used for (un)masking wakeup interrupts. | ||
311 | * @req: Request data that need to persist between requests. | ||
312 | */ | ||
313 | static struct { | ||
314 | spinlock_t lock; | ||
315 | spinlock_t dbb_irqs_lock; | ||
316 | struct work_struct mask_work; | ||
317 | struct mutex ac_wake_lock; | ||
318 | struct completion ac_wake_work; | ||
319 | struct { | ||
320 | u32 dbb_irqs; | ||
321 | u32 dbb_wakeups; | ||
322 | u32 abb_events; | ||
323 | } req; | ||
324 | } mb0_transfer; | ||
325 | |||
326 | /* | ||
327 | * mb1_transfer - state needed for mailbox 1 communication. | ||
328 | * @lock: The transaction lock. | ||
329 | * @work: The transaction completion structure. | ||
330 | * @ack: Reply ("acknowledge") data. | ||
331 | */ | ||
332 | static struct { | ||
333 | struct mutex lock; | ||
334 | struct completion work; | ||
335 | struct { | ||
336 | u8 header; | ||
337 | u8 arm_opp; | ||
338 | u8 ape_opp; | ||
339 | u8 ape_voltage_status; | ||
340 | } ack; | ||
341 | } mb1_transfer; | ||
342 | |||
343 | /* | ||
344 | * mb2_transfer - state needed for mailbox 2 communication. | ||
345 | * @lock: The transaction lock. | ||
346 | * @work: The transaction completion structure. | ||
347 | * @auto_pm_lock: The autonomous power management configuration lock. | ||
348 | * @auto_pm_enabled: A flag indicating whether autonomous PM is enabled. | ||
349 | * @req: Request data that need to persist between requests. | ||
350 | * @ack: Reply ("acknowledge") data. | ||
351 | */ | ||
352 | static struct { | ||
353 | struct mutex lock; | ||
354 | struct completion work; | ||
355 | spinlock_t auto_pm_lock; | ||
356 | bool auto_pm_enabled; | ||
357 | struct { | ||
358 | u8 status; | ||
359 | } ack; | ||
360 | } mb2_transfer; | ||
361 | |||
362 | /* | ||
363 | * mb3_transfer - state needed for mailbox 3 communication. | ||
364 | * @lock: The request lock. | ||
365 | * @sysclk_lock: A lock used to handle concurrent sysclk requests. | ||
366 | * @sysclk_work: Work structure used for sysclk requests. | ||
367 | */ | ||
368 | static struct { | ||
369 | spinlock_t lock; | ||
370 | struct mutex sysclk_lock; | ||
371 | struct completion sysclk_work; | ||
372 | } mb3_transfer; | ||
373 | |||
374 | /* | ||
375 | * mb4_transfer - state needed for mailbox 4 communication. | ||
376 | * @lock: The transaction lock. | ||
377 | * @work: The transaction completion structure. | ||
378 | */ | ||
379 | static struct { | ||
380 | struct mutex lock; | ||
381 | struct completion work; | ||
382 | } mb4_transfer; | ||
383 | |||
384 | /* | ||
385 | * mb5_transfer - state needed for mailbox 5 communication. | ||
386 | * @lock: The transaction lock. | ||
387 | * @work: The transaction completion structure. | ||
388 | * @ack: Reply ("acknowledge") data. | ||
389 | */ | ||
390 | static struct { | ||
391 | struct mutex lock; | ||
392 | struct completion work; | ||
393 | struct { | ||
394 | u8 status; | ||
395 | u8 value; | ||
396 | } ack; | ||
397 | } mb5_transfer; | ||
398 | |||
399 | static atomic_t ac_wake_req_state = ATOMIC_INIT(0); | ||
400 | |||
401 | /* Spinlocks */ | ||
402 | static DEFINE_SPINLOCK(clkout_lock); | ||
403 | static DEFINE_SPINLOCK(gpiocr_lock); | ||
404 | |||
405 | /* Global var to runtime determine TCDM base for v2 or v1 */ | ||
406 | static __iomem void *tcdm_base; | ||
407 | |||
408 | struct clk_mgt { | ||
409 | unsigned int offset; | ||
410 | u32 pllsw; | ||
411 | }; | ||
412 | |||
413 | static DEFINE_SPINLOCK(clk_mgt_lock); | ||
414 | |||
415 | #define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT), 0 } | ||
416 | struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = { | ||
417 | CLK_MGT_ENTRY(SGACLK), | ||
418 | CLK_MGT_ENTRY(UARTCLK), | ||
419 | CLK_MGT_ENTRY(MSP02CLK), | ||
420 | CLK_MGT_ENTRY(MSP1CLK), | ||
421 | CLK_MGT_ENTRY(I2CCLK), | ||
422 | CLK_MGT_ENTRY(SDMMCCLK), | ||
423 | CLK_MGT_ENTRY(SLIMCLK), | ||
424 | CLK_MGT_ENTRY(PER1CLK), | ||
425 | CLK_MGT_ENTRY(PER2CLK), | ||
426 | CLK_MGT_ENTRY(PER3CLK), | ||
427 | CLK_MGT_ENTRY(PER5CLK), | ||
428 | CLK_MGT_ENTRY(PER6CLK), | ||
429 | CLK_MGT_ENTRY(PER7CLK), | ||
430 | CLK_MGT_ENTRY(LCDCLK), | ||
431 | CLK_MGT_ENTRY(BMLCLK), | ||
432 | CLK_MGT_ENTRY(HSITXCLK), | ||
433 | CLK_MGT_ENTRY(HSIRXCLK), | ||
434 | CLK_MGT_ENTRY(HDMICLK), | ||
435 | CLK_MGT_ENTRY(APEATCLK), | ||
436 | CLK_MGT_ENTRY(APETRACECLK), | ||
437 | CLK_MGT_ENTRY(MCDECLK), | ||
438 | CLK_MGT_ENTRY(IPI2CCLK), | ||
439 | CLK_MGT_ENTRY(DSIALTCLK), | ||
440 | CLK_MGT_ENTRY(DMACLK), | ||
441 | CLK_MGT_ENTRY(B2R2CLK), | ||
442 | CLK_MGT_ENTRY(TVCLK), | ||
443 | CLK_MGT_ENTRY(SSPCLK), | ||
444 | CLK_MGT_ENTRY(RNGCLK), | ||
445 | CLK_MGT_ENTRY(UICCCLK), | ||
446 | }; | ||
447 | |||
448 | /* | ||
449 | * Used by MCDE to setup all necessary PRCMU registers | ||
450 | */ | ||
451 | #define PRCMU_RESET_DSIPLL 0x00004000 | ||
452 | #define PRCMU_UNCLAMP_DSIPLL 0x00400800 | ||
453 | |||
454 | #define PRCMU_CLK_PLL_DIV_SHIFT 0 | ||
455 | #define PRCMU_CLK_PLL_SW_SHIFT 5 | ||
456 | #define PRCMU_CLK_38 (1 << 9) | ||
457 | #define PRCMU_CLK_38_SRC (1 << 10) | ||
458 | #define PRCMU_CLK_38_DIV (1 << 11) | ||
459 | |||
460 | /* PLLDIV=12, PLLSW=4 (PLLDDR) */ | ||
461 | #define PRCMU_DSI_CLOCK_SETTING 0x0000008C | ||
462 | |||
463 | /* PLLDIV=8, PLLSW=4 (PLLDDR) */ | ||
464 | #define PRCMU_DSI_CLOCK_SETTING_U8400 0x00000088 | ||
465 | |||
466 | /* DPI 50000000 Hz */ | ||
467 | #define PRCMU_DPI_CLOCK_SETTING ((1 << PRCMU_CLK_PLL_SW_SHIFT) | \ | ||
468 | (16 << PRCMU_CLK_PLL_DIV_SHIFT)) | ||
469 | #define PRCMU_DSI_LP_CLOCK_SETTING 0x00000E00 | ||
470 | |||
471 | /* D=101, N=1, R=4, SELDIV2=0 */ | ||
472 | #define PRCMU_PLLDSI_FREQ_SETTING 0x00040165 | ||
473 | |||
474 | /* D=70, N=1, R=3, SELDIV2=0 */ | ||
475 | #define PRCMU_PLLDSI_FREQ_SETTING_U8400 0x00030146 | ||
476 | |||
477 | #define PRCMU_ENABLE_PLLDSI 0x00000001 | ||
478 | #define PRCMU_DISABLE_PLLDSI 0x00000000 | ||
479 | #define PRCMU_RELEASE_RESET_DSS 0x0000400C | ||
480 | #define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000202 | ||
481 | /* ESC clk, div0=1, div1=1, div2=3 */ | ||
482 | #define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x07030101 | ||
483 | #define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00030101 | ||
484 | #define PRCMU_DSI_RESET_SW 0x00000007 | ||
485 | |||
486 | #define PRCMU_PLLDSI_LOCKP_LOCKED 0x3 | ||
487 | |||
488 | static struct { | ||
489 | u8 project_number; | ||
490 | u8 api_version; | ||
491 | u8 func_version; | ||
492 | u8 errata; | ||
493 | } prcmu_version; | ||
494 | |||
495 | |||
496 | int prcmu_enable_dsipll(void) | ||
497 | { | ||
498 | int i; | ||
499 | unsigned int plldsifreq; | ||
500 | |||
501 | /* Clear DSIPLL_RESETN */ | ||
502 | writel(PRCMU_RESET_DSIPLL, (_PRCMU_BASE + PRCM_APE_RESETN_CLR)); | ||
503 | /* Unclamp DSIPLL in/out */ | ||
504 | writel(PRCMU_UNCLAMP_DSIPLL, (_PRCMU_BASE + PRCM_MMIP_LS_CLAMP_CLR)); | ||
505 | |||
506 | if (prcmu_is_u8400()) | ||
507 | plldsifreq = PRCMU_PLLDSI_FREQ_SETTING_U8400; | ||
508 | else | ||
509 | plldsifreq = PRCMU_PLLDSI_FREQ_SETTING; | ||
510 | /* Set DSI PLL FREQ */ | ||
511 | writel(plldsifreq, (_PRCMU_BASE + PRCM_PLLDSI_FREQ)); | ||
512 | writel(PRCMU_DSI_PLLOUT_SEL_SETTING, | ||
513 | (_PRCMU_BASE + PRCM_DSI_PLLOUT_SEL)); | ||
514 | /* Enable Escape clocks */ | ||
515 | writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, | ||
516 | (_PRCMU_BASE + PRCM_DSITVCLK_DIV)); | ||
517 | |||
518 | /* Start DSI PLL */ | ||
519 | writel(PRCMU_ENABLE_PLLDSI, (_PRCMU_BASE + PRCM_PLLDSI_ENABLE)); | ||
520 | /* Reset DSI PLL */ | ||
521 | writel(PRCMU_DSI_RESET_SW, (_PRCMU_BASE + PRCM_DSI_SW_RESET)); | ||
522 | for (i = 0; i < 10; i++) { | ||
523 | if ((readl(_PRCMU_BASE + PRCM_PLLDSI_LOCKP) & | ||
524 | PRCMU_PLLDSI_LOCKP_LOCKED) | ||
525 | == PRCMU_PLLDSI_LOCKP_LOCKED) | ||
526 | break; | ||
527 | udelay(100); | ||
528 | } | ||
529 | /* Set DSIPLL_RESETN */ | ||
530 | writel(PRCMU_RESET_DSIPLL, (_PRCMU_BASE + PRCM_APE_RESETN_SET)); | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | int prcmu_disable_dsipll(void) | ||
535 | { | ||
536 | /* Disable dsi pll */ | ||
537 | writel(PRCMU_DISABLE_PLLDSI, (_PRCMU_BASE + PRCM_PLLDSI_ENABLE)); | ||
538 | /* Disable escapeclock */ | ||
539 | writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, | ||
540 | (_PRCMU_BASE + PRCM_DSITVCLK_DIV)); | ||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | int prcmu_set_display_clocks(void) | ||
545 | { | ||
546 | unsigned long flags; | ||
547 | unsigned int dsiclk; | ||
548 | |||
549 | if (prcmu_is_u8400()) | ||
550 | dsiclk = PRCMU_DSI_CLOCK_SETTING_U8400; | ||
551 | else | ||
552 | dsiclk = PRCMU_DSI_CLOCK_SETTING; | ||
553 | |||
554 | spin_lock_irqsave(&clk_mgt_lock, flags); | ||
555 | |||
556 | /* Grab the HW semaphore. */ | ||
557 | while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0) | ||
558 | cpu_relax(); | ||
559 | |||
560 | writel(dsiclk, (_PRCMU_BASE + PRCM_HDMICLK_MGT)); | ||
561 | writel(PRCMU_DSI_LP_CLOCK_SETTING, (_PRCMU_BASE + PRCM_TVCLK_MGT)); | ||
562 | writel(PRCMU_DPI_CLOCK_SETTING, (_PRCMU_BASE + PRCM_LCDCLK_MGT)); | ||
563 | |||
564 | /* Release the HW semaphore. */ | ||
565 | writel(0, (_PRCMU_BASE + PRCM_SEM)); | ||
566 | |||
567 | spin_unlock_irqrestore(&clk_mgt_lock, flags); | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | /** | ||
573 | * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1. | ||
574 | */ | ||
575 | void prcmu_enable_spi2(void) | ||
576 | { | ||
577 | u32 reg; | ||
578 | unsigned long flags; | ||
579 | |||
580 | spin_lock_irqsave(&gpiocr_lock, flags); | ||
581 | reg = readl(_PRCMU_BASE + PRCM_GPIOCR); | ||
582 | writel(reg | PRCM_GPIOCR_SPI2_SELECT, _PRCMU_BASE + PRCM_GPIOCR); | ||
583 | spin_unlock_irqrestore(&gpiocr_lock, flags); | ||
584 | } | ||
585 | |||
586 | /** | ||
587 | * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1. | ||
588 | */ | ||
589 | void prcmu_disable_spi2(void) | ||
590 | { | ||
591 | u32 reg; | ||
592 | unsigned long flags; | ||
593 | |||
594 | spin_lock_irqsave(&gpiocr_lock, flags); | ||
595 | reg = readl(_PRCMU_BASE + PRCM_GPIOCR); | ||
596 | writel(reg & ~PRCM_GPIOCR_SPI2_SELECT, _PRCMU_BASE + PRCM_GPIOCR); | ||
597 | spin_unlock_irqrestore(&gpiocr_lock, flags); | ||
598 | } | ||
599 | |||
600 | bool prcmu_has_arm_maxopp(void) | ||
601 | { | ||
602 | return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) & | ||
603 | PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK; | ||
604 | } | ||
605 | |||
606 | bool prcmu_is_u8400(void) | ||
607 | { | ||
608 | return prcmu_version.project_number == PRCMU_PROJECT_ID_8400V2_0; | ||
609 | } | ||
610 | |||
611 | /** | ||
612 | * prcmu_get_boot_status - PRCMU boot status checking | ||
613 | * Returns: the current PRCMU boot status | ||
614 | */ | ||
615 | int prcmu_get_boot_status(void) | ||
616 | { | ||
617 | return readb(tcdm_base + PRCM_BOOT_STATUS); | ||
618 | } | ||
619 | |||
620 | /** | ||
621 | * prcmu_set_rc_a2p - This function is used to run few power state sequences | ||
622 | * @val: Value to be set, i.e. transition requested | ||
623 | * Returns: 0 on success, -EINVAL on invalid argument | ||
624 | * | ||
625 | * This function is used to run the following power state sequences - | ||
626 | * any state to ApReset, ApDeepSleep to ApExecute, ApExecute to ApDeepSleep | ||
627 | */ | ||
628 | int prcmu_set_rc_a2p(enum romcode_write val) | ||
629 | { | ||
630 | if (val < RDY_2_DS || val > RDY_2_XP70_RST) | ||
631 | return -EINVAL; | ||
632 | writeb(val, (tcdm_base + PRCM_ROMCODE_A2P)); | ||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | /** | ||
637 | * prcmu_get_rc_p2a - This function is used to get power state sequences | ||
638 | * Returns: the power transition that has last happened | ||
639 | * | ||
640 | * This function can return the following transitions- | ||
641 | * any state to ApReset, ApDeepSleep to ApExecute, ApExecute to ApDeepSleep | ||
642 | */ | ||
643 | enum romcode_read prcmu_get_rc_p2a(void) | ||
644 | { | ||
645 | return readb(tcdm_base + PRCM_ROMCODE_P2A); | ||
646 | } | ||
647 | |||
648 | /** | ||
649 | * prcmu_get_current_mode - Return the current XP70 power mode | ||
650 | * Returns: Returns the current AP(ARM) power mode: init, | ||
651 | * apBoot, apExecute, apDeepSleep, apSleep, apIdle, apReset | ||
652 | */ | ||
653 | enum ap_pwrst prcmu_get_xp70_current_state(void) | ||
654 | { | ||
655 | return readb(tcdm_base + PRCM_XP70_CUR_PWR_STATE); | ||
656 | } | ||
657 | |||
658 | /** | ||
659 | * prcmu_config_clkout - Configure one of the programmable clock outputs. | ||
660 | * @clkout: The CLKOUT number (0 or 1). | ||
661 | * @source: The clock to be used (one of the PRCMU_CLKSRC_*). | ||
662 | * @div: The divider to be applied. | ||
663 | * | ||
664 | * Configures one of the programmable clock outputs (CLKOUTs). | ||
665 | * @div should be in the range [1,63] to request a configuration, or 0 to | ||
666 | * inform that the configuration is no longer requested. | ||
667 | */ | ||
668 | int prcmu_config_clkout(u8 clkout, u8 source, u8 div) | ||
669 | { | ||
670 | static int requests[2]; | ||
671 | int r = 0; | ||
672 | unsigned long flags; | ||
673 | u32 val; | ||
674 | u32 bits; | ||
675 | u32 mask; | ||
676 | u32 div_mask; | ||
677 | |||
678 | BUG_ON(clkout > 1); | ||
679 | BUG_ON(div > 63); | ||
680 | BUG_ON((clkout == 0) && (source > PRCMU_CLKSRC_CLK009)); | ||
681 | |||
682 | if (!div && !requests[clkout]) | ||
683 | return -EINVAL; | ||
684 | |||
685 | switch (clkout) { | ||
686 | case 0: | ||
687 | div_mask = PRCM_CLKOCR_CLKODIV0_MASK; | ||
688 | mask = (PRCM_CLKOCR_CLKODIV0_MASK | PRCM_CLKOCR_CLKOSEL0_MASK); | ||
689 | bits = ((source << PRCM_CLKOCR_CLKOSEL0_SHIFT) | | ||
690 | (div << PRCM_CLKOCR_CLKODIV0_SHIFT)); | ||
691 | break; | ||
692 | case 1: | ||
693 | div_mask = PRCM_CLKOCR_CLKODIV1_MASK; | ||
694 | mask = (PRCM_CLKOCR_CLKODIV1_MASK | PRCM_CLKOCR_CLKOSEL1_MASK | | ||
695 | PRCM_CLKOCR_CLK1TYPE); | ||
696 | bits = ((source << PRCM_CLKOCR_CLKOSEL1_SHIFT) | | ||
697 | (div << PRCM_CLKOCR_CLKODIV1_SHIFT)); | ||
698 | break; | ||
699 | } | ||
700 | bits &= mask; | ||
701 | |||
702 | spin_lock_irqsave(&clkout_lock, flags); | ||
703 | |||
704 | val = readl(_PRCMU_BASE + PRCM_CLKOCR); | ||
705 | if (val & div_mask) { | ||
706 | if (div) { | ||
707 | if ((val & mask) != bits) { | ||
708 | r = -EBUSY; | ||
709 | goto unlock_and_return; | ||
710 | } | ||
711 | } else { | ||
712 | if ((val & mask & ~div_mask) != bits) { | ||
713 | r = -EINVAL; | ||
714 | goto unlock_and_return; | ||
715 | } | ||
716 | } | ||
717 | } | ||
718 | writel((bits | (val & ~mask)), (_PRCMU_BASE + PRCM_CLKOCR)); | ||
719 | requests[clkout] += (div ? 1 : -1); | ||
720 | |||
721 | unlock_and_return: | ||
722 | spin_unlock_irqrestore(&clkout_lock, flags); | ||
723 | |||
724 | return r; | ||
725 | } | ||
726 | |||
727 | int prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll) | ||
728 | { | ||
729 | unsigned long flags; | ||
730 | |||
731 | BUG_ON((state < PRCMU_AP_SLEEP) || (PRCMU_AP_DEEP_IDLE < state)); | ||
732 | |||
733 | spin_lock_irqsave(&mb0_transfer.lock, flags); | ||
734 | |||
735 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) | ||
736 | cpu_relax(); | ||
737 | |||
738 | writeb(MB0H_POWER_STATE_TRANS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0)); | ||
739 | writeb(state, (tcdm_base + PRCM_REQ_MB0_AP_POWER_STATE)); | ||
740 | writeb((keep_ap_pll ? 1 : 0), (tcdm_base + PRCM_REQ_MB0_AP_PLL_STATE)); | ||
741 | writeb((keep_ulp_clk ? 1 : 0), | ||
742 | (tcdm_base + PRCM_REQ_MB0_ULP_CLOCK_STATE)); | ||
743 | writeb(0, (tcdm_base + PRCM_REQ_MB0_DO_NOT_WFI)); | ||
744 | writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
745 | |||
746 | spin_unlock_irqrestore(&mb0_transfer.lock, flags); | ||
747 | |||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | /* This function should only be called while mb0_transfer.lock is held. */ | ||
752 | static void config_wakeups(void) | ||
753 | { | ||
754 | const u8 header[2] = { | ||
755 | MB0H_CONFIG_WAKEUPS_EXE, | ||
756 | MB0H_CONFIG_WAKEUPS_SLEEP | ||
757 | }; | ||
758 | static u32 last_dbb_events; | ||
759 | static u32 last_abb_events; | ||
760 | u32 dbb_events; | ||
761 | u32 abb_events; | ||
762 | unsigned int i; | ||
763 | |||
764 | dbb_events = mb0_transfer.req.dbb_irqs | mb0_transfer.req.dbb_wakeups; | ||
765 | dbb_events |= (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK); | ||
766 | |||
767 | abb_events = mb0_transfer.req.abb_events; | ||
768 | |||
769 | if ((dbb_events == last_dbb_events) && (abb_events == last_abb_events)) | ||
770 | return; | ||
771 | |||
772 | for (i = 0; i < 2; i++) { | ||
773 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) | ||
774 | cpu_relax(); | ||
775 | writel(dbb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_8500)); | ||
776 | writel(abb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_4500)); | ||
777 | writeb(header[i], (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0)); | ||
778 | writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
779 | } | ||
780 | last_dbb_events = dbb_events; | ||
781 | last_abb_events = abb_events; | ||
782 | } | ||
783 | |||
784 | void prcmu_enable_wakeups(u32 wakeups) | ||
785 | { | ||
786 | unsigned long flags; | ||
787 | u32 bits; | ||
788 | int i; | ||
789 | |||
790 | BUG_ON(wakeups != (wakeups & VALID_WAKEUPS)); | ||
791 | |||
792 | for (i = 0, bits = 0; i < NUM_PRCMU_WAKEUP_INDICES; i++) { | ||
793 | if (wakeups & BIT(i)) | ||
794 | bits |= prcmu_wakeup_bit[i]; | ||
795 | } | ||
796 | |||
797 | spin_lock_irqsave(&mb0_transfer.lock, flags); | ||
798 | |||
799 | mb0_transfer.req.dbb_wakeups = bits; | ||
800 | config_wakeups(); | ||
801 | |||
802 | spin_unlock_irqrestore(&mb0_transfer.lock, flags); | ||
803 | } | ||
804 | |||
805 | void prcmu_config_abb_event_readout(u32 abb_events) | ||
806 | { | ||
807 | unsigned long flags; | ||
808 | |||
809 | spin_lock_irqsave(&mb0_transfer.lock, flags); | ||
810 | |||
811 | mb0_transfer.req.abb_events = abb_events; | ||
812 | config_wakeups(); | ||
813 | |||
814 | spin_unlock_irqrestore(&mb0_transfer.lock, flags); | ||
815 | } | ||
816 | |||
817 | void prcmu_get_abb_event_buffer(void __iomem **buf) | ||
818 | { | ||
819 | if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1) | ||
820 | *buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_1_4500); | ||
821 | else | ||
822 | *buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_0_4500); | ||
823 | } | ||
824 | |||
825 | /** | ||
826 | * prcmu_set_arm_opp - set the appropriate ARM OPP | ||
827 | * @opp: The new ARM operating point to which transition is to be made | ||
828 | * Returns: 0 on success, non-zero on failure | ||
829 | * | ||
830 | * This function sets the the operating point of the ARM. | ||
831 | */ | ||
832 | int prcmu_set_arm_opp(u8 opp) | ||
833 | { | ||
834 | int r; | ||
835 | |||
836 | if (opp < ARM_NO_CHANGE || opp > ARM_EXTCLK) | ||
837 | return -EINVAL; | ||
838 | |||
839 | r = 0; | ||
840 | |||
841 | mutex_lock(&mb1_transfer.lock); | ||
842 | |||
843 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) | ||
844 | cpu_relax(); | ||
845 | |||
846 | writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); | ||
847 | writeb(opp, (tcdm_base + PRCM_REQ_MB1_ARM_OPP)); | ||
848 | writeb(APE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_APE_OPP)); | ||
849 | |||
850 | writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
851 | wait_for_completion(&mb1_transfer.work); | ||
852 | |||
853 | if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) || | ||
854 | (mb1_transfer.ack.arm_opp != opp)) | ||
855 | r = -EIO; | ||
856 | |||
857 | mutex_unlock(&mb1_transfer.lock); | ||
858 | |||
859 | return r; | ||
860 | } | ||
861 | |||
862 | /** | ||
863 | * prcmu_get_arm_opp - get the current ARM OPP | ||
864 | * | ||
865 | * Returns: the current ARM OPP | ||
866 | */ | ||
867 | int prcmu_get_arm_opp(void) | ||
868 | { | ||
869 | return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_ARM_OPP); | ||
870 | } | ||
871 | |||
872 | /** | ||
873 | * prcmu_get_ddr_opp - get the current DDR OPP | ||
874 | * | ||
875 | * Returns: the current DDR OPP | ||
876 | */ | ||
877 | int prcmu_get_ddr_opp(void) | ||
878 | { | ||
879 | return readb(_PRCMU_BASE + PRCM_DDR_SUBSYS_APE_MINBW); | ||
880 | } | ||
881 | |||
882 | /** | ||
883 | * set_ddr_opp - set the appropriate DDR OPP | ||
884 | * @opp: The new DDR operating point to which transition is to be made | ||
885 | * Returns: 0 on success, non-zero on failure | ||
886 | * | ||
887 | * This function sets the operating point of the DDR. | ||
888 | */ | ||
889 | int prcmu_set_ddr_opp(u8 opp) | ||
890 | { | ||
891 | if (opp < DDR_100_OPP || opp > DDR_25_OPP) | ||
892 | return -EINVAL; | ||
893 | /* Changing the DDR OPP can hang the hardware pre-v21 */ | ||
894 | if (cpu_is_u8500v20_or_later() && !cpu_is_u8500v20()) | ||
895 | writeb(opp, (_PRCMU_BASE + PRCM_DDR_SUBSYS_APE_MINBW)); | ||
896 | |||
897 | return 0; | ||
898 | } | ||
899 | /** | ||
900 | * set_ape_opp - set the appropriate APE OPP | ||
901 | * @opp: The new APE operating point to which transition is to be made | ||
902 | * Returns: 0 on success, non-zero on failure | ||
903 | * | ||
904 | * This function sets the operating point of the APE. | ||
905 | */ | ||
906 | int prcmu_set_ape_opp(u8 opp) | ||
907 | { | ||
908 | int r = 0; | ||
909 | |||
910 | mutex_lock(&mb1_transfer.lock); | ||
911 | |||
912 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) | ||
913 | cpu_relax(); | ||
914 | |||
915 | writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); | ||
916 | writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP)); | ||
917 | writeb(opp, (tcdm_base + PRCM_REQ_MB1_APE_OPP)); | ||
918 | |||
919 | writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
920 | wait_for_completion(&mb1_transfer.work); | ||
921 | |||
922 | if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) || | ||
923 | (mb1_transfer.ack.ape_opp != opp)) | ||
924 | r = -EIO; | ||
925 | |||
926 | mutex_unlock(&mb1_transfer.lock); | ||
927 | |||
928 | return r; | ||
929 | } | ||
930 | |||
931 | /** | ||
932 | * prcmu_get_ape_opp - get the current APE OPP | ||
933 | * | ||
934 | * Returns: the current APE OPP | ||
935 | */ | ||
936 | int prcmu_get_ape_opp(void) | ||
937 | { | ||
938 | return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP); | ||
939 | } | ||
940 | |||
941 | /** | ||
942 | * prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage | ||
943 | * @enable: true to request the higher voltage, false to drop a request. | ||
944 | * | ||
945 | * Calls to this function to enable and disable requests must be balanced. | ||
946 | */ | ||
947 | int prcmu_request_ape_opp_100_voltage(bool enable) | ||
948 | { | ||
949 | int r = 0; | ||
950 | u8 header; | ||
951 | static unsigned int requests; | ||
952 | |||
953 | mutex_lock(&mb1_transfer.lock); | ||
954 | |||
955 | if (enable) { | ||
956 | if (0 != requests++) | ||
957 | goto unlock_and_return; | ||
958 | header = MB1H_REQUEST_APE_OPP_100_VOLT; | ||
959 | } else { | ||
960 | if (requests == 0) { | ||
961 | r = -EIO; | ||
962 | goto unlock_and_return; | ||
963 | } else if (1 != requests--) { | ||
964 | goto unlock_and_return; | ||
965 | } | ||
966 | header = MB1H_RELEASE_APE_OPP_100_VOLT; | ||
967 | } | ||
968 | |||
969 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) | ||
970 | cpu_relax(); | ||
971 | |||
972 | writeb(header, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); | ||
973 | |||
974 | writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
975 | wait_for_completion(&mb1_transfer.work); | ||
976 | |||
977 | if ((mb1_transfer.ack.header != header) || | ||
978 | ((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0)) | ||
979 | r = -EIO; | ||
980 | |||
981 | unlock_and_return: | ||
982 | mutex_unlock(&mb1_transfer.lock); | ||
983 | |||
984 | return r; | ||
985 | } | ||
986 | |||
987 | /** | ||
988 | * prcmu_release_usb_wakeup_state - release the state required by a USB wakeup | ||
989 | * | ||
990 | * This function releases the power state requirements of a USB wakeup. | ||
991 | */ | ||
992 | int prcmu_release_usb_wakeup_state(void) | ||
993 | { | ||
994 | int r = 0; | ||
995 | |||
996 | mutex_lock(&mb1_transfer.lock); | ||
997 | |||
998 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) | ||
999 | cpu_relax(); | ||
1000 | |||
1001 | writeb(MB1H_RELEASE_USB_WAKEUP, | ||
1002 | (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); | ||
1003 | |||
1004 | writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
1005 | wait_for_completion(&mb1_transfer.work); | ||
1006 | |||
1007 | if ((mb1_transfer.ack.header != MB1H_RELEASE_USB_WAKEUP) || | ||
1008 | ((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0)) | ||
1009 | r = -EIO; | ||
1010 | |||
1011 | mutex_unlock(&mb1_transfer.lock); | ||
1012 | |||
1013 | return r; | ||
1014 | } | ||
1015 | |||
1016 | /** | ||
1017 | * prcmu_set_epod - set the state of a EPOD (power domain) | ||
1018 | * @epod_id: The EPOD to set | ||
1019 | * @epod_state: The new EPOD state | ||
1020 | * | ||
1021 | * This function sets the state of a EPOD (power domain). It may not be called | ||
1022 | * from interrupt context. | ||
1023 | */ | ||
1024 | int prcmu_set_epod(u16 epod_id, u8 epod_state) | ||
1025 | { | ||
1026 | int r = 0; | ||
1027 | bool ram_retention = false; | ||
1028 | int i; | ||
1029 | |||
1030 | /* check argument */ | ||
1031 | BUG_ON(epod_id >= NUM_EPOD_ID); | ||
1032 | |||
1033 | /* set flag if retention is possible */ | ||
1034 | switch (epod_id) { | ||
1035 | case EPOD_ID_SVAMMDSP: | ||
1036 | case EPOD_ID_SIAMMDSP: | ||
1037 | case EPOD_ID_ESRAM12: | ||
1038 | case EPOD_ID_ESRAM34: | ||
1039 | ram_retention = true; | ||
1040 | break; | ||
1041 | } | ||
1042 | |||
1043 | /* check argument */ | ||
1044 | BUG_ON(epod_state > EPOD_STATE_ON); | ||
1045 | BUG_ON(epod_state == EPOD_STATE_RAMRET && !ram_retention); | ||
1046 | |||
1047 | /* get lock */ | ||
1048 | mutex_lock(&mb2_transfer.lock); | ||
1049 | |||
1050 | /* wait for mailbox */ | ||
1051 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(2)) | ||
1052 | cpu_relax(); | ||
1053 | |||
1054 | /* fill in mailbox */ | ||
1055 | for (i = 0; i < NUM_EPOD_ID; i++) | ||
1056 | writeb(EPOD_STATE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB2 + i)); | ||
1057 | writeb(epod_state, (tcdm_base + PRCM_REQ_MB2 + epod_id)); | ||
1058 | |||
1059 | writeb(MB2H_DPS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB2)); | ||
1060 | |||
1061 | writel(MBOX_BIT(2), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
1062 | |||
1063 | /* | ||
1064 | * The current firmware version does not handle errors correctly, | ||
1065 | * and we cannot recover if there is an error. | ||
1066 | * This is expected to change when the firmware is updated. | ||
1067 | */ | ||
1068 | if (!wait_for_completion_timeout(&mb2_transfer.work, | ||
1069 | msecs_to_jiffies(20000))) { | ||
1070 | pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", | ||
1071 | __func__); | ||
1072 | r = -EIO; | ||
1073 | goto unlock_and_return; | ||
1074 | } | ||
1075 | |||
1076 | if (mb2_transfer.ack.status != HWACC_PWR_ST_OK) | ||
1077 | r = -EIO; | ||
1078 | |||
1079 | unlock_and_return: | ||
1080 | mutex_unlock(&mb2_transfer.lock); | ||
1081 | return r; | ||
1082 | } | ||
1083 | |||
1084 | /** | ||
1085 | * prcmu_configure_auto_pm - Configure autonomous power management. | ||
1086 | * @sleep: Configuration for ApSleep. | ||
1087 | * @idle: Configuration for ApIdle. | ||
1088 | */ | ||
1089 | void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep, | ||
1090 | struct prcmu_auto_pm_config *idle) | ||
1091 | { | ||
1092 | u32 sleep_cfg; | ||
1093 | u32 idle_cfg; | ||
1094 | unsigned long flags; | ||
1095 | |||
1096 | BUG_ON((sleep == NULL) || (idle == NULL)); | ||
1097 | |||
1098 | sleep_cfg = (sleep->sva_auto_pm_enable & 0xF); | ||
1099 | sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_auto_pm_enable & 0xF)); | ||
1100 | sleep_cfg = ((sleep_cfg << 8) | (sleep->sva_power_on & 0xFF)); | ||
1101 | sleep_cfg = ((sleep_cfg << 8) | (sleep->sia_power_on & 0xFF)); | ||
1102 | sleep_cfg = ((sleep_cfg << 4) | (sleep->sva_policy & 0xF)); | ||
1103 | sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_policy & 0xF)); | ||
1104 | |||
1105 | idle_cfg = (idle->sva_auto_pm_enable & 0xF); | ||
1106 | idle_cfg = ((idle_cfg << 4) | (idle->sia_auto_pm_enable & 0xF)); | ||
1107 | idle_cfg = ((idle_cfg << 8) | (idle->sva_power_on & 0xFF)); | ||
1108 | idle_cfg = ((idle_cfg << 8) | (idle->sia_power_on & 0xFF)); | ||
1109 | idle_cfg = ((idle_cfg << 4) | (idle->sva_policy & 0xF)); | ||
1110 | idle_cfg = ((idle_cfg << 4) | (idle->sia_policy & 0xF)); | ||
1111 | |||
1112 | spin_lock_irqsave(&mb2_transfer.auto_pm_lock, flags); | ||
1113 | |||
1114 | /* | ||
1115 | * The autonomous power management configuration is done through | ||
1116 | * fields in mailbox 2, but these fields are only used as shared | ||
1117 | * variables - i.e. there is no need to send a message. | ||
1118 | */ | ||
1119 | writel(sleep_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_SLEEP)); | ||
1120 | writel(idle_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_IDLE)); | ||
1121 | |||
1122 | mb2_transfer.auto_pm_enabled = | ||
1123 | ((sleep->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) || | ||
1124 | (sleep->sia_auto_pm_enable == PRCMU_AUTO_PM_ON) || | ||
1125 | (idle->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) || | ||
1126 | (idle->sia_auto_pm_enable == PRCMU_AUTO_PM_ON)); | ||
1127 | |||
1128 | spin_unlock_irqrestore(&mb2_transfer.auto_pm_lock, flags); | ||
1129 | } | ||
1130 | EXPORT_SYMBOL(prcmu_configure_auto_pm); | ||
1131 | |||
1132 | bool prcmu_is_auto_pm_enabled(void) | ||
1133 | { | ||
1134 | return mb2_transfer.auto_pm_enabled; | ||
1135 | } | ||
1136 | |||
1137 | static int request_sysclk(bool enable) | ||
1138 | { | ||
1139 | int r; | ||
1140 | unsigned long flags; | ||
1141 | |||
1142 | r = 0; | ||
1143 | |||
1144 | mutex_lock(&mb3_transfer.sysclk_lock); | ||
1145 | |||
1146 | spin_lock_irqsave(&mb3_transfer.lock, flags); | ||
1147 | |||
1148 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(3)) | ||
1149 | cpu_relax(); | ||
1150 | |||
1151 | writeb((enable ? ON : OFF), (tcdm_base + PRCM_REQ_MB3_SYSCLK_MGT)); | ||
1152 | |||
1153 | writeb(MB3H_SYSCLK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB3)); | ||
1154 | writel(MBOX_BIT(3), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
1155 | |||
1156 | spin_unlock_irqrestore(&mb3_transfer.lock, flags); | ||
1157 | |||
1158 | /* | ||
1159 | * The firmware only sends an ACK if we want to enable the | ||
1160 | * SysClk, and it succeeds. | ||
1161 | */ | ||
1162 | if (enable && !wait_for_completion_timeout(&mb3_transfer.sysclk_work, | ||
1163 | msecs_to_jiffies(20000))) { | ||
1164 | pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", | ||
1165 | __func__); | ||
1166 | r = -EIO; | ||
1167 | } | ||
1168 | |||
1169 | mutex_unlock(&mb3_transfer.sysclk_lock); | ||
1170 | |||
1171 | return r; | ||
1172 | } | ||
1173 | |||
1174 | static int request_timclk(bool enable) | ||
1175 | { | ||
1176 | u32 val = (PRCM_TCR_DOZE_MODE | PRCM_TCR_TENSEL_MASK); | ||
1177 | |||
1178 | if (!enable) | ||
1179 | val |= PRCM_TCR_STOP_TIMERS; | ||
1180 | writel(val, (_PRCMU_BASE + PRCM_TCR)); | ||
1181 | |||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1185 | static int request_reg_clock(u8 clock, bool enable) | ||
1186 | { | ||
1187 | u32 val; | ||
1188 | unsigned long flags; | ||
1189 | |||
1190 | spin_lock_irqsave(&clk_mgt_lock, flags); | ||
1191 | |||
1192 | /* Grab the HW semaphore. */ | ||
1193 | while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0) | ||
1194 | cpu_relax(); | ||
1195 | |||
1196 | val = readl(_PRCMU_BASE + clk_mgt[clock].offset); | ||
1197 | if (enable) { | ||
1198 | val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw); | ||
1199 | } else { | ||
1200 | clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK); | ||
1201 | val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK); | ||
1202 | } | ||
1203 | writel(val, (_PRCMU_BASE + clk_mgt[clock].offset)); | ||
1204 | |||
1205 | /* Release the HW semaphore. */ | ||
1206 | writel(0, (_PRCMU_BASE + PRCM_SEM)); | ||
1207 | |||
1208 | spin_unlock_irqrestore(&clk_mgt_lock, flags); | ||
1209 | |||
1210 | return 0; | ||
1211 | } | ||
1212 | |||
1213 | /** | ||
1214 | * prcmu_request_clock() - Request for a clock to be enabled or disabled. | ||
1215 | * @clock: The clock for which the request is made. | ||
1216 | * @enable: Whether the clock should be enabled (true) or disabled (false). | ||
1217 | * | ||
1218 | * This function should only be used by the clock implementation. | ||
1219 | * Do not use it from any other place! | ||
1220 | */ | ||
1221 | int prcmu_request_clock(u8 clock, bool enable) | ||
1222 | { | ||
1223 | if (clock < PRCMU_NUM_REG_CLOCKS) | ||
1224 | return request_reg_clock(clock, enable); | ||
1225 | else if (clock == PRCMU_TIMCLK) | ||
1226 | return request_timclk(enable); | ||
1227 | else if (clock == PRCMU_SYSCLK) | ||
1228 | return request_sysclk(enable); | ||
1229 | else | ||
1230 | return -EINVAL; | ||
1231 | } | ||
1232 | |||
1233 | int prcmu_config_esram0_deep_sleep(u8 state) | ||
1234 | { | ||
1235 | if ((state > ESRAM0_DEEP_SLEEP_STATE_RET) || | ||
1236 | (state < ESRAM0_DEEP_SLEEP_STATE_OFF)) | ||
1237 | return -EINVAL; | ||
1238 | |||
1239 | mutex_lock(&mb4_transfer.lock); | ||
1240 | |||
1241 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4)) | ||
1242 | cpu_relax(); | ||
1243 | |||
1244 | writeb(MB4H_MEM_ST, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4)); | ||
1245 | writeb(((DDR_PWR_STATE_OFFHIGHLAT << 4) | DDR_PWR_STATE_ON), | ||
1246 | (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE)); | ||
1247 | writeb(DDR_PWR_STATE_ON, | ||
1248 | (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE)); | ||
1249 | writeb(state, (tcdm_base + PRCM_REQ_MB4_ESRAM0_ST)); | ||
1250 | |||
1251 | writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
1252 | wait_for_completion(&mb4_transfer.work); | ||
1253 | |||
1254 | mutex_unlock(&mb4_transfer.lock); | ||
1255 | |||
1256 | return 0; | ||
1257 | } | ||
1258 | |||
1259 | int prcmu_config_hotdog(u8 threshold) | ||
1260 | { | ||
1261 | mutex_lock(&mb4_transfer.lock); | ||
1262 | |||
1263 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4)) | ||
1264 | cpu_relax(); | ||
1265 | |||
1266 | writeb(threshold, (tcdm_base + PRCM_REQ_MB4_HOTDOG_THRESHOLD)); | ||
1267 | writeb(MB4H_HOTDOG, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4)); | ||
1268 | |||
1269 | writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
1270 | wait_for_completion(&mb4_transfer.work); | ||
1271 | |||
1272 | mutex_unlock(&mb4_transfer.lock); | ||
1273 | |||
1274 | return 0; | ||
1275 | } | ||
1276 | |||
1277 | int prcmu_config_hotmon(u8 low, u8 high) | ||
1278 | { | ||
1279 | mutex_lock(&mb4_transfer.lock); | ||
1280 | |||
1281 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4)) | ||
1282 | cpu_relax(); | ||
1283 | |||
1284 | writeb(low, (tcdm_base + PRCM_REQ_MB4_HOTMON_LOW)); | ||
1285 | writeb(high, (tcdm_base + PRCM_REQ_MB4_HOTMON_HIGH)); | ||
1286 | writeb((HOTMON_CONFIG_LOW | HOTMON_CONFIG_HIGH), | ||
1287 | (tcdm_base + PRCM_REQ_MB4_HOTMON_CONFIG)); | ||
1288 | writeb(MB4H_HOTMON, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4)); | ||
1289 | |||
1290 | writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
1291 | wait_for_completion(&mb4_transfer.work); | ||
1292 | |||
1293 | mutex_unlock(&mb4_transfer.lock); | ||
1294 | |||
1295 | return 0; | ||
1296 | } | ||
1297 | |||
1298 | static int config_hot_period(u16 val) | ||
1299 | { | ||
1300 | mutex_lock(&mb4_transfer.lock); | ||
1301 | |||
1302 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4)) | ||
1303 | cpu_relax(); | ||
1304 | |||
1305 | writew(val, (tcdm_base + PRCM_REQ_MB4_HOT_PERIOD)); | ||
1306 | writeb(MB4H_HOT_PERIOD, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4)); | ||
1307 | |||
1308 | writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
1309 | wait_for_completion(&mb4_transfer.work); | ||
1310 | |||
1311 | mutex_unlock(&mb4_transfer.lock); | ||
1312 | |||
1313 | return 0; | ||
1314 | } | ||
1315 | |||
1316 | int prcmu_start_temp_sense(u16 cycles32k) | ||
1317 | { | ||
1318 | if (cycles32k == 0xFFFF) | ||
1319 | return -EINVAL; | ||
1320 | |||
1321 | return config_hot_period(cycles32k); | ||
1322 | } | ||
1323 | |||
1324 | int prcmu_stop_temp_sense(void) | ||
1325 | { | ||
1326 | return config_hot_period(0xFFFF); | ||
1327 | } | ||
1328 | |||
1329 | /** | ||
1330 | * prcmu_set_clock_divider() - Configure the clock divider. | ||
1331 | * @clock: The clock for which the request is made. | ||
1332 | * @divider: The clock divider. (< 32) | ||
1333 | * | ||
1334 | * This function should only be used by the clock implementation. | ||
1335 | * Do not use it from any other place! | ||
1336 | */ | ||
1337 | int prcmu_set_clock_divider(u8 clock, u8 divider) | ||
1338 | { | ||
1339 | u32 val; | ||
1340 | unsigned long flags; | ||
1341 | |||
1342 | if ((clock >= PRCMU_NUM_REG_CLOCKS) || (divider < 1) || (31 < divider)) | ||
1343 | return -EINVAL; | ||
1344 | |||
1345 | spin_lock_irqsave(&clk_mgt_lock, flags); | ||
1346 | |||
1347 | /* Grab the HW semaphore. */ | ||
1348 | while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0) | ||
1349 | cpu_relax(); | ||
1350 | |||
1351 | val = readl(_PRCMU_BASE + clk_mgt[clock].offset); | ||
1352 | val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK); | ||
1353 | val |= (u32)divider; | ||
1354 | writel(val, (_PRCMU_BASE + clk_mgt[clock].offset)); | ||
1355 | |||
1356 | /* Release the HW semaphore. */ | ||
1357 | writel(0, (_PRCMU_BASE + PRCM_SEM)); | ||
1358 | |||
1359 | spin_unlock_irqrestore(&clk_mgt_lock, flags); | ||
1360 | |||
1361 | return 0; | ||
1362 | } | ||
1363 | |||
1364 | /** | ||
1365 | * prcmu_abb_read() - Read register value(s) from the ABB. | ||
1366 | * @slave: The I2C slave address. | ||
1367 | * @reg: The (start) register address. | ||
1368 | * @value: The read out value(s). | ||
1369 | * @size: The number of registers to read. | ||
1370 | * | ||
1371 | * Reads register value(s) from the ABB. | ||
1372 | * @size has to be 1 for the current firmware version. | ||
1373 | */ | ||
1374 | int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size) | ||
1375 | { | ||
1376 | int r; | ||
1377 | |||
1378 | if (size != 1) | ||
1379 | return -EINVAL; | ||
1380 | |||
1381 | mutex_lock(&mb5_transfer.lock); | ||
1382 | |||
1383 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(5)) | ||
1384 | cpu_relax(); | ||
1385 | |||
1386 | writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP)); | ||
1387 | writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS)); | ||
1388 | writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG)); | ||
1389 | writeb(0, (tcdm_base + PRCM_REQ_MB5_I2C_VAL)); | ||
1390 | |||
1391 | writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
1392 | |||
1393 | if (!wait_for_completion_timeout(&mb5_transfer.work, | ||
1394 | msecs_to_jiffies(20000))) { | ||
1395 | pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", | ||
1396 | __func__); | ||
1397 | r = -EIO; | ||
1398 | } else { | ||
1399 | r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO); | ||
1400 | } | ||
1401 | |||
1402 | if (!r) | ||
1403 | *value = mb5_transfer.ack.value; | ||
1404 | |||
1405 | mutex_unlock(&mb5_transfer.lock); | ||
1406 | |||
1407 | return r; | ||
1408 | } | ||
1409 | |||
1410 | /** | ||
1411 | * prcmu_abb_write() - Write register value(s) to the ABB. | ||
1412 | * @slave: The I2C slave address. | ||
1413 | * @reg: The (start) register address. | ||
1414 | * @value: The value(s) to write. | ||
1415 | * @size: The number of registers to write. | ||
1416 | * | ||
1417 | * Reads register value(s) from the ABB. | ||
1418 | * @size has to be 1 for the current firmware version. | ||
1419 | */ | ||
1420 | int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size) | ||
1421 | { | ||
1422 | int r; | ||
1423 | |||
1424 | if (size != 1) | ||
1425 | return -EINVAL; | ||
1426 | |||
1427 | mutex_lock(&mb5_transfer.lock); | ||
1428 | |||
1429 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(5)) | ||
1430 | cpu_relax(); | ||
1431 | |||
1432 | writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP)); | ||
1433 | writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS)); | ||
1434 | writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG)); | ||
1435 | writeb(*value, (tcdm_base + PRCM_REQ_MB5_I2C_VAL)); | ||
1436 | |||
1437 | writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
1438 | |||
1439 | if (!wait_for_completion_timeout(&mb5_transfer.work, | ||
1440 | msecs_to_jiffies(20000))) { | ||
1441 | pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", | ||
1442 | __func__); | ||
1443 | r = -EIO; | ||
1444 | } else { | ||
1445 | r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO); | ||
1446 | } | ||
1447 | |||
1448 | mutex_unlock(&mb5_transfer.lock); | ||
1449 | |||
1450 | return r; | ||
1451 | } | ||
1452 | |||
1453 | /** | ||
1454 | * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem | ||
1455 | */ | ||
1456 | void prcmu_ac_wake_req(void) | ||
1457 | { | ||
1458 | u32 val; | ||
1459 | |||
1460 | mutex_lock(&mb0_transfer.ac_wake_lock); | ||
1461 | |||
1462 | val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ); | ||
1463 | if (val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ) | ||
1464 | goto unlock_and_return; | ||
1465 | |||
1466 | atomic_set(&ac_wake_req_state, 1); | ||
1467 | |||
1468 | writel((val | PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ), | ||
1469 | (_PRCMU_BASE + PRCM_HOSTACCESS_REQ)); | ||
1470 | |||
1471 | if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work, | ||
1472 | msecs_to_jiffies(20000))) { | ||
1473 | pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", | ||
1474 | __func__); | ||
1475 | } | ||
1476 | |||
1477 | unlock_and_return: | ||
1478 | mutex_unlock(&mb0_transfer.ac_wake_lock); | ||
1479 | } | ||
1480 | |||
1481 | /** | ||
1482 | * prcmu_ac_sleep_req - called when ARM no longer needs to talk to modem | ||
1483 | */ | ||
1484 | void prcmu_ac_sleep_req() | ||
1485 | { | ||
1486 | u32 val; | ||
1487 | |||
1488 | mutex_lock(&mb0_transfer.ac_wake_lock); | ||
1489 | |||
1490 | val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ); | ||
1491 | if (!(val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ)) | ||
1492 | goto unlock_and_return; | ||
1493 | |||
1494 | writel((val & ~PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ), | ||
1495 | (_PRCMU_BASE + PRCM_HOSTACCESS_REQ)); | ||
1496 | |||
1497 | if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work, | ||
1498 | msecs_to_jiffies(20000))) { | ||
1499 | pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", | ||
1500 | __func__); | ||
1501 | } | ||
1502 | |||
1503 | atomic_set(&ac_wake_req_state, 0); | ||
1504 | |||
1505 | unlock_and_return: | ||
1506 | mutex_unlock(&mb0_transfer.ac_wake_lock); | ||
1507 | } | ||
1508 | |||
1509 | bool prcmu_is_ac_wake_requested(void) | ||
1510 | { | ||
1511 | return (atomic_read(&ac_wake_req_state) != 0); | ||
1512 | } | ||
1513 | |||
1514 | /** | ||
1515 | * prcmu_system_reset - System reset | ||
1516 | * | ||
1517 | * Saves the reset reason code and then sets the APE_SOFRST register which | ||
1518 | * fires interrupt to fw | ||
1519 | */ | ||
1520 | void prcmu_system_reset(u16 reset_code) | ||
1521 | { | ||
1522 | writew(reset_code, (tcdm_base + PRCM_SW_RST_REASON)); | ||
1523 | writel(1, (_PRCMU_BASE + PRCM_APE_SOFTRST)); | ||
1524 | } | ||
1525 | |||
1526 | /** | ||
1527 | * prcmu_reset_modem - ask the PRCMU to reset modem | ||
1528 | */ | ||
1529 | void prcmu_modem_reset(void) | ||
1530 | { | ||
1531 | mutex_lock(&mb1_transfer.lock); | ||
1532 | |||
1533 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) | ||
1534 | cpu_relax(); | ||
1535 | |||
1536 | writeb(MB1H_RESET_MODEM, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); | ||
1537 | writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
1538 | wait_for_completion(&mb1_transfer.work); | ||
1539 | |||
1540 | /* | ||
1541 | * No need to check return from PRCMU as modem should go in reset state | ||
1542 | * This state is already managed by upper layer | ||
1543 | */ | ||
1544 | |||
1545 | mutex_unlock(&mb1_transfer.lock); | ||
1546 | } | ||
1547 | |||
1548 | static void ack_dbb_wakeup(void) | ||
1549 | { | ||
1550 | unsigned long flags; | ||
1551 | |||
1552 | spin_lock_irqsave(&mb0_transfer.lock, flags); | ||
1553 | |||
1554 | while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) | ||
1555 | cpu_relax(); | ||
1556 | |||
1557 | writeb(MB0H_READ_WAKEUP_ACK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0)); | ||
1558 | writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); | ||
1559 | |||
1560 | spin_unlock_irqrestore(&mb0_transfer.lock, flags); | ||
1561 | } | ||
1562 | |||
1563 | static inline void print_unknown_header_warning(u8 n, u8 header) | ||
1564 | { | ||
1565 | pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n", | ||
1566 | header, n); | ||
1567 | } | ||
1568 | |||
1569 | static bool read_mailbox_0(void) | ||
1570 | { | ||
1571 | bool r; | ||
1572 | u32 ev; | ||
1573 | unsigned int n; | ||
1574 | u8 header; | ||
1575 | |||
1576 | header = readb(tcdm_base + PRCM_MBOX_HEADER_ACK_MB0); | ||
1577 | switch (header) { | ||
1578 | case MB0H_WAKEUP_EXE: | ||
1579 | case MB0H_WAKEUP_SLEEP: | ||
1580 | if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1) | ||
1581 | ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_1_8500); | ||
1582 | else | ||
1583 | ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_0_8500); | ||
1584 | |||
1585 | if (ev & (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK)) | ||
1586 | complete(&mb0_transfer.ac_wake_work); | ||
1587 | if (ev & WAKEUP_BIT_SYSCLK_OK) | ||
1588 | complete(&mb3_transfer.sysclk_work); | ||
1589 | |||
1590 | ev &= mb0_transfer.req.dbb_irqs; | ||
1591 | |||
1592 | for (n = 0; n < NUM_PRCMU_WAKEUPS; n++) { | ||
1593 | if (ev & prcmu_irq_bit[n]) | ||
1594 | generic_handle_irq(IRQ_PRCMU_BASE + n); | ||
1595 | } | ||
1596 | r = true; | ||
1597 | break; | ||
1598 | default: | ||
1599 | print_unknown_header_warning(0, header); | ||
1600 | r = false; | ||
1601 | break; | ||
1602 | } | ||
1603 | writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); | ||
1604 | return r; | ||
1605 | } | ||
1606 | |||
1607 | static bool read_mailbox_1(void) | ||
1608 | { | ||
1609 | mb1_transfer.ack.header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB1); | ||
1610 | mb1_transfer.ack.arm_opp = readb(tcdm_base + | ||
1611 | PRCM_ACK_MB1_CURRENT_ARM_OPP); | ||
1612 | mb1_transfer.ack.ape_opp = readb(tcdm_base + | ||
1613 | PRCM_ACK_MB1_CURRENT_APE_OPP); | ||
1614 | mb1_transfer.ack.ape_voltage_status = readb(tcdm_base + | ||
1615 | PRCM_ACK_MB1_APE_VOLTAGE_STATUS); | ||
1616 | writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); | ||
1617 | complete(&mb1_transfer.work); | ||
1618 | return false; | ||
1619 | } | ||
1620 | |||
1621 | static bool read_mailbox_2(void) | ||
1622 | { | ||
1623 | mb2_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB2_DPS_STATUS); | ||
1624 | writel(MBOX_BIT(2), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); | ||
1625 | complete(&mb2_transfer.work); | ||
1626 | return false; | ||
1627 | } | ||
1628 | |||
1629 | static bool read_mailbox_3(void) | ||
1630 | { | ||
1631 | writel(MBOX_BIT(3), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); | ||
1632 | return false; | ||
1633 | } | ||
1634 | |||
1635 | static bool read_mailbox_4(void) | ||
1636 | { | ||
1637 | u8 header; | ||
1638 | bool do_complete = true; | ||
1639 | |||
1640 | header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB4); | ||
1641 | switch (header) { | ||
1642 | case MB4H_MEM_ST: | ||
1643 | case MB4H_HOTDOG: | ||
1644 | case MB4H_HOTMON: | ||
1645 | case MB4H_HOT_PERIOD: | ||
1646 | break; | ||
1647 | default: | ||
1648 | print_unknown_header_warning(4, header); | ||
1649 | do_complete = false; | ||
1650 | break; | ||
1651 | } | ||
1652 | |||
1653 | writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); | ||
1654 | |||
1655 | if (do_complete) | ||
1656 | complete(&mb4_transfer.work); | ||
1657 | |||
1658 | return false; | ||
1659 | } | ||
1660 | |||
1661 | static bool read_mailbox_5(void) | ||
1662 | { | ||
1663 | mb5_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB5_I2C_STATUS); | ||
1664 | mb5_transfer.ack.value = readb(tcdm_base + PRCM_ACK_MB5_I2C_VAL); | ||
1665 | writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); | ||
1666 | complete(&mb5_transfer.work); | ||
1667 | return false; | ||
1668 | } | ||
1669 | |||
1670 | static bool read_mailbox_6(void) | ||
1671 | { | ||
1672 | writel(MBOX_BIT(6), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); | ||
1673 | return false; | ||
1674 | } | ||
1675 | |||
1676 | static bool read_mailbox_7(void) | ||
1677 | { | ||
1678 | writel(MBOX_BIT(7), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); | ||
1679 | return false; | ||
1680 | } | ||
1681 | |||
1682 | static bool (* const read_mailbox[NUM_MB])(void) = { | ||
1683 | read_mailbox_0, | ||
1684 | read_mailbox_1, | ||
1685 | read_mailbox_2, | ||
1686 | read_mailbox_3, | ||
1687 | read_mailbox_4, | ||
1688 | read_mailbox_5, | ||
1689 | read_mailbox_6, | ||
1690 | read_mailbox_7 | ||
1691 | }; | ||
1692 | |||
1693 | static irqreturn_t prcmu_irq_handler(int irq, void *data) | ||
1694 | { | ||
1695 | u32 bits; | ||
1696 | u8 n; | ||
1697 | irqreturn_t r; | ||
1698 | |||
1699 | bits = (readl(_PRCMU_BASE + PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS); | ||
1700 | if (unlikely(!bits)) | ||
1701 | return IRQ_NONE; | ||
1702 | |||
1703 | r = IRQ_HANDLED; | ||
1704 | for (n = 0; bits; n++) { | ||
1705 | if (bits & MBOX_BIT(n)) { | ||
1706 | bits -= MBOX_BIT(n); | ||
1707 | if (read_mailbox[n]()) | ||
1708 | r = IRQ_WAKE_THREAD; | ||
1709 | } | ||
1710 | } | ||
1711 | return r; | ||
1712 | } | ||
1713 | |||
1714 | static irqreturn_t prcmu_irq_thread_fn(int irq, void *data) | ||
1715 | { | ||
1716 | ack_dbb_wakeup(); | ||
1717 | return IRQ_HANDLED; | ||
1718 | } | ||
1719 | |||
1720 | static void prcmu_mask_work(struct work_struct *work) | ||
1721 | { | ||
1722 | unsigned long flags; | ||
1723 | |||
1724 | spin_lock_irqsave(&mb0_transfer.lock, flags); | ||
1725 | |||
1726 | config_wakeups(); | ||
1727 | |||
1728 | spin_unlock_irqrestore(&mb0_transfer.lock, flags); | ||
1729 | } | ||
1730 | |||
1731 | static void prcmu_irq_mask(struct irq_data *d) | ||
1732 | { | ||
1733 | unsigned long flags; | ||
1734 | |||
1735 | spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); | ||
1736 | |||
1737 | mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE]; | ||
1738 | |||
1739 | spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); | ||
1740 | |||
1741 | if (d->irq != IRQ_PRCMU_CA_SLEEP) | ||
1742 | schedule_work(&mb0_transfer.mask_work); | ||
1743 | } | ||
1744 | |||
1745 | static void prcmu_irq_unmask(struct irq_data *d) | ||
1746 | { | ||
1747 | unsigned long flags; | ||
1748 | |||
1749 | spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); | ||
1750 | |||
1751 | mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE]; | ||
1752 | |||
1753 | spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); | ||
1754 | |||
1755 | if (d->irq != IRQ_PRCMU_CA_SLEEP) | ||
1756 | schedule_work(&mb0_transfer.mask_work); | ||
1757 | } | ||
1758 | |||
1759 | static void noop(struct irq_data *d) | ||
1760 | { | ||
1761 | } | ||
1762 | |||
1763 | static struct irq_chip prcmu_irq_chip = { | ||
1764 | .name = "prcmu", | ||
1765 | .irq_disable = prcmu_irq_mask, | ||
1766 | .irq_ack = noop, | ||
1767 | .irq_mask = prcmu_irq_mask, | ||
1768 | .irq_unmask = prcmu_irq_unmask, | ||
1769 | }; | ||
1770 | |||
1771 | void __init prcmu_early_init(void) | ||
1772 | { | ||
1773 | unsigned int i; | ||
1774 | |||
1775 | if (cpu_is_u8500v1()) { | ||
1776 | tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1); | ||
1777 | } else if (cpu_is_u8500v2()) { | ||
1778 | void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K); | ||
1779 | |||
1780 | if (tcpm_base != NULL) { | ||
1781 | int version; | ||
1782 | version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET); | ||
1783 | prcmu_version.project_number = version & 0xFF; | ||
1784 | prcmu_version.api_version = (version >> 8) & 0xFF; | ||
1785 | prcmu_version.func_version = (version >> 16) & 0xFF; | ||
1786 | prcmu_version.errata = (version >> 24) & 0xFF; | ||
1787 | pr_info("PRCMU firmware version %d.%d.%d\n", | ||
1788 | (version >> 8) & 0xFF, (version >> 16) & 0xFF, | ||
1789 | (version >> 24) & 0xFF); | ||
1790 | iounmap(tcpm_base); | ||
1791 | } | ||
1792 | |||
1793 | tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE); | ||
1794 | } else { | ||
1795 | pr_err("prcmu: Unsupported chip version\n"); | ||
1796 | BUG(); | ||
1797 | } | ||
1798 | |||
1799 | spin_lock_init(&mb0_transfer.lock); | ||
1800 | spin_lock_init(&mb0_transfer.dbb_irqs_lock); | ||
1801 | mutex_init(&mb0_transfer.ac_wake_lock); | ||
1802 | init_completion(&mb0_transfer.ac_wake_work); | ||
1803 | mutex_init(&mb1_transfer.lock); | ||
1804 | init_completion(&mb1_transfer.work); | ||
1805 | mutex_init(&mb2_transfer.lock); | ||
1806 | init_completion(&mb2_transfer.work); | ||
1807 | spin_lock_init(&mb2_transfer.auto_pm_lock); | ||
1808 | spin_lock_init(&mb3_transfer.lock); | ||
1809 | mutex_init(&mb3_transfer.sysclk_lock); | ||
1810 | init_completion(&mb3_transfer.sysclk_work); | ||
1811 | mutex_init(&mb4_transfer.lock); | ||
1812 | init_completion(&mb4_transfer.work); | ||
1813 | mutex_init(&mb5_transfer.lock); | ||
1814 | init_completion(&mb5_transfer.work); | ||
1815 | |||
1816 | INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work); | ||
1817 | |||
1818 | /* Initalize irqs. */ | ||
1819 | for (i = 0; i < NUM_PRCMU_WAKEUPS; i++) { | ||
1820 | unsigned int irq; | ||
1821 | |||
1822 | irq = IRQ_PRCMU_BASE + i; | ||
1823 | irq_set_chip_and_handler(irq, &prcmu_irq_chip, | ||
1824 | handle_simple_irq); | ||
1825 | set_irq_flags(irq, IRQF_VALID); | ||
1826 | } | ||
1827 | } | ||
1828 | |||
1829 | /* | ||
1830 | * Power domain switches (ePODs) modeled as regulators for the DB8500 SoC | ||
1831 | */ | ||
1832 | static struct regulator_consumer_supply db8500_vape_consumers[] = { | ||
1833 | REGULATOR_SUPPLY("v-ape", NULL), | ||
1834 | REGULATOR_SUPPLY("v-i2c", "nmk-i2c.0"), | ||
1835 | REGULATOR_SUPPLY("v-i2c", "nmk-i2c.1"), | ||
1836 | REGULATOR_SUPPLY("v-i2c", "nmk-i2c.2"), | ||
1837 | REGULATOR_SUPPLY("v-i2c", "nmk-i2c.3"), | ||
1838 | /* "v-mmc" changed to "vcore" in the mainline kernel */ | ||
1839 | REGULATOR_SUPPLY("vcore", "sdi0"), | ||
1840 | REGULATOR_SUPPLY("vcore", "sdi1"), | ||
1841 | REGULATOR_SUPPLY("vcore", "sdi2"), | ||
1842 | REGULATOR_SUPPLY("vcore", "sdi3"), | ||
1843 | REGULATOR_SUPPLY("vcore", "sdi4"), | ||
1844 | REGULATOR_SUPPLY("v-dma", "dma40.0"), | ||
1845 | REGULATOR_SUPPLY("v-ape", "ab8500-usb.0"), | ||
1846 | /* "v-uart" changed to "vcore" in the mainline kernel */ | ||
1847 | REGULATOR_SUPPLY("vcore", "uart0"), | ||
1848 | REGULATOR_SUPPLY("vcore", "uart1"), | ||
1849 | REGULATOR_SUPPLY("vcore", "uart2"), | ||
1850 | REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"), | ||
1851 | }; | ||
1852 | |||
1853 | static struct regulator_consumer_supply db8500_vsmps2_consumers[] = { | ||
1854 | /* CG2900 and CW1200 power to off-chip peripherals */ | ||
1855 | REGULATOR_SUPPLY("gbf_1v8", "cg2900-uart.0"), | ||
1856 | REGULATOR_SUPPLY("wlan_1v8", "cw1200.0"), | ||
1857 | REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"), | ||
1858 | /* AV8100 regulator */ | ||
1859 | REGULATOR_SUPPLY("hdmi_1v8", "0-0070"), | ||
1860 | }; | ||
1861 | |||
1862 | static struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = { | ||
1863 | REGULATOR_SUPPLY("vsupply", "b2r2.0"), | ||
1864 | REGULATOR_SUPPLY("vsupply", "mcde.0"), | ||
1865 | }; | ||
1866 | |||
1867 | static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = { | ||
1868 | [DB8500_REGULATOR_VAPE] = { | ||
1869 | .constraints = { | ||
1870 | .name = "db8500-vape", | ||
1871 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1872 | }, | ||
1873 | .consumer_supplies = db8500_vape_consumers, | ||
1874 | .num_consumer_supplies = ARRAY_SIZE(db8500_vape_consumers), | ||
1875 | }, | ||
1876 | [DB8500_REGULATOR_VARM] = { | ||
1877 | .constraints = { | ||
1878 | .name = "db8500-varm", | ||
1879 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1880 | }, | ||
1881 | }, | ||
1882 | [DB8500_REGULATOR_VMODEM] = { | ||
1883 | .constraints = { | ||
1884 | .name = "db8500-vmodem", | ||
1885 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1886 | }, | ||
1887 | }, | ||
1888 | [DB8500_REGULATOR_VPLL] = { | ||
1889 | .constraints = { | ||
1890 | .name = "db8500-vpll", | ||
1891 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1892 | }, | ||
1893 | }, | ||
1894 | [DB8500_REGULATOR_VSMPS1] = { | ||
1895 | .constraints = { | ||
1896 | .name = "db8500-vsmps1", | ||
1897 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1898 | }, | ||
1899 | }, | ||
1900 | [DB8500_REGULATOR_VSMPS2] = { | ||
1901 | .constraints = { | ||
1902 | .name = "db8500-vsmps2", | ||
1903 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1904 | }, | ||
1905 | .consumer_supplies = db8500_vsmps2_consumers, | ||
1906 | .num_consumer_supplies = ARRAY_SIZE(db8500_vsmps2_consumers), | ||
1907 | }, | ||
1908 | [DB8500_REGULATOR_VSMPS3] = { | ||
1909 | .constraints = { | ||
1910 | .name = "db8500-vsmps3", | ||
1911 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1912 | }, | ||
1913 | }, | ||
1914 | [DB8500_REGULATOR_VRF1] = { | ||
1915 | .constraints = { | ||
1916 | .name = "db8500-vrf1", | ||
1917 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1918 | }, | ||
1919 | }, | ||
1920 | [DB8500_REGULATOR_SWITCH_SVAMMDSP] = { | ||
1921 | .supply_regulator = "db8500-vape", | ||
1922 | .constraints = { | ||
1923 | .name = "db8500-sva-mmdsp", | ||
1924 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1925 | }, | ||
1926 | }, | ||
1927 | [DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = { | ||
1928 | .constraints = { | ||
1929 | /* "ret" means "retention" */ | ||
1930 | .name = "db8500-sva-mmdsp-ret", | ||
1931 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1932 | }, | ||
1933 | }, | ||
1934 | [DB8500_REGULATOR_SWITCH_SVAPIPE] = { | ||
1935 | .supply_regulator = "db8500-vape", | ||
1936 | .constraints = { | ||
1937 | .name = "db8500-sva-pipe", | ||
1938 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1939 | }, | ||
1940 | }, | ||
1941 | [DB8500_REGULATOR_SWITCH_SIAMMDSP] = { | ||
1942 | .supply_regulator = "db8500-vape", | ||
1943 | .constraints = { | ||
1944 | .name = "db8500-sia-mmdsp", | ||
1945 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1946 | }, | ||
1947 | }, | ||
1948 | [DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = { | ||
1949 | .constraints = { | ||
1950 | .name = "db8500-sia-mmdsp-ret", | ||
1951 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1952 | }, | ||
1953 | }, | ||
1954 | [DB8500_REGULATOR_SWITCH_SIAPIPE] = { | ||
1955 | .supply_regulator = "db8500-vape", | ||
1956 | .constraints = { | ||
1957 | .name = "db8500-sia-pipe", | ||
1958 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1959 | }, | ||
1960 | }, | ||
1961 | [DB8500_REGULATOR_SWITCH_SGA] = { | ||
1962 | .supply_regulator = "db8500-vape", | ||
1963 | .constraints = { | ||
1964 | .name = "db8500-sga", | ||
1965 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1966 | }, | ||
1967 | }, | ||
1968 | [DB8500_REGULATOR_SWITCH_B2R2_MCDE] = { | ||
1969 | .supply_regulator = "db8500-vape", | ||
1970 | .constraints = { | ||
1971 | .name = "db8500-b2r2-mcde", | ||
1972 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1973 | }, | ||
1974 | .consumer_supplies = db8500_b2r2_mcde_consumers, | ||
1975 | .num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers), | ||
1976 | }, | ||
1977 | [DB8500_REGULATOR_SWITCH_ESRAM12] = { | ||
1978 | .supply_regulator = "db8500-vape", | ||
1979 | .constraints = { | ||
1980 | .name = "db8500-esram12", | ||
1981 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1982 | }, | ||
1983 | }, | ||
1984 | [DB8500_REGULATOR_SWITCH_ESRAM12RET] = { | ||
1985 | .constraints = { | ||
1986 | .name = "db8500-esram12-ret", | ||
1987 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1988 | }, | ||
1989 | }, | ||
1990 | [DB8500_REGULATOR_SWITCH_ESRAM34] = { | ||
1991 | .supply_regulator = "db8500-vape", | ||
1992 | .constraints = { | ||
1993 | .name = "db8500-esram34", | ||
1994 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
1995 | }, | ||
1996 | }, | ||
1997 | [DB8500_REGULATOR_SWITCH_ESRAM34RET] = { | ||
1998 | .constraints = { | ||
1999 | .name = "db8500-esram34-ret", | ||
2000 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
2001 | }, | ||
2002 | }, | ||
2003 | }; | ||
2004 | |||
2005 | static struct mfd_cell db8500_prcmu_devs[] = { | ||
2006 | { | ||
2007 | .name = "db8500-prcmu-regulators", | ||
2008 | .platform_data = &db8500_regulators, | ||
2009 | .pdata_size = sizeof(db8500_regulators), | ||
2010 | }, | ||
2011 | { | ||
2012 | .name = "cpufreq-u8500", | ||
2013 | }, | ||
2014 | }; | ||
2015 | |||
2016 | /** | ||
2017 | * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic | ||
2018 | * | ||
2019 | */ | ||
2020 | static int __init db8500_prcmu_probe(struct platform_device *pdev) | ||
2021 | { | ||
2022 | int err = 0; | ||
2023 | |||
2024 | if (ux500_is_svp()) | ||
2025 | return -ENODEV; | ||
2026 | |||
2027 | /* Clean up the mailbox interrupts after pre-kernel code. */ | ||
2028 | writel(ALL_MBOX_BITS, (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); | ||
2029 | |||
2030 | err = request_threaded_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler, | ||
2031 | prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL); | ||
2032 | if (err < 0) { | ||
2033 | pr_err("prcmu: Failed to allocate IRQ_DB8500_PRCMU1.\n"); | ||
2034 | err = -EBUSY; | ||
2035 | goto no_irq_return; | ||
2036 | } | ||
2037 | |||
2038 | if (cpu_is_u8500v20_or_later()) | ||
2039 | prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); | ||
2040 | |||
2041 | err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, | ||
2042 | ARRAY_SIZE(db8500_prcmu_devs), NULL, | ||
2043 | 0); | ||
2044 | |||
2045 | if (err) | ||
2046 | pr_err("prcmu: Failed to add subdevices\n"); | ||
2047 | else | ||
2048 | pr_info("DB8500 PRCMU initialized\n"); | ||
2049 | |||
2050 | no_irq_return: | ||
2051 | return err; | ||
2052 | } | ||
2053 | |||
2054 | static struct platform_driver db8500_prcmu_driver = { | ||
2055 | .driver = { | ||
2056 | .name = "db8500-prcmu", | ||
2057 | .owner = THIS_MODULE, | ||
2058 | }, | ||
2059 | }; | ||
2060 | |||
2061 | static int __init db8500_prcmu_init(void) | ||
2062 | { | ||
2063 | return platform_driver_probe(&db8500_prcmu_driver, db8500_prcmu_probe); | ||
2064 | } | ||
2065 | |||
2066 | arch_initcall(db8500_prcmu_init); | ||
2067 | |||
2068 | MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com>"); | ||
2069 | MODULE_DESCRIPTION("DB8500 PRCM Unit driver"); | ||
2070 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 134c69aa4790..43a76c41cfcc 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c | |||
@@ -144,26 +144,27 @@ int pcap_to_irq(struct pcap_chip *pcap, int irq) | |||
144 | } | 144 | } |
145 | EXPORT_SYMBOL_GPL(pcap_to_irq); | 145 | EXPORT_SYMBOL_GPL(pcap_to_irq); |
146 | 146 | ||
147 | static void pcap_mask_irq(unsigned int irq) | 147 | static void pcap_mask_irq(struct irq_data *d) |
148 | { | 148 | { |
149 | struct pcap_chip *pcap = get_irq_chip_data(irq); | 149 | struct pcap_chip *pcap = irq_data_get_irq_chip_data(d); |
150 | 150 | ||
151 | pcap->msr |= 1 << irq_to_pcap(pcap, irq); | 151 | pcap->msr |= 1 << irq_to_pcap(pcap, d->irq); |
152 | queue_work(pcap->workqueue, &pcap->msr_work); | 152 | queue_work(pcap->workqueue, &pcap->msr_work); |
153 | } | 153 | } |
154 | 154 | ||
155 | static void pcap_unmask_irq(unsigned int irq) | 155 | static void pcap_unmask_irq(struct irq_data *d) |
156 | { | 156 | { |
157 | struct pcap_chip *pcap = get_irq_chip_data(irq); | 157 | struct pcap_chip *pcap = irq_data_get_irq_chip_data(d); |
158 | 158 | ||
159 | pcap->msr &= ~(1 << irq_to_pcap(pcap, irq)); | 159 | pcap->msr &= ~(1 << irq_to_pcap(pcap, d->irq)); |
160 | queue_work(pcap->workqueue, &pcap->msr_work); | 160 | queue_work(pcap->workqueue, &pcap->msr_work); |
161 | } | 161 | } |
162 | 162 | ||
163 | static struct irq_chip pcap_irq_chip = { | 163 | static struct irq_chip pcap_irq_chip = { |
164 | .name = "pcap", | 164 | .name = "pcap", |
165 | .mask = pcap_mask_irq, | 165 | .irq_disable = pcap_mask_irq, |
166 | .unmask = pcap_unmask_irq, | 166 | .irq_mask = pcap_mask_irq, |
167 | .irq_unmask = pcap_unmask_irq, | ||
167 | }; | 168 | }; |
168 | 169 | ||
169 | static void pcap_msr_work(struct work_struct *work) | 170 | static void pcap_msr_work(struct work_struct *work) |
@@ -184,7 +185,7 @@ static void pcap_isr_work(struct work_struct *work) | |||
184 | ezx_pcap_read(pcap, PCAP_REG_MSR, &msr); | 185 | ezx_pcap_read(pcap, PCAP_REG_MSR, &msr); |
185 | ezx_pcap_read(pcap, PCAP_REG_ISR, &isr); | 186 | ezx_pcap_read(pcap, PCAP_REG_ISR, &isr); |
186 | 187 | ||
187 | /* We cant service/ack irqs that are assigned to port 2 */ | 188 | /* We can't service/ack irqs that are assigned to port 2 */ |
188 | if (!(pdata->config & PCAP_SECOND_PORT)) { | 189 | if (!(pdata->config & PCAP_SECOND_PORT)) { |
189 | ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel); | 190 | ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel); |
190 | isr &= ~int_sel; | 191 | isr &= ~int_sel; |
@@ -196,18 +197,8 @@ static void pcap_isr_work(struct work_struct *work) | |||
196 | local_irq_disable(); | 197 | local_irq_disable(); |
197 | service = isr & ~msr; | 198 | service = isr & ~msr; |
198 | for (irq = pcap->irq_base; service; service >>= 1, irq++) { | 199 | for (irq = pcap->irq_base; service; service >>= 1, irq++) { |
199 | if (service & 1) { | 200 | if (service & 1) |
200 | struct irq_desc *desc = irq_to_desc(irq); | 201 | generic_handle_irq(irq); |
201 | |||
202 | if (WARN(!desc, KERN_WARNING | ||
203 | "Invalid PCAP IRQ %d\n", irq)) | ||
204 | break; | ||
205 | |||
206 | if (desc->status & IRQ_DISABLED) | ||
207 | note_interrupt(irq, desc, IRQ_NONE); | ||
208 | else | ||
209 | desc->handle_irq(irq, desc); | ||
210 | } | ||
211 | } | 202 | } |
212 | local_irq_enable(); | 203 | local_irq_enable(); |
213 | ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr); | 204 | ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr); |
@@ -216,9 +207,9 @@ static void pcap_isr_work(struct work_struct *work) | |||
216 | 207 | ||
217 | static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) | 208 | static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) |
218 | { | 209 | { |
219 | struct pcap_chip *pcap = get_irq_data(irq); | 210 | struct pcap_chip *pcap = irq_get_handler_data(irq); |
220 | 211 | ||
221 | desc->chip->ack(irq); | 212 | desc->irq_data.chip->irq_ack(&desc->irq_data); |
222 | queue_work(pcap->workqueue, &pcap->isr_work); | 213 | queue_work(pcap->workqueue, &pcap->isr_work); |
223 | return; | 214 | return; |
224 | } | 215 | } |
@@ -282,7 +273,7 @@ static irqreturn_t pcap_adc_irq(int irq, void *_pcap) | |||
282 | mutex_lock(&pcap->adc_mutex); | 273 | mutex_lock(&pcap->adc_mutex); |
283 | req = pcap->adc_queue[pcap->adc_head]; | 274 | req = pcap->adc_queue[pcap->adc_head]; |
284 | 275 | ||
285 | if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) { | 276 | if (WARN(!req, "adc irq without pending request\n")) { |
286 | mutex_unlock(&pcap->adc_mutex); | 277 | mutex_unlock(&pcap->adc_mutex); |
287 | return IRQ_HANDLED; | 278 | return IRQ_HANDLED; |
288 | } | 279 | } |
@@ -384,12 +375,20 @@ static int __devinit pcap_add_subdev(struct pcap_chip *pcap, | |||
384 | struct pcap_subdev *subdev) | 375 | struct pcap_subdev *subdev) |
385 | { | 376 | { |
386 | struct platform_device *pdev; | 377 | struct platform_device *pdev; |
378 | int ret; | ||
387 | 379 | ||
388 | pdev = platform_device_alloc(subdev->name, subdev->id); | 380 | pdev = platform_device_alloc(subdev->name, subdev->id); |
381 | if (!pdev) | ||
382 | return -ENOMEM; | ||
383 | |||
389 | pdev->dev.parent = &pcap->spi->dev; | 384 | pdev->dev.parent = &pcap->spi->dev; |
390 | pdev->dev.platform_data = subdev->platform_data; | 385 | pdev->dev.platform_data = subdev->platform_data; |
391 | 386 | ||
392 | return platform_device_add(pdev); | 387 | ret = platform_device_add(pdev); |
388 | if (ret) | ||
389 | platform_device_put(pdev); | ||
390 | |||
391 | return ret; | ||
393 | } | 392 | } |
394 | 393 | ||
395 | static int __devexit ezx_pcap_remove(struct spi_device *spi) | 394 | static int __devexit ezx_pcap_remove(struct spi_device *spi) |
@@ -412,7 +411,7 @@ static int __devexit ezx_pcap_remove(struct spi_device *spi) | |||
412 | 411 | ||
413 | /* cleanup irqchip */ | 412 | /* cleanup irqchip */ |
414 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) | 413 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) |
415 | set_irq_chip_and_handler(i, NULL, NULL); | 414 | irq_set_chip_and_handler(i, NULL, NULL); |
416 | 415 | ||
417 | destroy_workqueue(pcap->workqueue); | 416 | destroy_workqueue(pcap->workqueue); |
418 | 417 | ||
@@ -457,7 +456,8 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi) | |||
457 | pcap->irq_base = pdata->irq_base; | 456 | pcap->irq_base = pdata->irq_base; |
458 | pcap->workqueue = create_singlethread_workqueue("pcapd"); | 457 | pcap->workqueue = create_singlethread_workqueue("pcapd"); |
459 | if (!pcap->workqueue) { | 458 | if (!pcap->workqueue) { |
460 | dev_err(&spi->dev, "cant create pcap thread\n"); | 459 | ret = -ENOMEM; |
460 | dev_err(&spi->dev, "can't create pcap thread\n"); | ||
461 | goto free_pcap; | 461 | goto free_pcap; |
462 | } | 462 | } |
463 | 463 | ||
@@ -468,12 +468,12 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi) | |||
468 | 468 | ||
469 | /* setup irq chip */ | 469 | /* setup irq chip */ |
470 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) { | 470 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) { |
471 | set_irq_chip_and_handler(i, &pcap_irq_chip, handle_simple_irq); | 471 | irq_set_chip_and_handler(i, &pcap_irq_chip, handle_simple_irq); |
472 | set_irq_chip_data(i, pcap); | 472 | irq_set_chip_data(i, pcap); |
473 | #ifdef CONFIG_ARM | 473 | #ifdef CONFIG_ARM |
474 | set_irq_flags(i, IRQF_VALID); | 474 | set_irq_flags(i, IRQF_VALID); |
475 | #else | 475 | #else |
476 | set_irq_noprobe(i); | 476 | irq_set_noprobe(i); |
477 | #endif | 477 | #endif |
478 | } | 478 | } |
479 | 479 | ||
@@ -482,10 +482,10 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi) | |||
482 | ezx_pcap_write(pcap, PCAP_REG_ISR, PCAP_CLEAR_INTERRUPT_REGISTER); | 482 | ezx_pcap_write(pcap, PCAP_REG_ISR, PCAP_CLEAR_INTERRUPT_REGISTER); |
483 | pcap->msr = PCAP_MASK_ALL_INTERRUPT; | 483 | pcap->msr = PCAP_MASK_ALL_INTERRUPT; |
484 | 484 | ||
485 | set_irq_type(spi->irq, IRQ_TYPE_EDGE_RISING); | 485 | irq_set_irq_type(spi->irq, IRQ_TYPE_EDGE_RISING); |
486 | set_irq_data(spi->irq, pcap); | 486 | irq_set_handler_data(spi->irq, pcap); |
487 | set_irq_chained_handler(spi->irq, pcap_irq_handler); | 487 | irq_set_chained_handler(spi->irq, pcap_irq_handler); |
488 | set_irq_wake(spi->irq, 1); | 488 | irq_set_irq_wake(spi->irq, 1); |
489 | 489 | ||
490 | /* ADC */ | 490 | /* ADC */ |
491 | adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? | 491 | adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? |
@@ -514,7 +514,7 @@ remove_subdevs: | |||
514 | free_irq(adc_irq, pcap); | 514 | free_irq(adc_irq, pcap); |
515 | free_irqchip: | 515 | free_irqchip: |
516 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) | 516 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) |
517 | set_irq_chip_and_handler(i, NULL, NULL); | 517 | irq_set_chip_and_handler(i, NULL, NULL); |
518 | /* destroy_workqueue: */ | 518 | /* destroy_workqueue: */ |
519 | destroy_workqueue(pcap->workqueue); | 519 | destroy_workqueue(pcap->workqueue); |
520 | free_pcap: | 520 | free_pcap: |
diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c index d3e74f8585e0..bbaec0ccba8f 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/mfd/htc-egpio.c | |||
@@ -70,36 +70,37 @@ static inline void ack_irqs(struct egpio_info *ei) | |||
70 | ei->ack_write, ei->ack_register << ei->bus_shift); | 70 | ei->ack_write, ei->ack_register << ei->bus_shift); |
71 | } | 71 | } |
72 | 72 | ||
73 | static void egpio_ack(unsigned int irq) | 73 | static void egpio_ack(struct irq_data *data) |
74 | { | 74 | { |
75 | } | 75 | } |
76 | 76 | ||
77 | /* There does not appear to be a way to proactively mask interrupts | 77 | /* There does not appear to be a way to proactively mask interrupts |
78 | * on the egpio chip itself. So, we simply ignore interrupts that | 78 | * on the egpio chip itself. So, we simply ignore interrupts that |
79 | * aren't desired. */ | 79 | * aren't desired. */ |
80 | static void egpio_mask(unsigned int irq) | 80 | static void egpio_mask(struct irq_data *data) |
81 | { | 81 | { |
82 | struct egpio_info *ei = get_irq_chip_data(irq); | 82 | struct egpio_info *ei = irq_data_get_irq_chip_data(data); |
83 | ei->irqs_enabled &= ~(1 << (irq - ei->irq_start)); | 83 | ei->irqs_enabled &= ~(1 << (data->irq - ei->irq_start)); |
84 | pr_debug("EGPIO mask %d %04x\n", irq, ei->irqs_enabled); | 84 | pr_debug("EGPIO mask %d %04x\n", data->irq, ei->irqs_enabled); |
85 | } | 85 | } |
86 | static void egpio_unmask(unsigned int irq) | 86 | |
87 | static void egpio_unmask(struct irq_data *data) | ||
87 | { | 88 | { |
88 | struct egpio_info *ei = get_irq_chip_data(irq); | 89 | struct egpio_info *ei = irq_data_get_irq_chip_data(data); |
89 | ei->irqs_enabled |= 1 << (irq - ei->irq_start); | 90 | ei->irqs_enabled |= 1 << (data->irq - ei->irq_start); |
90 | pr_debug("EGPIO unmask %d %04x\n", irq, ei->irqs_enabled); | 91 | pr_debug("EGPIO unmask %d %04x\n", data->irq, ei->irqs_enabled); |
91 | } | 92 | } |
92 | 93 | ||
93 | static struct irq_chip egpio_muxed_chip = { | 94 | static struct irq_chip egpio_muxed_chip = { |
94 | .name = "htc-egpio", | 95 | .name = "htc-egpio", |
95 | .ack = egpio_ack, | 96 | .irq_ack = egpio_ack, |
96 | .mask = egpio_mask, | 97 | .irq_mask = egpio_mask, |
97 | .unmask = egpio_unmask, | 98 | .irq_unmask = egpio_unmask, |
98 | }; | 99 | }; |
99 | 100 | ||
100 | static void egpio_handler(unsigned int irq, struct irq_desc *desc) | 101 | static void egpio_handler(unsigned int irq, struct irq_desc *desc) |
101 | { | 102 | { |
102 | struct egpio_info *ei = get_irq_data(irq); | 103 | struct egpio_info *ei = irq_desc_get_handler_data(desc); |
103 | int irqpin; | 104 | int irqpin; |
104 | 105 | ||
105 | /* Read current pins. */ | 106 | /* Read current pins. */ |
@@ -112,9 +113,7 @@ static void egpio_handler(unsigned int irq, struct irq_desc *desc) | |||
112 | for_each_set_bit(irqpin, &readval, ei->nirqs) { | 113 | for_each_set_bit(irqpin, &readval, ei->nirqs) { |
113 | /* Run irq handler */ | 114 | /* Run irq handler */ |
114 | pr_debug("got IRQ %d\n", irqpin); | 115 | pr_debug("got IRQ %d\n", irqpin); |
115 | irq = ei->irq_start + irqpin; | 116 | generic_handle_irq(ei->irq_start + irqpin); |
116 | desc = irq_to_desc(irq); | ||
117 | desc->handle_irq(irq, desc); | ||
118 | } | 117 | } |
119 | } | 118 | } |
120 | 119 | ||
@@ -345,14 +344,14 @@ static int __init egpio_probe(struct platform_device *pdev) | |||
345 | ei->ack_write = 0; | 344 | ei->ack_write = 0; |
346 | irq_end = ei->irq_start + ei->nirqs; | 345 | irq_end = ei->irq_start + ei->nirqs; |
347 | for (irq = ei->irq_start; irq < irq_end; irq++) { | 346 | for (irq = ei->irq_start; irq < irq_end; irq++) { |
348 | set_irq_chip(irq, &egpio_muxed_chip); | 347 | irq_set_chip_and_handler(irq, &egpio_muxed_chip, |
349 | set_irq_chip_data(irq, ei); | 348 | handle_simple_irq); |
350 | set_irq_handler(irq, handle_simple_irq); | 349 | irq_set_chip_data(irq, ei); |
351 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 350 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
352 | } | 351 | } |
353 | set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING); | 352 | irq_set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING); |
354 | set_irq_data(ei->chained_irq, ei); | 353 | irq_set_handler_data(ei->chained_irq, ei); |
355 | set_irq_chained_handler(ei->chained_irq, egpio_handler); | 354 | irq_set_chained_handler(ei->chained_irq, egpio_handler); |
356 | ack_irqs(ei); | 355 | ack_irqs(ei); |
357 | 356 | ||
358 | device_init_wakeup(&pdev->dev, 1); | 357 | device_init_wakeup(&pdev->dev, 1); |
@@ -374,11 +373,10 @@ static int __exit egpio_remove(struct platform_device *pdev) | |||
374 | if (ei->chained_irq) { | 373 | if (ei->chained_irq) { |
375 | irq_end = ei->irq_start + ei->nirqs; | 374 | irq_end = ei->irq_start + ei->nirqs; |
376 | for (irq = ei->irq_start; irq < irq_end; irq++) { | 375 | for (irq = ei->irq_start; irq < irq_end; irq++) { |
377 | set_irq_chip(irq, NULL); | 376 | irq_set_chip_and_handler(irq, NULL, NULL); |
378 | set_irq_handler(irq, NULL); | ||
379 | set_irq_flags(irq, 0); | 377 | set_irq_flags(irq, 0); |
380 | } | 378 | } |
381 | set_irq_chained_handler(ei->chained_irq, NULL); | 379 | irq_set_chained_handler(ei->chained_irq, NULL); |
382 | device_init_wakeup(&pdev->dev, 0); | 380 | device_init_wakeup(&pdev->dev, 0); |
383 | } | 381 | } |
384 | iounmap(ei->base_addr); | 382 | iounmap(ei->base_addr); |
diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index 594c9a8e25e1..d55065cc324c 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c | |||
@@ -58,6 +58,7 @@ struct htcpld_chip { | |||
58 | uint irq_start; | 58 | uint irq_start; |
59 | int nirqs; | 59 | int nirqs; |
60 | 60 | ||
61 | unsigned int flow_type; | ||
61 | /* | 62 | /* |
62 | * Work structure to allow for setting values outside of any | 63 | * Work structure to allow for setting values outside of any |
63 | * possible interrupt context | 64 | * possible interrupt context |
@@ -82,27 +83,22 @@ struct htcpld_data { | |||
82 | /* There does not appear to be a way to proactively mask interrupts | 83 | /* There does not appear to be a way to proactively mask interrupts |
83 | * on the htcpld chip itself. So, we simply ignore interrupts that | 84 | * on the htcpld chip itself. So, we simply ignore interrupts that |
84 | * aren't desired. */ | 85 | * aren't desired. */ |
85 | static void htcpld_mask(unsigned int irq) | 86 | static void htcpld_mask(struct irq_data *data) |
86 | { | 87 | { |
87 | struct htcpld_chip *chip = get_irq_chip_data(irq); | 88 | struct htcpld_chip *chip = irq_data_get_irq_chip_data(data); |
88 | chip->irqs_enabled &= ~(1 << (irq - chip->irq_start)); | 89 | chip->irqs_enabled &= ~(1 << (data->irq - chip->irq_start)); |
89 | pr_debug("HTCPLD mask %d %04x\n", irq, chip->irqs_enabled); | 90 | pr_debug("HTCPLD mask %d %04x\n", data->irq, chip->irqs_enabled); |
90 | } | 91 | } |
91 | static void htcpld_unmask(unsigned int irq) | 92 | static void htcpld_unmask(struct irq_data *data) |
92 | { | 93 | { |
93 | struct htcpld_chip *chip = get_irq_chip_data(irq); | 94 | struct htcpld_chip *chip = irq_data_get_irq_chip_data(data); |
94 | chip->irqs_enabled |= 1 << (irq - chip->irq_start); | 95 | chip->irqs_enabled |= 1 << (data->irq - chip->irq_start); |
95 | pr_debug("HTCPLD unmask %d %04x\n", irq, chip->irqs_enabled); | 96 | pr_debug("HTCPLD unmask %d %04x\n", data->irq, chip->irqs_enabled); |
96 | } | 97 | } |
97 | 98 | ||
98 | static int htcpld_set_type(unsigned int irq, unsigned int flags) | 99 | static int htcpld_set_type(struct irq_data *data, unsigned int flags) |
99 | { | 100 | { |
100 | struct irq_desc *d = irq_to_desc(irq); | 101 | struct htcpld_chip *chip = irq_data_get_irq_chip_data(data); |
101 | |||
102 | if (!d) { | ||
103 | pr_err("HTCPLD invalid IRQ: %d\n", irq); | ||
104 | return -EINVAL; | ||
105 | } | ||
106 | 102 | ||
107 | if (flags & ~IRQ_TYPE_SENSE_MASK) | 103 | if (flags & ~IRQ_TYPE_SENSE_MASK) |
108 | return -EINVAL; | 104 | return -EINVAL; |
@@ -111,17 +107,15 @@ static int htcpld_set_type(unsigned int irq, unsigned int flags) | |||
111 | if (flags & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)) | 107 | if (flags & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)) |
112 | return -EINVAL; | 108 | return -EINVAL; |
113 | 109 | ||
114 | d->status &= ~IRQ_TYPE_SENSE_MASK; | 110 | chip->flow_type = flags; |
115 | d->status |= flags; | ||
116 | |||
117 | return 0; | 111 | return 0; |
118 | } | 112 | } |
119 | 113 | ||
120 | static struct irq_chip htcpld_muxed_chip = { | 114 | static struct irq_chip htcpld_muxed_chip = { |
121 | .name = "htcpld", | 115 | .name = "htcpld", |
122 | .mask = htcpld_mask, | 116 | .irq_mask = htcpld_mask, |
123 | .unmask = htcpld_unmask, | 117 | .irq_unmask = htcpld_unmask, |
124 | .set_type = htcpld_set_type, | 118 | .irq_set_type = htcpld_set_type, |
125 | }; | 119 | }; |
126 | 120 | ||
127 | /* To properly dispatch IRQ events, we need to read from the | 121 | /* To properly dispatch IRQ events, we need to read from the |
@@ -135,7 +129,6 @@ static irqreturn_t htcpld_handler(int irq, void *dev) | |||
135 | unsigned int i; | 129 | unsigned int i; |
136 | unsigned long flags; | 130 | unsigned long flags; |
137 | int irqpin; | 131 | int irqpin; |
138 | struct irq_desc *desc; | ||
139 | 132 | ||
140 | if (!htcpld) { | 133 | if (!htcpld) { |
141 | pr_debug("htcpld is null in ISR\n"); | 134 | pr_debug("htcpld is null in ISR\n"); |
@@ -195,23 +188,19 @@ static irqreturn_t htcpld_handler(int irq, void *dev) | |||
195 | * associated interrupts. | 188 | * associated interrupts. |
196 | */ | 189 | */ |
197 | for (irqpin = 0; irqpin < chip->nirqs; irqpin++) { | 190 | for (irqpin = 0; irqpin < chip->nirqs; irqpin++) { |
198 | unsigned oldb, newb; | 191 | unsigned oldb, newb, type = chip->flow_type; |
199 | int flags; | ||
200 | 192 | ||
201 | irq = chip->irq_start + irqpin; | 193 | irq = chip->irq_start + irqpin; |
202 | desc = irq_to_desc(irq); | ||
203 | flags = desc->status; | ||
204 | 194 | ||
205 | /* Run the IRQ handler, but only if the bit value | 195 | /* Run the IRQ handler, but only if the bit value |
206 | * changed, and the proper flags are set */ | 196 | * changed, and the proper flags are set */ |
207 | oldb = (old_val >> irqpin) & 1; | 197 | oldb = (old_val >> irqpin) & 1; |
208 | newb = (uval >> irqpin) & 1; | 198 | newb = (uval >> irqpin) & 1; |
209 | 199 | ||
210 | if ((!oldb && newb && (flags & IRQ_TYPE_EDGE_RISING)) || | 200 | if ((!oldb && newb && (type & IRQ_TYPE_EDGE_RISING)) || |
211 | (oldb && !newb && | 201 | (oldb && !newb && (type & IRQ_TYPE_EDGE_FALLING))) { |
212 | (flags & IRQ_TYPE_EDGE_FALLING))) { | ||
213 | pr_debug("fire IRQ %d\n", irqpin); | 202 | pr_debug("fire IRQ %d\n", irqpin); |
214 | desc->handle_irq(irq, desc); | 203 | generic_handle_irq(irq); |
215 | } | 204 | } |
216 | } | 205 | } |
217 | } | 206 | } |
@@ -235,7 +224,7 @@ static irqreturn_t htcpld_handler(int irq, void *dev) | |||
235 | * and that work is scheduled in the set routine. The kernel can then run | 224 | * and that work is scheduled in the set routine. The kernel can then run |
236 | * the I2C functions, which will sleep, in process context. | 225 | * the I2C functions, which will sleep, in process context. |
237 | */ | 226 | */ |
238 | void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val) | 227 | static void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val) |
239 | { | 228 | { |
240 | struct i2c_client *client; | 229 | struct i2c_client *client; |
241 | struct htcpld_chip *chip_data; | 230 | struct htcpld_chip *chip_data; |
@@ -259,7 +248,7 @@ void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val) | |||
259 | schedule_work(&(chip_data->set_val_work)); | 248 | schedule_work(&(chip_data->set_val_work)); |
260 | } | 249 | } |
261 | 250 | ||
262 | void htcpld_chip_set_ni(struct work_struct *work) | 251 | static void htcpld_chip_set_ni(struct work_struct *work) |
263 | { | 252 | { |
264 | struct htcpld_chip *chip_data; | 253 | struct htcpld_chip *chip_data; |
265 | struct i2c_client *client; | 254 | struct i2c_client *client; |
@@ -269,7 +258,7 @@ void htcpld_chip_set_ni(struct work_struct *work) | |||
269 | i2c_smbus_read_byte_data(client, chip_data->cache_out); | 258 | i2c_smbus_read_byte_data(client, chip_data->cache_out); |
270 | } | 259 | } |
271 | 260 | ||
272 | int htcpld_chip_get(struct gpio_chip *chip, unsigned offset) | 261 | static int htcpld_chip_get(struct gpio_chip *chip, unsigned offset) |
273 | { | 262 | { |
274 | struct htcpld_chip *chip_data; | 263 | struct htcpld_chip *chip_data; |
275 | int val = 0; | 264 | int val = 0; |
@@ -316,7 +305,7 @@ static int htcpld_direction_input(struct gpio_chip *chip, | |||
316 | return (offset < chip->ngpio) ? 0 : -EINVAL; | 305 | return (offset < chip->ngpio) ? 0 : -EINVAL; |
317 | } | 306 | } |
318 | 307 | ||
319 | int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset) | 308 | static int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset) |
320 | { | 309 | { |
321 | struct htcpld_chip *chip_data; | 310 | struct htcpld_chip *chip_data; |
322 | 311 | ||
@@ -328,7 +317,7 @@ int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset) | |||
328 | return -EINVAL; | 317 | return -EINVAL; |
329 | } | 318 | } |
330 | 319 | ||
331 | void htcpld_chip_reset(struct i2c_client *client) | 320 | static void htcpld_chip_reset(struct i2c_client *client) |
332 | { | 321 | { |
333 | struct htcpld_chip *chip_data = i2c_get_clientdata(client); | 322 | struct htcpld_chip *chip_data = i2c_get_clientdata(client); |
334 | if (!chip_data) | 323 | if (!chip_data) |
@@ -359,13 +348,13 @@ static int __devinit htcpld_setup_chip_irq( | |||
359 | /* Setup irq handlers */ | 348 | /* Setup irq handlers */ |
360 | irq_end = chip->irq_start + chip->nirqs; | 349 | irq_end = chip->irq_start + chip->nirqs; |
361 | for (irq = chip->irq_start; irq < irq_end; irq++) { | 350 | for (irq = chip->irq_start; irq < irq_end; irq++) { |
362 | set_irq_chip(irq, &htcpld_muxed_chip); | 351 | irq_set_chip_and_handler(irq, &htcpld_muxed_chip, |
363 | set_irq_chip_data(irq, chip); | 352 | handle_simple_irq); |
364 | set_irq_handler(irq, handle_simple_irq); | 353 | irq_set_chip_data(irq, chip); |
365 | #ifdef CONFIG_ARM | 354 | #ifdef CONFIG_ARM |
366 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 355 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
367 | #else | 356 | #else |
368 | set_irq_probe(irq); | 357 | irq_set_probe(irq); |
369 | #endif | 358 | #endif |
370 | } | 359 | } |
371 | 360 | ||
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index f04300e05fd6..04c7093d6499 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c | |||
@@ -99,6 +99,7 @@ static int ds1wm_disable(struct platform_device *pdev) | |||
99 | 99 | ||
100 | static struct ds1wm_driver_data ds1wm_pdata = { | 100 | static struct ds1wm_driver_data ds1wm_pdata = { |
101 | .active_high = 0, | 101 | .active_high = 0, |
102 | .reset_recover_delay = 1, | ||
102 | }; | 103 | }; |
103 | 104 | ||
104 | static struct resource ds1wm_resources[] __initdata = { | 105 | static struct resource ds1wm_resources[] __initdata = { |
@@ -117,7 +118,8 @@ static struct mfd_cell ds1wm_cell __initdata = { | |||
117 | .name = "ds1wm", | 118 | .name = "ds1wm", |
118 | .enable = ds1wm_enable, | 119 | .enable = ds1wm_enable, |
119 | .disable = ds1wm_disable, | 120 | .disable = ds1wm_disable, |
120 | .driver_data = &ds1wm_pdata, | 121 | .platform_data = &ds1wm_pdata, |
122 | .pdata_size = sizeof(ds1wm_pdata), | ||
121 | .num_resources = 2, | 123 | .num_resources = 2, |
122 | .resources = ds1wm_resources, | 124 | .resources = ds1wm_resources, |
123 | }; | 125 | }; |
@@ -138,13 +140,6 @@ static int __init pasic3_probe(struct platform_device *pdev) | |||
138 | irq = r->start; | 140 | irq = r->start; |
139 | } | 141 | } |
140 | 142 | ||
141 | r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
142 | if (r) { | ||
143 | ds1wm_resources[1].flags = IORESOURCE_IRQ | (r->flags & | ||
144 | (IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE)); | ||
145 | irq = r->start; | ||
146 | } | ||
147 | |||
148 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 143 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
149 | if (!r) | 144 | if (!r) |
150 | return -ENXIO; | 145 | return -ENXIO; |
@@ -172,8 +167,6 @@ static int __init pasic3_probe(struct platform_device *pdev) | |||
172 | ds1wm_pdata.clock_rate = pdata->clock_rate; | 167 | ds1wm_pdata.clock_rate = pdata->clock_rate; |
173 | /* the first 5 PASIC3 registers control the DS1WM */ | 168 | /* the first 5 PASIC3 registers control the DS1WM */ |
174 | ds1wm_resources[0].end = (5 << asic->bus_shift) - 1; | 169 | ds1wm_resources[0].end = (5 << asic->bus_shift) - 1; |
175 | ds1wm_cell.platform_data = &ds1wm_cell; | ||
176 | ds1wm_cell.data_size = sizeof(ds1wm_cell); | ||
177 | ret = mfd_add_devices(&pdev->dev, pdev->id, | 170 | ret = mfd_add_devices(&pdev->dev, pdev->id, |
178 | &ds1wm_cell, 1, r, irq); | 171 | &ds1wm_cell, 1, r, irq); |
179 | if (ret < 0) | 172 | if (ret < 0) |
@@ -181,9 +174,8 @@ static int __init pasic3_probe(struct platform_device *pdev) | |||
181 | } | 174 | } |
182 | 175 | ||
183 | if (pdata && pdata->led_pdata) { | 176 | if (pdata && pdata->led_pdata) { |
184 | led_cell.driver_data = pdata->led_pdata; | 177 | led_cell.platform_data = pdata->led_pdata; |
185 | led_cell.platform_data = &led_cell; | 178 | led_cell.pdata_size = sizeof(struct pasic3_leds_machinfo); |
186 | led_cell.data_size = sizeof(ds1wm_cell); | ||
187 | ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0); | 179 | ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0); |
188 | if (ret < 0) | 180 | if (ret < 0) |
189 | dev_warn(dev, "failed to register LED device\n"); | 181 | dev_warn(dev, "failed to register LED device\n"); |
diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c index 36a166bcdb08..5c2a06acb77f 100644 --- a/drivers/mfd/janz-cmodio.c +++ b/drivers/mfd/janz-cmodio.c | |||
@@ -87,7 +87,7 @@ static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv, | |||
87 | /* Add platform data */ | 87 | /* Add platform data */ |
88 | pdata->modno = modno; | 88 | pdata->modno = modno; |
89 | cell->platform_data = pdata; | 89 | cell->platform_data = pdata; |
90 | cell->data_size = sizeof(*pdata); | 90 | cell->pdata_size = sizeof(*pdata); |
91 | 91 | ||
92 | /* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */ | 92 | /* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */ |
93 | res->flags = IORESOURCE_MEM; | 93 | res->flags = IORESOURCE_MEM; |
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index 3ad492cb6c41..a0bd0cf05af3 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c | |||
@@ -84,36 +84,35 @@ static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq, | |||
84 | spin_unlock_irqrestore(&adc->lock, flags); | 84 | spin_unlock_irqrestore(&adc->lock, flags); |
85 | } | 85 | } |
86 | 86 | ||
87 | static void jz4740_adc_irq_mask(unsigned int irq) | 87 | static void jz4740_adc_irq_mask(struct irq_data *data) |
88 | { | 88 | { |
89 | struct jz4740_adc *adc = get_irq_chip_data(irq); | 89 | struct jz4740_adc *adc = irq_data_get_irq_chip_data(data); |
90 | jz4740_adc_irq_set_masked(adc, irq, true); | 90 | jz4740_adc_irq_set_masked(adc, data->irq, true); |
91 | } | 91 | } |
92 | 92 | ||
93 | static void jz4740_adc_irq_unmask(unsigned int irq) | 93 | static void jz4740_adc_irq_unmask(struct irq_data *data) |
94 | { | 94 | { |
95 | struct jz4740_adc *adc = get_irq_chip_data(irq); | 95 | struct jz4740_adc *adc = irq_data_get_irq_chip_data(data); |
96 | jz4740_adc_irq_set_masked(adc, irq, false); | 96 | jz4740_adc_irq_set_masked(adc, data->irq, false); |
97 | } | 97 | } |
98 | 98 | ||
99 | static void jz4740_adc_irq_ack(unsigned int irq) | 99 | static void jz4740_adc_irq_ack(struct irq_data *data) |
100 | { | 100 | { |
101 | struct jz4740_adc *adc = get_irq_chip_data(irq); | 101 | struct jz4740_adc *adc = irq_data_get_irq_chip_data(data); |
102 | 102 | unsigned int irq = data->irq - adc->irq_base; | |
103 | irq -= adc->irq_base; | ||
104 | writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS); | 103 | writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS); |
105 | } | 104 | } |
106 | 105 | ||
107 | static struct irq_chip jz4740_adc_irq_chip = { | 106 | static struct irq_chip jz4740_adc_irq_chip = { |
108 | .name = "jz4740-adc", | 107 | .name = "jz4740-adc", |
109 | .mask = jz4740_adc_irq_mask, | 108 | .irq_mask = jz4740_adc_irq_mask, |
110 | .unmask = jz4740_adc_irq_unmask, | 109 | .irq_unmask = jz4740_adc_irq_unmask, |
111 | .ack = jz4740_adc_irq_ack, | 110 | .irq_ack = jz4740_adc_irq_ack, |
112 | }; | 111 | }; |
113 | 112 | ||
114 | static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc) | 113 | static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc) |
115 | { | 114 | { |
116 | struct jz4740_adc *adc = get_irq_desc_data(desc); | 115 | struct jz4740_adc *adc = irq_desc_get_handler_data(desc); |
117 | uint8_t status; | 116 | uint8_t status; |
118 | unsigned int i; | 117 | unsigned int i; |
119 | 118 | ||
@@ -153,7 +152,7 @@ static inline void jz4740_adc_set_enabled(struct jz4740_adc *adc, int engine, | |||
153 | if (enabled) | 152 | if (enabled) |
154 | val |= BIT(engine); | 153 | val |= BIT(engine); |
155 | else | 154 | else |
156 | val &= BIT(engine); | 155 | val &= ~BIT(engine); |
157 | writeb(val, adc->base + JZ_REG_ADC_ENABLE); | 156 | writeb(val, adc->base + JZ_REG_ADC_ENABLE); |
158 | 157 | ||
159 | spin_unlock_irqrestore(&adc->lock, flags); | 158 | spin_unlock_irqrestore(&adc->lock, flags); |
@@ -233,8 +232,6 @@ const struct mfd_cell jz4740_adc_cells[] = { | |||
233 | .name = "jz4740-hwmon", | 232 | .name = "jz4740-hwmon", |
234 | .num_resources = ARRAY_SIZE(jz4740_hwmon_resources), | 233 | .num_resources = ARRAY_SIZE(jz4740_hwmon_resources), |
235 | .resources = jz4740_hwmon_resources, | 234 | .resources = jz4740_hwmon_resources, |
236 | .platform_data = (void *)&jz4740_adc_cells[0], | ||
237 | .data_size = sizeof(struct mfd_cell), | ||
238 | 235 | ||
239 | .enable = jz4740_adc_cell_enable, | 236 | .enable = jz4740_adc_cell_enable, |
240 | .disable = jz4740_adc_cell_disable, | 237 | .disable = jz4740_adc_cell_disable, |
@@ -244,8 +241,6 @@ const struct mfd_cell jz4740_adc_cells[] = { | |||
244 | .name = "jz4740-battery", | 241 | .name = "jz4740-battery", |
245 | .num_resources = ARRAY_SIZE(jz4740_battery_resources), | 242 | .num_resources = ARRAY_SIZE(jz4740_battery_resources), |
246 | .resources = jz4740_battery_resources, | 243 | .resources = jz4740_battery_resources, |
247 | .platform_data = (void *)&jz4740_adc_cells[1], | ||
248 | .data_size = sizeof(struct mfd_cell), | ||
249 | 244 | ||
250 | .enable = jz4740_adc_cell_enable, | 245 | .enable = jz4740_adc_cell_enable, |
251 | .disable = jz4740_adc_cell_disable, | 246 | .disable = jz4740_adc_cell_disable, |
@@ -315,13 +310,13 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev) | |||
315 | platform_set_drvdata(pdev, adc); | 310 | platform_set_drvdata(pdev, adc); |
316 | 311 | ||
317 | for (irq = adc->irq_base; irq < adc->irq_base + 5; ++irq) { | 312 | for (irq = adc->irq_base; irq < adc->irq_base + 5; ++irq) { |
318 | set_irq_chip_data(irq, adc); | 313 | irq_set_chip_data(irq, adc); |
319 | set_irq_chip_and_handler(irq, &jz4740_adc_irq_chip, | 314 | irq_set_chip_and_handler(irq, &jz4740_adc_irq_chip, |
320 | handle_level_irq); | 315 | handle_level_irq); |
321 | } | 316 | } |
322 | 317 | ||
323 | set_irq_data(adc->irq, adc); | 318 | irq_set_handler_data(adc->irq, adc); |
324 | set_irq_chained_handler(adc->irq, jz4740_adc_irq_demux); | 319 | irq_set_chained_handler(adc->irq, jz4740_adc_irq_demux); |
325 | 320 | ||
326 | writeb(0x00, adc->base + JZ_REG_ADC_ENABLE); | 321 | writeb(0x00, adc->base + JZ_REG_ADC_ENABLE); |
327 | writeb(0xff, adc->base + JZ_REG_ADC_CTRL); | 322 | writeb(0xff, adc->base + JZ_REG_ADC_CTRL); |
@@ -352,8 +347,8 @@ static int __devexit jz4740_adc_remove(struct platform_device *pdev) | |||
352 | 347 | ||
353 | mfd_remove_devices(&pdev->dev); | 348 | mfd_remove_devices(&pdev->dev); |
354 | 349 | ||
355 | set_irq_data(adc->irq, NULL); | 350 | irq_set_handler_data(adc->irq, NULL); |
356 | set_irq_chained_handler(adc->irq, NULL); | 351 | irq_set_chained_handler(adc->irq, NULL); |
357 | 352 | ||
358 | iounmap(adc->base); | 353 | iounmap(adc->base); |
359 | release_mem_region(adc->mem->start, resource_size(adc->mem)); | 354 | release_mem_region(adc->mem->start, resource_size(adc->mem)); |
diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c index 51b2f6065a0b..ea3f52c07ef7 100644 --- a/drivers/mfd/lpc_sch.c +++ b/drivers/mfd/lpc_sch.c | |||
@@ -61,6 +61,7 @@ static struct mfd_cell lpc_sch_cells[] = { | |||
61 | 61 | ||
62 | static struct pci_device_id lpc_sch_ids[] = { | 62 | static struct pci_device_id lpc_sch_ids[] = { |
63 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) }, | 63 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) }, |
64 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) }, | ||
64 | { 0, } | 65 | { 0, } |
65 | }; | 66 | }; |
66 | MODULE_DEVICE_TABLE(pci, lpc_sch_ids); | 67 | MODULE_DEVICE_TABLE(pci, lpc_sch_ids); |
@@ -70,6 +71,7 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev, | |||
70 | { | 71 | { |
71 | unsigned int base_addr_cfg; | 72 | unsigned int base_addr_cfg; |
72 | unsigned short base_addr; | 73 | unsigned short base_addr; |
74 | int i; | ||
73 | 75 | ||
74 | pci_read_config_dword(dev, SMBASE, &base_addr_cfg); | 76 | pci_read_config_dword(dev, SMBASE, &base_addr_cfg); |
75 | if (!(base_addr_cfg & (1 << 31))) { | 77 | if (!(base_addr_cfg & (1 << 31))) { |
@@ -99,7 +101,10 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev, | |||
99 | gpio_sch_resource.start = base_addr; | 101 | gpio_sch_resource.start = base_addr; |
100 | gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1; | 102 | gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1; |
101 | 103 | ||
102 | return mfd_add_devices(&dev->dev, -1, | 104 | for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++) |
105 | lpc_sch_cells[i].id = id->device; | ||
106 | |||
107 | return mfd_add_devices(&dev->dev, 0, | ||
103 | lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0); | 108 | lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0); |
104 | } | 109 | } |
105 | 110 | ||
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 428377a5a6f5..e1e59c92f758 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c | |||
@@ -93,8 +93,13 @@ static struct mfd_cell rtc_devs[] = { | |||
93 | static struct resource onkey_resources[] = { | 93 | static struct resource onkey_resources[] = { |
94 | { | 94 | { |
95 | .name = "max8925-onkey", | 95 | .name = "max8925-onkey", |
96 | .start = MAX8925_IRQ_GPM_SW_3SEC, | 96 | .start = MAX8925_IRQ_GPM_SW_R, |
97 | .end = MAX8925_IRQ_GPM_SW_3SEC, | 97 | .end = MAX8925_IRQ_GPM_SW_R, |
98 | .flags = IORESOURCE_IRQ, | ||
99 | }, { | ||
100 | .name = "max8925-onkey", | ||
101 | .start = MAX8925_IRQ_GPM_SW_F, | ||
102 | .end = MAX8925_IRQ_GPM_SW_F, | ||
98 | .flags = IORESOURCE_IRQ, | 103 | .flags = IORESOURCE_IRQ, |
99 | }, | 104 | }, |
100 | }; | 105 | }; |
@@ -102,7 +107,7 @@ static struct resource onkey_resources[] = { | |||
102 | static struct mfd_cell onkey_devs[] = { | 107 | static struct mfd_cell onkey_devs[] = { |
103 | { | 108 | { |
104 | .name = "max8925-onkey", | 109 | .name = "max8925-onkey", |
105 | .num_resources = 1, | 110 | .num_resources = 2, |
106 | .resources = &onkey_resources[0], | 111 | .resources = &onkey_resources[0], |
107 | .id = -1, | 112 | .id = -1, |
108 | }, | 113 | }, |
@@ -402,16 +407,16 @@ static irqreturn_t max8925_tsc_irq(int irq, void *data) | |||
402 | return IRQ_HANDLED; | 407 | return IRQ_HANDLED; |
403 | } | 408 | } |
404 | 409 | ||
405 | static void max8925_irq_lock(unsigned int irq) | 410 | static void max8925_irq_lock(struct irq_data *data) |
406 | { | 411 | { |
407 | struct max8925_chip *chip = get_irq_chip_data(irq); | 412 | struct max8925_chip *chip = irq_data_get_irq_chip_data(data); |
408 | 413 | ||
409 | mutex_lock(&chip->irq_lock); | 414 | mutex_lock(&chip->irq_lock); |
410 | } | 415 | } |
411 | 416 | ||
412 | static void max8925_irq_sync_unlock(unsigned int irq) | 417 | static void max8925_irq_sync_unlock(struct irq_data *data) |
413 | { | 418 | { |
414 | struct max8925_chip *chip = get_irq_chip_data(irq); | 419 | struct max8925_chip *chip = irq_data_get_irq_chip_data(data); |
415 | struct max8925_irq_data *irq_data; | 420 | struct max8925_irq_data *irq_data; |
416 | static unsigned char cache_chg[2] = {0xff, 0xff}; | 421 | static unsigned char cache_chg[2] = {0xff, 0xff}; |
417 | static unsigned char cache_on[2] = {0xff, 0xff}; | 422 | static unsigned char cache_on[2] = {0xff, 0xff}; |
@@ -487,32 +492,31 @@ static void max8925_irq_sync_unlock(unsigned int irq) | |||
487 | mutex_unlock(&chip->irq_lock); | 492 | mutex_unlock(&chip->irq_lock); |
488 | } | 493 | } |
489 | 494 | ||
490 | static void max8925_irq_enable(unsigned int irq) | 495 | static void max8925_irq_enable(struct irq_data *data) |
491 | { | 496 | { |
492 | struct max8925_chip *chip = get_irq_chip_data(irq); | 497 | struct max8925_chip *chip = irq_data_get_irq_chip_data(data); |
493 | max8925_irqs[irq - chip->irq_base].enable | 498 | max8925_irqs[data->irq - chip->irq_base].enable |
494 | = max8925_irqs[irq - chip->irq_base].offs; | 499 | = max8925_irqs[data->irq - chip->irq_base].offs; |
495 | } | 500 | } |
496 | 501 | ||
497 | static void max8925_irq_disable(unsigned int irq) | 502 | static void max8925_irq_disable(struct irq_data *data) |
498 | { | 503 | { |
499 | struct max8925_chip *chip = get_irq_chip_data(irq); | 504 | struct max8925_chip *chip = irq_data_get_irq_chip_data(data); |
500 | max8925_irqs[irq - chip->irq_base].enable = 0; | 505 | max8925_irqs[data->irq - chip->irq_base].enable = 0; |
501 | } | 506 | } |
502 | 507 | ||
503 | static struct irq_chip max8925_irq_chip = { | 508 | static struct irq_chip max8925_irq_chip = { |
504 | .name = "max8925", | 509 | .name = "max8925", |
505 | .bus_lock = max8925_irq_lock, | 510 | .irq_bus_lock = max8925_irq_lock, |
506 | .bus_sync_unlock = max8925_irq_sync_unlock, | 511 | .irq_bus_sync_unlock = max8925_irq_sync_unlock, |
507 | .enable = max8925_irq_enable, | 512 | .irq_enable = max8925_irq_enable, |
508 | .disable = max8925_irq_disable, | 513 | .irq_disable = max8925_irq_disable, |
509 | }; | 514 | }; |
510 | 515 | ||
511 | static int max8925_irq_init(struct max8925_chip *chip, int irq, | 516 | static int max8925_irq_init(struct max8925_chip *chip, int irq, |
512 | struct max8925_platform_data *pdata) | 517 | struct max8925_platform_data *pdata) |
513 | { | 518 | { |
514 | unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; | 519 | unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; |
515 | struct irq_desc *desc; | ||
516 | int i, ret; | 520 | int i, ret; |
517 | int __irq; | 521 | int __irq; |
518 | 522 | ||
@@ -539,19 +543,18 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, | |||
539 | mutex_init(&chip->irq_lock); | 543 | mutex_init(&chip->irq_lock); |
540 | chip->core_irq = irq; | 544 | chip->core_irq = irq; |
541 | chip->irq_base = pdata->irq_base; | 545 | chip->irq_base = pdata->irq_base; |
542 | desc = irq_to_desc(chip->core_irq); | ||
543 | 546 | ||
544 | /* register with genirq */ | 547 | /* register with genirq */ |
545 | for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { | 548 | for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { |
546 | __irq = i + chip->irq_base; | 549 | __irq = i + chip->irq_base; |
547 | set_irq_chip_data(__irq, chip); | 550 | irq_set_chip_data(__irq, chip); |
548 | set_irq_chip_and_handler(__irq, &max8925_irq_chip, | 551 | irq_set_chip_and_handler(__irq, &max8925_irq_chip, |
549 | handle_edge_irq); | 552 | handle_edge_irq); |
550 | set_irq_nested_thread(__irq, 1); | 553 | irq_set_nested_thread(__irq, 1); |
551 | #ifdef CONFIG_ARM | 554 | #ifdef CONFIG_ARM |
552 | set_irq_flags(__irq, IRQF_VALID); | 555 | set_irq_flags(__irq, IRQF_VALID); |
553 | #else | 556 | #else |
554 | set_irq_noprobe(__irq); | 557 | irq_set_noprobe(__irq); |
555 | #endif | 558 | #endif |
556 | } | 559 | } |
557 | if (!irq) { | 560 | if (!irq) { |
@@ -624,7 +627,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, | |||
624 | goto out_dev; | 627 | goto out_dev; |
625 | } | 628 | } |
626 | 629 | ||
627 | if (pdata && pdata->regulator[0]) { | 630 | if (pdata) { |
628 | ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], | 631 | ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], |
629 | ARRAY_SIZE(regulator_devs), | 632 | ARRAY_SIZE(regulator_devs), |
630 | ®ulator_resources[0], 0); | 633 | ®ulator_resources[0], 0); |
diff --git a/drivers/mfd/max8997-irq.c b/drivers/mfd/max8997-irq.c new file mode 100644 index 000000000000..638bf7e4d3b3 --- /dev/null +++ b/drivers/mfd/max8997-irq.c | |||
@@ -0,0 +1,377 @@ | |||
1 | /* | ||
2 | * max8997-irq.c - Interrupt controller support for MAX8997 | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics Co.Ltd | ||
5 | * MyungJoo Ham <myungjoo.ham@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | * This driver is based on max8998-irq.c | ||
22 | */ | ||
23 | |||
24 | #include <linux/err.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/mfd/max8997.h> | ||
28 | #include <linux/mfd/max8997-private.h> | ||
29 | |||
30 | static const u8 max8997_mask_reg[] = { | ||
31 | [PMIC_INT1] = MAX8997_REG_INT1MSK, | ||
32 | [PMIC_INT2] = MAX8997_REG_INT2MSK, | ||
33 | [PMIC_INT3] = MAX8997_REG_INT3MSK, | ||
34 | [PMIC_INT4] = MAX8997_REG_INT4MSK, | ||
35 | [FUEL_GAUGE] = MAX8997_REG_INVALID, | ||
36 | [MUIC_INT1] = MAX8997_MUIC_REG_INTMASK1, | ||
37 | [MUIC_INT2] = MAX8997_MUIC_REG_INTMASK2, | ||
38 | [MUIC_INT3] = MAX8997_MUIC_REG_INTMASK3, | ||
39 | [GPIO_LOW] = MAX8997_REG_INVALID, | ||
40 | [GPIO_HI] = MAX8997_REG_INVALID, | ||
41 | [FLASH_STATUS] = MAX8997_REG_INVALID, | ||
42 | }; | ||
43 | |||
44 | static struct i2c_client *get_i2c(struct max8997_dev *max8997, | ||
45 | enum max8997_irq_source src) | ||
46 | { | ||
47 | switch (src) { | ||
48 | case PMIC_INT1 ... PMIC_INT4: | ||
49 | return max8997->i2c; | ||
50 | case FUEL_GAUGE: | ||
51 | return NULL; | ||
52 | case MUIC_INT1 ... MUIC_INT3: | ||
53 | return max8997->muic; | ||
54 | case GPIO_LOW ... GPIO_HI: | ||
55 | return max8997->i2c; | ||
56 | case FLASH_STATUS: | ||
57 | return max8997->i2c; | ||
58 | default: | ||
59 | return ERR_PTR(-EINVAL); | ||
60 | } | ||
61 | |||
62 | return ERR_PTR(-EINVAL); | ||
63 | } | ||
64 | |||
65 | struct max8997_irq_data { | ||
66 | int mask; | ||
67 | enum max8997_irq_source group; | ||
68 | }; | ||
69 | |||
70 | #define DECLARE_IRQ(idx, _group, _mask) \ | ||
71 | [(idx)] = { .group = (_group), .mask = (_mask) } | ||
72 | static const struct max8997_irq_data max8997_irqs[] = { | ||
73 | DECLARE_IRQ(MAX8997_PMICIRQ_PWRONR, PMIC_INT1, 1 << 0), | ||
74 | DECLARE_IRQ(MAX8997_PMICIRQ_PWRONF, PMIC_INT1, 1 << 1), | ||
75 | DECLARE_IRQ(MAX8997_PMICIRQ_PWRON1SEC, PMIC_INT1, 1 << 3), | ||
76 | DECLARE_IRQ(MAX8997_PMICIRQ_JIGONR, PMIC_INT1, 1 << 4), | ||
77 | DECLARE_IRQ(MAX8997_PMICIRQ_JIGONF, PMIC_INT1, 1 << 5), | ||
78 | DECLARE_IRQ(MAX8997_PMICIRQ_LOWBAT2, PMIC_INT1, 1 << 6), | ||
79 | DECLARE_IRQ(MAX8997_PMICIRQ_LOWBAT1, PMIC_INT1, 1 << 7), | ||
80 | |||
81 | DECLARE_IRQ(MAX8997_PMICIRQ_JIGR, PMIC_INT2, 1 << 0), | ||
82 | DECLARE_IRQ(MAX8997_PMICIRQ_JIGF, PMIC_INT2, 1 << 1), | ||
83 | DECLARE_IRQ(MAX8997_PMICIRQ_MR, PMIC_INT2, 1 << 2), | ||
84 | DECLARE_IRQ(MAX8997_PMICIRQ_DVS1OK, PMIC_INT2, 1 << 3), | ||
85 | DECLARE_IRQ(MAX8997_PMICIRQ_DVS2OK, PMIC_INT2, 1 << 4), | ||
86 | DECLARE_IRQ(MAX8997_PMICIRQ_DVS3OK, PMIC_INT2, 1 << 5), | ||
87 | DECLARE_IRQ(MAX8997_PMICIRQ_DVS4OK, PMIC_INT2, 1 << 6), | ||
88 | |||
89 | DECLARE_IRQ(MAX8997_PMICIRQ_CHGINS, PMIC_INT3, 1 << 0), | ||
90 | DECLARE_IRQ(MAX8997_PMICIRQ_CHGRM, PMIC_INT3, 1 << 1), | ||
91 | DECLARE_IRQ(MAX8997_PMICIRQ_DCINOVP, PMIC_INT3, 1 << 2), | ||
92 | DECLARE_IRQ(MAX8997_PMICIRQ_TOPOFFR, PMIC_INT3, 1 << 3), | ||
93 | DECLARE_IRQ(MAX8997_PMICIRQ_CHGRSTF, PMIC_INT3, 1 << 5), | ||
94 | DECLARE_IRQ(MAX8997_PMICIRQ_MBCHGTMEXPD, PMIC_INT3, 1 << 7), | ||
95 | |||
96 | DECLARE_IRQ(MAX8997_PMICIRQ_RTC60S, PMIC_INT4, 1 << 0), | ||
97 | DECLARE_IRQ(MAX8997_PMICIRQ_RTCA1, PMIC_INT4, 1 << 1), | ||
98 | DECLARE_IRQ(MAX8997_PMICIRQ_RTCA2, PMIC_INT4, 1 << 2), | ||
99 | DECLARE_IRQ(MAX8997_PMICIRQ_SMPL_INT, PMIC_INT4, 1 << 3), | ||
100 | DECLARE_IRQ(MAX8997_PMICIRQ_RTC1S, PMIC_INT4, 1 << 4), | ||
101 | DECLARE_IRQ(MAX8997_PMICIRQ_WTSR, PMIC_INT4, 1 << 5), | ||
102 | |||
103 | DECLARE_IRQ(MAX8997_MUICIRQ_ADCError, MUIC_INT1, 1 << 2), | ||
104 | DECLARE_IRQ(MAX8997_MUICIRQ_ADCLow, MUIC_INT1, 1 << 1), | ||
105 | DECLARE_IRQ(MAX8997_MUICIRQ_ADC, MUIC_INT1, 1 << 0), | ||
106 | |||
107 | DECLARE_IRQ(MAX8997_MUICIRQ_VBVolt, MUIC_INT2, 1 << 4), | ||
108 | DECLARE_IRQ(MAX8997_MUICIRQ_DBChg, MUIC_INT2, 1 << 3), | ||
109 | DECLARE_IRQ(MAX8997_MUICIRQ_DCDTmr, MUIC_INT2, 1 << 2), | ||
110 | DECLARE_IRQ(MAX8997_MUICIRQ_ChgDetRun, MUIC_INT2, 1 << 1), | ||
111 | DECLARE_IRQ(MAX8997_MUICIRQ_ChgTyp, MUIC_INT2, 1 << 0), | ||
112 | |||
113 | DECLARE_IRQ(MAX8997_MUICIRQ_OVP, MUIC_INT3, 1 << 2), | ||
114 | }; | ||
115 | |||
116 | static void max8997_irq_lock(struct irq_data *data) | ||
117 | { | ||
118 | struct max8997_dev *max8997 = irq_get_chip_data(data->irq); | ||
119 | |||
120 | mutex_lock(&max8997->irqlock); | ||
121 | } | ||
122 | |||
123 | static void max8997_irq_sync_unlock(struct irq_data *data) | ||
124 | { | ||
125 | struct max8997_dev *max8997 = irq_get_chip_data(data->irq); | ||
126 | int i; | ||
127 | |||
128 | for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) { | ||
129 | u8 mask_reg = max8997_mask_reg[i]; | ||
130 | struct i2c_client *i2c = get_i2c(max8997, i); | ||
131 | |||
132 | if (mask_reg == MAX8997_REG_INVALID || | ||
133 | IS_ERR_OR_NULL(i2c)) | ||
134 | continue; | ||
135 | max8997->irq_masks_cache[i] = max8997->irq_masks_cur[i]; | ||
136 | |||
137 | max8997_write_reg(i2c, max8997_mask_reg[i], | ||
138 | max8997->irq_masks_cur[i]); | ||
139 | } | ||
140 | |||
141 | mutex_unlock(&max8997->irqlock); | ||
142 | } | ||
143 | |||
144 | static const inline struct max8997_irq_data * | ||
145 | irq_to_max8997_irq(struct max8997_dev *max8997, int irq) | ||
146 | { | ||
147 | return &max8997_irqs[irq - max8997->irq_base]; | ||
148 | } | ||
149 | |||
150 | static void max8997_irq_mask(struct irq_data *data) | ||
151 | { | ||
152 | struct max8997_dev *max8997 = irq_get_chip_data(data->irq); | ||
153 | const struct max8997_irq_data *irq_data = irq_to_max8997_irq(max8997, | ||
154 | data->irq); | ||
155 | |||
156 | max8997->irq_masks_cur[irq_data->group] |= irq_data->mask; | ||
157 | } | ||
158 | |||
159 | static void max8997_irq_unmask(struct irq_data *data) | ||
160 | { | ||
161 | struct max8997_dev *max8997 = irq_get_chip_data(data->irq); | ||
162 | const struct max8997_irq_data *irq_data = irq_to_max8997_irq(max8997, | ||
163 | data->irq); | ||
164 | |||
165 | max8997->irq_masks_cur[irq_data->group] &= ~irq_data->mask; | ||
166 | } | ||
167 | |||
168 | static struct irq_chip max8997_irq_chip = { | ||
169 | .name = "max8997", | ||
170 | .irq_bus_lock = max8997_irq_lock, | ||
171 | .irq_bus_sync_unlock = max8997_irq_sync_unlock, | ||
172 | .irq_mask = max8997_irq_mask, | ||
173 | .irq_unmask = max8997_irq_unmask, | ||
174 | }; | ||
175 | |||
176 | #define MAX8997_IRQSRC_PMIC (1 << 1) | ||
177 | #define MAX8997_IRQSRC_FUELGAUGE (1 << 2) | ||
178 | #define MAX8997_IRQSRC_MUIC (1 << 3) | ||
179 | #define MAX8997_IRQSRC_GPIO (1 << 4) | ||
180 | #define MAX8997_IRQSRC_FLASH (1 << 5) | ||
181 | static irqreturn_t max8997_irq_thread(int irq, void *data) | ||
182 | { | ||
183 | struct max8997_dev *max8997 = data; | ||
184 | u8 irq_reg[MAX8997_IRQ_GROUP_NR] = {}; | ||
185 | u8 irq_src; | ||
186 | int ret; | ||
187 | int i; | ||
188 | |||
189 | ret = max8997_read_reg(max8997->i2c, MAX8997_REG_INTSRC, &irq_src); | ||
190 | if (ret < 0) { | ||
191 | dev_err(max8997->dev, "Failed to read interrupt source: %d\n", | ||
192 | ret); | ||
193 | return IRQ_NONE; | ||
194 | } | ||
195 | |||
196 | if (irq_src & MAX8997_IRQSRC_PMIC) { | ||
197 | /* PMIC INT1 ~ INT4 */ | ||
198 | max8997_bulk_read(max8997->i2c, MAX8997_REG_INT1, 4, | ||
199 | &irq_reg[PMIC_INT1]); | ||
200 | } | ||
201 | if (irq_src & MAX8997_IRQSRC_FUELGAUGE) { | ||
202 | /* | ||
203 | * TODO: FUEL GAUGE | ||
204 | * | ||
205 | * This is to be supported by Max17042 driver. When | ||
206 | * an interrupt incurs here, it should be relayed to a | ||
207 | * Max17042 device that is connected (probably by | ||
208 | * platform-data). However, we do not have interrupt | ||
209 | * handling in Max17042 driver currently. The Max17042 IRQ | ||
210 | * driver should be ready to be used as a stand-alone device and | ||
211 | * a Max8997-dependent device. Because it is not ready in | ||
212 | * Max17042-side and it is not too critical in operating | ||
213 | * Max8997, we do not implement this in initial releases. | ||
214 | */ | ||
215 | irq_reg[FUEL_GAUGE] = 0; | ||
216 | } | ||
217 | if (irq_src & MAX8997_IRQSRC_MUIC) { | ||
218 | /* MUIC INT1 ~ INT3 */ | ||
219 | max8997_bulk_read(max8997->muic, MAX8997_MUIC_REG_INT1, 3, | ||
220 | &irq_reg[MUIC_INT1]); | ||
221 | } | ||
222 | if (irq_src & MAX8997_IRQSRC_GPIO) { | ||
223 | /* GPIO Interrupt */ | ||
224 | u8 gpio_info[MAX8997_NUM_GPIO]; | ||
225 | |||
226 | irq_reg[GPIO_LOW] = 0; | ||
227 | irq_reg[GPIO_HI] = 0; | ||
228 | |||
229 | max8997_bulk_read(max8997->i2c, MAX8997_REG_GPIOCNTL1, | ||
230 | MAX8997_NUM_GPIO, gpio_info); | ||
231 | for (i = 0; i < MAX8997_NUM_GPIO; i++) { | ||
232 | bool interrupt = false; | ||
233 | |||
234 | switch (gpio_info[i] & MAX8997_GPIO_INT_MASK) { | ||
235 | case MAX8997_GPIO_INT_BOTH: | ||
236 | if (max8997->gpio_status[i] != gpio_info[i]) | ||
237 | interrupt = true; | ||
238 | break; | ||
239 | case MAX8997_GPIO_INT_RISE: | ||
240 | if ((max8997->gpio_status[i] != gpio_info[i]) && | ||
241 | (gpio_info[i] & MAX8997_GPIO_DATA_MASK)) | ||
242 | interrupt = true; | ||
243 | break; | ||
244 | case MAX8997_GPIO_INT_FALL: | ||
245 | if ((max8997->gpio_status[i] != gpio_info[i]) && | ||
246 | !(gpio_info[i] & MAX8997_GPIO_DATA_MASK)) | ||
247 | interrupt = true; | ||
248 | break; | ||
249 | default: | ||
250 | break; | ||
251 | } | ||
252 | |||
253 | if (interrupt) { | ||
254 | if (i < 8) | ||
255 | irq_reg[GPIO_LOW] |= (1 << i); | ||
256 | else | ||
257 | irq_reg[GPIO_HI] |= (1 << (i - 8)); | ||
258 | } | ||
259 | |||
260 | } | ||
261 | } | ||
262 | if (irq_src & MAX8997_IRQSRC_FLASH) { | ||
263 | /* Flash Status Interrupt */ | ||
264 | ret = max8997_read_reg(max8997->i2c, MAX8997_REG_FLASHSTATUS, | ||
265 | &irq_reg[FLASH_STATUS]); | ||
266 | } | ||
267 | |||
268 | /* Apply masking */ | ||
269 | for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) | ||
270 | irq_reg[i] &= ~max8997->irq_masks_cur[i]; | ||
271 | |||
272 | /* Report */ | ||
273 | for (i = 0; i < MAX8997_IRQ_NR; i++) { | ||
274 | if (irq_reg[max8997_irqs[i].group] & max8997_irqs[i].mask) | ||
275 | handle_nested_irq(max8997->irq_base + i); | ||
276 | } | ||
277 | |||
278 | return IRQ_HANDLED; | ||
279 | } | ||
280 | |||
281 | int max8997_irq_resume(struct max8997_dev *max8997) | ||
282 | { | ||
283 | if (max8997->irq && max8997->irq_base) | ||
284 | max8997_irq_thread(max8997->irq_base, max8997); | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | int max8997_irq_init(struct max8997_dev *max8997) | ||
289 | { | ||
290 | int i; | ||
291 | int cur_irq; | ||
292 | int ret; | ||
293 | u8 val; | ||
294 | |||
295 | if (!max8997->irq) { | ||
296 | dev_warn(max8997->dev, "No interrupt specified.\n"); | ||
297 | max8997->irq_base = 0; | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | if (!max8997->irq_base) { | ||
302 | dev_err(max8997->dev, "No interrupt base specified.\n"); | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | mutex_init(&max8997->irqlock); | ||
307 | |||
308 | /* Mask individual interrupt sources */ | ||
309 | for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) { | ||
310 | struct i2c_client *i2c; | ||
311 | |||
312 | max8997->irq_masks_cur[i] = 0xff; | ||
313 | max8997->irq_masks_cache[i] = 0xff; | ||
314 | i2c = get_i2c(max8997, i); | ||
315 | |||
316 | if (IS_ERR_OR_NULL(i2c)) | ||
317 | continue; | ||
318 | if (max8997_mask_reg[i] == MAX8997_REG_INVALID) | ||
319 | continue; | ||
320 | |||
321 | max8997_write_reg(i2c, max8997_mask_reg[i], 0xff); | ||
322 | } | ||
323 | |||
324 | for (i = 0; i < MAX8997_NUM_GPIO; i++) { | ||
325 | max8997->gpio_status[i] = (max8997_read_reg(max8997->i2c, | ||
326 | MAX8997_REG_GPIOCNTL1 + i, | ||
327 | &val) | ||
328 | & MAX8997_GPIO_DATA_MASK) ? | ||
329 | true : false; | ||
330 | } | ||
331 | |||
332 | /* Register with genirq */ | ||
333 | for (i = 0; i < MAX8997_IRQ_NR; i++) { | ||
334 | cur_irq = i + max8997->irq_base; | ||
335 | irq_set_chip_data(cur_irq, max8997); | ||
336 | irq_set_chip_and_handler(cur_irq, &max8997_irq_chip, | ||
337 | handle_edge_irq); | ||
338 | irq_set_nested_thread(cur_irq, 1); | ||
339 | #ifdef CONFIG_ARM | ||
340 | set_irq_flags(cur_irq, IRQF_VALID); | ||
341 | #else | ||
342 | irq_set_noprobe(cur_irq); | ||
343 | #endif | ||
344 | } | ||
345 | |||
346 | ret = request_threaded_irq(max8997->irq, NULL, max8997_irq_thread, | ||
347 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
348 | "max8997-irq", max8997); | ||
349 | |||
350 | if (ret) { | ||
351 | dev_err(max8997->dev, "Failed to request IRQ %d: %d\n", | ||
352 | max8997->irq, ret); | ||
353 | return ret; | ||
354 | } | ||
355 | |||
356 | if (!max8997->ono) | ||
357 | return 0; | ||
358 | |||
359 | ret = request_threaded_irq(max8997->ono, NULL, max8997_irq_thread, | ||
360 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | | ||
361 | IRQF_ONESHOT, "max8997-ono", max8997); | ||
362 | |||
363 | if (ret) | ||
364 | dev_err(max8997->dev, "Failed to request ono-IRQ %d: %d\n", | ||
365 | max8997->ono, ret); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | void max8997_irq_exit(struct max8997_dev *max8997) | ||
371 | { | ||
372 | if (max8997->ono) | ||
373 | free_irq(max8997->ono, max8997); | ||
374 | |||
375 | if (max8997->irq) | ||
376 | free_irq(max8997->irq, max8997); | ||
377 | } | ||
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c new file mode 100644 index 000000000000..5d1fca0277ef --- /dev/null +++ b/drivers/mfd/max8997.c | |||
@@ -0,0 +1,427 @@ | |||
1 | /* | ||
2 | * max8997.c - mfd core driver for the Maxim 8966 and 8997 | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics | ||
5 | * MyungJoo Ham <myungjoo.ham@smasung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | * This driver is based on max8998.c | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <linux/mutex.h> | ||
28 | #include <linux/mfd/core.h> | ||
29 | #include <linux/mfd/max8997.h> | ||
30 | #include <linux/mfd/max8997-private.h> | ||
31 | |||
32 | #define I2C_ADDR_PMIC (0xCC >> 1) | ||
33 | #define I2C_ADDR_MUIC (0x4A >> 1) | ||
34 | #define I2C_ADDR_BATTERY (0x6C >> 1) | ||
35 | #define I2C_ADDR_RTC (0x0C >> 1) | ||
36 | #define I2C_ADDR_HAPTIC (0x90 >> 1) | ||
37 | |||
38 | static struct mfd_cell max8997_devs[] = { | ||
39 | { .name = "max8997-pmic", }, | ||
40 | { .name = "max8997-rtc", }, | ||
41 | { .name = "max8997-battery", }, | ||
42 | { .name = "max8997-haptic", }, | ||
43 | { .name = "max8997-muic", }, | ||
44 | { .name = "max8997-flash", }, | ||
45 | }; | ||
46 | |||
47 | int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest) | ||
48 | { | ||
49 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
50 | int ret; | ||
51 | |||
52 | mutex_lock(&max8997->iolock); | ||
53 | ret = i2c_smbus_read_byte_data(i2c, reg); | ||
54 | mutex_unlock(&max8997->iolock); | ||
55 | if (ret < 0) | ||
56 | return ret; | ||
57 | |||
58 | ret &= 0xff; | ||
59 | *dest = ret; | ||
60 | return 0; | ||
61 | } | ||
62 | EXPORT_SYMBOL_GPL(max8997_read_reg); | ||
63 | |||
64 | int max8997_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf) | ||
65 | { | ||
66 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
67 | int ret; | ||
68 | |||
69 | mutex_lock(&max8997->iolock); | ||
70 | ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf); | ||
71 | mutex_unlock(&max8997->iolock); | ||
72 | if (ret < 0) | ||
73 | return ret; | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | EXPORT_SYMBOL_GPL(max8997_bulk_read); | ||
78 | |||
79 | int max8997_write_reg(struct i2c_client *i2c, u8 reg, u8 value) | ||
80 | { | ||
81 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
82 | int ret; | ||
83 | |||
84 | mutex_lock(&max8997->iolock); | ||
85 | ret = i2c_smbus_write_byte_data(i2c, reg, value); | ||
86 | mutex_unlock(&max8997->iolock); | ||
87 | return ret; | ||
88 | } | ||
89 | EXPORT_SYMBOL_GPL(max8997_write_reg); | ||
90 | |||
91 | int max8997_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf) | ||
92 | { | ||
93 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
94 | int ret; | ||
95 | |||
96 | mutex_lock(&max8997->iolock); | ||
97 | ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf); | ||
98 | mutex_unlock(&max8997->iolock); | ||
99 | if (ret < 0) | ||
100 | return ret; | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | EXPORT_SYMBOL_GPL(max8997_bulk_write); | ||
105 | |||
106 | int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask) | ||
107 | { | ||
108 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
109 | int ret; | ||
110 | |||
111 | mutex_lock(&max8997->iolock); | ||
112 | ret = i2c_smbus_read_byte_data(i2c, reg); | ||
113 | if (ret >= 0) { | ||
114 | u8 old_val = ret & 0xff; | ||
115 | u8 new_val = (val & mask) | (old_val & (~mask)); | ||
116 | ret = i2c_smbus_write_byte_data(i2c, reg, new_val); | ||
117 | } | ||
118 | mutex_unlock(&max8997->iolock); | ||
119 | return ret; | ||
120 | } | ||
121 | EXPORT_SYMBOL_GPL(max8997_update_reg); | ||
122 | |||
123 | static int max8997_i2c_probe(struct i2c_client *i2c, | ||
124 | const struct i2c_device_id *id) | ||
125 | { | ||
126 | struct max8997_dev *max8997; | ||
127 | struct max8997_platform_data *pdata = i2c->dev.platform_data; | ||
128 | int ret = 0; | ||
129 | |||
130 | max8997 = kzalloc(sizeof(struct max8997_dev), GFP_KERNEL); | ||
131 | if (max8997 == NULL) | ||
132 | return -ENOMEM; | ||
133 | |||
134 | i2c_set_clientdata(i2c, max8997); | ||
135 | max8997->dev = &i2c->dev; | ||
136 | max8997->i2c = i2c; | ||
137 | max8997->type = id->driver_data; | ||
138 | |||
139 | if (!pdata) | ||
140 | goto err; | ||
141 | |||
142 | max8997->wakeup = pdata->wakeup; | ||
143 | |||
144 | mutex_init(&max8997->iolock); | ||
145 | |||
146 | max8997->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC); | ||
147 | i2c_set_clientdata(max8997->rtc, max8997); | ||
148 | max8997->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC); | ||
149 | i2c_set_clientdata(max8997->haptic, max8997); | ||
150 | max8997->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC); | ||
151 | i2c_set_clientdata(max8997->muic, max8997); | ||
152 | |||
153 | pm_runtime_set_active(max8997->dev); | ||
154 | |||
155 | mfd_add_devices(max8997->dev, -1, max8997_devs, | ||
156 | ARRAY_SIZE(max8997_devs), | ||
157 | NULL, 0); | ||
158 | |||
159 | /* | ||
160 | * TODO: enable others (flash, muic, rtc, battery, ...) and | ||
161 | * check the return value | ||
162 | */ | ||
163 | |||
164 | if (ret < 0) | ||
165 | goto err_mfd; | ||
166 | |||
167 | return ret; | ||
168 | |||
169 | err_mfd: | ||
170 | mfd_remove_devices(max8997->dev); | ||
171 | i2c_unregister_device(max8997->muic); | ||
172 | i2c_unregister_device(max8997->haptic); | ||
173 | i2c_unregister_device(max8997->rtc); | ||
174 | err: | ||
175 | kfree(max8997); | ||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static int max8997_i2c_remove(struct i2c_client *i2c) | ||
180 | { | ||
181 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
182 | |||
183 | mfd_remove_devices(max8997->dev); | ||
184 | i2c_unregister_device(max8997->muic); | ||
185 | i2c_unregister_device(max8997->haptic); | ||
186 | i2c_unregister_device(max8997->rtc); | ||
187 | kfree(max8997); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static const struct i2c_device_id max8997_i2c_id[] = { | ||
193 | { "max8997", TYPE_MAX8997 }, | ||
194 | { "max8966", TYPE_MAX8966 }, | ||
195 | { } | ||
196 | }; | ||
197 | MODULE_DEVICE_TABLE(i2c, max8998_i2c_id); | ||
198 | |||
199 | u8 max8997_dumpaddr_pmic[] = { | ||
200 | MAX8997_REG_INT1MSK, | ||
201 | MAX8997_REG_INT2MSK, | ||
202 | MAX8997_REG_INT3MSK, | ||
203 | MAX8997_REG_INT4MSK, | ||
204 | MAX8997_REG_MAINCON1, | ||
205 | MAX8997_REG_MAINCON2, | ||
206 | MAX8997_REG_BUCKRAMP, | ||
207 | MAX8997_REG_BUCK1CTRL, | ||
208 | MAX8997_REG_BUCK1DVS1, | ||
209 | MAX8997_REG_BUCK1DVS2, | ||
210 | MAX8997_REG_BUCK1DVS3, | ||
211 | MAX8997_REG_BUCK1DVS4, | ||
212 | MAX8997_REG_BUCK1DVS5, | ||
213 | MAX8997_REG_BUCK1DVS6, | ||
214 | MAX8997_REG_BUCK1DVS7, | ||
215 | MAX8997_REG_BUCK1DVS8, | ||
216 | MAX8997_REG_BUCK2CTRL, | ||
217 | MAX8997_REG_BUCK2DVS1, | ||
218 | MAX8997_REG_BUCK2DVS2, | ||
219 | MAX8997_REG_BUCK2DVS3, | ||
220 | MAX8997_REG_BUCK2DVS4, | ||
221 | MAX8997_REG_BUCK2DVS5, | ||
222 | MAX8997_REG_BUCK2DVS6, | ||
223 | MAX8997_REG_BUCK2DVS7, | ||
224 | MAX8997_REG_BUCK2DVS8, | ||
225 | MAX8997_REG_BUCK3CTRL, | ||
226 | MAX8997_REG_BUCK3DVS, | ||
227 | MAX8997_REG_BUCK4CTRL, | ||
228 | MAX8997_REG_BUCK4DVS, | ||
229 | MAX8997_REG_BUCK5CTRL, | ||
230 | MAX8997_REG_BUCK5DVS1, | ||
231 | MAX8997_REG_BUCK5DVS2, | ||
232 | MAX8997_REG_BUCK5DVS3, | ||
233 | MAX8997_REG_BUCK5DVS4, | ||
234 | MAX8997_REG_BUCK5DVS5, | ||
235 | MAX8997_REG_BUCK5DVS6, | ||
236 | MAX8997_REG_BUCK5DVS7, | ||
237 | MAX8997_REG_BUCK5DVS8, | ||
238 | MAX8997_REG_BUCK6CTRL, | ||
239 | MAX8997_REG_BUCK6BPSKIPCTRL, | ||
240 | MAX8997_REG_BUCK7CTRL, | ||
241 | MAX8997_REG_BUCK7DVS, | ||
242 | MAX8997_REG_LDO1CTRL, | ||
243 | MAX8997_REG_LDO2CTRL, | ||
244 | MAX8997_REG_LDO3CTRL, | ||
245 | MAX8997_REG_LDO4CTRL, | ||
246 | MAX8997_REG_LDO5CTRL, | ||
247 | MAX8997_REG_LDO6CTRL, | ||
248 | MAX8997_REG_LDO7CTRL, | ||
249 | MAX8997_REG_LDO8CTRL, | ||
250 | MAX8997_REG_LDO9CTRL, | ||
251 | MAX8997_REG_LDO10CTRL, | ||
252 | MAX8997_REG_LDO11CTRL, | ||
253 | MAX8997_REG_LDO12CTRL, | ||
254 | MAX8997_REG_LDO13CTRL, | ||
255 | MAX8997_REG_LDO14CTRL, | ||
256 | MAX8997_REG_LDO15CTRL, | ||
257 | MAX8997_REG_LDO16CTRL, | ||
258 | MAX8997_REG_LDO17CTRL, | ||
259 | MAX8997_REG_LDO18CTRL, | ||
260 | MAX8997_REG_LDO21CTRL, | ||
261 | MAX8997_REG_MBCCTRL1, | ||
262 | MAX8997_REG_MBCCTRL2, | ||
263 | MAX8997_REG_MBCCTRL3, | ||
264 | MAX8997_REG_MBCCTRL4, | ||
265 | MAX8997_REG_MBCCTRL5, | ||
266 | MAX8997_REG_MBCCTRL6, | ||
267 | MAX8997_REG_OTPCGHCVS, | ||
268 | MAX8997_REG_SAFEOUTCTRL, | ||
269 | MAX8997_REG_LBCNFG1, | ||
270 | MAX8997_REG_LBCNFG2, | ||
271 | MAX8997_REG_BBCCTRL, | ||
272 | |||
273 | MAX8997_REG_FLASH1_CUR, | ||
274 | MAX8997_REG_FLASH2_CUR, | ||
275 | MAX8997_REG_MOVIE_CUR, | ||
276 | MAX8997_REG_GSMB_CUR, | ||
277 | MAX8997_REG_BOOST_CNTL, | ||
278 | MAX8997_REG_LEN_CNTL, | ||
279 | MAX8997_REG_FLASH_CNTL, | ||
280 | MAX8997_REG_WDT_CNTL, | ||
281 | MAX8997_REG_MAXFLASH1, | ||
282 | MAX8997_REG_MAXFLASH2, | ||
283 | MAX8997_REG_FLASHSTATUSMASK, | ||
284 | |||
285 | MAX8997_REG_GPIOCNTL1, | ||
286 | MAX8997_REG_GPIOCNTL2, | ||
287 | MAX8997_REG_GPIOCNTL3, | ||
288 | MAX8997_REG_GPIOCNTL4, | ||
289 | MAX8997_REG_GPIOCNTL5, | ||
290 | MAX8997_REG_GPIOCNTL6, | ||
291 | MAX8997_REG_GPIOCNTL7, | ||
292 | MAX8997_REG_GPIOCNTL8, | ||
293 | MAX8997_REG_GPIOCNTL9, | ||
294 | MAX8997_REG_GPIOCNTL10, | ||
295 | MAX8997_REG_GPIOCNTL11, | ||
296 | MAX8997_REG_GPIOCNTL12, | ||
297 | |||
298 | MAX8997_REG_LDO1CONFIG, | ||
299 | MAX8997_REG_LDO2CONFIG, | ||
300 | MAX8997_REG_LDO3CONFIG, | ||
301 | MAX8997_REG_LDO4CONFIG, | ||
302 | MAX8997_REG_LDO5CONFIG, | ||
303 | MAX8997_REG_LDO6CONFIG, | ||
304 | MAX8997_REG_LDO7CONFIG, | ||
305 | MAX8997_REG_LDO8CONFIG, | ||
306 | MAX8997_REG_LDO9CONFIG, | ||
307 | MAX8997_REG_LDO10CONFIG, | ||
308 | MAX8997_REG_LDO11CONFIG, | ||
309 | MAX8997_REG_LDO12CONFIG, | ||
310 | MAX8997_REG_LDO13CONFIG, | ||
311 | MAX8997_REG_LDO14CONFIG, | ||
312 | MAX8997_REG_LDO15CONFIG, | ||
313 | MAX8997_REG_LDO16CONFIG, | ||
314 | MAX8997_REG_LDO17CONFIG, | ||
315 | MAX8997_REG_LDO18CONFIG, | ||
316 | MAX8997_REG_LDO21CONFIG, | ||
317 | |||
318 | MAX8997_REG_DVSOKTIMER1, | ||
319 | MAX8997_REG_DVSOKTIMER2, | ||
320 | MAX8997_REG_DVSOKTIMER4, | ||
321 | MAX8997_REG_DVSOKTIMER5, | ||
322 | }; | ||
323 | |||
324 | u8 max8997_dumpaddr_muic[] = { | ||
325 | MAX8997_MUIC_REG_INTMASK1, | ||
326 | MAX8997_MUIC_REG_INTMASK2, | ||
327 | MAX8997_MUIC_REG_INTMASK3, | ||
328 | MAX8997_MUIC_REG_CDETCTRL, | ||
329 | MAX8997_MUIC_REG_CONTROL1, | ||
330 | MAX8997_MUIC_REG_CONTROL2, | ||
331 | MAX8997_MUIC_REG_CONTROL3, | ||
332 | }; | ||
333 | |||
334 | u8 max8997_dumpaddr_haptic[] = { | ||
335 | MAX8997_HAPTIC_REG_CONF1, | ||
336 | MAX8997_HAPTIC_REG_CONF2, | ||
337 | MAX8997_HAPTIC_REG_DRVCONF, | ||
338 | MAX8997_HAPTIC_REG_CYCLECONF1, | ||
339 | MAX8997_HAPTIC_REG_CYCLECONF2, | ||
340 | MAX8997_HAPTIC_REG_SIGCONF1, | ||
341 | MAX8997_HAPTIC_REG_SIGCONF2, | ||
342 | MAX8997_HAPTIC_REG_SIGCONF3, | ||
343 | MAX8997_HAPTIC_REG_SIGCONF4, | ||
344 | MAX8997_HAPTIC_REG_SIGDC1, | ||
345 | MAX8997_HAPTIC_REG_SIGDC2, | ||
346 | MAX8997_HAPTIC_REG_SIGPWMDC1, | ||
347 | MAX8997_HAPTIC_REG_SIGPWMDC2, | ||
348 | MAX8997_HAPTIC_REG_SIGPWMDC3, | ||
349 | MAX8997_HAPTIC_REG_SIGPWMDC4, | ||
350 | }; | ||
351 | |||
352 | static int max8997_freeze(struct device *dev) | ||
353 | { | ||
354 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
355 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
356 | int i; | ||
357 | |||
358 | for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++) | ||
359 | max8997_read_reg(i2c, max8997_dumpaddr_pmic[i], | ||
360 | &max8997->reg_dump[i]); | ||
361 | |||
362 | for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++) | ||
363 | max8997_read_reg(i2c, max8997_dumpaddr_muic[i], | ||
364 | &max8997->reg_dump[i + MAX8997_REG_PMIC_END]); | ||
365 | |||
366 | for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++) | ||
367 | max8997_read_reg(i2c, max8997_dumpaddr_haptic[i], | ||
368 | &max8997->reg_dump[i + MAX8997_REG_PMIC_END + | ||
369 | MAX8997_MUIC_REG_END]); | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int max8997_restore(struct device *dev) | ||
375 | { | ||
376 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
377 | struct max8997_dev *max8997 = i2c_get_clientdata(i2c); | ||
378 | int i; | ||
379 | |||
380 | for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++) | ||
381 | max8997_write_reg(i2c, max8997_dumpaddr_pmic[i], | ||
382 | max8997->reg_dump[i]); | ||
383 | |||
384 | for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++) | ||
385 | max8997_write_reg(i2c, max8997_dumpaddr_muic[i], | ||
386 | max8997->reg_dump[i + MAX8997_REG_PMIC_END]); | ||
387 | |||
388 | for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++) | ||
389 | max8997_write_reg(i2c, max8997_dumpaddr_haptic[i], | ||
390 | max8997->reg_dump[i + MAX8997_REG_PMIC_END + | ||
391 | MAX8997_MUIC_REG_END]); | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | const struct dev_pm_ops max8997_pm = { | ||
397 | .freeze = max8997_freeze, | ||
398 | .restore = max8997_restore, | ||
399 | }; | ||
400 | |||
401 | static struct i2c_driver max8997_i2c_driver = { | ||
402 | .driver = { | ||
403 | .name = "max8997", | ||
404 | .owner = THIS_MODULE, | ||
405 | .pm = &max8997_pm, | ||
406 | }, | ||
407 | .probe = max8997_i2c_probe, | ||
408 | .remove = max8997_i2c_remove, | ||
409 | .id_table = max8997_i2c_id, | ||
410 | }; | ||
411 | |||
412 | static int __init max8997_i2c_init(void) | ||
413 | { | ||
414 | return i2c_add_driver(&max8997_i2c_driver); | ||
415 | } | ||
416 | /* init early so consumer devices can complete system boot */ | ||
417 | subsys_initcall(max8997_i2c_init); | ||
418 | |||
419 | static void __exit max8997_i2c_exit(void) | ||
420 | { | ||
421 | i2c_del_driver(&max8997_i2c_driver); | ||
422 | } | ||
423 | module_exit(max8997_i2c_exit); | ||
424 | |||
425 | MODULE_DESCRIPTION("MAXIM 8997 multi-function core driver"); | ||
426 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); | ||
427 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c new file mode 100644 index 000000000000..5919710dc9ed --- /dev/null +++ b/drivers/mfd/max8998-irq.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * Interrupt controller support for MAX8998 | ||
3 | * | ||
4 | * Copyright (C) 2010 Samsung Electronics Co.Ltd | ||
5 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/mfd/max8998-private.h> | ||
18 | |||
19 | struct max8998_irq_data { | ||
20 | int reg; | ||
21 | int mask; | ||
22 | }; | ||
23 | |||
24 | static struct max8998_irq_data max8998_irqs[] = { | ||
25 | [MAX8998_IRQ_DCINF] = { | ||
26 | .reg = 1, | ||
27 | .mask = MAX8998_IRQ_DCINF_MASK, | ||
28 | }, | ||
29 | [MAX8998_IRQ_DCINR] = { | ||
30 | .reg = 1, | ||
31 | .mask = MAX8998_IRQ_DCINR_MASK, | ||
32 | }, | ||
33 | [MAX8998_IRQ_JIGF] = { | ||
34 | .reg = 1, | ||
35 | .mask = MAX8998_IRQ_JIGF_MASK, | ||
36 | }, | ||
37 | [MAX8998_IRQ_JIGR] = { | ||
38 | .reg = 1, | ||
39 | .mask = MAX8998_IRQ_JIGR_MASK, | ||
40 | }, | ||
41 | [MAX8998_IRQ_PWRONF] = { | ||
42 | .reg = 1, | ||
43 | .mask = MAX8998_IRQ_PWRONF_MASK, | ||
44 | }, | ||
45 | [MAX8998_IRQ_PWRONR] = { | ||
46 | .reg = 1, | ||
47 | .mask = MAX8998_IRQ_PWRONR_MASK, | ||
48 | }, | ||
49 | [MAX8998_IRQ_WTSREVNT] = { | ||
50 | .reg = 2, | ||
51 | .mask = MAX8998_IRQ_WTSREVNT_MASK, | ||
52 | }, | ||
53 | [MAX8998_IRQ_SMPLEVNT] = { | ||
54 | .reg = 2, | ||
55 | .mask = MAX8998_IRQ_SMPLEVNT_MASK, | ||
56 | }, | ||
57 | [MAX8998_IRQ_ALARM1] = { | ||
58 | .reg = 2, | ||
59 | .mask = MAX8998_IRQ_ALARM1_MASK, | ||
60 | }, | ||
61 | [MAX8998_IRQ_ALARM0] = { | ||
62 | .reg = 2, | ||
63 | .mask = MAX8998_IRQ_ALARM0_MASK, | ||
64 | }, | ||
65 | [MAX8998_IRQ_ONKEY1S] = { | ||
66 | .reg = 3, | ||
67 | .mask = MAX8998_IRQ_ONKEY1S_MASK, | ||
68 | }, | ||
69 | [MAX8998_IRQ_TOPOFFR] = { | ||
70 | .reg = 3, | ||
71 | .mask = MAX8998_IRQ_TOPOFFR_MASK, | ||
72 | }, | ||
73 | [MAX8998_IRQ_DCINOVPR] = { | ||
74 | .reg = 3, | ||
75 | .mask = MAX8998_IRQ_DCINOVPR_MASK, | ||
76 | }, | ||
77 | [MAX8998_IRQ_CHGRSTF] = { | ||
78 | .reg = 3, | ||
79 | .mask = MAX8998_IRQ_CHGRSTF_MASK, | ||
80 | }, | ||
81 | [MAX8998_IRQ_DONER] = { | ||
82 | .reg = 3, | ||
83 | .mask = MAX8998_IRQ_DONER_MASK, | ||
84 | }, | ||
85 | [MAX8998_IRQ_CHGFAULT] = { | ||
86 | .reg = 3, | ||
87 | .mask = MAX8998_IRQ_CHGFAULT_MASK, | ||
88 | }, | ||
89 | [MAX8998_IRQ_LOBAT1] = { | ||
90 | .reg = 4, | ||
91 | .mask = MAX8998_IRQ_LOBAT1_MASK, | ||
92 | }, | ||
93 | [MAX8998_IRQ_LOBAT2] = { | ||
94 | .reg = 4, | ||
95 | .mask = MAX8998_IRQ_LOBAT2_MASK, | ||
96 | }, | ||
97 | }; | ||
98 | |||
99 | static inline struct max8998_irq_data * | ||
100 | irq_to_max8998_irq(struct max8998_dev *max8998, int irq) | ||
101 | { | ||
102 | return &max8998_irqs[irq - max8998->irq_base]; | ||
103 | } | ||
104 | |||
105 | static void max8998_irq_lock(struct irq_data *data) | ||
106 | { | ||
107 | struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data); | ||
108 | |||
109 | mutex_lock(&max8998->irqlock); | ||
110 | } | ||
111 | |||
112 | static void max8998_irq_sync_unlock(struct irq_data *data) | ||
113 | { | ||
114 | struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data); | ||
115 | int i; | ||
116 | |||
117 | for (i = 0; i < ARRAY_SIZE(max8998->irq_masks_cur); i++) { | ||
118 | /* | ||
119 | * If there's been a change in the mask write it back | ||
120 | * to the hardware. | ||
121 | */ | ||
122 | if (max8998->irq_masks_cur[i] != max8998->irq_masks_cache[i]) { | ||
123 | max8998->irq_masks_cache[i] = max8998->irq_masks_cur[i]; | ||
124 | max8998_write_reg(max8998->i2c, MAX8998_REG_IRQM1 + i, | ||
125 | max8998->irq_masks_cur[i]); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | mutex_unlock(&max8998->irqlock); | ||
130 | } | ||
131 | |||
132 | static void max8998_irq_unmask(struct irq_data *data) | ||
133 | { | ||
134 | struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data); | ||
135 | struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, | ||
136 | data->irq); | ||
137 | |||
138 | max8998->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; | ||
139 | } | ||
140 | |||
141 | static void max8998_irq_mask(struct irq_data *data) | ||
142 | { | ||
143 | struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data); | ||
144 | struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, | ||
145 | data->irq); | ||
146 | |||
147 | max8998->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; | ||
148 | } | ||
149 | |||
150 | static struct irq_chip max8998_irq_chip = { | ||
151 | .name = "max8998", | ||
152 | .irq_bus_lock = max8998_irq_lock, | ||
153 | .irq_bus_sync_unlock = max8998_irq_sync_unlock, | ||
154 | .irq_mask = max8998_irq_mask, | ||
155 | .irq_unmask = max8998_irq_unmask, | ||
156 | }; | ||
157 | |||
158 | static irqreturn_t max8998_irq_thread(int irq, void *data) | ||
159 | { | ||
160 | struct max8998_dev *max8998 = data; | ||
161 | u8 irq_reg[MAX8998_NUM_IRQ_REGS]; | ||
162 | int ret; | ||
163 | int i; | ||
164 | |||
165 | ret = max8998_bulk_read(max8998->i2c, MAX8998_REG_IRQ1, | ||
166 | MAX8998_NUM_IRQ_REGS, irq_reg); | ||
167 | if (ret < 0) { | ||
168 | dev_err(max8998->dev, "Failed to read interrupt register: %d\n", | ||
169 | ret); | ||
170 | return IRQ_NONE; | ||
171 | } | ||
172 | |||
173 | /* Apply masking */ | ||
174 | for (i = 0; i < MAX8998_NUM_IRQ_REGS; i++) | ||
175 | irq_reg[i] &= ~max8998->irq_masks_cur[i]; | ||
176 | |||
177 | /* Report */ | ||
178 | for (i = 0; i < MAX8998_IRQ_NR; i++) { | ||
179 | if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask) | ||
180 | handle_nested_irq(max8998->irq_base + i); | ||
181 | } | ||
182 | |||
183 | return IRQ_HANDLED; | ||
184 | } | ||
185 | |||
186 | int max8998_irq_resume(struct max8998_dev *max8998) | ||
187 | { | ||
188 | if (max8998->irq && max8998->irq_base) | ||
189 | max8998_irq_thread(max8998->irq_base, max8998); | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | int max8998_irq_init(struct max8998_dev *max8998) | ||
194 | { | ||
195 | int i; | ||
196 | int cur_irq; | ||
197 | int ret; | ||
198 | |||
199 | if (!max8998->irq) { | ||
200 | dev_warn(max8998->dev, | ||
201 | "No interrupt specified, no interrupts\n"); | ||
202 | max8998->irq_base = 0; | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | if (!max8998->irq_base) { | ||
207 | dev_err(max8998->dev, | ||
208 | "No interrupt base specified, no interrupts\n"); | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | mutex_init(&max8998->irqlock); | ||
213 | |||
214 | /* Mask the individual interrupt sources */ | ||
215 | for (i = 0; i < MAX8998_NUM_IRQ_REGS; i++) { | ||
216 | max8998->irq_masks_cur[i] = 0xff; | ||
217 | max8998->irq_masks_cache[i] = 0xff; | ||
218 | max8998_write_reg(max8998->i2c, MAX8998_REG_IRQM1 + i, 0xff); | ||
219 | } | ||
220 | |||
221 | max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM1, 0xff); | ||
222 | max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM2, 0xff); | ||
223 | |||
224 | /* register with genirq */ | ||
225 | for (i = 0; i < MAX8998_IRQ_NR; i++) { | ||
226 | cur_irq = i + max8998->irq_base; | ||
227 | irq_set_chip_data(cur_irq, max8998); | ||
228 | irq_set_chip_and_handler(cur_irq, &max8998_irq_chip, | ||
229 | handle_edge_irq); | ||
230 | irq_set_nested_thread(cur_irq, 1); | ||
231 | #ifdef CONFIG_ARM | ||
232 | set_irq_flags(cur_irq, IRQF_VALID); | ||
233 | #else | ||
234 | irq_set_noprobe(cur_irq); | ||
235 | #endif | ||
236 | } | ||
237 | |||
238 | ret = request_threaded_irq(max8998->irq, NULL, max8998_irq_thread, | ||
239 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
240 | "max8998-irq", max8998); | ||
241 | if (ret) { | ||
242 | dev_err(max8998->dev, "Failed to request IRQ %d: %d\n", | ||
243 | max8998->irq, ret); | ||
244 | return ret; | ||
245 | } | ||
246 | |||
247 | if (!max8998->ono) | ||
248 | return 0; | ||
249 | |||
250 | ret = request_threaded_irq(max8998->ono, NULL, max8998_irq_thread, | ||
251 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | | ||
252 | IRQF_ONESHOT, "max8998-ono", max8998); | ||
253 | if (ret) | ||
254 | dev_err(max8998->dev, "Failed to request IRQ %d: %d\n", | ||
255 | max8998->ono, ret); | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | void max8998_irq_exit(struct max8998_dev *max8998) | ||
261 | { | ||
262 | if (max8998->ono) | ||
263 | free_irq(max8998->ono, max8998); | ||
264 | |||
265 | if (max8998->irq) | ||
266 | free_irq(max8998->irq, max8998); | ||
267 | } | ||
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 73e6f5c4efc9..9ec7570f5b81 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * max8698.c - mfd core driver for the Maxim 8998 | 2 | * max8998.c - mfd core driver for the Maxim 8998 |
3 | * | 3 | * |
4 | * Copyright (C) 2009-2010 Samsung Electronics | 4 | * Copyright (C) 2009-2010 Samsung Electronics |
5 | * Kyungmin Park <kyungmin.park@samsung.com> | 5 | * Kyungmin Park <kyungmin.park@samsung.com> |
@@ -25,24 +25,38 @@ | |||
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/pm_runtime.h> | ||
28 | #include <linux/mutex.h> | 30 | #include <linux/mutex.h> |
29 | #include <linux/mfd/core.h> | 31 | #include <linux/mfd/core.h> |
30 | #include <linux/mfd/max8998.h> | 32 | #include <linux/mfd/max8998.h> |
31 | #include <linux/mfd/max8998-private.h> | 33 | #include <linux/mfd/max8998-private.h> |
32 | 34 | ||
35 | #define RTC_I2C_ADDR (0x0c >> 1) | ||
36 | |||
33 | static struct mfd_cell max8998_devs[] = { | 37 | static struct mfd_cell max8998_devs[] = { |
34 | { | 38 | { |
35 | .name = "max8998-pmic", | 39 | .name = "max8998-pmic", |
36 | } | 40 | }, { |
41 | .name = "max8998-rtc", | ||
42 | }, | ||
37 | }; | 43 | }; |
38 | 44 | ||
39 | static int max8998_i2c_device_read(struct max8998_dev *max8998, u8 reg, u8 *dest) | 45 | static struct mfd_cell lp3974_devs[] = { |
46 | { | ||
47 | .name = "lp3974-pmic", | ||
48 | }, { | ||
49 | .name = "lp3974-rtc", | ||
50 | }, | ||
51 | }; | ||
52 | |||
53 | int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest) | ||
40 | { | 54 | { |
41 | struct i2c_client *client = max8998->i2c_client; | 55 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); |
42 | int ret; | 56 | int ret; |
43 | 57 | ||
44 | mutex_lock(&max8998->iolock); | 58 | mutex_lock(&max8998->iolock); |
45 | ret = i2c_smbus_read_byte_data(client, reg); | 59 | ret = i2c_smbus_read_byte_data(i2c, reg); |
46 | mutex_unlock(&max8998->iolock); | 60 | mutex_unlock(&max8998->iolock); |
47 | if (ret < 0) | 61 | if (ret < 0) |
48 | return ret; | 62 | return ret; |
@@ -51,40 +65,71 @@ static int max8998_i2c_device_read(struct max8998_dev *max8998, u8 reg, u8 *dest | |||
51 | *dest = ret; | 65 | *dest = ret; |
52 | return 0; | 66 | return 0; |
53 | } | 67 | } |
68 | EXPORT_SYMBOL(max8998_read_reg); | ||
69 | |||
70 | int max8998_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf) | ||
71 | { | ||
72 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); | ||
73 | int ret; | ||
74 | |||
75 | mutex_lock(&max8998->iolock); | ||
76 | ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf); | ||
77 | mutex_unlock(&max8998->iolock); | ||
78 | if (ret < 0) | ||
79 | return ret; | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | EXPORT_SYMBOL(max8998_bulk_read); | ||
54 | 84 | ||
55 | static int max8998_i2c_device_write(struct max8998_dev *max8998, u8 reg, u8 value) | 85 | int max8998_write_reg(struct i2c_client *i2c, u8 reg, u8 value) |
56 | { | 86 | { |
57 | struct i2c_client *client = max8998->i2c_client; | 87 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); |
58 | int ret; | 88 | int ret; |
59 | 89 | ||
60 | mutex_lock(&max8998->iolock); | 90 | mutex_lock(&max8998->iolock); |
61 | ret = i2c_smbus_write_byte_data(client, reg, value); | 91 | ret = i2c_smbus_write_byte_data(i2c, reg, value); |
62 | mutex_unlock(&max8998->iolock); | 92 | mutex_unlock(&max8998->iolock); |
63 | return ret; | 93 | return ret; |
64 | } | 94 | } |
95 | EXPORT_SYMBOL(max8998_write_reg); | ||
65 | 96 | ||
66 | static int max8998_i2c_device_update(struct max8998_dev *max8998, u8 reg, | 97 | int max8998_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf) |
67 | u8 val, u8 mask) | ||
68 | { | 98 | { |
69 | struct i2c_client *client = max8998->i2c_client; | 99 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); |
100 | int ret; | ||
101 | |||
102 | mutex_lock(&max8998->iolock); | ||
103 | ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf); | ||
104 | mutex_unlock(&max8998->iolock); | ||
105 | if (ret < 0) | ||
106 | return ret; | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | EXPORT_SYMBOL(max8998_bulk_write); | ||
111 | |||
112 | int max8998_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask) | ||
113 | { | ||
114 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); | ||
70 | int ret; | 115 | int ret; |
71 | 116 | ||
72 | mutex_lock(&max8998->iolock); | 117 | mutex_lock(&max8998->iolock); |
73 | ret = i2c_smbus_read_byte_data(client, reg); | 118 | ret = i2c_smbus_read_byte_data(i2c, reg); |
74 | if (ret >= 0) { | 119 | if (ret >= 0) { |
75 | u8 old_val = ret & 0xff; | 120 | u8 old_val = ret & 0xff; |
76 | u8 new_val = (val & mask) | (old_val & (~mask)); | 121 | u8 new_val = (val & mask) | (old_val & (~mask)); |
77 | ret = i2c_smbus_write_byte_data(client, reg, new_val); | 122 | ret = i2c_smbus_write_byte_data(i2c, reg, new_val); |
78 | if (ret >= 0) | ||
79 | ret = 0; | ||
80 | } | 123 | } |
81 | mutex_unlock(&max8998->iolock); | 124 | mutex_unlock(&max8998->iolock); |
82 | return ret; | 125 | return ret; |
83 | } | 126 | } |
127 | EXPORT_SYMBOL(max8998_update_reg); | ||
84 | 128 | ||
85 | static int max8998_i2c_probe(struct i2c_client *i2c, | 129 | static int max8998_i2c_probe(struct i2c_client *i2c, |
86 | const struct i2c_device_id *id) | 130 | const struct i2c_device_id *id) |
87 | { | 131 | { |
132 | struct max8998_platform_data *pdata = i2c->dev.platform_data; | ||
88 | struct max8998_dev *max8998; | 133 | struct max8998_dev *max8998; |
89 | int ret = 0; | 134 | int ret = 0; |
90 | 135 | ||
@@ -94,15 +139,38 @@ static int max8998_i2c_probe(struct i2c_client *i2c, | |||
94 | 139 | ||
95 | i2c_set_clientdata(i2c, max8998); | 140 | i2c_set_clientdata(i2c, max8998); |
96 | max8998->dev = &i2c->dev; | 141 | max8998->dev = &i2c->dev; |
97 | max8998->i2c_client = i2c; | 142 | max8998->i2c = i2c; |
98 | max8998->dev_read = max8998_i2c_device_read; | 143 | max8998->irq = i2c->irq; |
99 | max8998->dev_write = max8998_i2c_device_write; | 144 | max8998->type = id->driver_data; |
100 | max8998->dev_update = max8998_i2c_device_update; | 145 | if (pdata) { |
146 | max8998->ono = pdata->ono; | ||
147 | max8998->irq_base = pdata->irq_base; | ||
148 | max8998->wakeup = pdata->wakeup; | ||
149 | } | ||
101 | mutex_init(&max8998->iolock); | 150 | mutex_init(&max8998->iolock); |
102 | 151 | ||
103 | ret = mfd_add_devices(max8998->dev, -1, | 152 | max8998->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); |
104 | max8998_devs, ARRAY_SIZE(max8998_devs), | 153 | i2c_set_clientdata(max8998->rtc, max8998); |
105 | NULL, 0); | 154 | |
155 | max8998_irq_init(max8998); | ||
156 | |||
157 | pm_runtime_set_active(max8998->dev); | ||
158 | |||
159 | switch (id->driver_data) { | ||
160 | case TYPE_LP3974: | ||
161 | ret = mfd_add_devices(max8998->dev, -1, | ||
162 | lp3974_devs, ARRAY_SIZE(lp3974_devs), | ||
163 | NULL, 0); | ||
164 | break; | ||
165 | case TYPE_MAX8998: | ||
166 | ret = mfd_add_devices(max8998->dev, -1, | ||
167 | max8998_devs, ARRAY_SIZE(max8998_devs), | ||
168 | NULL, 0); | ||
169 | break; | ||
170 | default: | ||
171 | ret = -EINVAL; | ||
172 | } | ||
173 | |||
106 | if (ret < 0) | 174 | if (ret < 0) |
107 | goto err; | 175 | goto err; |
108 | 176 | ||
@@ -110,6 +178,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c, | |||
110 | 178 | ||
111 | err: | 179 | err: |
112 | mfd_remove_devices(max8998->dev); | 180 | mfd_remove_devices(max8998->dev); |
181 | max8998_irq_exit(max8998); | ||
182 | i2c_unregister_device(max8998->rtc); | ||
113 | kfree(max8998); | 183 | kfree(max8998); |
114 | return ret; | 184 | return ret; |
115 | } | 185 | } |
@@ -119,21 +189,127 @@ static int max8998_i2c_remove(struct i2c_client *i2c) | |||
119 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); | 189 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); |
120 | 190 | ||
121 | mfd_remove_devices(max8998->dev); | 191 | mfd_remove_devices(max8998->dev); |
192 | max8998_irq_exit(max8998); | ||
193 | i2c_unregister_device(max8998->rtc); | ||
122 | kfree(max8998); | 194 | kfree(max8998); |
123 | 195 | ||
124 | return 0; | 196 | return 0; |
125 | } | 197 | } |
126 | 198 | ||
127 | static const struct i2c_device_id max8998_i2c_id[] = { | 199 | static const struct i2c_device_id max8998_i2c_id[] = { |
128 | { "max8998", 0 }, | 200 | { "max8998", TYPE_MAX8998 }, |
129 | { } | 201 | { "lp3974", TYPE_LP3974}, |
202 | { } | ||
130 | }; | 203 | }; |
131 | MODULE_DEVICE_TABLE(i2c, max8998_i2c_id); | 204 | MODULE_DEVICE_TABLE(i2c, max8998_i2c_id); |
132 | 205 | ||
206 | static int max8998_suspend(struct device *dev) | ||
207 | { | ||
208 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
209 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); | ||
210 | |||
211 | if (max8998->wakeup) | ||
212 | irq_set_irq_wake(max8998->irq, 1); | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int max8998_resume(struct device *dev) | ||
217 | { | ||
218 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
219 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); | ||
220 | |||
221 | if (max8998->wakeup) | ||
222 | irq_set_irq_wake(max8998->irq, 0); | ||
223 | /* | ||
224 | * In LP3974, if IRQ registers are not "read & clear" | ||
225 | * when it's set during sleep, the interrupt becomes | ||
226 | * disabled. | ||
227 | */ | ||
228 | return max8998_irq_resume(i2c_get_clientdata(i2c)); | ||
229 | } | ||
230 | |||
231 | struct max8998_reg_dump { | ||
232 | u8 addr; | ||
233 | u8 val; | ||
234 | }; | ||
235 | #define SAVE_ITEM(x) { .addr = (x), .val = 0x0, } | ||
236 | static struct max8998_reg_dump max8998_dump[] = { | ||
237 | SAVE_ITEM(MAX8998_REG_IRQM1), | ||
238 | SAVE_ITEM(MAX8998_REG_IRQM2), | ||
239 | SAVE_ITEM(MAX8998_REG_IRQM3), | ||
240 | SAVE_ITEM(MAX8998_REG_IRQM4), | ||
241 | SAVE_ITEM(MAX8998_REG_STATUSM1), | ||
242 | SAVE_ITEM(MAX8998_REG_STATUSM2), | ||
243 | SAVE_ITEM(MAX8998_REG_CHGR1), | ||
244 | SAVE_ITEM(MAX8998_REG_CHGR2), | ||
245 | SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1), | ||
246 | SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1), | ||
247 | SAVE_ITEM(MAX8998_REG_BUCK_ACTIVE_DISCHARGE3), | ||
248 | SAVE_ITEM(MAX8998_REG_ONOFF1), | ||
249 | SAVE_ITEM(MAX8998_REG_ONOFF2), | ||
250 | SAVE_ITEM(MAX8998_REG_ONOFF3), | ||
251 | SAVE_ITEM(MAX8998_REG_ONOFF4), | ||
252 | SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE1), | ||
253 | SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE2), | ||
254 | SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE3), | ||
255 | SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE4), | ||
256 | SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE1), | ||
257 | SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE2), | ||
258 | SAVE_ITEM(MAX8998_REG_LDO2_LDO3), | ||
259 | SAVE_ITEM(MAX8998_REG_LDO4), | ||
260 | SAVE_ITEM(MAX8998_REG_LDO5), | ||
261 | SAVE_ITEM(MAX8998_REG_LDO6), | ||
262 | SAVE_ITEM(MAX8998_REG_LDO7), | ||
263 | SAVE_ITEM(MAX8998_REG_LDO8_LDO9), | ||
264 | SAVE_ITEM(MAX8998_REG_LDO10_LDO11), | ||
265 | SAVE_ITEM(MAX8998_REG_LDO12), | ||
266 | SAVE_ITEM(MAX8998_REG_LDO13), | ||
267 | SAVE_ITEM(MAX8998_REG_LDO14), | ||
268 | SAVE_ITEM(MAX8998_REG_LDO15), | ||
269 | SAVE_ITEM(MAX8998_REG_LDO16), | ||
270 | SAVE_ITEM(MAX8998_REG_LDO17), | ||
271 | SAVE_ITEM(MAX8998_REG_BKCHR), | ||
272 | SAVE_ITEM(MAX8998_REG_LBCNFG1), | ||
273 | SAVE_ITEM(MAX8998_REG_LBCNFG2), | ||
274 | }; | ||
275 | /* Save registers before hibernation */ | ||
276 | static int max8998_freeze(struct device *dev) | ||
277 | { | ||
278 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
279 | int i; | ||
280 | |||
281 | for (i = 0; i < ARRAY_SIZE(max8998_dump); i++) | ||
282 | max8998_read_reg(i2c, max8998_dump[i].addr, | ||
283 | &max8998_dump[i].val); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | /* Restore registers after hibernation */ | ||
289 | static int max8998_restore(struct device *dev) | ||
290 | { | ||
291 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
292 | int i; | ||
293 | |||
294 | for (i = 0; i < ARRAY_SIZE(max8998_dump); i++) | ||
295 | max8998_write_reg(i2c, max8998_dump[i].addr, | ||
296 | max8998_dump[i].val); | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static const struct dev_pm_ops max8998_pm = { | ||
302 | .suspend = max8998_suspend, | ||
303 | .resume = max8998_resume, | ||
304 | .freeze = max8998_freeze, | ||
305 | .restore = max8998_restore, | ||
306 | }; | ||
307 | |||
133 | static struct i2c_driver max8998_i2c_driver = { | 308 | static struct i2c_driver max8998_i2c_driver = { |
134 | .driver = { | 309 | .driver = { |
135 | .name = "max8998", | 310 | .name = "max8998", |
136 | .owner = THIS_MODULE, | 311 | .owner = THIS_MODULE, |
312 | .pm = &max8998_pm, | ||
137 | }, | 313 | }, |
138 | .probe = max8998_i2c_probe, | 314 | .probe = max8998_i2c_probe, |
139 | .remove = max8998_i2c_remove, | 315 | .remove = max8998_i2c_remove, |
diff --git a/drivers/mfd/mc13783-core.c b/drivers/mfd/mc13783-core.c deleted file mode 100644 index 6df34989c1f6..000000000000 --- a/drivers/mfd/mc13783-core.c +++ /dev/null | |||
@@ -1,752 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2009 Pengutronix | ||
3 | * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> | ||
4 | * | ||
5 | * loosely based on an earlier driver that has | ||
6 | * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it under | ||
9 | * the terms of the GNU General Public License version 2 as published by the | ||
10 | * Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/mutex.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/spi/spi.h> | ||
18 | #include <linux/mfd/core.h> | ||
19 | #include <linux/mfd/mc13783.h> | ||
20 | |||
21 | struct mc13783 { | ||
22 | struct spi_device *spidev; | ||
23 | struct mutex lock; | ||
24 | int irq; | ||
25 | int flags; | ||
26 | |||
27 | irq_handler_t irqhandler[MC13783_NUM_IRQ]; | ||
28 | void *irqdata[MC13783_NUM_IRQ]; | ||
29 | |||
30 | /* XXX these should go as platformdata to the regulator subdevice */ | ||
31 | struct mc13783_regulator_init_data *regulators; | ||
32 | int num_regulators; | ||
33 | }; | ||
34 | |||
35 | #define MC13783_REG_REVISION 7 | ||
36 | #define MC13783_REG_ADC_0 43 | ||
37 | #define MC13783_REG_ADC_1 44 | ||
38 | #define MC13783_REG_ADC_2 45 | ||
39 | |||
40 | #define MC13783_IRQSTAT0 0 | ||
41 | #define MC13783_IRQSTAT0_ADCDONEI (1 << 0) | ||
42 | #define MC13783_IRQSTAT0_ADCBISDONEI (1 << 1) | ||
43 | #define MC13783_IRQSTAT0_TSI (1 << 2) | ||
44 | #define MC13783_IRQSTAT0_WHIGHI (1 << 3) | ||
45 | #define MC13783_IRQSTAT0_WLOWI (1 << 4) | ||
46 | #define MC13783_IRQSTAT0_CHGDETI (1 << 6) | ||
47 | #define MC13783_IRQSTAT0_CHGOVI (1 << 7) | ||
48 | #define MC13783_IRQSTAT0_CHGREVI (1 << 8) | ||
49 | #define MC13783_IRQSTAT0_CHGSHORTI (1 << 9) | ||
50 | #define MC13783_IRQSTAT0_CCCVI (1 << 10) | ||
51 | #define MC13783_IRQSTAT0_CHGCURRI (1 << 11) | ||
52 | #define MC13783_IRQSTAT0_BPONI (1 << 12) | ||
53 | #define MC13783_IRQSTAT0_LOBATLI (1 << 13) | ||
54 | #define MC13783_IRQSTAT0_LOBATHI (1 << 14) | ||
55 | #define MC13783_IRQSTAT0_UDPI (1 << 15) | ||
56 | #define MC13783_IRQSTAT0_USBI (1 << 16) | ||
57 | #define MC13783_IRQSTAT0_IDI (1 << 19) | ||
58 | #define MC13783_IRQSTAT0_SE1I (1 << 21) | ||
59 | #define MC13783_IRQSTAT0_CKDETI (1 << 22) | ||
60 | #define MC13783_IRQSTAT0_UDMI (1 << 23) | ||
61 | |||
62 | #define MC13783_IRQMASK0 1 | ||
63 | #define MC13783_IRQMASK0_ADCDONEM MC13783_IRQSTAT0_ADCDONEI | ||
64 | #define MC13783_IRQMASK0_ADCBISDONEM MC13783_IRQSTAT0_ADCBISDONEI | ||
65 | #define MC13783_IRQMASK0_TSM MC13783_IRQSTAT0_TSI | ||
66 | #define MC13783_IRQMASK0_WHIGHM MC13783_IRQSTAT0_WHIGHI | ||
67 | #define MC13783_IRQMASK0_WLOWM MC13783_IRQSTAT0_WLOWI | ||
68 | #define MC13783_IRQMASK0_CHGDETM MC13783_IRQSTAT0_CHGDETI | ||
69 | #define MC13783_IRQMASK0_CHGOVM MC13783_IRQSTAT0_CHGOVI | ||
70 | #define MC13783_IRQMASK0_CHGREVM MC13783_IRQSTAT0_CHGREVI | ||
71 | #define MC13783_IRQMASK0_CHGSHORTM MC13783_IRQSTAT0_CHGSHORTI | ||
72 | #define MC13783_IRQMASK0_CCCVM MC13783_IRQSTAT0_CCCVI | ||
73 | #define MC13783_IRQMASK0_CHGCURRM MC13783_IRQSTAT0_CHGCURRI | ||
74 | #define MC13783_IRQMASK0_BPONM MC13783_IRQSTAT0_BPONI | ||
75 | #define MC13783_IRQMASK0_LOBATLM MC13783_IRQSTAT0_LOBATLI | ||
76 | #define MC13783_IRQMASK0_LOBATHM MC13783_IRQSTAT0_LOBATHI | ||
77 | #define MC13783_IRQMASK0_UDPM MC13783_IRQSTAT0_UDPI | ||
78 | #define MC13783_IRQMASK0_USBM MC13783_IRQSTAT0_USBI | ||
79 | #define MC13783_IRQMASK0_IDM MC13783_IRQSTAT0_IDI | ||
80 | #define MC13783_IRQMASK0_SE1M MC13783_IRQSTAT0_SE1I | ||
81 | #define MC13783_IRQMASK0_CKDETM MC13783_IRQSTAT0_CKDETI | ||
82 | #define MC13783_IRQMASK0_UDMM MC13783_IRQSTAT0_UDMI | ||
83 | |||
84 | #define MC13783_IRQSTAT1 3 | ||
85 | #define MC13783_IRQSTAT1_1HZI (1 << 0) | ||
86 | #define MC13783_IRQSTAT1_TODAI (1 << 1) | ||
87 | #define MC13783_IRQSTAT1_ONOFD1I (1 << 3) | ||
88 | #define MC13783_IRQSTAT1_ONOFD2I (1 << 4) | ||
89 | #define MC13783_IRQSTAT1_ONOFD3I (1 << 5) | ||
90 | #define MC13783_IRQSTAT1_SYSRSTI (1 << 6) | ||
91 | #define MC13783_IRQSTAT1_RTCRSTI (1 << 7) | ||
92 | #define MC13783_IRQSTAT1_PCI (1 << 8) | ||
93 | #define MC13783_IRQSTAT1_WARMI (1 << 9) | ||
94 | #define MC13783_IRQSTAT1_MEMHLDI (1 << 10) | ||
95 | #define MC13783_IRQSTAT1_PWRRDYI (1 << 11) | ||
96 | #define MC13783_IRQSTAT1_THWARNLI (1 << 12) | ||
97 | #define MC13783_IRQSTAT1_THWARNHI (1 << 13) | ||
98 | #define MC13783_IRQSTAT1_CLKI (1 << 14) | ||
99 | #define MC13783_IRQSTAT1_SEMAFI (1 << 15) | ||
100 | #define MC13783_IRQSTAT1_MC2BI (1 << 17) | ||
101 | #define MC13783_IRQSTAT1_HSDETI (1 << 18) | ||
102 | #define MC13783_IRQSTAT1_HSLI (1 << 19) | ||
103 | #define MC13783_IRQSTAT1_ALSPTHI (1 << 20) | ||
104 | #define MC13783_IRQSTAT1_AHSSHORTI (1 << 21) | ||
105 | |||
106 | #define MC13783_IRQMASK1 4 | ||
107 | #define MC13783_IRQMASK1_1HZM MC13783_IRQSTAT1_1HZI | ||
108 | #define MC13783_IRQMASK1_TODAM MC13783_IRQSTAT1_TODAI | ||
109 | #define MC13783_IRQMASK1_ONOFD1M MC13783_IRQSTAT1_ONOFD1I | ||
110 | #define MC13783_IRQMASK1_ONOFD2M MC13783_IRQSTAT1_ONOFD2I | ||
111 | #define MC13783_IRQMASK1_ONOFD3M MC13783_IRQSTAT1_ONOFD3I | ||
112 | #define MC13783_IRQMASK1_SYSRSTM MC13783_IRQSTAT1_SYSRSTI | ||
113 | #define MC13783_IRQMASK1_RTCRSTM MC13783_IRQSTAT1_RTCRSTI | ||
114 | #define MC13783_IRQMASK1_PCM MC13783_IRQSTAT1_PCI | ||
115 | #define MC13783_IRQMASK1_WARMM MC13783_IRQSTAT1_WARMI | ||
116 | #define MC13783_IRQMASK1_MEMHLDM MC13783_IRQSTAT1_MEMHLDI | ||
117 | #define MC13783_IRQMASK1_PWRRDYM MC13783_IRQSTAT1_PWRRDYI | ||
118 | #define MC13783_IRQMASK1_THWARNLM MC13783_IRQSTAT1_THWARNLI | ||
119 | #define MC13783_IRQMASK1_THWARNHM MC13783_IRQSTAT1_THWARNHI | ||
120 | #define MC13783_IRQMASK1_CLKM MC13783_IRQSTAT1_CLKI | ||
121 | #define MC13783_IRQMASK1_SEMAFM MC13783_IRQSTAT1_SEMAFI | ||
122 | #define MC13783_IRQMASK1_MC2BM MC13783_IRQSTAT1_MC2BI | ||
123 | #define MC13783_IRQMASK1_HSDETM MC13783_IRQSTAT1_HSDETI | ||
124 | #define MC13783_IRQMASK1_HSLM MC13783_IRQSTAT1_HSLI | ||
125 | #define MC13783_IRQMASK1_ALSPTHM MC13783_IRQSTAT1_ALSPTHI | ||
126 | #define MC13783_IRQMASK1_AHSSHORTM MC13783_IRQSTAT1_AHSSHORTI | ||
127 | |||
128 | #define MC13783_ADC1 44 | ||
129 | #define MC13783_ADC1_ADEN (1 << 0) | ||
130 | #define MC13783_ADC1_RAND (1 << 1) | ||
131 | #define MC13783_ADC1_ADSEL (1 << 3) | ||
132 | #define MC13783_ADC1_ASC (1 << 20) | ||
133 | #define MC13783_ADC1_ADTRIGIGN (1 << 21) | ||
134 | |||
135 | #define MC13783_NUMREGS 0x3f | ||
136 | |||
137 | void mc13783_lock(struct mc13783 *mc13783) | ||
138 | { | ||
139 | if (!mutex_trylock(&mc13783->lock)) { | ||
140 | dev_dbg(&mc13783->spidev->dev, "wait for %s from %pf\n", | ||
141 | __func__, __builtin_return_address(0)); | ||
142 | |||
143 | mutex_lock(&mc13783->lock); | ||
144 | } | ||
145 | dev_dbg(&mc13783->spidev->dev, "%s from %pf\n", | ||
146 | __func__, __builtin_return_address(0)); | ||
147 | } | ||
148 | EXPORT_SYMBOL(mc13783_lock); | ||
149 | |||
150 | void mc13783_unlock(struct mc13783 *mc13783) | ||
151 | { | ||
152 | dev_dbg(&mc13783->spidev->dev, "%s from %pf\n", | ||
153 | __func__, __builtin_return_address(0)); | ||
154 | mutex_unlock(&mc13783->lock); | ||
155 | } | ||
156 | EXPORT_SYMBOL(mc13783_unlock); | ||
157 | |||
158 | #define MC13783_REGOFFSET_SHIFT 25 | ||
159 | int mc13783_reg_read(struct mc13783 *mc13783, unsigned int offset, u32 *val) | ||
160 | { | ||
161 | struct spi_transfer t; | ||
162 | struct spi_message m; | ||
163 | int ret; | ||
164 | |||
165 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
166 | |||
167 | if (offset > MC13783_NUMREGS) | ||
168 | return -EINVAL; | ||
169 | |||
170 | *val = offset << MC13783_REGOFFSET_SHIFT; | ||
171 | |||
172 | memset(&t, 0, sizeof(t)); | ||
173 | |||
174 | t.tx_buf = val; | ||
175 | t.rx_buf = val; | ||
176 | t.len = sizeof(u32); | ||
177 | |||
178 | spi_message_init(&m); | ||
179 | spi_message_add_tail(&t, &m); | ||
180 | |||
181 | ret = spi_sync(mc13783->spidev, &m); | ||
182 | |||
183 | /* error in message.status implies error return from spi_sync */ | ||
184 | BUG_ON(!ret && m.status); | ||
185 | |||
186 | if (ret) | ||
187 | return ret; | ||
188 | |||
189 | *val &= 0xffffff; | ||
190 | |||
191 | dev_vdbg(&mc13783->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val); | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | EXPORT_SYMBOL(mc13783_reg_read); | ||
196 | |||
197 | int mc13783_reg_write(struct mc13783 *mc13783, unsigned int offset, u32 val) | ||
198 | { | ||
199 | u32 buf; | ||
200 | struct spi_transfer t; | ||
201 | struct spi_message m; | ||
202 | int ret; | ||
203 | |||
204 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
205 | |||
206 | dev_vdbg(&mc13783->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val); | ||
207 | |||
208 | if (offset > MC13783_NUMREGS || val > 0xffffff) | ||
209 | return -EINVAL; | ||
210 | |||
211 | buf = 1 << 31 | offset << MC13783_REGOFFSET_SHIFT | val; | ||
212 | |||
213 | memset(&t, 0, sizeof(t)); | ||
214 | |||
215 | t.tx_buf = &buf; | ||
216 | t.rx_buf = &buf; | ||
217 | t.len = sizeof(u32); | ||
218 | |||
219 | spi_message_init(&m); | ||
220 | spi_message_add_tail(&t, &m); | ||
221 | |||
222 | ret = spi_sync(mc13783->spidev, &m); | ||
223 | |||
224 | BUG_ON(!ret && m.status); | ||
225 | |||
226 | if (ret) | ||
227 | return ret; | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | EXPORT_SYMBOL(mc13783_reg_write); | ||
232 | |||
233 | int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset, | ||
234 | u32 mask, u32 val) | ||
235 | { | ||
236 | int ret; | ||
237 | u32 valread; | ||
238 | |||
239 | BUG_ON(val & ~mask); | ||
240 | |||
241 | ret = mc13783_reg_read(mc13783, offset, &valread); | ||
242 | if (ret) | ||
243 | return ret; | ||
244 | |||
245 | valread = (valread & ~mask) | val; | ||
246 | |||
247 | return mc13783_reg_write(mc13783, offset, valread); | ||
248 | } | ||
249 | EXPORT_SYMBOL(mc13783_reg_rmw); | ||
250 | |||
251 | int mc13783_get_flags(struct mc13783 *mc13783) | ||
252 | { | ||
253 | return mc13783->flags; | ||
254 | } | ||
255 | EXPORT_SYMBOL(mc13783_get_flags); | ||
256 | |||
257 | int mc13783_irq_mask(struct mc13783 *mc13783, int irq) | ||
258 | { | ||
259 | int ret; | ||
260 | unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; | ||
261 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
262 | u32 mask; | ||
263 | |||
264 | if (irq < 0 || irq >= MC13783_NUM_IRQ) | ||
265 | return -EINVAL; | ||
266 | |||
267 | ret = mc13783_reg_read(mc13783, offmask, &mask); | ||
268 | if (ret) | ||
269 | return ret; | ||
270 | |||
271 | if (mask & irqbit) | ||
272 | /* already masked */ | ||
273 | return 0; | ||
274 | |||
275 | return mc13783_reg_write(mc13783, offmask, mask | irqbit); | ||
276 | } | ||
277 | EXPORT_SYMBOL(mc13783_irq_mask); | ||
278 | |||
279 | int mc13783_irq_unmask(struct mc13783 *mc13783, int irq) | ||
280 | { | ||
281 | int ret; | ||
282 | unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; | ||
283 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
284 | u32 mask; | ||
285 | |||
286 | if (irq < 0 || irq >= MC13783_NUM_IRQ) | ||
287 | return -EINVAL; | ||
288 | |||
289 | ret = mc13783_reg_read(mc13783, offmask, &mask); | ||
290 | if (ret) | ||
291 | return ret; | ||
292 | |||
293 | if (!(mask & irqbit)) | ||
294 | /* already unmasked */ | ||
295 | return 0; | ||
296 | |||
297 | return mc13783_reg_write(mc13783, offmask, mask & ~irqbit); | ||
298 | } | ||
299 | EXPORT_SYMBOL(mc13783_irq_unmask); | ||
300 | |||
301 | int mc13783_irq_status(struct mc13783 *mc13783, int irq, | ||
302 | int *enabled, int *pending) | ||
303 | { | ||
304 | int ret; | ||
305 | unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; | ||
306 | unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1; | ||
307 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
308 | |||
309 | if (irq < 0 || irq >= MC13783_NUM_IRQ) | ||
310 | return -EINVAL; | ||
311 | |||
312 | if (enabled) { | ||
313 | u32 mask; | ||
314 | |||
315 | ret = mc13783_reg_read(mc13783, offmask, &mask); | ||
316 | if (ret) | ||
317 | return ret; | ||
318 | |||
319 | *enabled = mask & irqbit; | ||
320 | } | ||
321 | |||
322 | if (pending) { | ||
323 | u32 stat; | ||
324 | |||
325 | ret = mc13783_reg_read(mc13783, offstat, &stat); | ||
326 | if (ret) | ||
327 | return ret; | ||
328 | |||
329 | *pending = stat & irqbit; | ||
330 | } | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | EXPORT_SYMBOL(mc13783_irq_status); | ||
335 | |||
336 | int mc13783_irq_ack(struct mc13783 *mc13783, int irq) | ||
337 | { | ||
338 | unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1; | ||
339 | unsigned int val = 1 << (irq < 24 ? irq : irq - 24); | ||
340 | |||
341 | BUG_ON(irq < 0 || irq >= MC13783_NUM_IRQ); | ||
342 | |||
343 | return mc13783_reg_write(mc13783, offstat, val); | ||
344 | } | ||
345 | EXPORT_SYMBOL(mc13783_irq_ack); | ||
346 | |||
347 | int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq, | ||
348 | irq_handler_t handler, const char *name, void *dev) | ||
349 | { | ||
350 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
351 | BUG_ON(!handler); | ||
352 | |||
353 | if (irq < 0 || irq >= MC13783_NUM_IRQ) | ||
354 | return -EINVAL; | ||
355 | |||
356 | if (mc13783->irqhandler[irq]) | ||
357 | return -EBUSY; | ||
358 | |||
359 | mc13783->irqhandler[irq] = handler; | ||
360 | mc13783->irqdata[irq] = dev; | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | EXPORT_SYMBOL(mc13783_irq_request_nounmask); | ||
365 | |||
366 | int mc13783_irq_request(struct mc13783 *mc13783, int irq, | ||
367 | irq_handler_t handler, const char *name, void *dev) | ||
368 | { | ||
369 | int ret; | ||
370 | |||
371 | ret = mc13783_irq_request_nounmask(mc13783, irq, handler, name, dev); | ||
372 | if (ret) | ||
373 | return ret; | ||
374 | |||
375 | ret = mc13783_irq_unmask(mc13783, irq); | ||
376 | if (ret) { | ||
377 | mc13783->irqhandler[irq] = NULL; | ||
378 | mc13783->irqdata[irq] = NULL; | ||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | EXPORT_SYMBOL(mc13783_irq_request); | ||
385 | |||
386 | int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev) | ||
387 | { | ||
388 | int ret; | ||
389 | BUG_ON(!mutex_is_locked(&mc13783->lock)); | ||
390 | |||
391 | if (irq < 0 || irq >= MC13783_NUM_IRQ || !mc13783->irqhandler[irq] || | ||
392 | mc13783->irqdata[irq] != dev) | ||
393 | return -EINVAL; | ||
394 | |||
395 | ret = mc13783_irq_mask(mc13783, irq); | ||
396 | if (ret) | ||
397 | return ret; | ||
398 | |||
399 | mc13783->irqhandler[irq] = NULL; | ||
400 | mc13783->irqdata[irq] = NULL; | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | EXPORT_SYMBOL(mc13783_irq_free); | ||
405 | |||
406 | static inline irqreturn_t mc13783_irqhandler(struct mc13783 *mc13783, int irq) | ||
407 | { | ||
408 | return mc13783->irqhandler[irq](irq, mc13783->irqdata[irq]); | ||
409 | } | ||
410 | |||
411 | /* | ||
412 | * returns: number of handled irqs or negative error | ||
413 | * locking: holds mc13783->lock | ||
414 | */ | ||
415 | static int mc13783_irq_handle(struct mc13783 *mc13783, | ||
416 | unsigned int offstat, unsigned int offmask, int baseirq) | ||
417 | { | ||
418 | u32 stat, mask; | ||
419 | int ret = mc13783_reg_read(mc13783, offstat, &stat); | ||
420 | int num_handled = 0; | ||
421 | |||
422 | if (ret) | ||
423 | return ret; | ||
424 | |||
425 | ret = mc13783_reg_read(mc13783, offmask, &mask); | ||
426 | if (ret) | ||
427 | return ret; | ||
428 | |||
429 | while (stat & ~mask) { | ||
430 | int irq = __ffs(stat & ~mask); | ||
431 | |||
432 | stat &= ~(1 << irq); | ||
433 | |||
434 | if (likely(mc13783->irqhandler[baseirq + irq])) { | ||
435 | irqreturn_t handled; | ||
436 | |||
437 | handled = mc13783_irqhandler(mc13783, baseirq + irq); | ||
438 | if (handled == IRQ_HANDLED) | ||
439 | num_handled++; | ||
440 | } else { | ||
441 | dev_err(&mc13783->spidev->dev, | ||
442 | "BUG: irq %u but no handler\n", | ||
443 | baseirq + irq); | ||
444 | |||
445 | mask |= 1 << irq; | ||
446 | |||
447 | ret = mc13783_reg_write(mc13783, offmask, mask); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | return num_handled; | ||
452 | } | ||
453 | |||
454 | static irqreturn_t mc13783_irq_thread(int irq, void *data) | ||
455 | { | ||
456 | struct mc13783 *mc13783 = data; | ||
457 | irqreturn_t ret; | ||
458 | int handled = 0; | ||
459 | |||
460 | mc13783_lock(mc13783); | ||
461 | |||
462 | ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT0, | ||
463 | MC13783_IRQMASK0, MC13783_IRQ_ADCDONE); | ||
464 | if (ret > 0) | ||
465 | handled = 1; | ||
466 | |||
467 | ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT1, | ||
468 | MC13783_IRQMASK1, MC13783_IRQ_1HZ); | ||
469 | if (ret > 0) | ||
470 | handled = 1; | ||
471 | |||
472 | mc13783_unlock(mc13783); | ||
473 | |||
474 | return IRQ_RETVAL(handled); | ||
475 | } | ||
476 | |||
477 | #define MC13783_ADC1_CHAN0_SHIFT 5 | ||
478 | #define MC13783_ADC1_CHAN1_SHIFT 8 | ||
479 | |||
480 | struct mc13783_adcdone_data { | ||
481 | struct mc13783 *mc13783; | ||
482 | struct completion done; | ||
483 | }; | ||
484 | |||
485 | static irqreturn_t mc13783_handler_adcdone(int irq, void *data) | ||
486 | { | ||
487 | struct mc13783_adcdone_data *adcdone_data = data; | ||
488 | |||
489 | mc13783_irq_ack(adcdone_data->mc13783, irq); | ||
490 | |||
491 | complete_all(&adcdone_data->done); | ||
492 | |||
493 | return IRQ_HANDLED; | ||
494 | } | ||
495 | |||
496 | #define MC13783_ADC_WORKING (1 << 16) | ||
497 | |||
498 | int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, | ||
499 | unsigned int channel, unsigned int *sample) | ||
500 | { | ||
501 | u32 adc0, adc1, old_adc0; | ||
502 | int i, ret; | ||
503 | struct mc13783_adcdone_data adcdone_data = { | ||
504 | .mc13783 = mc13783, | ||
505 | }; | ||
506 | init_completion(&adcdone_data.done); | ||
507 | |||
508 | dev_dbg(&mc13783->spidev->dev, "%s\n", __func__); | ||
509 | |||
510 | mc13783_lock(mc13783); | ||
511 | |||
512 | if (mc13783->flags & MC13783_ADC_WORKING) { | ||
513 | ret = -EBUSY; | ||
514 | goto out; | ||
515 | } | ||
516 | |||
517 | mc13783->flags |= MC13783_ADC_WORKING; | ||
518 | |||
519 | mc13783_reg_read(mc13783, MC13783_ADC0, &old_adc0); | ||
520 | |||
521 | adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; | ||
522 | adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC; | ||
523 | |||
524 | if (channel > 7) | ||
525 | adc1 |= MC13783_ADC1_ADSEL; | ||
526 | |||
527 | switch (mode) { | ||
528 | case MC13783_ADC_MODE_TS: | ||
529 | adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 | | ||
530 | MC13783_ADC0_TSMOD1; | ||
531 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | ||
532 | break; | ||
533 | |||
534 | case MC13783_ADC_MODE_SINGLE_CHAN: | ||
535 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; | ||
536 | adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; | ||
537 | adc1 |= MC13783_ADC1_RAND; | ||
538 | break; | ||
539 | |||
540 | case MC13783_ADC_MODE_MULT_CHAN: | ||
541 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; | ||
542 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | ||
543 | break; | ||
544 | |||
545 | default: | ||
546 | mc13783_unlock(mc13783); | ||
547 | return -EINVAL; | ||
548 | } | ||
549 | |||
550 | dev_dbg(&mc13783->spidev->dev, "%s: request irq\n", __func__); | ||
551 | mc13783_irq_request(mc13783, MC13783_IRQ_ADCDONE, | ||
552 | mc13783_handler_adcdone, __func__, &adcdone_data); | ||
553 | mc13783_irq_ack(mc13783, MC13783_IRQ_ADCDONE); | ||
554 | |||
555 | mc13783_reg_write(mc13783, MC13783_REG_ADC_0, adc0); | ||
556 | mc13783_reg_write(mc13783, MC13783_REG_ADC_1, adc1); | ||
557 | |||
558 | mc13783_unlock(mc13783); | ||
559 | |||
560 | ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ); | ||
561 | |||
562 | if (!ret) | ||
563 | ret = -ETIMEDOUT; | ||
564 | |||
565 | mc13783_lock(mc13783); | ||
566 | |||
567 | mc13783_irq_free(mc13783, MC13783_IRQ_ADCDONE, &adcdone_data); | ||
568 | |||
569 | if (ret > 0) | ||
570 | for (i = 0; i < 4; ++i) { | ||
571 | ret = mc13783_reg_read(mc13783, | ||
572 | MC13783_REG_ADC_2, &sample[i]); | ||
573 | if (ret) | ||
574 | break; | ||
575 | } | ||
576 | |||
577 | if (mode == MC13783_ADC_MODE_TS) | ||
578 | /* restore TSMOD */ | ||
579 | mc13783_reg_write(mc13783, MC13783_REG_ADC_0, old_adc0); | ||
580 | |||
581 | mc13783->flags &= ~MC13783_ADC_WORKING; | ||
582 | out: | ||
583 | mc13783_unlock(mc13783); | ||
584 | |||
585 | return ret; | ||
586 | } | ||
587 | EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); | ||
588 | |||
589 | static int mc13783_add_subdevice_pdata(struct mc13783 *mc13783, | ||
590 | const char *name, void *pdata, size_t pdata_size) | ||
591 | { | ||
592 | struct mfd_cell cell = { | ||
593 | .name = name, | ||
594 | .platform_data = pdata, | ||
595 | .data_size = pdata_size, | ||
596 | }; | ||
597 | |||
598 | return mfd_add_devices(&mc13783->spidev->dev, -1, &cell, 1, NULL, 0); | ||
599 | } | ||
600 | |||
601 | static int mc13783_add_subdevice(struct mc13783 *mc13783, const char *name) | ||
602 | { | ||
603 | return mc13783_add_subdevice_pdata(mc13783, name, NULL, 0); | ||
604 | } | ||
605 | |||
606 | static int mc13783_check_revision(struct mc13783 *mc13783) | ||
607 | { | ||
608 | u32 rev_id, rev1, rev2, finid, icid; | ||
609 | |||
610 | mc13783_reg_read(mc13783, MC13783_REG_REVISION, &rev_id); | ||
611 | |||
612 | rev1 = (rev_id & 0x018) >> 3; | ||
613 | rev2 = (rev_id & 0x007); | ||
614 | icid = (rev_id & 0x01C0) >> 6; | ||
615 | finid = (rev_id & 0x01E00) >> 9; | ||
616 | |||
617 | /* Ver 0.2 is actually 3.2a. Report as 3.2 */ | ||
618 | if ((rev1 == 0) && (rev2 == 2)) | ||
619 | rev1 = 3; | ||
620 | |||
621 | if (rev1 == 0 || icid != 2) { | ||
622 | dev_err(&mc13783->spidev->dev, "No MC13783 detected.\n"); | ||
623 | return -ENODEV; | ||
624 | } | ||
625 | |||
626 | dev_info(&mc13783->spidev->dev, | ||
627 | "MC13783 Rev %d.%d FinVer %x detected\n", | ||
628 | rev1, rev2, finid); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | static int mc13783_probe(struct spi_device *spi) | ||
634 | { | ||
635 | struct mc13783 *mc13783; | ||
636 | struct mc13783_platform_data *pdata = dev_get_platdata(&spi->dev); | ||
637 | int ret; | ||
638 | |||
639 | mc13783 = kzalloc(sizeof(*mc13783), GFP_KERNEL); | ||
640 | if (!mc13783) | ||
641 | return -ENOMEM; | ||
642 | |||
643 | dev_set_drvdata(&spi->dev, mc13783); | ||
644 | spi->mode = SPI_MODE_0 | SPI_CS_HIGH; | ||
645 | spi->bits_per_word = 32; | ||
646 | spi_setup(spi); | ||
647 | |||
648 | mc13783->spidev = spi; | ||
649 | |||
650 | mutex_init(&mc13783->lock); | ||
651 | mc13783_lock(mc13783); | ||
652 | |||
653 | ret = mc13783_check_revision(mc13783); | ||
654 | if (ret) | ||
655 | goto err_revision; | ||
656 | |||
657 | /* mask all irqs */ | ||
658 | ret = mc13783_reg_write(mc13783, MC13783_IRQMASK0, 0x00ffffff); | ||
659 | if (ret) | ||
660 | goto err_mask; | ||
661 | |||
662 | ret = mc13783_reg_write(mc13783, MC13783_IRQMASK1, 0x00ffffff); | ||
663 | if (ret) | ||
664 | goto err_mask; | ||
665 | |||
666 | ret = request_threaded_irq(spi->irq, NULL, mc13783_irq_thread, | ||
667 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13783", mc13783); | ||
668 | |||
669 | if (ret) { | ||
670 | err_mask: | ||
671 | err_revision: | ||
672 | mutex_unlock(&mc13783->lock); | ||
673 | dev_set_drvdata(&spi->dev, NULL); | ||
674 | kfree(mc13783); | ||
675 | return ret; | ||
676 | } | ||
677 | |||
678 | /* This should go away (BEGIN) */ | ||
679 | if (pdata) { | ||
680 | mc13783->flags = pdata->flags; | ||
681 | mc13783->regulators = pdata->regulators; | ||
682 | mc13783->num_regulators = pdata->num_regulators; | ||
683 | } | ||
684 | /* This should go away (END) */ | ||
685 | |||
686 | mc13783_unlock(mc13783); | ||
687 | |||
688 | if (pdata->flags & MC13783_USE_ADC) | ||
689 | mc13783_add_subdevice(mc13783, "mc13783-adc"); | ||
690 | |||
691 | if (pdata->flags & MC13783_USE_CODEC) | ||
692 | mc13783_add_subdevice(mc13783, "mc13783-codec"); | ||
693 | |||
694 | if (pdata->flags & MC13783_USE_REGULATOR) { | ||
695 | struct mc13783_regulator_platform_data regulator_pdata = { | ||
696 | .num_regulators = pdata->num_regulators, | ||
697 | .regulators = pdata->regulators, | ||
698 | }; | ||
699 | |||
700 | mc13783_add_subdevice_pdata(mc13783, "mc13783-regulator", | ||
701 | ®ulator_pdata, sizeof(regulator_pdata)); | ||
702 | } | ||
703 | |||
704 | if (pdata->flags & MC13783_USE_RTC) | ||
705 | mc13783_add_subdevice(mc13783, "mc13783-rtc"); | ||
706 | |||
707 | if (pdata->flags & MC13783_USE_TOUCHSCREEN) | ||
708 | mc13783_add_subdevice(mc13783, "mc13783-ts"); | ||
709 | |||
710 | if (pdata->flags & MC13783_USE_LED) | ||
711 | mc13783_add_subdevice_pdata(mc13783, "mc13783-led", | ||
712 | pdata->leds, sizeof(*pdata->leds)); | ||
713 | |||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | static int __devexit mc13783_remove(struct spi_device *spi) | ||
718 | { | ||
719 | struct mc13783 *mc13783 = dev_get_drvdata(&spi->dev); | ||
720 | |||
721 | free_irq(mc13783->spidev->irq, mc13783); | ||
722 | |||
723 | mfd_remove_devices(&spi->dev); | ||
724 | |||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | static struct spi_driver mc13783_driver = { | ||
729 | .driver = { | ||
730 | .name = "mc13783", | ||
731 | .bus = &spi_bus_type, | ||
732 | .owner = THIS_MODULE, | ||
733 | }, | ||
734 | .probe = mc13783_probe, | ||
735 | .remove = __devexit_p(mc13783_remove), | ||
736 | }; | ||
737 | |||
738 | static int __init mc13783_init(void) | ||
739 | { | ||
740 | return spi_register_driver(&mc13783_driver); | ||
741 | } | ||
742 | subsys_initcall(mc13783_init); | ||
743 | |||
744 | static void __exit mc13783_exit(void) | ||
745 | { | ||
746 | spi_unregister_driver(&mc13783_driver); | ||
747 | } | ||
748 | module_exit(mc13783_exit); | ||
749 | |||
750 | MODULE_DESCRIPTION("Core driver for Freescale MC13783 PMIC"); | ||
751 | MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); | ||
752 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c new file mode 100644 index 000000000000..7e4d44bf92ab --- /dev/null +++ b/drivers/mfd/mc13xxx-core.c | |||
@@ -0,0 +1,835 @@ | |||
1 | /* | ||
2 | * Copyright 2009-2010 Pengutronix | ||
3 | * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> | ||
4 | * | ||
5 | * loosely based on an earlier driver that has | ||
6 | * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it under | ||
9 | * the terms of the GNU General Public License version 2 as published by the | ||
10 | * Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/slab.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/mutex.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/spi/spi.h> | ||
19 | #include <linux/mfd/core.h> | ||
20 | #include <linux/mfd/mc13xxx.h> | ||
21 | |||
22 | struct mc13xxx { | ||
23 | struct spi_device *spidev; | ||
24 | struct mutex lock; | ||
25 | int irq; | ||
26 | |||
27 | irq_handler_t irqhandler[MC13XXX_NUM_IRQ]; | ||
28 | void *irqdata[MC13XXX_NUM_IRQ]; | ||
29 | }; | ||
30 | |||
31 | struct mc13783 { | ||
32 | struct mc13xxx mc13xxx; | ||
33 | |||
34 | int adcflags; | ||
35 | }; | ||
36 | |||
37 | struct mc13xxx *mc13783_to_mc13xxx(struct mc13783 *mc13783) | ||
38 | { | ||
39 | return &mc13783->mc13xxx; | ||
40 | } | ||
41 | EXPORT_SYMBOL(mc13783_to_mc13xxx); | ||
42 | |||
43 | #define MC13XXX_IRQSTAT0 0 | ||
44 | #define MC13XXX_IRQSTAT0_ADCDONEI (1 << 0) | ||
45 | #define MC13XXX_IRQSTAT0_ADCBISDONEI (1 << 1) | ||
46 | #define MC13XXX_IRQSTAT0_TSI (1 << 2) | ||
47 | #define MC13783_IRQSTAT0_WHIGHI (1 << 3) | ||
48 | #define MC13783_IRQSTAT0_WLOWI (1 << 4) | ||
49 | #define MC13XXX_IRQSTAT0_CHGDETI (1 << 6) | ||
50 | #define MC13783_IRQSTAT0_CHGOVI (1 << 7) | ||
51 | #define MC13XXX_IRQSTAT0_CHGREVI (1 << 8) | ||
52 | #define MC13XXX_IRQSTAT0_CHGSHORTI (1 << 9) | ||
53 | #define MC13XXX_IRQSTAT0_CCCVI (1 << 10) | ||
54 | #define MC13XXX_IRQSTAT0_CHGCURRI (1 << 11) | ||
55 | #define MC13XXX_IRQSTAT0_BPONI (1 << 12) | ||
56 | #define MC13XXX_IRQSTAT0_LOBATLI (1 << 13) | ||
57 | #define MC13XXX_IRQSTAT0_LOBATHI (1 << 14) | ||
58 | #define MC13783_IRQSTAT0_UDPI (1 << 15) | ||
59 | #define MC13783_IRQSTAT0_USBI (1 << 16) | ||
60 | #define MC13783_IRQSTAT0_IDI (1 << 19) | ||
61 | #define MC13783_IRQSTAT0_SE1I (1 << 21) | ||
62 | #define MC13783_IRQSTAT0_CKDETI (1 << 22) | ||
63 | #define MC13783_IRQSTAT0_UDMI (1 << 23) | ||
64 | |||
65 | #define MC13XXX_IRQMASK0 1 | ||
66 | #define MC13XXX_IRQMASK0_ADCDONEM MC13XXX_IRQSTAT0_ADCDONEI | ||
67 | #define MC13XXX_IRQMASK0_ADCBISDONEM MC13XXX_IRQSTAT0_ADCBISDONEI | ||
68 | #define MC13XXX_IRQMASK0_TSM MC13XXX_IRQSTAT0_TSI | ||
69 | #define MC13783_IRQMASK0_WHIGHM MC13783_IRQSTAT0_WHIGHI | ||
70 | #define MC13783_IRQMASK0_WLOWM MC13783_IRQSTAT0_WLOWI | ||
71 | #define MC13XXX_IRQMASK0_CHGDETM MC13XXX_IRQSTAT0_CHGDETI | ||
72 | #define MC13783_IRQMASK0_CHGOVM MC13783_IRQSTAT0_CHGOVI | ||
73 | #define MC13XXX_IRQMASK0_CHGREVM MC13XXX_IRQSTAT0_CHGREVI | ||
74 | #define MC13XXX_IRQMASK0_CHGSHORTM MC13XXX_IRQSTAT0_CHGSHORTI | ||
75 | #define MC13XXX_IRQMASK0_CCCVM MC13XXX_IRQSTAT0_CCCVI | ||
76 | #define MC13XXX_IRQMASK0_CHGCURRM MC13XXX_IRQSTAT0_CHGCURRI | ||
77 | #define MC13XXX_IRQMASK0_BPONM MC13XXX_IRQSTAT0_BPONI | ||
78 | #define MC13XXX_IRQMASK0_LOBATLM MC13XXX_IRQSTAT0_LOBATLI | ||
79 | #define MC13XXX_IRQMASK0_LOBATHM MC13XXX_IRQSTAT0_LOBATHI | ||
80 | #define MC13783_IRQMASK0_UDPM MC13783_IRQSTAT0_UDPI | ||
81 | #define MC13783_IRQMASK0_USBM MC13783_IRQSTAT0_USBI | ||
82 | #define MC13783_IRQMASK0_IDM MC13783_IRQSTAT0_IDI | ||
83 | #define MC13783_IRQMASK0_SE1M MC13783_IRQSTAT0_SE1I | ||
84 | #define MC13783_IRQMASK0_CKDETM MC13783_IRQSTAT0_CKDETI | ||
85 | #define MC13783_IRQMASK0_UDMM MC13783_IRQSTAT0_UDMI | ||
86 | |||
87 | #define MC13XXX_IRQSTAT1 3 | ||
88 | #define MC13XXX_IRQSTAT1_1HZI (1 << 0) | ||
89 | #define MC13XXX_IRQSTAT1_TODAI (1 << 1) | ||
90 | #define MC13783_IRQSTAT1_ONOFD1I (1 << 3) | ||
91 | #define MC13783_IRQSTAT1_ONOFD2I (1 << 4) | ||
92 | #define MC13783_IRQSTAT1_ONOFD3I (1 << 5) | ||
93 | #define MC13XXX_IRQSTAT1_SYSRSTI (1 << 6) | ||
94 | #define MC13XXX_IRQSTAT1_RTCRSTI (1 << 7) | ||
95 | #define MC13XXX_IRQSTAT1_PCI (1 << 8) | ||
96 | #define MC13XXX_IRQSTAT1_WARMI (1 << 9) | ||
97 | #define MC13XXX_IRQSTAT1_MEMHLDI (1 << 10) | ||
98 | #define MC13783_IRQSTAT1_PWRRDYI (1 << 11) | ||
99 | #define MC13XXX_IRQSTAT1_THWARNLI (1 << 12) | ||
100 | #define MC13XXX_IRQSTAT1_THWARNHI (1 << 13) | ||
101 | #define MC13XXX_IRQSTAT1_CLKI (1 << 14) | ||
102 | #define MC13783_IRQSTAT1_SEMAFI (1 << 15) | ||
103 | #define MC13783_IRQSTAT1_MC2BI (1 << 17) | ||
104 | #define MC13783_IRQSTAT1_HSDETI (1 << 18) | ||
105 | #define MC13783_IRQSTAT1_HSLI (1 << 19) | ||
106 | #define MC13783_IRQSTAT1_ALSPTHI (1 << 20) | ||
107 | #define MC13783_IRQSTAT1_AHSSHORTI (1 << 21) | ||
108 | |||
109 | #define MC13XXX_IRQMASK1 4 | ||
110 | #define MC13XXX_IRQMASK1_1HZM MC13XXX_IRQSTAT1_1HZI | ||
111 | #define MC13XXX_IRQMASK1_TODAM MC13XXX_IRQSTAT1_TODAI | ||
112 | #define MC13783_IRQMASK1_ONOFD1M MC13783_IRQSTAT1_ONOFD1I | ||
113 | #define MC13783_IRQMASK1_ONOFD2M MC13783_IRQSTAT1_ONOFD2I | ||
114 | #define MC13783_IRQMASK1_ONOFD3M MC13783_IRQSTAT1_ONOFD3I | ||
115 | #define MC13XXX_IRQMASK1_SYSRSTM MC13XXX_IRQSTAT1_SYSRSTI | ||
116 | #define MC13XXX_IRQMASK1_RTCRSTM MC13XXX_IRQSTAT1_RTCRSTI | ||
117 | #define MC13XXX_IRQMASK1_PCM MC13XXX_IRQSTAT1_PCI | ||
118 | #define MC13XXX_IRQMASK1_WARMM MC13XXX_IRQSTAT1_WARMI | ||
119 | #define MC13XXX_IRQMASK1_MEMHLDM MC13XXX_IRQSTAT1_MEMHLDI | ||
120 | #define MC13783_IRQMASK1_PWRRDYM MC13783_IRQSTAT1_PWRRDYI | ||
121 | #define MC13XXX_IRQMASK1_THWARNLM MC13XXX_IRQSTAT1_THWARNLI | ||
122 | #define MC13XXX_IRQMASK1_THWARNHM MC13XXX_IRQSTAT1_THWARNHI | ||
123 | #define MC13XXX_IRQMASK1_CLKM MC13XXX_IRQSTAT1_CLKI | ||
124 | #define MC13783_IRQMASK1_SEMAFM MC13783_IRQSTAT1_SEMAFI | ||
125 | #define MC13783_IRQMASK1_MC2BM MC13783_IRQSTAT1_MC2BI | ||
126 | #define MC13783_IRQMASK1_HSDETM MC13783_IRQSTAT1_HSDETI | ||
127 | #define MC13783_IRQMASK1_HSLM MC13783_IRQSTAT1_HSLI | ||
128 | #define MC13783_IRQMASK1_ALSPTHM MC13783_IRQSTAT1_ALSPTHI | ||
129 | #define MC13783_IRQMASK1_AHSSHORTM MC13783_IRQSTAT1_AHSSHORTI | ||
130 | |||
131 | #define MC13XXX_REVISION 7 | ||
132 | #define MC13XXX_REVISION_REVMETAL (0x07 << 0) | ||
133 | #define MC13XXX_REVISION_REVFULL (0x03 << 3) | ||
134 | #define MC13XXX_REVISION_ICID (0x07 << 6) | ||
135 | #define MC13XXX_REVISION_FIN (0x03 << 9) | ||
136 | #define MC13XXX_REVISION_FAB (0x03 << 11) | ||
137 | #define MC13XXX_REVISION_ICIDCODE (0x3f << 13) | ||
138 | |||
139 | #define MC13783_ADC1 44 | ||
140 | #define MC13783_ADC1_ADEN (1 << 0) | ||
141 | #define MC13783_ADC1_RAND (1 << 1) | ||
142 | #define MC13783_ADC1_ADSEL (1 << 3) | ||
143 | #define MC13783_ADC1_ASC (1 << 20) | ||
144 | #define MC13783_ADC1_ADTRIGIGN (1 << 21) | ||
145 | |||
146 | #define MC13783_ADC2 45 | ||
147 | |||
148 | #define MC13XXX_NUMREGS 0x3f | ||
149 | |||
150 | void mc13xxx_lock(struct mc13xxx *mc13xxx) | ||
151 | { | ||
152 | if (!mutex_trylock(&mc13xxx->lock)) { | ||
153 | dev_dbg(&mc13xxx->spidev->dev, "wait for %s from %pf\n", | ||
154 | __func__, __builtin_return_address(0)); | ||
155 | |||
156 | mutex_lock(&mc13xxx->lock); | ||
157 | } | ||
158 | dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n", | ||
159 | __func__, __builtin_return_address(0)); | ||
160 | } | ||
161 | EXPORT_SYMBOL(mc13xxx_lock); | ||
162 | |||
163 | void mc13xxx_unlock(struct mc13xxx *mc13xxx) | ||
164 | { | ||
165 | dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n", | ||
166 | __func__, __builtin_return_address(0)); | ||
167 | mutex_unlock(&mc13xxx->lock); | ||
168 | } | ||
169 | EXPORT_SYMBOL(mc13xxx_unlock); | ||
170 | |||
171 | #define MC13XXX_REGOFFSET_SHIFT 25 | ||
172 | int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val) | ||
173 | { | ||
174 | struct spi_transfer t; | ||
175 | struct spi_message m; | ||
176 | int ret; | ||
177 | |||
178 | BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | ||
179 | |||
180 | if (offset > MC13XXX_NUMREGS) | ||
181 | return -EINVAL; | ||
182 | |||
183 | *val = offset << MC13XXX_REGOFFSET_SHIFT; | ||
184 | |||
185 | memset(&t, 0, sizeof(t)); | ||
186 | |||
187 | t.tx_buf = val; | ||
188 | t.rx_buf = val; | ||
189 | t.len = sizeof(u32); | ||
190 | |||
191 | spi_message_init(&m); | ||
192 | spi_message_add_tail(&t, &m); | ||
193 | |||
194 | ret = spi_sync(mc13xxx->spidev, &m); | ||
195 | |||
196 | /* error in message.status implies error return from spi_sync */ | ||
197 | BUG_ON(!ret && m.status); | ||
198 | |||
199 | if (ret) | ||
200 | return ret; | ||
201 | |||
202 | *val &= 0xffffff; | ||
203 | |||
204 | dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val); | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | EXPORT_SYMBOL(mc13xxx_reg_read); | ||
209 | |||
210 | int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val) | ||
211 | { | ||
212 | u32 buf; | ||
213 | struct spi_transfer t; | ||
214 | struct spi_message m; | ||
215 | int ret; | ||
216 | |||
217 | BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | ||
218 | |||
219 | dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val); | ||
220 | |||
221 | if (offset > MC13XXX_NUMREGS || val > 0xffffff) | ||
222 | return -EINVAL; | ||
223 | |||
224 | buf = 1 << 31 | offset << MC13XXX_REGOFFSET_SHIFT | val; | ||
225 | |||
226 | memset(&t, 0, sizeof(t)); | ||
227 | |||
228 | t.tx_buf = &buf; | ||
229 | t.rx_buf = &buf; | ||
230 | t.len = sizeof(u32); | ||
231 | |||
232 | spi_message_init(&m); | ||
233 | spi_message_add_tail(&t, &m); | ||
234 | |||
235 | ret = spi_sync(mc13xxx->spidev, &m); | ||
236 | |||
237 | BUG_ON(!ret && m.status); | ||
238 | |||
239 | if (ret) | ||
240 | return ret; | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | EXPORT_SYMBOL(mc13xxx_reg_write); | ||
245 | |||
246 | int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset, | ||
247 | u32 mask, u32 val) | ||
248 | { | ||
249 | int ret; | ||
250 | u32 valread; | ||
251 | |||
252 | BUG_ON(val & ~mask); | ||
253 | |||
254 | ret = mc13xxx_reg_read(mc13xxx, offset, &valread); | ||
255 | if (ret) | ||
256 | return ret; | ||
257 | |||
258 | valread = (valread & ~mask) | val; | ||
259 | |||
260 | return mc13xxx_reg_write(mc13xxx, offset, valread); | ||
261 | } | ||
262 | EXPORT_SYMBOL(mc13xxx_reg_rmw); | ||
263 | |||
264 | int mc13xxx_irq_mask(struct mc13xxx *mc13xxx, int irq) | ||
265 | { | ||
266 | int ret; | ||
267 | unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1; | ||
268 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
269 | u32 mask; | ||
270 | |||
271 | if (irq < 0 || irq >= MC13XXX_NUM_IRQ) | ||
272 | return -EINVAL; | ||
273 | |||
274 | ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); | ||
275 | if (ret) | ||
276 | return ret; | ||
277 | |||
278 | if (mask & irqbit) | ||
279 | /* already masked */ | ||
280 | return 0; | ||
281 | |||
282 | return mc13xxx_reg_write(mc13xxx, offmask, mask | irqbit); | ||
283 | } | ||
284 | EXPORT_SYMBOL(mc13xxx_irq_mask); | ||
285 | |||
286 | int mc13xxx_irq_unmask(struct mc13xxx *mc13xxx, int irq) | ||
287 | { | ||
288 | int ret; | ||
289 | unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1; | ||
290 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
291 | u32 mask; | ||
292 | |||
293 | if (irq < 0 || irq >= MC13XXX_NUM_IRQ) | ||
294 | return -EINVAL; | ||
295 | |||
296 | ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); | ||
297 | if (ret) | ||
298 | return ret; | ||
299 | |||
300 | if (!(mask & irqbit)) | ||
301 | /* already unmasked */ | ||
302 | return 0; | ||
303 | |||
304 | return mc13xxx_reg_write(mc13xxx, offmask, mask & ~irqbit); | ||
305 | } | ||
306 | EXPORT_SYMBOL(mc13xxx_irq_unmask); | ||
307 | |||
308 | int mc13xxx_irq_status(struct mc13xxx *mc13xxx, int irq, | ||
309 | int *enabled, int *pending) | ||
310 | { | ||
311 | int ret; | ||
312 | unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1; | ||
313 | unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1; | ||
314 | u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | ||
315 | |||
316 | if (irq < 0 || irq >= MC13XXX_NUM_IRQ) | ||
317 | return -EINVAL; | ||
318 | |||
319 | if (enabled) { | ||
320 | u32 mask; | ||
321 | |||
322 | ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); | ||
323 | if (ret) | ||
324 | return ret; | ||
325 | |||
326 | *enabled = mask & irqbit; | ||
327 | } | ||
328 | |||
329 | if (pending) { | ||
330 | u32 stat; | ||
331 | |||
332 | ret = mc13xxx_reg_read(mc13xxx, offstat, &stat); | ||
333 | if (ret) | ||
334 | return ret; | ||
335 | |||
336 | *pending = stat & irqbit; | ||
337 | } | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | EXPORT_SYMBOL(mc13xxx_irq_status); | ||
342 | |||
343 | int mc13xxx_irq_ack(struct mc13xxx *mc13xxx, int irq) | ||
344 | { | ||
345 | unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1; | ||
346 | unsigned int val = 1 << (irq < 24 ? irq : irq - 24); | ||
347 | |||
348 | BUG_ON(irq < 0 || irq >= MC13XXX_NUM_IRQ); | ||
349 | |||
350 | return mc13xxx_reg_write(mc13xxx, offstat, val); | ||
351 | } | ||
352 | EXPORT_SYMBOL(mc13xxx_irq_ack); | ||
353 | |||
354 | int mc13xxx_irq_request_nounmask(struct mc13xxx *mc13xxx, int irq, | ||
355 | irq_handler_t handler, const char *name, void *dev) | ||
356 | { | ||
357 | BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | ||
358 | BUG_ON(!handler); | ||
359 | |||
360 | if (irq < 0 || irq >= MC13XXX_NUM_IRQ) | ||
361 | return -EINVAL; | ||
362 | |||
363 | if (mc13xxx->irqhandler[irq]) | ||
364 | return -EBUSY; | ||
365 | |||
366 | mc13xxx->irqhandler[irq] = handler; | ||
367 | mc13xxx->irqdata[irq] = dev; | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | EXPORT_SYMBOL(mc13xxx_irq_request_nounmask); | ||
372 | |||
373 | int mc13xxx_irq_request(struct mc13xxx *mc13xxx, int irq, | ||
374 | irq_handler_t handler, const char *name, void *dev) | ||
375 | { | ||
376 | int ret; | ||
377 | |||
378 | ret = mc13xxx_irq_request_nounmask(mc13xxx, irq, handler, name, dev); | ||
379 | if (ret) | ||
380 | return ret; | ||
381 | |||
382 | ret = mc13xxx_irq_unmask(mc13xxx, irq); | ||
383 | if (ret) { | ||
384 | mc13xxx->irqhandler[irq] = NULL; | ||
385 | mc13xxx->irqdata[irq] = NULL; | ||
386 | return ret; | ||
387 | } | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | EXPORT_SYMBOL(mc13xxx_irq_request); | ||
392 | |||
393 | int mc13xxx_irq_free(struct mc13xxx *mc13xxx, int irq, void *dev) | ||
394 | { | ||
395 | int ret; | ||
396 | BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | ||
397 | |||
398 | if (irq < 0 || irq >= MC13XXX_NUM_IRQ || !mc13xxx->irqhandler[irq] || | ||
399 | mc13xxx->irqdata[irq] != dev) | ||
400 | return -EINVAL; | ||
401 | |||
402 | ret = mc13xxx_irq_mask(mc13xxx, irq); | ||
403 | if (ret) | ||
404 | return ret; | ||
405 | |||
406 | mc13xxx->irqhandler[irq] = NULL; | ||
407 | mc13xxx->irqdata[irq] = NULL; | ||
408 | |||
409 | return 0; | ||
410 | } | ||
411 | EXPORT_SYMBOL(mc13xxx_irq_free); | ||
412 | |||
413 | static inline irqreturn_t mc13xxx_irqhandler(struct mc13xxx *mc13xxx, int irq) | ||
414 | { | ||
415 | return mc13xxx->irqhandler[irq](irq, mc13xxx->irqdata[irq]); | ||
416 | } | ||
417 | |||
418 | /* | ||
419 | * returns: number of handled irqs or negative error | ||
420 | * locking: holds mc13xxx->lock | ||
421 | */ | ||
422 | static int mc13xxx_irq_handle(struct mc13xxx *mc13xxx, | ||
423 | unsigned int offstat, unsigned int offmask, int baseirq) | ||
424 | { | ||
425 | u32 stat, mask; | ||
426 | int ret = mc13xxx_reg_read(mc13xxx, offstat, &stat); | ||
427 | int num_handled = 0; | ||
428 | |||
429 | if (ret) | ||
430 | return ret; | ||
431 | |||
432 | ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); | ||
433 | if (ret) | ||
434 | return ret; | ||
435 | |||
436 | while (stat & ~mask) { | ||
437 | int irq = __ffs(stat & ~mask); | ||
438 | |||
439 | stat &= ~(1 << irq); | ||
440 | |||
441 | if (likely(mc13xxx->irqhandler[baseirq + irq])) { | ||
442 | irqreturn_t handled; | ||
443 | |||
444 | handled = mc13xxx_irqhandler(mc13xxx, baseirq + irq); | ||
445 | if (handled == IRQ_HANDLED) | ||
446 | num_handled++; | ||
447 | } else { | ||
448 | dev_err(&mc13xxx->spidev->dev, | ||
449 | "BUG: irq %u but no handler\n", | ||
450 | baseirq + irq); | ||
451 | |||
452 | mask |= 1 << irq; | ||
453 | |||
454 | ret = mc13xxx_reg_write(mc13xxx, offmask, mask); | ||
455 | } | ||
456 | } | ||
457 | |||
458 | return num_handled; | ||
459 | } | ||
460 | |||
461 | static irqreturn_t mc13xxx_irq_thread(int irq, void *data) | ||
462 | { | ||
463 | struct mc13xxx *mc13xxx = data; | ||
464 | irqreturn_t ret; | ||
465 | int handled = 0; | ||
466 | |||
467 | mc13xxx_lock(mc13xxx); | ||
468 | |||
469 | ret = mc13xxx_irq_handle(mc13xxx, MC13XXX_IRQSTAT0, | ||
470 | MC13XXX_IRQMASK0, 0); | ||
471 | if (ret > 0) | ||
472 | handled = 1; | ||
473 | |||
474 | ret = mc13xxx_irq_handle(mc13xxx, MC13XXX_IRQSTAT1, | ||
475 | MC13XXX_IRQMASK1, 24); | ||
476 | if (ret > 0) | ||
477 | handled = 1; | ||
478 | |||
479 | mc13xxx_unlock(mc13xxx); | ||
480 | |||
481 | return IRQ_RETVAL(handled); | ||
482 | } | ||
483 | |||
484 | enum mc13xxx_id { | ||
485 | MC13XXX_ID_MC13783, | ||
486 | MC13XXX_ID_MC13892, | ||
487 | MC13XXX_ID_INVALID, | ||
488 | }; | ||
489 | |||
490 | const char *mc13xxx_chipname[] = { | ||
491 | [MC13XXX_ID_MC13783] = "mc13783", | ||
492 | [MC13XXX_ID_MC13892] = "mc13892", | ||
493 | }; | ||
494 | |||
495 | #define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask)) | ||
496 | static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id) | ||
497 | { | ||
498 | u32 icid; | ||
499 | u32 revision; | ||
500 | const char *name; | ||
501 | int ret; | ||
502 | |||
503 | ret = mc13xxx_reg_read(mc13xxx, 46, &icid); | ||
504 | if (ret) | ||
505 | return ret; | ||
506 | |||
507 | icid = (icid >> 6) & 0x7; | ||
508 | |||
509 | switch (icid) { | ||
510 | case 2: | ||
511 | *id = MC13XXX_ID_MC13783; | ||
512 | name = "mc13783"; | ||
513 | break; | ||
514 | case 7: | ||
515 | *id = MC13XXX_ID_MC13892; | ||
516 | name = "mc13892"; | ||
517 | break; | ||
518 | default: | ||
519 | *id = MC13XXX_ID_INVALID; | ||
520 | break; | ||
521 | } | ||
522 | |||
523 | if (*id == MC13XXX_ID_MC13783 || *id == MC13XXX_ID_MC13892) { | ||
524 | ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision); | ||
525 | if (ret) | ||
526 | return ret; | ||
527 | |||
528 | dev_info(&mc13xxx->spidev->dev, "%s: rev: %d.%d, " | ||
529 | "fin: %d, fab: %d, icid: %d/%d\n", | ||
530 | mc13xxx_chipname[*id], | ||
531 | maskval(revision, MC13XXX_REVISION_REVFULL), | ||
532 | maskval(revision, MC13XXX_REVISION_REVMETAL), | ||
533 | maskval(revision, MC13XXX_REVISION_FIN), | ||
534 | maskval(revision, MC13XXX_REVISION_FAB), | ||
535 | maskval(revision, MC13XXX_REVISION_ICID), | ||
536 | maskval(revision, MC13XXX_REVISION_ICIDCODE)); | ||
537 | } | ||
538 | |||
539 | if (*id != MC13XXX_ID_INVALID) { | ||
540 | const struct spi_device_id *devid = | ||
541 | spi_get_device_id(mc13xxx->spidev); | ||
542 | if (!devid || devid->driver_data != *id) | ||
543 | dev_warn(&mc13xxx->spidev->dev, "device id doesn't " | ||
544 | "match auto detection!\n"); | ||
545 | } | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx) | ||
551 | { | ||
552 | const struct spi_device_id *devid = | ||
553 | spi_get_device_id(mc13xxx->spidev); | ||
554 | |||
555 | if (!devid) | ||
556 | return NULL; | ||
557 | |||
558 | return mc13xxx_chipname[devid->driver_data]; | ||
559 | } | ||
560 | |||
561 | #include <linux/mfd/mc13783.h> | ||
562 | |||
563 | int mc13xxx_get_flags(struct mc13xxx *mc13xxx) | ||
564 | { | ||
565 | struct mc13xxx_platform_data *pdata = | ||
566 | dev_get_platdata(&mc13xxx->spidev->dev); | ||
567 | |||
568 | return pdata->flags; | ||
569 | } | ||
570 | EXPORT_SYMBOL(mc13xxx_get_flags); | ||
571 | |||
572 | #define MC13783_ADC1_CHAN0_SHIFT 5 | ||
573 | #define MC13783_ADC1_CHAN1_SHIFT 8 | ||
574 | |||
575 | struct mc13xxx_adcdone_data { | ||
576 | struct mc13xxx *mc13xxx; | ||
577 | struct completion done; | ||
578 | }; | ||
579 | |||
580 | static irqreturn_t mc13783_handler_adcdone(int irq, void *data) | ||
581 | { | ||
582 | struct mc13xxx_adcdone_data *adcdone_data = data; | ||
583 | |||
584 | mc13xxx_irq_ack(adcdone_data->mc13xxx, irq); | ||
585 | |||
586 | complete_all(&adcdone_data->done); | ||
587 | |||
588 | return IRQ_HANDLED; | ||
589 | } | ||
590 | |||
591 | #define MC13783_ADC_WORKING (1 << 0) | ||
592 | |||
593 | int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, | ||
594 | unsigned int channel, unsigned int *sample) | ||
595 | { | ||
596 | struct mc13xxx *mc13xxx = &mc13783->mc13xxx; | ||
597 | u32 adc0, adc1, old_adc0; | ||
598 | int i, ret; | ||
599 | struct mc13xxx_adcdone_data adcdone_data = { | ||
600 | .mc13xxx = mc13xxx, | ||
601 | }; | ||
602 | init_completion(&adcdone_data.done); | ||
603 | |||
604 | dev_dbg(&mc13xxx->spidev->dev, "%s\n", __func__); | ||
605 | |||
606 | mc13xxx_lock(mc13xxx); | ||
607 | |||
608 | if (mc13783->adcflags & MC13783_ADC_WORKING) { | ||
609 | ret = -EBUSY; | ||
610 | goto out; | ||
611 | } | ||
612 | |||
613 | mc13783->adcflags |= MC13783_ADC_WORKING; | ||
614 | |||
615 | mc13xxx_reg_read(mc13xxx, MC13783_ADC0, &old_adc0); | ||
616 | |||
617 | adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; | ||
618 | adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC; | ||
619 | |||
620 | if (channel > 7) | ||
621 | adc1 |= MC13783_ADC1_ADSEL; | ||
622 | |||
623 | switch (mode) { | ||
624 | case MC13783_ADC_MODE_TS: | ||
625 | adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 | | ||
626 | MC13783_ADC0_TSMOD1; | ||
627 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | ||
628 | break; | ||
629 | |||
630 | case MC13783_ADC_MODE_SINGLE_CHAN: | ||
631 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; | ||
632 | adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; | ||
633 | adc1 |= MC13783_ADC1_RAND; | ||
634 | break; | ||
635 | |||
636 | case MC13783_ADC_MODE_MULT_CHAN: | ||
637 | adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; | ||
638 | adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | ||
639 | break; | ||
640 | |||
641 | default: | ||
642 | mc13783_unlock(mc13783); | ||
643 | return -EINVAL; | ||
644 | } | ||
645 | |||
646 | dev_dbg(&mc13783->mc13xxx.spidev->dev, "%s: request irq\n", __func__); | ||
647 | mc13xxx_irq_request(mc13xxx, MC13783_IRQ_ADCDONE, | ||
648 | mc13783_handler_adcdone, __func__, &adcdone_data); | ||
649 | mc13xxx_irq_ack(mc13xxx, MC13783_IRQ_ADCDONE); | ||
650 | |||
651 | mc13xxx_reg_write(mc13xxx, MC13783_ADC0, adc0); | ||
652 | mc13xxx_reg_write(mc13xxx, MC13783_ADC1, adc1); | ||
653 | |||
654 | mc13xxx_unlock(mc13xxx); | ||
655 | |||
656 | ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ); | ||
657 | |||
658 | if (!ret) | ||
659 | ret = -ETIMEDOUT; | ||
660 | |||
661 | mc13xxx_lock(mc13xxx); | ||
662 | |||
663 | mc13xxx_irq_free(mc13xxx, MC13783_IRQ_ADCDONE, &adcdone_data); | ||
664 | |||
665 | if (ret > 0) | ||
666 | for (i = 0; i < 4; ++i) { | ||
667 | ret = mc13xxx_reg_read(mc13xxx, | ||
668 | MC13783_ADC2, &sample[i]); | ||
669 | if (ret) | ||
670 | break; | ||
671 | } | ||
672 | |||
673 | if (mode == MC13783_ADC_MODE_TS) | ||
674 | /* restore TSMOD */ | ||
675 | mc13xxx_reg_write(mc13xxx, MC13783_ADC0, old_adc0); | ||
676 | |||
677 | mc13783->adcflags &= ~MC13783_ADC_WORKING; | ||
678 | out: | ||
679 | mc13xxx_unlock(mc13xxx); | ||
680 | |||
681 | return ret; | ||
682 | } | ||
683 | EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); | ||
684 | |||
685 | static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, | ||
686 | const char *format, void *pdata, size_t pdata_size) | ||
687 | { | ||
688 | char buf[30]; | ||
689 | const char *name = mc13xxx_get_chipname(mc13xxx); | ||
690 | |||
691 | struct mfd_cell cell = { | ||
692 | .platform_data = pdata, | ||
693 | .pdata_size = pdata_size, | ||
694 | }; | ||
695 | |||
696 | /* there is no asnprintf in the kernel :-( */ | ||
697 | if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf)) | ||
698 | return -E2BIG; | ||
699 | |||
700 | cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL); | ||
701 | if (!cell.name) | ||
702 | return -ENOMEM; | ||
703 | |||
704 | return mfd_add_devices(&mc13xxx->spidev->dev, -1, &cell, 1, NULL, 0); | ||
705 | } | ||
706 | |||
707 | static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) | ||
708 | { | ||
709 | return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0); | ||
710 | } | ||
711 | |||
712 | static int mc13xxx_probe(struct spi_device *spi) | ||
713 | { | ||
714 | struct mc13xxx *mc13xxx; | ||
715 | struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev); | ||
716 | enum mc13xxx_id id; | ||
717 | int ret; | ||
718 | |||
719 | mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL); | ||
720 | if (!mc13xxx) | ||
721 | return -ENOMEM; | ||
722 | |||
723 | dev_set_drvdata(&spi->dev, mc13xxx); | ||
724 | spi->mode = SPI_MODE_0 | SPI_CS_HIGH; | ||
725 | spi->bits_per_word = 32; | ||
726 | spi_setup(spi); | ||
727 | |||
728 | mc13xxx->spidev = spi; | ||
729 | |||
730 | mutex_init(&mc13xxx->lock); | ||
731 | mc13xxx_lock(mc13xxx); | ||
732 | |||
733 | ret = mc13xxx_identify(mc13xxx, &id); | ||
734 | if (ret || id == MC13XXX_ID_INVALID) | ||
735 | goto err_revision; | ||
736 | |||
737 | /* mask all irqs */ | ||
738 | ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff); | ||
739 | if (ret) | ||
740 | goto err_mask; | ||
741 | |||
742 | ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK1, 0x00ffffff); | ||
743 | if (ret) | ||
744 | goto err_mask; | ||
745 | |||
746 | ret = request_threaded_irq(spi->irq, NULL, mc13xxx_irq_thread, | ||
747 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx); | ||
748 | |||
749 | if (ret) { | ||
750 | err_mask: | ||
751 | err_revision: | ||
752 | mc13xxx_unlock(mc13xxx); | ||
753 | dev_set_drvdata(&spi->dev, NULL); | ||
754 | kfree(mc13xxx); | ||
755 | return ret; | ||
756 | } | ||
757 | |||
758 | mc13xxx_unlock(mc13xxx); | ||
759 | |||
760 | if (pdata->flags & MC13XXX_USE_ADC) | ||
761 | mc13xxx_add_subdevice(mc13xxx, "%s-adc"); | ||
762 | |||
763 | if (pdata->flags & MC13XXX_USE_CODEC) | ||
764 | mc13xxx_add_subdevice(mc13xxx, "%s-codec"); | ||
765 | |||
766 | if (pdata->flags & MC13XXX_USE_REGULATOR) { | ||
767 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", | ||
768 | &pdata->regulators, sizeof(pdata->regulators)); | ||
769 | } | ||
770 | |||
771 | if (pdata->flags & MC13XXX_USE_RTC) | ||
772 | mc13xxx_add_subdevice(mc13xxx, "%s-rtc"); | ||
773 | |||
774 | if (pdata->flags & MC13XXX_USE_TOUCHSCREEN) | ||
775 | mc13xxx_add_subdevice(mc13xxx, "%s-ts"); | ||
776 | |||
777 | if (pdata->flags & MC13XXX_USE_LED) | ||
778 | mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", | ||
779 | pdata->leds, sizeof(*pdata->leds)); | ||
780 | |||
781 | return 0; | ||
782 | } | ||
783 | |||
784 | static int __devexit mc13xxx_remove(struct spi_device *spi) | ||
785 | { | ||
786 | struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev); | ||
787 | |||
788 | free_irq(mc13xxx->spidev->irq, mc13xxx); | ||
789 | |||
790 | mfd_remove_devices(&spi->dev); | ||
791 | |||
792 | kfree(mc13xxx); | ||
793 | |||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | static const struct spi_device_id mc13xxx_device_id[] = { | ||
798 | { | ||
799 | .name = "mc13783", | ||
800 | .driver_data = MC13XXX_ID_MC13783, | ||
801 | }, { | ||
802 | .name = "mc13892", | ||
803 | .driver_data = MC13XXX_ID_MC13892, | ||
804 | }, { | ||
805 | /* sentinel */ | ||
806 | } | ||
807 | }; | ||
808 | MODULE_DEVICE_TABLE(spi, mc13xxx_device_id); | ||
809 | |||
810 | static struct spi_driver mc13xxx_driver = { | ||
811 | .id_table = mc13xxx_device_id, | ||
812 | .driver = { | ||
813 | .name = "mc13xxx", | ||
814 | .bus = &spi_bus_type, | ||
815 | .owner = THIS_MODULE, | ||
816 | }, | ||
817 | .probe = mc13xxx_probe, | ||
818 | .remove = __devexit_p(mc13xxx_remove), | ||
819 | }; | ||
820 | |||
821 | static int __init mc13xxx_init(void) | ||
822 | { | ||
823 | return spi_register_driver(&mc13xxx_driver); | ||
824 | } | ||
825 | subsys_initcall(mc13xxx_init); | ||
826 | |||
827 | static void __exit mc13xxx_exit(void) | ||
828 | { | ||
829 | spi_unregister_driver(&mc13xxx_driver); | ||
830 | } | ||
831 | module_exit(mc13xxx_exit); | ||
832 | |||
833 | MODULE_DESCRIPTION("Core driver for Freescale MC13XXX PMIC"); | ||
834 | MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); | ||
835 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 4ba85bbdb4c1..9cee8e7f0bcb 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c | |||
@@ -1259,7 +1259,7 @@ static int menelaus_probe(struct i2c_client *client, | |||
1259 | return 0; | 1259 | return 0; |
1260 | fail2: | 1260 | fail2: |
1261 | free_irq(client->irq, menelaus); | 1261 | free_irq(client->irq, menelaus); |
1262 | flush_scheduled_work(); | 1262 | flush_work_sync(&menelaus->work); |
1263 | fail1: | 1263 | fail1: |
1264 | kfree(menelaus); | 1264 | kfree(menelaus); |
1265 | return err; | 1265 | return err; |
@@ -1270,6 +1270,7 @@ static int __exit menelaus_remove(struct i2c_client *client) | |||
1270 | struct menelaus_chip *menelaus = i2c_get_clientdata(client); | 1270 | struct menelaus_chip *menelaus = i2c_get_clientdata(client); |
1271 | 1271 | ||
1272 | free_irq(client->irq, menelaus); | 1272 | free_irq(client->irq, menelaus); |
1273 | flush_work_sync(&menelaus->work); | ||
1273 | kfree(menelaus); | 1274 | kfree(menelaus); |
1274 | the_menelaus = NULL; | 1275 | the_menelaus = NULL; |
1275 | return 0; | 1276 | return 0; |
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 1823a57b7d8f..0902523af62d 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c | |||
@@ -15,8 +15,59 @@ | |||
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/acpi.h> | 16 | #include <linux/acpi.h> |
17 | #include <linux/mfd/core.h> | 17 | #include <linux/mfd/core.h> |
18 | #include <linux/pm_runtime.h> | ||
18 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
19 | 20 | ||
21 | int mfd_cell_enable(struct platform_device *pdev) | ||
22 | { | ||
23 | const struct mfd_cell *cell = mfd_get_cell(pdev); | ||
24 | int err = 0; | ||
25 | |||
26 | /* only call enable hook if the cell wasn't previously enabled */ | ||
27 | if (atomic_inc_return(cell->usage_count) == 1) | ||
28 | err = cell->enable(pdev); | ||
29 | |||
30 | /* if the enable hook failed, decrement counter to allow retries */ | ||
31 | if (err) | ||
32 | atomic_dec(cell->usage_count); | ||
33 | |||
34 | return err; | ||
35 | } | ||
36 | EXPORT_SYMBOL(mfd_cell_enable); | ||
37 | |||
38 | int mfd_cell_disable(struct platform_device *pdev) | ||
39 | { | ||
40 | const struct mfd_cell *cell = mfd_get_cell(pdev); | ||
41 | int err = 0; | ||
42 | |||
43 | /* only disable if no other clients are using it */ | ||
44 | if (atomic_dec_return(cell->usage_count) == 0) | ||
45 | err = cell->disable(pdev); | ||
46 | |||
47 | /* if the disable hook failed, increment to allow retries */ | ||
48 | if (err) | ||
49 | atomic_inc(cell->usage_count); | ||
50 | |||
51 | /* sanity check; did someone call disable too many times? */ | ||
52 | WARN_ON(atomic_read(cell->usage_count) < 0); | ||
53 | |||
54 | return err; | ||
55 | } | ||
56 | EXPORT_SYMBOL(mfd_cell_disable); | ||
57 | |||
58 | static int mfd_platform_add_cell(struct platform_device *pdev, | ||
59 | const struct mfd_cell *cell) | ||
60 | { | ||
61 | if (!cell) | ||
62 | return 0; | ||
63 | |||
64 | pdev->mfd_cell = kmemdup(cell, sizeof(*cell), GFP_KERNEL); | ||
65 | if (!pdev->mfd_cell) | ||
66 | return -ENOMEM; | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
20 | static int mfd_add_device(struct device *parent, int id, | 71 | static int mfd_add_device(struct device *parent, int id, |
21 | const struct mfd_cell *cell, | 72 | const struct mfd_cell *cell, |
22 | struct resource *mem_base, | 73 | struct resource *mem_base, |
@@ -36,10 +87,15 @@ static int mfd_add_device(struct device *parent, int id, | |||
36 | goto fail_device; | 87 | goto fail_device; |
37 | 88 | ||
38 | pdev->dev.parent = parent; | 89 | pdev->dev.parent = parent; |
39 | platform_set_drvdata(pdev, cell->driver_data); | ||
40 | 90 | ||
41 | ret = platform_device_add_data(pdev, | 91 | if (cell->pdata_size) { |
42 | cell->platform_data, cell->data_size); | 92 | ret = platform_device_add_data(pdev, |
93 | cell->platform_data, cell->pdata_size); | ||
94 | if (ret) | ||
95 | goto fail_res; | ||
96 | } | ||
97 | |||
98 | ret = mfd_platform_add_cell(pdev, cell); | ||
43 | if (ret) | 99 | if (ret) |
44 | goto fail_res; | 100 | goto fail_res; |
45 | 101 | ||
@@ -65,9 +121,11 @@ static int mfd_add_device(struct device *parent, int id, | |||
65 | res[r].end = cell->resources[r].end; | 121 | res[r].end = cell->resources[r].end; |
66 | } | 122 | } |
67 | 123 | ||
68 | ret = acpi_check_resource_conflict(res); | 124 | if (!cell->ignore_resource_conflicts) { |
69 | if (ret) | 125 | ret = acpi_check_resource_conflict(res); |
70 | goto fail_res; | 126 | if (ret) |
127 | goto fail_res; | ||
128 | } | ||
71 | } | 129 | } |
72 | 130 | ||
73 | ret = platform_device_add_resources(pdev, res, cell->num_resources); | 131 | ret = platform_device_add_resources(pdev, res, cell->num_resources); |
@@ -78,11 +136,13 @@ static int mfd_add_device(struct device *parent, int id, | |||
78 | if (ret) | 136 | if (ret) |
79 | goto fail_res; | 137 | goto fail_res; |
80 | 138 | ||
139 | if (cell->pm_runtime_no_callbacks) | ||
140 | pm_runtime_no_callbacks(&pdev->dev); | ||
141 | |||
81 | kfree(res); | 142 | kfree(res); |
82 | 143 | ||
83 | return 0; | 144 | return 0; |
84 | 145 | ||
85 | /* platform_device_del(pdev); */ | ||
86 | fail_res: | 146 | fail_res: |
87 | kfree(res); | 147 | kfree(res); |
88 | fail_device: | 148 | fail_device: |
@@ -92,14 +152,22 @@ fail_alloc: | |||
92 | } | 152 | } |
93 | 153 | ||
94 | int mfd_add_devices(struct device *parent, int id, | 154 | int mfd_add_devices(struct device *parent, int id, |
95 | const struct mfd_cell *cells, int n_devs, | 155 | struct mfd_cell *cells, int n_devs, |
96 | struct resource *mem_base, | 156 | struct resource *mem_base, |
97 | int irq_base) | 157 | int irq_base) |
98 | { | 158 | { |
99 | int i; | 159 | int i; |
100 | int ret = 0; | 160 | int ret = 0; |
161 | atomic_t *cnts; | ||
162 | |||
163 | /* initialize reference counting for all cells */ | ||
164 | cnts = kcalloc(sizeof(*cnts), n_devs, GFP_KERNEL); | ||
165 | if (!cnts) | ||
166 | return -ENOMEM; | ||
101 | 167 | ||
102 | for (i = 0; i < n_devs; i++) { | 168 | for (i = 0; i < n_devs; i++) { |
169 | atomic_set(&cnts[i], 0); | ||
170 | cells[i].usage_count = &cnts[i]; | ||
103 | ret = mfd_add_device(parent, id, cells + i, mem_base, irq_base); | 171 | ret = mfd_add_device(parent, id, cells + i, mem_base, irq_base); |
104 | if (ret) | 172 | if (ret) |
105 | break; | 173 | break; |
@@ -112,17 +180,58 @@ int mfd_add_devices(struct device *parent, int id, | |||
112 | } | 180 | } |
113 | EXPORT_SYMBOL(mfd_add_devices); | 181 | EXPORT_SYMBOL(mfd_add_devices); |
114 | 182 | ||
115 | static int mfd_remove_devices_fn(struct device *dev, void *unused) | 183 | static int mfd_remove_devices_fn(struct device *dev, void *c) |
116 | { | 184 | { |
117 | platform_device_unregister(to_platform_device(dev)); | 185 | struct platform_device *pdev = to_platform_device(dev); |
186 | const struct mfd_cell *cell = mfd_get_cell(pdev); | ||
187 | atomic_t **usage_count = c; | ||
188 | |||
189 | /* find the base address of usage_count pointers (for freeing) */ | ||
190 | if (!*usage_count || (cell->usage_count < *usage_count)) | ||
191 | *usage_count = cell->usage_count; | ||
192 | |||
193 | platform_device_unregister(pdev); | ||
118 | return 0; | 194 | return 0; |
119 | } | 195 | } |
120 | 196 | ||
121 | void mfd_remove_devices(struct device *parent) | 197 | void mfd_remove_devices(struct device *parent) |
122 | { | 198 | { |
123 | device_for_each_child(parent, NULL, mfd_remove_devices_fn); | 199 | atomic_t *cnts = NULL; |
200 | |||
201 | device_for_each_child(parent, &cnts, mfd_remove_devices_fn); | ||
202 | kfree(cnts); | ||
124 | } | 203 | } |
125 | EXPORT_SYMBOL(mfd_remove_devices); | 204 | EXPORT_SYMBOL(mfd_remove_devices); |
126 | 205 | ||
206 | int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones) | ||
207 | { | ||
208 | struct mfd_cell cell_entry; | ||
209 | struct device *dev; | ||
210 | struct platform_device *pdev; | ||
211 | int i; | ||
212 | |||
213 | /* fetch the parent cell's device (should already be registered!) */ | ||
214 | dev = bus_find_device_by_name(&platform_bus_type, NULL, cell); | ||
215 | if (!dev) { | ||
216 | printk(KERN_ERR "failed to find device for cell %s\n", cell); | ||
217 | return -ENODEV; | ||
218 | } | ||
219 | pdev = to_platform_device(dev); | ||
220 | memcpy(&cell_entry, mfd_get_cell(pdev), sizeof(cell_entry)); | ||
221 | |||
222 | WARN_ON(!cell_entry.enable); | ||
223 | |||
224 | for (i = 0; i < n_clones; i++) { | ||
225 | cell_entry.name = clones[i]; | ||
226 | /* don't give up if a single call fails; just report error */ | ||
227 | if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0)) | ||
228 | dev_err(dev, "failed to create platform device '%s'\n", | ||
229 | clones[i]); | ||
230 | } | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | EXPORT_SYMBOL(mfd_clone_cell); | ||
235 | |||
127 | MODULE_LICENSE("GPL"); | 236 | MODULE_LICENSE("GPL"); |
128 | MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); | 237 | MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); |
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c new file mode 100644 index 000000000000..1717144fe7f4 --- /dev/null +++ b/drivers/mfd/omap-usb-host.c | |||
@@ -0,0 +1,1071 @@ | |||
1 | /** | ||
2 | * omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/dma-mapping.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/gpio.h> | ||
28 | #include <plat/usb.h> | ||
29 | |||
30 | #define USBHS_DRIVER_NAME "usbhs-omap" | ||
31 | #define OMAP_EHCI_DEVICE "ehci-omap" | ||
32 | #define OMAP_OHCI_DEVICE "ohci-omap3" | ||
33 | |||
34 | /* OMAP USBHOST Register addresses */ | ||
35 | |||
36 | /* TLL Register Set */ | ||
37 | #define OMAP_USBTLL_REVISION (0x00) | ||
38 | #define OMAP_USBTLL_SYSCONFIG (0x10) | ||
39 | #define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) | ||
40 | #define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) | ||
41 | #define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) | ||
42 | #define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) | ||
43 | #define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0) | ||
44 | |||
45 | #define OMAP_USBTLL_SYSSTATUS (0x14) | ||
46 | #define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0) | ||
47 | |||
48 | #define OMAP_USBTLL_IRQSTATUS (0x18) | ||
49 | #define OMAP_USBTLL_IRQENABLE (0x1C) | ||
50 | |||
51 | #define OMAP_TLL_SHARED_CONF (0x30) | ||
52 | #define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6) | ||
53 | #define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5) | ||
54 | #define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2) | ||
55 | #define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1) | ||
56 | #define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0) | ||
57 | |||
58 | #define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) | ||
59 | #define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24 | ||
60 | #define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) | ||
61 | #define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) | ||
62 | #define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) | ||
63 | #define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) | ||
64 | #define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1) | ||
65 | #define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) | ||
66 | |||
67 | #define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0 | ||
68 | #define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1 | ||
69 | #define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2 | ||
70 | #define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3 | ||
71 | #define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4 | ||
72 | #define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5 | ||
73 | #define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6 | ||
74 | #define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7 | ||
75 | #define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA | ||
76 | #define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB | ||
77 | |||
78 | #define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num) | ||
79 | #define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num) | ||
80 | #define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num) | ||
81 | #define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num) | ||
82 | #define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num) | ||
83 | #define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num) | ||
84 | #define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num) | ||
85 | #define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num) | ||
86 | #define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num) | ||
87 | |||
88 | #define OMAP_TLL_CHANNEL_COUNT 3 | ||
89 | #define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0) | ||
90 | #define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1) | ||
91 | #define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2) | ||
92 | |||
93 | /* UHH Register Set */ | ||
94 | #define OMAP_UHH_REVISION (0x00) | ||
95 | #define OMAP_UHH_SYSCONFIG (0x10) | ||
96 | #define OMAP_UHH_SYSCONFIG_MIDLEMODE (1 << 12) | ||
97 | #define OMAP_UHH_SYSCONFIG_CACTIVITY (1 << 8) | ||
98 | #define OMAP_UHH_SYSCONFIG_SIDLEMODE (1 << 3) | ||
99 | #define OMAP_UHH_SYSCONFIG_ENAWAKEUP (1 << 2) | ||
100 | #define OMAP_UHH_SYSCONFIG_SOFTRESET (1 << 1) | ||
101 | #define OMAP_UHH_SYSCONFIG_AUTOIDLE (1 << 0) | ||
102 | |||
103 | #define OMAP_UHH_SYSSTATUS (0x14) | ||
104 | #define OMAP_UHH_HOSTCONFIG (0x40) | ||
105 | #define OMAP_UHH_HOSTCONFIG_ULPI_BYPASS (1 << 0) | ||
106 | #define OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS (1 << 0) | ||
107 | #define OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS (1 << 11) | ||
108 | #define OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS (1 << 12) | ||
109 | #define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN (1 << 2) | ||
110 | #define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN (1 << 3) | ||
111 | #define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN (1 << 4) | ||
112 | #define OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN (1 << 5) | ||
113 | #define OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS (1 << 8) | ||
114 | #define OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS (1 << 9) | ||
115 | #define OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS (1 << 10) | ||
116 | #define OMAP4_UHH_HOSTCONFIG_APP_START_CLK (1 << 31) | ||
117 | |||
118 | /* OMAP4-specific defines */ | ||
119 | #define OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR (3 << 2) | ||
120 | #define OMAP4_UHH_SYSCONFIG_NOIDLE (1 << 2) | ||
121 | #define OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR (3 << 4) | ||
122 | #define OMAP4_UHH_SYSCONFIG_NOSTDBY (1 << 4) | ||
123 | #define OMAP4_UHH_SYSCONFIG_SOFTRESET (1 << 0) | ||
124 | |||
125 | #define OMAP4_P1_MODE_CLEAR (3 << 16) | ||
126 | #define OMAP4_P1_MODE_TLL (1 << 16) | ||
127 | #define OMAP4_P1_MODE_HSIC (3 << 16) | ||
128 | #define OMAP4_P2_MODE_CLEAR (3 << 18) | ||
129 | #define OMAP4_P2_MODE_TLL (1 << 18) | ||
130 | #define OMAP4_P2_MODE_HSIC (3 << 18) | ||
131 | |||
132 | #define OMAP_REV2_TLL_CHANNEL_COUNT 2 | ||
133 | |||
134 | #define OMAP_UHH_DEBUG_CSR (0x44) | ||
135 | |||
136 | /* Values of UHH_REVISION - Note: these are not given in the TRM */ | ||
137 | #define OMAP_USBHS_REV1 0x00000010 /* OMAP3 */ | ||
138 | #define OMAP_USBHS_REV2 0x50700100 /* OMAP4 */ | ||
139 | |||
140 | #define is_omap_usbhs_rev1(x) (x->usbhs_rev == OMAP_USBHS_REV1) | ||
141 | #define is_omap_usbhs_rev2(x) (x->usbhs_rev == OMAP_USBHS_REV2) | ||
142 | |||
143 | #define is_ehci_phy_mode(x) (x == OMAP_EHCI_PORT_MODE_PHY) | ||
144 | #define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL) | ||
145 | #define is_ehci_hsic_mode(x) (x == OMAP_EHCI_PORT_MODE_HSIC) | ||
146 | |||
147 | |||
148 | struct usbhs_hcd_omap { | ||
149 | struct clk *usbhost_ick; | ||
150 | struct clk *usbhost_hs_fck; | ||
151 | struct clk *usbhost_fs_fck; | ||
152 | struct clk *xclk60mhsp1_ck; | ||
153 | struct clk *xclk60mhsp2_ck; | ||
154 | struct clk *utmi_p1_fck; | ||
155 | struct clk *usbhost_p1_fck; | ||
156 | struct clk *usbtll_p1_fck; | ||
157 | struct clk *utmi_p2_fck; | ||
158 | struct clk *usbhost_p2_fck; | ||
159 | struct clk *usbtll_p2_fck; | ||
160 | struct clk *init_60m_fclk; | ||
161 | struct clk *usbtll_fck; | ||
162 | struct clk *usbtll_ick; | ||
163 | |||
164 | void __iomem *uhh_base; | ||
165 | void __iomem *tll_base; | ||
166 | |||
167 | struct usbhs_omap_platform_data platdata; | ||
168 | |||
169 | u32 usbhs_rev; | ||
170 | spinlock_t lock; | ||
171 | int count; | ||
172 | }; | ||
173 | /*-------------------------------------------------------------------------*/ | ||
174 | |||
175 | const char usbhs_driver_name[] = USBHS_DRIVER_NAME; | ||
176 | static u64 usbhs_dmamask = ~(u32)0; | ||
177 | |||
178 | /*-------------------------------------------------------------------------*/ | ||
179 | |||
180 | static inline void usbhs_write(void __iomem *base, u32 reg, u32 val) | ||
181 | { | ||
182 | __raw_writel(val, base + reg); | ||
183 | } | ||
184 | |||
185 | static inline u32 usbhs_read(void __iomem *base, u32 reg) | ||
186 | { | ||
187 | return __raw_readl(base + reg); | ||
188 | } | ||
189 | |||
190 | static inline void usbhs_writeb(void __iomem *base, u8 reg, u8 val) | ||
191 | { | ||
192 | __raw_writeb(val, base + reg); | ||
193 | } | ||
194 | |||
195 | static inline u8 usbhs_readb(void __iomem *base, u8 reg) | ||
196 | { | ||
197 | return __raw_readb(base + reg); | ||
198 | } | ||
199 | |||
200 | /*-------------------------------------------------------------------------*/ | ||
201 | |||
202 | static struct platform_device *omap_usbhs_alloc_child(const char *name, | ||
203 | struct resource *res, int num_resources, void *pdata, | ||
204 | size_t pdata_size, struct device *dev) | ||
205 | { | ||
206 | struct platform_device *child; | ||
207 | int ret; | ||
208 | |||
209 | child = platform_device_alloc(name, 0); | ||
210 | |||
211 | if (!child) { | ||
212 | dev_err(dev, "platform_device_alloc %s failed\n", name); | ||
213 | goto err_end; | ||
214 | } | ||
215 | |||
216 | ret = platform_device_add_resources(child, res, num_resources); | ||
217 | if (ret) { | ||
218 | dev_err(dev, "platform_device_add_resources failed\n"); | ||
219 | goto err_alloc; | ||
220 | } | ||
221 | |||
222 | ret = platform_device_add_data(child, pdata, pdata_size); | ||
223 | if (ret) { | ||
224 | dev_err(dev, "platform_device_add_data failed\n"); | ||
225 | goto err_alloc; | ||
226 | } | ||
227 | |||
228 | child->dev.dma_mask = &usbhs_dmamask; | ||
229 | child->dev.coherent_dma_mask = 0xffffffff; | ||
230 | child->dev.parent = dev; | ||
231 | |||
232 | ret = platform_device_add(child); | ||
233 | if (ret) { | ||
234 | dev_err(dev, "platform_device_add failed\n"); | ||
235 | goto err_alloc; | ||
236 | } | ||
237 | |||
238 | return child; | ||
239 | |||
240 | err_alloc: | ||
241 | platform_device_put(child); | ||
242 | |||
243 | err_end: | ||
244 | return NULL; | ||
245 | } | ||
246 | |||
247 | static int omap_usbhs_alloc_children(struct platform_device *pdev) | ||
248 | { | ||
249 | struct device *dev = &pdev->dev; | ||
250 | struct usbhs_hcd_omap *omap; | ||
251 | struct ehci_hcd_omap_platform_data *ehci_data; | ||
252 | struct ohci_hcd_omap_platform_data *ohci_data; | ||
253 | struct platform_device *ehci; | ||
254 | struct platform_device *ohci; | ||
255 | struct resource *res; | ||
256 | struct resource resources[2]; | ||
257 | int ret; | ||
258 | |||
259 | omap = platform_get_drvdata(pdev); | ||
260 | ehci_data = omap->platdata.ehci_data; | ||
261 | ohci_data = omap->platdata.ohci_data; | ||
262 | |||
263 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci"); | ||
264 | if (!res) { | ||
265 | dev_err(dev, "EHCI get resource IORESOURCE_MEM failed\n"); | ||
266 | ret = -ENODEV; | ||
267 | goto err_end; | ||
268 | } | ||
269 | resources[0] = *res; | ||
270 | |||
271 | res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ehci-irq"); | ||
272 | if (!res) { | ||
273 | dev_err(dev, " EHCI get resource IORESOURCE_IRQ failed\n"); | ||
274 | ret = -ENODEV; | ||
275 | goto err_end; | ||
276 | } | ||
277 | resources[1] = *res; | ||
278 | |||
279 | ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, ehci_data, | ||
280 | sizeof(*ehci_data), dev); | ||
281 | |||
282 | if (!ehci) { | ||
283 | dev_err(dev, "omap_usbhs_alloc_child failed\n"); | ||
284 | ret = -ENOMEM; | ||
285 | goto err_end; | ||
286 | } | ||
287 | |||
288 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ohci"); | ||
289 | if (!res) { | ||
290 | dev_err(dev, "OHCI get resource IORESOURCE_MEM failed\n"); | ||
291 | ret = -ENODEV; | ||
292 | goto err_ehci; | ||
293 | } | ||
294 | resources[0] = *res; | ||
295 | |||
296 | res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ohci-irq"); | ||
297 | if (!res) { | ||
298 | dev_err(dev, "OHCI get resource IORESOURCE_IRQ failed\n"); | ||
299 | ret = -ENODEV; | ||
300 | goto err_ehci; | ||
301 | } | ||
302 | resources[1] = *res; | ||
303 | |||
304 | ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, ohci_data, | ||
305 | sizeof(*ohci_data), dev); | ||
306 | if (!ohci) { | ||
307 | dev_err(dev, "omap_usbhs_alloc_child failed\n"); | ||
308 | ret = -ENOMEM; | ||
309 | goto err_ehci; | ||
310 | } | ||
311 | |||
312 | return 0; | ||
313 | |||
314 | err_ehci: | ||
315 | platform_device_unregister(ehci); | ||
316 | |||
317 | err_end: | ||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | /** | ||
322 | * usbhs_omap_probe - initialize TI-based HCDs | ||
323 | * | ||
324 | * Allocates basic resources for this USB host controller. | ||
325 | */ | ||
326 | static int __devinit usbhs_omap_probe(struct platform_device *pdev) | ||
327 | { | ||
328 | struct device *dev = &pdev->dev; | ||
329 | struct usbhs_omap_platform_data *pdata = dev->platform_data; | ||
330 | struct usbhs_hcd_omap *omap; | ||
331 | struct resource *res; | ||
332 | int ret = 0; | ||
333 | int i; | ||
334 | |||
335 | if (!pdata) { | ||
336 | dev_err(dev, "Missing platform data\n"); | ||
337 | ret = -ENOMEM; | ||
338 | goto end_probe; | ||
339 | } | ||
340 | |||
341 | omap = kzalloc(sizeof(*omap), GFP_KERNEL); | ||
342 | if (!omap) { | ||
343 | dev_err(dev, "Memory allocation failed\n"); | ||
344 | ret = -ENOMEM; | ||
345 | goto end_probe; | ||
346 | } | ||
347 | |||
348 | spin_lock_init(&omap->lock); | ||
349 | |||
350 | for (i = 0; i < OMAP3_HS_USB_PORTS; i++) | ||
351 | omap->platdata.port_mode[i] = pdata->port_mode[i]; | ||
352 | |||
353 | omap->platdata.ehci_data = pdata->ehci_data; | ||
354 | omap->platdata.ohci_data = pdata->ohci_data; | ||
355 | |||
356 | omap->usbhost_ick = clk_get(dev, "usbhost_ick"); | ||
357 | if (IS_ERR(omap->usbhost_ick)) { | ||
358 | ret = PTR_ERR(omap->usbhost_ick); | ||
359 | dev_err(dev, "usbhost_ick failed error:%d\n", ret); | ||
360 | goto err_end; | ||
361 | } | ||
362 | |||
363 | omap->usbhost_hs_fck = clk_get(dev, "hs_fck"); | ||
364 | if (IS_ERR(omap->usbhost_hs_fck)) { | ||
365 | ret = PTR_ERR(omap->usbhost_hs_fck); | ||
366 | dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret); | ||
367 | goto err_usbhost_ick; | ||
368 | } | ||
369 | |||
370 | omap->usbhost_fs_fck = clk_get(dev, "fs_fck"); | ||
371 | if (IS_ERR(omap->usbhost_fs_fck)) { | ||
372 | ret = PTR_ERR(omap->usbhost_fs_fck); | ||
373 | dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret); | ||
374 | goto err_usbhost_hs_fck; | ||
375 | } | ||
376 | |||
377 | omap->usbtll_fck = clk_get(dev, "usbtll_fck"); | ||
378 | if (IS_ERR(omap->usbtll_fck)) { | ||
379 | ret = PTR_ERR(omap->usbtll_fck); | ||
380 | dev_err(dev, "usbtll_fck failed error:%d\n", ret); | ||
381 | goto err_usbhost_fs_fck; | ||
382 | } | ||
383 | |||
384 | omap->usbtll_ick = clk_get(dev, "usbtll_ick"); | ||
385 | if (IS_ERR(omap->usbtll_ick)) { | ||
386 | ret = PTR_ERR(omap->usbtll_ick); | ||
387 | dev_err(dev, "usbtll_ick failed error:%d\n", ret); | ||
388 | goto err_usbtll_fck; | ||
389 | } | ||
390 | |||
391 | omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); | ||
392 | if (IS_ERR(omap->utmi_p1_fck)) { | ||
393 | ret = PTR_ERR(omap->utmi_p1_fck); | ||
394 | dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); | ||
395 | goto err_usbtll_ick; | ||
396 | } | ||
397 | |||
398 | omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); | ||
399 | if (IS_ERR(omap->xclk60mhsp1_ck)) { | ||
400 | ret = PTR_ERR(omap->xclk60mhsp1_ck); | ||
401 | dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret); | ||
402 | goto err_utmi_p1_fck; | ||
403 | } | ||
404 | |||
405 | omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk"); | ||
406 | if (IS_ERR(omap->utmi_p2_fck)) { | ||
407 | ret = PTR_ERR(omap->utmi_p2_fck); | ||
408 | dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret); | ||
409 | goto err_xclk60mhsp1_ck; | ||
410 | } | ||
411 | |||
412 | omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck"); | ||
413 | if (IS_ERR(omap->xclk60mhsp2_ck)) { | ||
414 | ret = PTR_ERR(omap->xclk60mhsp2_ck); | ||
415 | dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret); | ||
416 | goto err_utmi_p2_fck; | ||
417 | } | ||
418 | |||
419 | omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk"); | ||
420 | if (IS_ERR(omap->usbhost_p1_fck)) { | ||
421 | ret = PTR_ERR(omap->usbhost_p1_fck); | ||
422 | dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret); | ||
423 | goto err_xclk60mhsp2_ck; | ||
424 | } | ||
425 | |||
426 | omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); | ||
427 | if (IS_ERR(omap->usbtll_p1_fck)) { | ||
428 | ret = PTR_ERR(omap->usbtll_p1_fck); | ||
429 | dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); | ||
430 | goto err_usbhost_p1_fck; | ||
431 | } | ||
432 | |||
433 | omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk"); | ||
434 | if (IS_ERR(omap->usbhost_p2_fck)) { | ||
435 | ret = PTR_ERR(omap->usbhost_p2_fck); | ||
436 | dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret); | ||
437 | goto err_usbtll_p1_fck; | ||
438 | } | ||
439 | |||
440 | omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); | ||
441 | if (IS_ERR(omap->usbtll_p2_fck)) { | ||
442 | ret = PTR_ERR(omap->usbtll_p2_fck); | ||
443 | dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); | ||
444 | goto err_usbhost_p2_fck; | ||
445 | } | ||
446 | |||
447 | omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); | ||
448 | if (IS_ERR(omap->init_60m_fclk)) { | ||
449 | ret = PTR_ERR(omap->init_60m_fclk); | ||
450 | dev_err(dev, "init_60m_fclk failed error:%d\n", ret); | ||
451 | goto err_usbtll_p2_fck; | ||
452 | } | ||
453 | |||
454 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh"); | ||
455 | if (!res) { | ||
456 | dev_err(dev, "UHH EHCI get resource failed\n"); | ||
457 | ret = -ENODEV; | ||
458 | goto err_init_60m_fclk; | ||
459 | } | ||
460 | |||
461 | omap->uhh_base = ioremap(res->start, resource_size(res)); | ||
462 | if (!omap->uhh_base) { | ||
463 | dev_err(dev, "UHH ioremap failed\n"); | ||
464 | ret = -ENOMEM; | ||
465 | goto err_init_60m_fclk; | ||
466 | } | ||
467 | |||
468 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll"); | ||
469 | if (!res) { | ||
470 | dev_err(dev, "UHH EHCI get resource failed\n"); | ||
471 | ret = -ENODEV; | ||
472 | goto err_tll; | ||
473 | } | ||
474 | |||
475 | omap->tll_base = ioremap(res->start, resource_size(res)); | ||
476 | if (!omap->tll_base) { | ||
477 | dev_err(dev, "TLL ioremap failed\n"); | ||
478 | ret = -ENOMEM; | ||
479 | goto err_tll; | ||
480 | } | ||
481 | |||
482 | platform_set_drvdata(pdev, omap); | ||
483 | |||
484 | ret = omap_usbhs_alloc_children(pdev); | ||
485 | if (ret) { | ||
486 | dev_err(dev, "omap_usbhs_alloc_children failed\n"); | ||
487 | goto err_alloc; | ||
488 | } | ||
489 | |||
490 | goto end_probe; | ||
491 | |||
492 | err_alloc: | ||
493 | iounmap(omap->tll_base); | ||
494 | |||
495 | err_tll: | ||
496 | iounmap(omap->uhh_base); | ||
497 | |||
498 | err_init_60m_fclk: | ||
499 | clk_put(omap->init_60m_fclk); | ||
500 | |||
501 | err_usbtll_p2_fck: | ||
502 | clk_put(omap->usbtll_p2_fck); | ||
503 | |||
504 | err_usbhost_p2_fck: | ||
505 | clk_put(omap->usbhost_p2_fck); | ||
506 | |||
507 | err_usbtll_p1_fck: | ||
508 | clk_put(omap->usbtll_p1_fck); | ||
509 | |||
510 | err_usbhost_p1_fck: | ||
511 | clk_put(omap->usbhost_p1_fck); | ||
512 | |||
513 | err_xclk60mhsp2_ck: | ||
514 | clk_put(omap->xclk60mhsp2_ck); | ||
515 | |||
516 | err_utmi_p2_fck: | ||
517 | clk_put(omap->utmi_p2_fck); | ||
518 | |||
519 | err_xclk60mhsp1_ck: | ||
520 | clk_put(omap->xclk60mhsp1_ck); | ||
521 | |||
522 | err_utmi_p1_fck: | ||
523 | clk_put(omap->utmi_p1_fck); | ||
524 | |||
525 | err_usbtll_ick: | ||
526 | clk_put(omap->usbtll_ick); | ||
527 | |||
528 | err_usbtll_fck: | ||
529 | clk_put(omap->usbtll_fck); | ||
530 | |||
531 | err_usbhost_fs_fck: | ||
532 | clk_put(omap->usbhost_fs_fck); | ||
533 | |||
534 | err_usbhost_hs_fck: | ||
535 | clk_put(omap->usbhost_hs_fck); | ||
536 | |||
537 | err_usbhost_ick: | ||
538 | clk_put(omap->usbhost_ick); | ||
539 | |||
540 | err_end: | ||
541 | kfree(omap); | ||
542 | |||
543 | end_probe: | ||
544 | return ret; | ||
545 | } | ||
546 | |||
547 | /** | ||
548 | * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs | ||
549 | * @pdev: USB Host Controller being removed | ||
550 | * | ||
551 | * Reverses the effect of usbhs_omap_probe(). | ||
552 | */ | ||
553 | static int __devexit usbhs_omap_remove(struct platform_device *pdev) | ||
554 | { | ||
555 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); | ||
556 | |||
557 | if (omap->count != 0) { | ||
558 | dev_err(&pdev->dev, | ||
559 | "Either EHCI or OHCI is still using usbhs core\n"); | ||
560 | return -EBUSY; | ||
561 | } | ||
562 | |||
563 | iounmap(omap->tll_base); | ||
564 | iounmap(omap->uhh_base); | ||
565 | clk_put(omap->init_60m_fclk); | ||
566 | clk_put(omap->usbtll_p2_fck); | ||
567 | clk_put(omap->usbhost_p2_fck); | ||
568 | clk_put(omap->usbtll_p1_fck); | ||
569 | clk_put(omap->usbhost_p1_fck); | ||
570 | clk_put(omap->xclk60mhsp2_ck); | ||
571 | clk_put(omap->utmi_p2_fck); | ||
572 | clk_put(omap->xclk60mhsp1_ck); | ||
573 | clk_put(omap->utmi_p1_fck); | ||
574 | clk_put(omap->usbtll_ick); | ||
575 | clk_put(omap->usbtll_fck); | ||
576 | clk_put(omap->usbhost_fs_fck); | ||
577 | clk_put(omap->usbhost_hs_fck); | ||
578 | clk_put(omap->usbhost_ick); | ||
579 | kfree(omap); | ||
580 | |||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | static bool is_ohci_port(enum usbhs_omap_port_mode pmode) | ||
585 | { | ||
586 | switch (pmode) { | ||
587 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: | ||
588 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: | ||
589 | case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: | ||
590 | case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: | ||
591 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: | ||
592 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: | ||
593 | case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: | ||
594 | case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: | ||
595 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: | ||
596 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: | ||
597 | return true; | ||
598 | |||
599 | default: | ||
600 | return false; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | /* | ||
605 | * convert the port-mode enum to a value we can use in the FSLSMODE | ||
606 | * field of USBTLL_CHANNEL_CONF | ||
607 | */ | ||
608 | static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) | ||
609 | { | ||
610 | switch (mode) { | ||
611 | case OMAP_USBHS_PORT_MODE_UNUSED: | ||
612 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: | ||
613 | return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; | ||
614 | |||
615 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: | ||
616 | return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM; | ||
617 | |||
618 | case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: | ||
619 | return OMAP_TLL_FSLSMODE_3PIN_PHY; | ||
620 | |||
621 | case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: | ||
622 | return OMAP_TLL_FSLSMODE_4PIN_PHY; | ||
623 | |||
624 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: | ||
625 | return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0; | ||
626 | |||
627 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: | ||
628 | return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM; | ||
629 | |||
630 | case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: | ||
631 | return OMAP_TLL_FSLSMODE_3PIN_TLL; | ||
632 | |||
633 | case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: | ||
634 | return OMAP_TLL_FSLSMODE_4PIN_TLL; | ||
635 | |||
636 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: | ||
637 | return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0; | ||
638 | |||
639 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: | ||
640 | return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM; | ||
641 | default: | ||
642 | pr_warning("Invalid port mode, using default\n"); | ||
643 | return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; | ||
644 | } | ||
645 | } | ||
646 | |||
647 | static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count) | ||
648 | { | ||
649 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | ||
650 | struct usbhs_omap_platform_data *pdata = dev->platform_data; | ||
651 | unsigned reg; | ||
652 | int i; | ||
653 | |||
654 | /* Program Common TLL register */ | ||
655 | reg = usbhs_read(omap->tll_base, OMAP_TLL_SHARED_CONF); | ||
656 | reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON | ||
657 | | OMAP_TLL_SHARED_CONF_USB_DIVRATION); | ||
658 | reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; | ||
659 | reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN; | ||
660 | |||
661 | usbhs_write(omap->tll_base, OMAP_TLL_SHARED_CONF, reg); | ||
662 | |||
663 | /* Enable channels now */ | ||
664 | for (i = 0; i < tll_channel_count; i++) { | ||
665 | reg = usbhs_read(omap->tll_base, | ||
666 | OMAP_TLL_CHANNEL_CONF(i)); | ||
667 | |||
668 | if (is_ohci_port(pdata->port_mode[i])) { | ||
669 | reg |= ohci_omap3_fslsmode(pdata->port_mode[i]) | ||
670 | << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT; | ||
671 | reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS; | ||
672 | } else if (pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_TLL) { | ||
673 | |||
674 | /* Disable AutoIdle, BitStuffing and use SDR Mode */ | ||
675 | reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE | ||
676 | | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF | ||
677 | | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); | ||
678 | |||
679 | reg |= (1 << (i + 1)); | ||
680 | } else | ||
681 | continue; | ||
682 | |||
683 | reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; | ||
684 | usbhs_write(omap->tll_base, | ||
685 | OMAP_TLL_CHANNEL_CONF(i), reg); | ||
686 | |||
687 | usbhs_writeb(omap->tll_base, | ||
688 | OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 0xbe); | ||
689 | } | ||
690 | } | ||
691 | |||
692 | static int usbhs_enable(struct device *dev) | ||
693 | { | ||
694 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | ||
695 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | ||
696 | unsigned long flags = 0; | ||
697 | int ret = 0; | ||
698 | unsigned long timeout; | ||
699 | unsigned reg; | ||
700 | |||
701 | dev_dbg(dev, "starting TI HSUSB Controller\n"); | ||
702 | if (!pdata) { | ||
703 | dev_dbg(dev, "missing platform_data\n"); | ||
704 | return -ENODEV; | ||
705 | } | ||
706 | |||
707 | spin_lock_irqsave(&omap->lock, flags); | ||
708 | if (omap->count > 0) | ||
709 | goto end_count; | ||
710 | |||
711 | clk_enable(omap->usbhost_ick); | ||
712 | clk_enable(omap->usbhost_hs_fck); | ||
713 | clk_enable(omap->usbhost_fs_fck); | ||
714 | clk_enable(omap->usbtll_fck); | ||
715 | clk_enable(omap->usbtll_ick); | ||
716 | |||
717 | if (pdata->ehci_data->phy_reset) { | ||
718 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { | ||
719 | gpio_request(pdata->ehci_data->reset_gpio_port[0], | ||
720 | "USB1 PHY reset"); | ||
721 | gpio_direction_output | ||
722 | (pdata->ehci_data->reset_gpio_port[0], 0); | ||
723 | } | ||
724 | |||
725 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) { | ||
726 | gpio_request(pdata->ehci_data->reset_gpio_port[1], | ||
727 | "USB2 PHY reset"); | ||
728 | gpio_direction_output | ||
729 | (pdata->ehci_data->reset_gpio_port[1], 0); | ||
730 | } | ||
731 | |||
732 | /* Hold the PHY in RESET for enough time till DIR is high */ | ||
733 | udelay(10); | ||
734 | } | ||
735 | |||
736 | omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); | ||
737 | dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); | ||
738 | |||
739 | /* perform TLL soft reset, and wait until reset is complete */ | ||
740 | usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, | ||
741 | OMAP_USBTLL_SYSCONFIG_SOFTRESET); | ||
742 | |||
743 | /* Wait for TLL reset to complete */ | ||
744 | timeout = jiffies + msecs_to_jiffies(1000); | ||
745 | while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS) | ||
746 | & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { | ||
747 | cpu_relax(); | ||
748 | |||
749 | if (time_after(jiffies, timeout)) { | ||
750 | dev_dbg(dev, "operation timed out\n"); | ||
751 | ret = -EINVAL; | ||
752 | goto err_tll; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | dev_dbg(dev, "TLL RESET DONE\n"); | ||
757 | |||
758 | /* (1<<3) = no idle mode only for initial debugging */ | ||
759 | usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, | ||
760 | OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | | ||
761 | OMAP_USBTLL_SYSCONFIG_SIDLEMODE | | ||
762 | OMAP_USBTLL_SYSCONFIG_AUTOIDLE); | ||
763 | |||
764 | /* Put UHH in NoIdle/NoStandby mode */ | ||
765 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG); | ||
766 | if (is_omap_usbhs_rev1(omap)) { | ||
767 | reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP | ||
768 | | OMAP_UHH_SYSCONFIG_SIDLEMODE | ||
769 | | OMAP_UHH_SYSCONFIG_CACTIVITY | ||
770 | | OMAP_UHH_SYSCONFIG_MIDLEMODE); | ||
771 | reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE; | ||
772 | |||
773 | |||
774 | } else if (is_omap_usbhs_rev2(omap)) { | ||
775 | reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR; | ||
776 | reg |= OMAP4_UHH_SYSCONFIG_NOIDLE; | ||
777 | reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR; | ||
778 | reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY; | ||
779 | } | ||
780 | |||
781 | usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); | ||
782 | |||
783 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); | ||
784 | /* setup ULPI bypass and burst configurations */ | ||
785 | reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | ||
786 | | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN | ||
787 | | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN); | ||
788 | reg |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK; | ||
789 | reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; | ||
790 | |||
791 | if (is_omap_usbhs_rev1(omap)) { | ||
792 | if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED) | ||
793 | reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; | ||
794 | if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED) | ||
795 | reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; | ||
796 | if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED) | ||
797 | reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS; | ||
798 | |||
799 | /* Bypass the TLL module for PHY mode operation */ | ||
800 | if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) { | ||
801 | dev_dbg(dev, "OMAP3 ES version <= ES2.1\n"); | ||
802 | if (is_ehci_phy_mode(pdata->port_mode[0]) || | ||
803 | is_ehci_phy_mode(pdata->port_mode[1]) || | ||
804 | is_ehci_phy_mode(pdata->port_mode[2])) | ||
805 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; | ||
806 | else | ||
807 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; | ||
808 | } else { | ||
809 | dev_dbg(dev, "OMAP3 ES version > ES2.1\n"); | ||
810 | if (is_ehci_phy_mode(pdata->port_mode[0])) | ||
811 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; | ||
812 | else | ||
813 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; | ||
814 | if (is_ehci_phy_mode(pdata->port_mode[1])) | ||
815 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; | ||
816 | else | ||
817 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; | ||
818 | if (is_ehci_phy_mode(pdata->port_mode[2])) | ||
819 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; | ||
820 | else | ||
821 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; | ||
822 | } | ||
823 | } else if (is_omap_usbhs_rev2(omap)) { | ||
824 | /* Clear port mode fields for PHY mode*/ | ||
825 | reg &= ~OMAP4_P1_MODE_CLEAR; | ||
826 | reg &= ~OMAP4_P2_MODE_CLEAR; | ||
827 | |||
828 | if (is_ehci_phy_mode(pdata->port_mode[0])) { | ||
829 | ret = clk_set_parent(omap->utmi_p1_fck, | ||
830 | omap->xclk60mhsp1_ck); | ||
831 | if (ret != 0) { | ||
832 | dev_err(dev, "xclk60mhsp1_ck set parent" | ||
833 | "failed error:%d\n", ret); | ||
834 | goto err_tll; | ||
835 | } | ||
836 | } else if (is_ehci_tll_mode(pdata->port_mode[0])) { | ||
837 | ret = clk_set_parent(omap->utmi_p1_fck, | ||
838 | omap->init_60m_fclk); | ||
839 | if (ret != 0) { | ||
840 | dev_err(dev, "init_60m_fclk set parent" | ||
841 | "failed error:%d\n", ret); | ||
842 | goto err_tll; | ||
843 | } | ||
844 | clk_enable(omap->usbhost_p1_fck); | ||
845 | clk_enable(omap->usbtll_p1_fck); | ||
846 | } | ||
847 | |||
848 | if (is_ehci_phy_mode(pdata->port_mode[1])) { | ||
849 | ret = clk_set_parent(omap->utmi_p2_fck, | ||
850 | omap->xclk60mhsp2_ck); | ||
851 | if (ret != 0) { | ||
852 | dev_err(dev, "xclk60mhsp1_ck set parent" | ||
853 | "failed error:%d\n", ret); | ||
854 | goto err_tll; | ||
855 | } | ||
856 | } else if (is_ehci_tll_mode(pdata->port_mode[1])) { | ||
857 | ret = clk_set_parent(omap->utmi_p2_fck, | ||
858 | omap->init_60m_fclk); | ||
859 | if (ret != 0) { | ||
860 | dev_err(dev, "init_60m_fclk set parent" | ||
861 | "failed error:%d\n", ret); | ||
862 | goto err_tll; | ||
863 | } | ||
864 | clk_enable(omap->usbhost_p2_fck); | ||
865 | clk_enable(omap->usbtll_p2_fck); | ||
866 | } | ||
867 | |||
868 | clk_enable(omap->utmi_p1_fck); | ||
869 | clk_enable(omap->utmi_p2_fck); | ||
870 | |||
871 | if (is_ehci_tll_mode(pdata->port_mode[0]) || | ||
872 | (is_ohci_port(pdata->port_mode[0]))) | ||
873 | reg |= OMAP4_P1_MODE_TLL; | ||
874 | else if (is_ehci_hsic_mode(pdata->port_mode[0])) | ||
875 | reg |= OMAP4_P1_MODE_HSIC; | ||
876 | |||
877 | if (is_ehci_tll_mode(pdata->port_mode[1]) || | ||
878 | (is_ohci_port(pdata->port_mode[1]))) | ||
879 | reg |= OMAP4_P2_MODE_TLL; | ||
880 | else if (is_ehci_hsic_mode(pdata->port_mode[1])) | ||
881 | reg |= OMAP4_P2_MODE_HSIC; | ||
882 | } | ||
883 | |||
884 | usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); | ||
885 | dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); | ||
886 | |||
887 | if (is_ehci_tll_mode(pdata->port_mode[0]) || | ||
888 | is_ehci_tll_mode(pdata->port_mode[1]) || | ||
889 | is_ehci_tll_mode(pdata->port_mode[2]) || | ||
890 | (is_ohci_port(pdata->port_mode[0])) || | ||
891 | (is_ohci_port(pdata->port_mode[1])) || | ||
892 | (is_ohci_port(pdata->port_mode[2]))) { | ||
893 | |||
894 | /* Enable UTMI mode for required TLL channels */ | ||
895 | if (is_omap_usbhs_rev2(omap)) | ||
896 | usbhs_omap_tll_init(dev, OMAP_REV2_TLL_CHANNEL_COUNT); | ||
897 | else | ||
898 | usbhs_omap_tll_init(dev, OMAP_TLL_CHANNEL_COUNT); | ||
899 | } | ||
900 | |||
901 | if (pdata->ehci_data->phy_reset) { | ||
902 | /* Hold the PHY in RESET for enough time till | ||
903 | * PHY is settled and ready | ||
904 | */ | ||
905 | udelay(10); | ||
906 | |||
907 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | ||
908 | gpio_set_value | ||
909 | (pdata->ehci_data->reset_gpio_port[0], 1); | ||
910 | |||
911 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) | ||
912 | gpio_set_value | ||
913 | (pdata->ehci_data->reset_gpio_port[1], 1); | ||
914 | } | ||
915 | |||
916 | end_count: | ||
917 | omap->count++; | ||
918 | spin_unlock_irqrestore(&omap->lock, flags); | ||
919 | return 0; | ||
920 | |||
921 | err_tll: | ||
922 | if (pdata->ehci_data->phy_reset) { | ||
923 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | ||
924 | gpio_free(pdata->ehci_data->reset_gpio_port[0]); | ||
925 | |||
926 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) | ||
927 | gpio_free(pdata->ehci_data->reset_gpio_port[1]); | ||
928 | } | ||
929 | |||
930 | clk_disable(omap->usbtll_ick); | ||
931 | clk_disable(omap->usbtll_fck); | ||
932 | clk_disable(omap->usbhost_fs_fck); | ||
933 | clk_disable(omap->usbhost_hs_fck); | ||
934 | clk_disable(omap->usbhost_ick); | ||
935 | spin_unlock_irqrestore(&omap->lock, flags); | ||
936 | return ret; | ||
937 | } | ||
938 | |||
939 | static void usbhs_disable(struct device *dev) | ||
940 | { | ||
941 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | ||
942 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | ||
943 | unsigned long flags = 0; | ||
944 | unsigned long timeout; | ||
945 | |||
946 | dev_dbg(dev, "stopping TI HSUSB Controller\n"); | ||
947 | |||
948 | spin_lock_irqsave(&omap->lock, flags); | ||
949 | |||
950 | if (omap->count == 0) | ||
951 | goto end_disble; | ||
952 | |||
953 | omap->count--; | ||
954 | |||
955 | if (omap->count != 0) | ||
956 | goto end_disble; | ||
957 | |||
958 | /* Reset OMAP modules for insmod/rmmod to work */ | ||
959 | usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, | ||
960 | is_omap_usbhs_rev2(omap) ? | ||
961 | OMAP4_UHH_SYSCONFIG_SOFTRESET : | ||
962 | OMAP_UHH_SYSCONFIG_SOFTRESET); | ||
963 | |||
964 | timeout = jiffies + msecs_to_jiffies(100); | ||
965 | while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) | ||
966 | & (1 << 0))) { | ||
967 | cpu_relax(); | ||
968 | |||
969 | if (time_after(jiffies, timeout)) | ||
970 | dev_dbg(dev, "operation timed out\n"); | ||
971 | } | ||
972 | |||
973 | while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) | ||
974 | & (1 << 1))) { | ||
975 | cpu_relax(); | ||
976 | |||
977 | if (time_after(jiffies, timeout)) | ||
978 | dev_dbg(dev, "operation timed out\n"); | ||
979 | } | ||
980 | |||
981 | while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) | ||
982 | & (1 << 2))) { | ||
983 | cpu_relax(); | ||
984 | |||
985 | if (time_after(jiffies, timeout)) | ||
986 | dev_dbg(dev, "operation timed out\n"); | ||
987 | } | ||
988 | |||
989 | usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1)); | ||
990 | |||
991 | while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS) | ||
992 | & (1 << 0))) { | ||
993 | cpu_relax(); | ||
994 | |||
995 | if (time_after(jiffies, timeout)) | ||
996 | dev_dbg(dev, "operation timed out\n"); | ||
997 | } | ||
998 | |||
999 | if (is_omap_usbhs_rev2(omap)) { | ||
1000 | if (is_ehci_tll_mode(pdata->port_mode[0])) | ||
1001 | clk_enable(omap->usbtll_p1_fck); | ||
1002 | if (is_ehci_tll_mode(pdata->port_mode[1])) | ||
1003 | clk_enable(omap->usbtll_p2_fck); | ||
1004 | clk_disable(omap->utmi_p2_fck); | ||
1005 | clk_disable(omap->utmi_p1_fck); | ||
1006 | } | ||
1007 | |||
1008 | clk_disable(omap->usbtll_ick); | ||
1009 | clk_disable(omap->usbtll_fck); | ||
1010 | clk_disable(omap->usbhost_fs_fck); | ||
1011 | clk_disable(omap->usbhost_hs_fck); | ||
1012 | clk_disable(omap->usbhost_ick); | ||
1013 | |||
1014 | /* The gpio_free migh sleep; so unlock the spinlock */ | ||
1015 | spin_unlock_irqrestore(&omap->lock, flags); | ||
1016 | |||
1017 | if (pdata->ehci_data->phy_reset) { | ||
1018 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | ||
1019 | gpio_free(pdata->ehci_data->reset_gpio_port[0]); | ||
1020 | |||
1021 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) | ||
1022 | gpio_free(pdata->ehci_data->reset_gpio_port[1]); | ||
1023 | } | ||
1024 | return; | ||
1025 | |||
1026 | end_disble: | ||
1027 | spin_unlock_irqrestore(&omap->lock, flags); | ||
1028 | } | ||
1029 | |||
1030 | int omap_usbhs_enable(struct device *dev) | ||
1031 | { | ||
1032 | return usbhs_enable(dev->parent); | ||
1033 | } | ||
1034 | EXPORT_SYMBOL_GPL(omap_usbhs_enable); | ||
1035 | |||
1036 | void omap_usbhs_disable(struct device *dev) | ||
1037 | { | ||
1038 | usbhs_disable(dev->parent); | ||
1039 | } | ||
1040 | EXPORT_SYMBOL_GPL(omap_usbhs_disable); | ||
1041 | |||
1042 | static struct platform_driver usbhs_omap_driver = { | ||
1043 | .driver = { | ||
1044 | .name = (char *)usbhs_driver_name, | ||
1045 | .owner = THIS_MODULE, | ||
1046 | }, | ||
1047 | .remove = __exit_p(usbhs_omap_remove), | ||
1048 | }; | ||
1049 | |||
1050 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); | ||
1051 | MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); | ||
1052 | MODULE_LICENSE("GPL v2"); | ||
1053 | MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI"); | ||
1054 | |||
1055 | static int __init omap_usbhs_drvinit(void) | ||
1056 | { | ||
1057 | return platform_driver_probe(&usbhs_omap_driver, usbhs_omap_probe); | ||
1058 | } | ||
1059 | |||
1060 | /* | ||
1061 | * init before ehci and ohci drivers; | ||
1062 | * The usbhs core driver should be initialized much before | ||
1063 | * the omap ehci and ohci probe functions are called. | ||
1064 | */ | ||
1065 | fs_initcall(omap_usbhs_drvinit); | ||
1066 | |||
1067 | static void __exit omap_usbhs_drvexit(void) | ||
1068 | { | ||
1069 | platform_driver_unregister(&usbhs_omap_driver); | ||
1070 | } | ||
1071 | module_exit(omap_usbhs_drvexit); | ||
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 23e585527285..57868416c760 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c | |||
@@ -21,17 +21,11 @@ | |||
21 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
24 | #include <linux/pm.h> | ||
24 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
25 | 26 | ||
26 | #include <linux/mfd/pcf50633/core.h> | 27 | #include <linux/mfd/pcf50633/core.h> |
27 | 28 | ||
28 | int pcf50633_irq_init(struct pcf50633 *pcf, int irq); | ||
29 | void pcf50633_irq_free(struct pcf50633 *pcf); | ||
30 | #ifdef CONFIG_PM | ||
31 | int pcf50633_irq_suspend(struct pcf50633 *pcf); | ||
32 | int pcf50633_irq_resume(struct pcf50633 *pcf); | ||
33 | #endif | ||
34 | |||
35 | static int __pcf50633_read(struct pcf50633 *pcf, u8 reg, int num, u8 *data) | 29 | static int __pcf50633_read(struct pcf50633 *pcf, u8 reg, int num, u8 *data) |
36 | { | 30 | { |
37 | int ret; | 31 | int ret; |
@@ -57,7 +51,7 @@ static int __pcf50633_write(struct pcf50633 *pcf, u8 reg, int num, u8 *data) | |||
57 | 51 | ||
58 | } | 52 | } |
59 | 53 | ||
60 | /* Read a block of upto 32 regs */ | 54 | /* Read a block of up to 32 regs */ |
61 | int pcf50633_read_block(struct pcf50633 *pcf, u8 reg, | 55 | int pcf50633_read_block(struct pcf50633 *pcf, u8 reg, |
62 | int nr_regs, u8 *data) | 56 | int nr_regs, u8 *data) |
63 | { | 57 | { |
@@ -71,7 +65,7 @@ int pcf50633_read_block(struct pcf50633 *pcf, u8 reg, | |||
71 | } | 65 | } |
72 | EXPORT_SYMBOL_GPL(pcf50633_read_block); | 66 | EXPORT_SYMBOL_GPL(pcf50633_read_block); |
73 | 67 | ||
74 | /* Write a block of upto 32 regs */ | 68 | /* Write a block of up to 32 regs */ |
75 | int pcf50633_write_block(struct pcf50633 *pcf , u8 reg, | 69 | int pcf50633_write_block(struct pcf50633 *pcf , u8 reg, |
76 | int nr_regs, u8 *data) | 70 | int nr_regs, u8 *data) |
77 | { | 71 | { |
@@ -237,27 +231,26 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, | |||
237 | } | 231 | } |
238 | } | 232 | } |
239 | 233 | ||
240 | #ifdef CONFIG_PM | 234 | #ifdef CONFIG_PM_SLEEP |
241 | static int pcf50633_suspend(struct i2c_client *client, pm_message_t state) | 235 | static int pcf50633_suspend(struct device *dev) |
242 | { | 236 | { |
243 | struct pcf50633 *pcf; | 237 | struct i2c_client *client = to_i2c_client(dev); |
244 | pcf = i2c_get_clientdata(client); | 238 | struct pcf50633 *pcf = i2c_get_clientdata(client); |
245 | 239 | ||
246 | return pcf50633_irq_suspend(pcf); | 240 | return pcf50633_irq_suspend(pcf); |
247 | } | 241 | } |
248 | 242 | ||
249 | static int pcf50633_resume(struct i2c_client *client) | 243 | static int pcf50633_resume(struct device *dev) |
250 | { | 244 | { |
251 | struct pcf50633 *pcf; | 245 | struct i2c_client *client = to_i2c_client(dev); |
252 | pcf = i2c_get_clientdata(client); | 246 | struct pcf50633 *pcf = i2c_get_clientdata(client); |
253 | 247 | ||
254 | return pcf50633_irq_resume(pcf); | 248 | return pcf50633_irq_resume(pcf); |
255 | } | 249 | } |
256 | #else | ||
257 | #define pcf50633_suspend NULL | ||
258 | #define pcf50633_resume NULL | ||
259 | #endif | 250 | #endif |
260 | 251 | ||
252 | static SIMPLE_DEV_PM_OPS(pcf50633_pm, pcf50633_suspend, pcf50633_resume); | ||
253 | |||
261 | static int __devinit pcf50633_probe(struct i2c_client *client, | 254 | static int __devinit pcf50633_probe(struct i2c_client *client, |
262 | const struct i2c_device_id *ids) | 255 | const struct i2c_device_id *ids) |
263 | { | 256 | { |
@@ -346,12 +339,14 @@ static int __devexit pcf50633_remove(struct i2c_client *client) | |||
346 | struct pcf50633 *pcf = i2c_get_clientdata(client); | 339 | struct pcf50633 *pcf = i2c_get_clientdata(client); |
347 | int i; | 340 | int i; |
348 | 341 | ||
342 | sysfs_remove_group(&client->dev.kobj, &pcf_attr_group); | ||
349 | pcf50633_irq_free(pcf); | 343 | pcf50633_irq_free(pcf); |
350 | 344 | ||
351 | platform_device_unregister(pcf->input_pdev); | 345 | platform_device_unregister(pcf->input_pdev); |
352 | platform_device_unregister(pcf->rtc_pdev); | 346 | platform_device_unregister(pcf->rtc_pdev); |
353 | platform_device_unregister(pcf->mbc_pdev); | 347 | platform_device_unregister(pcf->mbc_pdev); |
354 | platform_device_unregister(pcf->adc_pdev); | 348 | platform_device_unregister(pcf->adc_pdev); |
349 | platform_device_unregister(pcf->bl_pdev); | ||
355 | 350 | ||
356 | for (i = 0; i < PCF50633_NUM_REGULATORS; i++) | 351 | for (i = 0; i < PCF50633_NUM_REGULATORS; i++) |
357 | platform_device_unregister(pcf->regulator_pdev[i]); | 352 | platform_device_unregister(pcf->regulator_pdev[i]); |
@@ -361,20 +356,20 @@ static int __devexit pcf50633_remove(struct i2c_client *client) | |||
361 | return 0; | 356 | return 0; |
362 | } | 357 | } |
363 | 358 | ||
364 | static struct i2c_device_id pcf50633_id_table[] = { | 359 | static const struct i2c_device_id pcf50633_id_table[] = { |
365 | {"pcf50633", 0x73}, | 360 | {"pcf50633", 0x73}, |
366 | {/* end of list */} | 361 | {/* end of list */} |
367 | }; | 362 | }; |
363 | MODULE_DEVICE_TABLE(i2c, pcf50633_id_table); | ||
368 | 364 | ||
369 | static struct i2c_driver pcf50633_driver = { | 365 | static struct i2c_driver pcf50633_driver = { |
370 | .driver = { | 366 | .driver = { |
371 | .name = "pcf50633", | 367 | .name = "pcf50633", |
368 | .pm = &pcf50633_pm, | ||
372 | }, | 369 | }, |
373 | .id_table = pcf50633_id_table, | 370 | .id_table = pcf50633_id_table, |
374 | .probe = pcf50633_probe, | 371 | .probe = pcf50633_probe, |
375 | .remove = __devexit_p(pcf50633_remove), | 372 | .remove = __devexit_p(pcf50633_remove), |
376 | .suspend = pcf50633_suspend, | ||
377 | .resume = pcf50633_resume, | ||
378 | }; | 373 | }; |
379 | 374 | ||
380 | static int __init pcf50633_init(void) | 375 | static int __init pcf50633_init(void) |
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c new file mode 100644 index 000000000000..e873b15753d8 --- /dev/null +++ b/drivers/mfd/pm8921-core.c | |||
@@ -0,0 +1,212 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011, Code Aurora Forum. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 and | ||
6 | * only version 2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #define pr_fmt(fmt) "%s: " fmt, __func__ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/msm_ssbi.h> | ||
21 | #include <linux/mfd/core.h> | ||
22 | #include <linux/mfd/pm8xxx/pm8921.h> | ||
23 | #include <linux/mfd/pm8xxx/core.h> | ||
24 | |||
25 | #define REG_HWREV 0x002 /* PMIC4 revision */ | ||
26 | #define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */ | ||
27 | |||
28 | struct pm8921 { | ||
29 | struct device *dev; | ||
30 | struct pm_irq_chip *irq_chip; | ||
31 | }; | ||
32 | |||
33 | static int pm8921_readb(const struct device *dev, u16 addr, u8 *val) | ||
34 | { | ||
35 | const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); | ||
36 | const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; | ||
37 | |||
38 | return msm_ssbi_read(pmic->dev->parent, addr, val, 1); | ||
39 | } | ||
40 | |||
41 | static int pm8921_writeb(const struct device *dev, u16 addr, u8 val) | ||
42 | { | ||
43 | const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); | ||
44 | const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; | ||
45 | |||
46 | return msm_ssbi_write(pmic->dev->parent, addr, &val, 1); | ||
47 | } | ||
48 | |||
49 | static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf, | ||
50 | int cnt) | ||
51 | { | ||
52 | const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); | ||
53 | const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; | ||
54 | |||
55 | return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt); | ||
56 | } | ||
57 | |||
58 | static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf, | ||
59 | int cnt) | ||
60 | { | ||
61 | const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); | ||
62 | const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; | ||
63 | |||
64 | return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt); | ||
65 | } | ||
66 | |||
67 | static int pm8921_read_irq_stat(const struct device *dev, int irq) | ||
68 | { | ||
69 | const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); | ||
70 | const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; | ||
71 | |||
72 | return pm8xxx_get_irq_stat(pmic->irq_chip, irq); | ||
73 | } | ||
74 | |||
75 | static struct pm8xxx_drvdata pm8921_drvdata = { | ||
76 | .pmic_readb = pm8921_readb, | ||
77 | .pmic_writeb = pm8921_writeb, | ||
78 | .pmic_read_buf = pm8921_read_buf, | ||
79 | .pmic_write_buf = pm8921_write_buf, | ||
80 | .pmic_read_irq_stat = pm8921_read_irq_stat, | ||
81 | }; | ||
82 | |||
83 | static int __devinit pm8921_add_subdevices(const struct pm8921_platform_data | ||
84 | *pdata, | ||
85 | struct pm8921 *pmic, | ||
86 | u32 rev) | ||
87 | { | ||
88 | int ret = 0, irq_base = 0; | ||
89 | struct pm_irq_chip *irq_chip; | ||
90 | |||
91 | if (pdata->irq_pdata) { | ||
92 | pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS; | ||
93 | pdata->irq_pdata->irq_cdata.rev = rev; | ||
94 | irq_base = pdata->irq_pdata->irq_base; | ||
95 | irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata); | ||
96 | |||
97 | if (IS_ERR(irq_chip)) { | ||
98 | pr_err("Failed to init interrupts ret=%ld\n", | ||
99 | PTR_ERR(irq_chip)); | ||
100 | return PTR_ERR(irq_chip); | ||
101 | } | ||
102 | pmic->irq_chip = irq_chip; | ||
103 | } | ||
104 | return ret; | ||
105 | } | ||
106 | |||
107 | static int __devinit pm8921_probe(struct platform_device *pdev) | ||
108 | { | ||
109 | const struct pm8921_platform_data *pdata = pdev->dev.platform_data; | ||
110 | struct pm8921 *pmic; | ||
111 | int rc; | ||
112 | u8 val; | ||
113 | u32 rev; | ||
114 | |||
115 | if (!pdata) { | ||
116 | pr_err("missing platform data\n"); | ||
117 | return -EINVAL; | ||
118 | } | ||
119 | |||
120 | pmic = kzalloc(sizeof(struct pm8921), GFP_KERNEL); | ||
121 | if (!pmic) { | ||
122 | pr_err("Cannot alloc pm8921 struct\n"); | ||
123 | return -ENOMEM; | ||
124 | } | ||
125 | |||
126 | /* Read PMIC chip revision */ | ||
127 | rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val)); | ||
128 | if (rc) { | ||
129 | pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc); | ||
130 | goto err_read_rev; | ||
131 | } | ||
132 | pr_info("PMIC revision 1: %02X\n", val); | ||
133 | rev = val; | ||
134 | |||
135 | /* Read PMIC chip revision 2 */ | ||
136 | rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val)); | ||
137 | if (rc) { | ||
138 | pr_err("Failed to read hw rev 2 reg %d:rc=%d\n", | ||
139 | REG_HWREV_2, rc); | ||
140 | goto err_read_rev; | ||
141 | } | ||
142 | pr_info("PMIC revision 2: %02X\n", val); | ||
143 | rev |= val << BITS_PER_BYTE; | ||
144 | |||
145 | pmic->dev = &pdev->dev; | ||
146 | pm8921_drvdata.pm_chip_data = pmic; | ||
147 | platform_set_drvdata(pdev, &pm8921_drvdata); | ||
148 | |||
149 | rc = pm8921_add_subdevices(pdata, pmic, rev); | ||
150 | if (rc) { | ||
151 | pr_err("Cannot add subdevices rc=%d\n", rc); | ||
152 | goto err; | ||
153 | } | ||
154 | |||
155 | /* gpio might not work if no irq device is found */ | ||
156 | WARN_ON(pmic->irq_chip == NULL); | ||
157 | |||
158 | return 0; | ||
159 | |||
160 | err: | ||
161 | mfd_remove_devices(pmic->dev); | ||
162 | platform_set_drvdata(pdev, NULL); | ||
163 | err_read_rev: | ||
164 | kfree(pmic); | ||
165 | return rc; | ||
166 | } | ||
167 | |||
168 | static int __devexit pm8921_remove(struct platform_device *pdev) | ||
169 | { | ||
170 | struct pm8xxx_drvdata *drvdata; | ||
171 | struct pm8921 *pmic = NULL; | ||
172 | |||
173 | drvdata = platform_get_drvdata(pdev); | ||
174 | if (drvdata) | ||
175 | pmic = drvdata->pm_chip_data; | ||
176 | if (pmic) | ||
177 | mfd_remove_devices(pmic->dev); | ||
178 | if (pmic->irq_chip) { | ||
179 | pm8xxx_irq_exit(pmic->irq_chip); | ||
180 | pmic->irq_chip = NULL; | ||
181 | } | ||
182 | platform_set_drvdata(pdev, NULL); | ||
183 | kfree(pmic); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static struct platform_driver pm8921_driver = { | ||
189 | .probe = pm8921_probe, | ||
190 | .remove = __devexit_p(pm8921_remove), | ||
191 | .driver = { | ||
192 | .name = "pm8921-core", | ||
193 | .owner = THIS_MODULE, | ||
194 | }, | ||
195 | }; | ||
196 | |||
197 | static int __init pm8921_init(void) | ||
198 | { | ||
199 | return platform_driver_register(&pm8921_driver); | ||
200 | } | ||
201 | subsys_initcall(pm8921_init); | ||
202 | |||
203 | static void __exit pm8921_exit(void) | ||
204 | { | ||
205 | platform_driver_unregister(&pm8921_driver); | ||
206 | } | ||
207 | module_exit(pm8921_exit); | ||
208 | |||
209 | MODULE_LICENSE("GPL v2"); | ||
210 | MODULE_DESCRIPTION("PMIC 8921 core driver"); | ||
211 | MODULE_VERSION("1.0"); | ||
212 | MODULE_ALIAS("platform:pm8921-core"); | ||
diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c new file mode 100644 index 000000000000..d452dd013081 --- /dev/null +++ b/drivers/mfd/pm8xxx-irq.c | |||
@@ -0,0 +1,371 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011, Code Aurora Forum. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 and | ||
6 | * only version 2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #define pr_fmt(fmt) "%s: " fmt, __func__ | ||
15 | |||
16 | #include <linux/err.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/irq.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/mfd/pm8xxx/core.h> | ||
21 | #include <linux/mfd/pm8xxx/irq.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | /* PMIC8xxx IRQ */ | ||
26 | |||
27 | #define SSBI_REG_ADDR_IRQ_BASE 0x1BB | ||
28 | |||
29 | #define SSBI_REG_ADDR_IRQ_ROOT (SSBI_REG_ADDR_IRQ_BASE + 0) | ||
30 | #define SSBI_REG_ADDR_IRQ_M_STATUS1 (SSBI_REG_ADDR_IRQ_BASE + 1) | ||
31 | #define SSBI_REG_ADDR_IRQ_M_STATUS2 (SSBI_REG_ADDR_IRQ_BASE + 2) | ||
32 | #define SSBI_REG_ADDR_IRQ_M_STATUS3 (SSBI_REG_ADDR_IRQ_BASE + 3) | ||
33 | #define SSBI_REG_ADDR_IRQ_M_STATUS4 (SSBI_REG_ADDR_IRQ_BASE + 4) | ||
34 | #define SSBI_REG_ADDR_IRQ_BLK_SEL (SSBI_REG_ADDR_IRQ_BASE + 5) | ||
35 | #define SSBI_REG_ADDR_IRQ_IT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 6) | ||
36 | #define SSBI_REG_ADDR_IRQ_CONFIG (SSBI_REG_ADDR_IRQ_BASE + 7) | ||
37 | #define SSBI_REG_ADDR_IRQ_RT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 8) | ||
38 | |||
39 | #define PM_IRQF_LVL_SEL 0x01 /* level select */ | ||
40 | #define PM_IRQF_MASK_FE 0x02 /* mask falling edge */ | ||
41 | #define PM_IRQF_MASK_RE 0x04 /* mask rising edge */ | ||
42 | #define PM_IRQF_CLR 0x08 /* clear interrupt */ | ||
43 | #define PM_IRQF_BITS_MASK 0x70 | ||
44 | #define PM_IRQF_BITS_SHIFT 4 | ||
45 | #define PM_IRQF_WRITE 0x80 | ||
46 | |||
47 | #define PM_IRQF_MASK_ALL (PM_IRQF_MASK_FE | \ | ||
48 | PM_IRQF_MASK_RE) | ||
49 | |||
50 | struct pm_irq_chip { | ||
51 | struct device *dev; | ||
52 | spinlock_t pm_irq_lock; | ||
53 | unsigned int devirq; | ||
54 | unsigned int irq_base; | ||
55 | unsigned int num_irqs; | ||
56 | unsigned int num_blocks; | ||
57 | unsigned int num_masters; | ||
58 | u8 config[0]; | ||
59 | }; | ||
60 | |||
61 | static int pm8xxx_read_root_irq(const struct pm_irq_chip *chip, u8 *rp) | ||
62 | { | ||
63 | return pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_ROOT, rp); | ||
64 | } | ||
65 | |||
66 | static int pm8xxx_read_master_irq(const struct pm_irq_chip *chip, u8 m, u8 *bp) | ||
67 | { | ||
68 | return pm8xxx_readb(chip->dev, | ||
69 | SSBI_REG_ADDR_IRQ_M_STATUS1 + m, bp); | ||
70 | } | ||
71 | |||
72 | static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, u8 bp, u8 *ip) | ||
73 | { | ||
74 | int rc; | ||
75 | |||
76 | spin_lock(&chip->pm_irq_lock); | ||
77 | rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp); | ||
78 | if (rc) { | ||
79 | pr_err("Failed Selecting Block %d rc=%d\n", bp, rc); | ||
80 | goto bail; | ||
81 | } | ||
82 | |||
83 | rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip); | ||
84 | if (rc) | ||
85 | pr_err("Failed Reading Status rc=%d\n", rc); | ||
86 | bail: | ||
87 | spin_unlock(&chip->pm_irq_lock); | ||
88 | return rc; | ||
89 | } | ||
90 | |||
91 | static int pm8xxx_config_irq(struct pm_irq_chip *chip, u8 bp, u8 cp) | ||
92 | { | ||
93 | int rc; | ||
94 | |||
95 | spin_lock(&chip->pm_irq_lock); | ||
96 | rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp); | ||
97 | if (rc) { | ||
98 | pr_err("Failed Selecting Block %d rc=%d\n", bp, rc); | ||
99 | goto bail; | ||
100 | } | ||
101 | |||
102 | cp |= PM_IRQF_WRITE; | ||
103 | rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp); | ||
104 | if (rc) | ||
105 | pr_err("Failed Configuring IRQ rc=%d\n", rc); | ||
106 | bail: | ||
107 | spin_unlock(&chip->pm_irq_lock); | ||
108 | return rc; | ||
109 | } | ||
110 | |||
111 | static int pm8xxx_irq_block_handler(struct pm_irq_chip *chip, int block) | ||
112 | { | ||
113 | int pmirq, irq, i, ret = 0; | ||
114 | u8 bits; | ||
115 | |||
116 | ret = pm8xxx_read_block_irq(chip, block, &bits); | ||
117 | if (ret) { | ||
118 | pr_err("Failed reading %d block ret=%d", block, ret); | ||
119 | return ret; | ||
120 | } | ||
121 | if (!bits) { | ||
122 | pr_err("block bit set in master but no irqs: %d", block); | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | /* Check IRQ bits */ | ||
127 | for (i = 0; i < 8; i++) { | ||
128 | if (bits & (1 << i)) { | ||
129 | pmirq = block * 8 + i; | ||
130 | irq = pmirq + chip->irq_base; | ||
131 | generic_handle_irq(irq); | ||
132 | } | ||
133 | } | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int pm8xxx_irq_master_handler(struct pm_irq_chip *chip, int master) | ||
138 | { | ||
139 | u8 blockbits; | ||
140 | int block_number, i, ret = 0; | ||
141 | |||
142 | ret = pm8xxx_read_master_irq(chip, master, &blockbits); | ||
143 | if (ret) { | ||
144 | pr_err("Failed to read master %d ret=%d\n", master, ret); | ||
145 | return ret; | ||
146 | } | ||
147 | if (!blockbits) { | ||
148 | pr_err("master bit set in root but no blocks: %d", master); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | for (i = 0; i < 8; i++) | ||
153 | if (blockbits & (1 << i)) { | ||
154 | block_number = master * 8 + i; /* block # */ | ||
155 | ret |= pm8xxx_irq_block_handler(chip, block_number); | ||
156 | } | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | static void pm8xxx_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
161 | { | ||
162 | struct pm_irq_chip *chip = irq_desc_get_handler_data(desc); | ||
163 | struct irq_chip *irq_chip = irq_desc_get_chip(desc); | ||
164 | u8 root; | ||
165 | int i, ret, masters = 0; | ||
166 | |||
167 | ret = pm8xxx_read_root_irq(chip, &root); | ||
168 | if (ret) { | ||
169 | pr_err("Can't read root status ret=%d\n", ret); | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | /* on pm8xxx series masters start from bit 1 of the root */ | ||
174 | masters = root >> 1; | ||
175 | |||
176 | /* Read allowed masters for blocks. */ | ||
177 | for (i = 0; i < chip->num_masters; i++) | ||
178 | if (masters & (1 << i)) | ||
179 | pm8xxx_irq_master_handler(chip, i); | ||
180 | |||
181 | irq_chip->irq_ack(&desc->irq_data); | ||
182 | } | ||
183 | |||
184 | static void pm8xxx_irq_mask_ack(struct irq_data *d) | ||
185 | { | ||
186 | struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); | ||
187 | unsigned int pmirq = d->irq - chip->irq_base; | ||
188 | int master, irq_bit; | ||
189 | u8 block, config; | ||
190 | |||
191 | block = pmirq / 8; | ||
192 | master = block / 8; | ||
193 | irq_bit = pmirq % 8; | ||
194 | |||
195 | config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR; | ||
196 | pm8xxx_config_irq(chip, block, config); | ||
197 | } | ||
198 | |||
199 | static void pm8xxx_irq_unmask(struct irq_data *d) | ||
200 | { | ||
201 | struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); | ||
202 | unsigned int pmirq = d->irq - chip->irq_base; | ||
203 | int master, irq_bit; | ||
204 | u8 block, config; | ||
205 | |||
206 | block = pmirq / 8; | ||
207 | master = block / 8; | ||
208 | irq_bit = pmirq % 8; | ||
209 | |||
210 | config = chip->config[pmirq]; | ||
211 | pm8xxx_config_irq(chip, block, config); | ||
212 | } | ||
213 | |||
214 | static int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) | ||
215 | { | ||
216 | struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); | ||
217 | unsigned int pmirq = d->irq - chip->irq_base; | ||
218 | int master, irq_bit; | ||
219 | u8 block, config; | ||
220 | |||
221 | block = pmirq / 8; | ||
222 | master = block / 8; | ||
223 | irq_bit = pmirq % 8; | ||
224 | |||
225 | chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT) | ||
226 | | PM_IRQF_MASK_ALL; | ||
227 | if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { | ||
228 | if (flow_type & IRQF_TRIGGER_RISING) | ||
229 | chip->config[pmirq] &= ~PM_IRQF_MASK_RE; | ||
230 | if (flow_type & IRQF_TRIGGER_FALLING) | ||
231 | chip->config[pmirq] &= ~PM_IRQF_MASK_FE; | ||
232 | } else { | ||
233 | chip->config[pmirq] |= PM_IRQF_LVL_SEL; | ||
234 | |||
235 | if (flow_type & IRQF_TRIGGER_HIGH) | ||
236 | chip->config[pmirq] &= ~PM_IRQF_MASK_RE; | ||
237 | else | ||
238 | chip->config[pmirq] &= ~PM_IRQF_MASK_FE; | ||
239 | } | ||
240 | |||
241 | config = chip->config[pmirq] | PM_IRQF_CLR; | ||
242 | return pm8xxx_config_irq(chip, block, config); | ||
243 | } | ||
244 | |||
245 | static int pm8xxx_irq_set_wake(struct irq_data *d, unsigned int on) | ||
246 | { | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static struct irq_chip pm8xxx_irq_chip = { | ||
251 | .name = "pm8xxx", | ||
252 | .irq_mask_ack = pm8xxx_irq_mask_ack, | ||
253 | .irq_unmask = pm8xxx_irq_unmask, | ||
254 | .irq_set_type = pm8xxx_irq_set_type, | ||
255 | .irq_set_wake = pm8xxx_irq_set_wake, | ||
256 | .flags = IRQCHIP_MASK_ON_SUSPEND, | ||
257 | }; | ||
258 | |||
259 | /** | ||
260 | * pm8xxx_get_irq_stat - get the status of the irq line | ||
261 | * @chip: pointer to identify a pmic irq controller | ||
262 | * @irq: the irq number | ||
263 | * | ||
264 | * The pm8xxx gpio and mpp rely on the interrupt block to read | ||
265 | * the values on their pins. This function is to facilitate reading | ||
266 | * the status of a gpio or an mpp line. The caller has to convert the | ||
267 | * gpio number to irq number. | ||
268 | * | ||
269 | * RETURNS: | ||
270 | * an int indicating the value read on that line | ||
271 | */ | ||
272 | int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq) | ||
273 | { | ||
274 | int pmirq, rc; | ||
275 | u8 block, bits, bit; | ||
276 | unsigned long flags; | ||
277 | |||
278 | if (chip == NULL || irq < chip->irq_base || | ||
279 | irq >= chip->irq_base + chip->num_irqs) | ||
280 | return -EINVAL; | ||
281 | |||
282 | pmirq = irq - chip->irq_base; | ||
283 | |||
284 | block = pmirq / 8; | ||
285 | bit = pmirq % 8; | ||
286 | |||
287 | spin_lock_irqsave(&chip->pm_irq_lock, flags); | ||
288 | |||
289 | rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, block); | ||
290 | if (rc) { | ||
291 | pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n", | ||
292 | irq, pmirq, block, rc); | ||
293 | goto bail_out; | ||
294 | } | ||
295 | |||
296 | rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits); | ||
297 | if (rc) { | ||
298 | pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n", | ||
299 | irq, pmirq, block, rc); | ||
300 | goto bail_out; | ||
301 | } | ||
302 | |||
303 | rc = (bits & (1 << bit)) ? 1 : 0; | ||
304 | |||
305 | bail_out: | ||
306 | spin_unlock_irqrestore(&chip->pm_irq_lock, flags); | ||
307 | |||
308 | return rc; | ||
309 | } | ||
310 | EXPORT_SYMBOL_GPL(pm8xxx_get_irq_stat); | ||
311 | |||
312 | struct pm_irq_chip * __devinit pm8xxx_irq_init(struct device *dev, | ||
313 | const struct pm8xxx_irq_platform_data *pdata) | ||
314 | { | ||
315 | struct pm_irq_chip *chip; | ||
316 | int devirq, rc; | ||
317 | unsigned int pmirq; | ||
318 | |||
319 | if (!pdata) { | ||
320 | pr_err("No platform data\n"); | ||
321 | return ERR_PTR(-EINVAL); | ||
322 | } | ||
323 | |||
324 | devirq = pdata->devirq; | ||
325 | if (devirq < 0) { | ||
326 | pr_err("missing devirq\n"); | ||
327 | rc = devirq; | ||
328 | return ERR_PTR(-EINVAL); | ||
329 | } | ||
330 | |||
331 | chip = kzalloc(sizeof(struct pm_irq_chip) | ||
332 | + sizeof(u8) * pdata->irq_cdata.nirqs, GFP_KERNEL); | ||
333 | if (!chip) { | ||
334 | pr_err("Cannot alloc pm_irq_chip struct\n"); | ||
335 | return ERR_PTR(-EINVAL); | ||
336 | } | ||
337 | |||
338 | chip->dev = dev; | ||
339 | chip->devirq = devirq; | ||
340 | chip->irq_base = pdata->irq_base; | ||
341 | chip->num_irqs = pdata->irq_cdata.nirqs; | ||
342 | chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8); | ||
343 | chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8); | ||
344 | spin_lock_init(&chip->pm_irq_lock); | ||
345 | |||
346 | for (pmirq = 0; pmirq < chip->num_irqs; pmirq++) { | ||
347 | irq_set_chip_and_handler(chip->irq_base + pmirq, | ||
348 | &pm8xxx_irq_chip, | ||
349 | handle_level_irq); | ||
350 | irq_set_chip_data(chip->irq_base + pmirq, chip); | ||
351 | #ifdef CONFIG_ARM | ||
352 | set_irq_flags(chip->irq_base + pmirq, IRQF_VALID); | ||
353 | #else | ||
354 | irq_set_noprobe(chip->irq_base + pmirq); | ||
355 | #endif | ||
356 | } | ||
357 | |||
358 | irq_set_irq_type(devirq, pdata->irq_trigger_flag); | ||
359 | irq_set_handler_data(devirq, chip); | ||
360 | irq_set_chained_handler(devirq, pm8xxx_irq_handler); | ||
361 | set_irq_wake(devirq, 1); | ||
362 | |||
363 | return chip; | ||
364 | } | ||
365 | |||
366 | int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip) | ||
367 | { | ||
368 | irq_set_chained_handler(chip->devirq, NULL); | ||
369 | kfree(chip); | ||
370 | return 0; | ||
371 | } | ||
diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c index 50922975bda3..809bd4a61089 100644 --- a/drivers/mfd/rdc321x-southbridge.c +++ b/drivers/mfd/rdc321x-southbridge.c | |||
@@ -61,12 +61,14 @@ static struct mfd_cell rdc321x_sb_cells[] = { | |||
61 | .name = "rdc321x-wdt", | 61 | .name = "rdc321x-wdt", |
62 | .resources = rdc321x_wdt_resource, | 62 | .resources = rdc321x_wdt_resource, |
63 | .num_resources = ARRAY_SIZE(rdc321x_wdt_resource), | 63 | .num_resources = ARRAY_SIZE(rdc321x_wdt_resource), |
64 | .driver_data = &rdc321x_wdt_pdata, | 64 | .platform_data = &rdc321x_wdt_pdata, |
65 | .pdata_size = sizeof(rdc321x_wdt_pdata), | ||
65 | }, { | 66 | }, { |
66 | .name = "rdc321x-gpio", | 67 | .name = "rdc321x-gpio", |
67 | .resources = rdc321x_gpio_resources, | 68 | .resources = rdc321x_gpio_resources, |
68 | .num_resources = ARRAY_SIZE(rdc321x_gpio_resources), | 69 | .num_resources = ARRAY_SIZE(rdc321x_gpio_resources), |
69 | .driver_data = &rdc321x_gpio_pdata, | 70 | .platform_data = &rdc321x_gpio_pdata, |
71 | .pdata_size = sizeof(rdc321x_gpio_pdata), | ||
70 | }, | 72 | }, |
71 | }; | 73 | }; |
72 | 74 | ||
@@ -97,6 +99,7 @@ static DEFINE_PCI_DEVICE_TABLE(rdc321x_sb_table) = { | |||
97 | { PCI_DEVICE(PCI_VENDOR_ID_RDC, PCI_DEVICE_ID_RDC_R6030) }, | 99 | { PCI_DEVICE(PCI_VENDOR_ID_RDC, PCI_DEVICE_ID_RDC_R6030) }, |
98 | {} | 100 | {} |
99 | }; | 101 | }; |
102 | MODULE_DEVICE_TABLE(pci, rdc321x_sb_table); | ||
100 | 103 | ||
101 | static struct pci_driver rdc321x_sb_driver = { | 104 | static struct pci_driver rdc321x_sb_driver = { |
102 | .name = "RDC321x Southbridge", | 105 | .name = "RDC321x Southbridge", |
diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c deleted file mode 100644 index cd164595f08a..000000000000 --- a/drivers/mfd/sh_mobile_sdhi.c +++ /dev/null | |||
@@ -1,177 +0,0 @@ | |||
1 | /* | ||
2 | * SuperH Mobile SDHI | ||
3 | * | ||
4 | * Copyright (C) 2009 Magnus Damm | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Based on "Compaq ASIC3 support": | ||
11 | * | ||
12 | * Copyright 2001 Compaq Computer Corporation. | ||
13 | * Copyright 2004-2005 Phil Blundell | ||
14 | * Copyright 2007-2008 OpenedHand Ltd. | ||
15 | * | ||
16 | * Authors: Phil Blundell <pb@handhelds.org>, | ||
17 | * Samuel Ortiz <sameo@openedhand.com> | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/mmc/host.h> | ||
26 | #include <linux/mfd/core.h> | ||
27 | #include <linux/mfd/tmio.h> | ||
28 | #include <linux/mfd/sh_mobile_sdhi.h> | ||
29 | #include <linux/sh_dma.h> | ||
30 | |||
31 | struct sh_mobile_sdhi { | ||
32 | struct clk *clk; | ||
33 | struct tmio_mmc_data mmc_data; | ||
34 | struct mfd_cell cell_mmc; | ||
35 | struct sh_dmae_slave param_tx; | ||
36 | struct sh_dmae_slave param_rx; | ||
37 | struct tmio_mmc_dma dma_priv; | ||
38 | }; | ||
39 | |||
40 | static struct resource sh_mobile_sdhi_resources[] = { | ||
41 | { | ||
42 | .start = 0x000, | ||
43 | .end = 0x1ff, | ||
44 | .flags = IORESOURCE_MEM, | ||
45 | }, | ||
46 | { | ||
47 | .start = 0, | ||
48 | .end = 0, | ||
49 | .flags = IORESOURCE_IRQ, | ||
50 | }, | ||
51 | }; | ||
52 | |||
53 | static struct mfd_cell sh_mobile_sdhi_cell = { | ||
54 | .name = "tmio-mmc", | ||
55 | .num_resources = ARRAY_SIZE(sh_mobile_sdhi_resources), | ||
56 | .resources = sh_mobile_sdhi_resources, | ||
57 | }; | ||
58 | |||
59 | static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state) | ||
60 | { | ||
61 | struct platform_device *pdev = to_platform_device(tmio->dev.parent); | ||
62 | struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; | ||
63 | |||
64 | if (p && p->set_pwr) | ||
65 | p->set_pwr(pdev, state); | ||
66 | } | ||
67 | |||
68 | static int __init sh_mobile_sdhi_probe(struct platform_device *pdev) | ||
69 | { | ||
70 | struct sh_mobile_sdhi *priv; | ||
71 | struct tmio_mmc_data *mmc_data; | ||
72 | struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; | ||
73 | struct resource *mem; | ||
74 | char clk_name[8]; | ||
75 | int ret, irq; | ||
76 | |||
77 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
78 | if (!mem) | ||
79 | dev_err(&pdev->dev, "missing MEM resource\n"); | ||
80 | |||
81 | irq = platform_get_irq(pdev, 0); | ||
82 | if (irq < 0) | ||
83 | dev_err(&pdev->dev, "missing IRQ resource\n"); | ||
84 | |||
85 | if (!mem || (irq < 0)) | ||
86 | return -EINVAL; | ||
87 | |||
88 | priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL); | ||
89 | if (priv == NULL) { | ||
90 | dev_err(&pdev->dev, "kzalloc failed\n"); | ||
91 | return -ENOMEM; | ||
92 | } | ||
93 | |||
94 | mmc_data = &priv->mmc_data; | ||
95 | |||
96 | snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id); | ||
97 | priv->clk = clk_get(&pdev->dev, clk_name); | ||
98 | if (IS_ERR(priv->clk)) { | ||
99 | dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); | ||
100 | ret = PTR_ERR(priv->clk); | ||
101 | kfree(priv); | ||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | clk_enable(priv->clk); | ||
106 | |||
107 | mmc_data->hclk = clk_get_rate(priv->clk); | ||
108 | mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; | ||
109 | mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; | ||
110 | if (p) { | ||
111 | mmc_data->flags = p->tmio_flags; | ||
112 | mmc_data->ocr_mask = p->tmio_ocr_mask; | ||
113 | } | ||
114 | |||
115 | if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) { | ||
116 | priv->param_tx.slave_id = p->dma_slave_tx; | ||
117 | priv->param_rx.slave_id = p->dma_slave_rx; | ||
118 | priv->dma_priv.chan_priv_tx = &priv->param_tx; | ||
119 | priv->dma_priv.chan_priv_rx = &priv->param_rx; | ||
120 | mmc_data->dma = &priv->dma_priv; | ||
121 | } | ||
122 | |||
123 | memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc)); | ||
124 | priv->cell_mmc.driver_data = mmc_data; | ||
125 | priv->cell_mmc.platform_data = &priv->cell_mmc; | ||
126 | priv->cell_mmc.data_size = sizeof(priv->cell_mmc); | ||
127 | |||
128 | platform_set_drvdata(pdev, priv); | ||
129 | |||
130 | ret = mfd_add_devices(&pdev->dev, pdev->id, | ||
131 | &priv->cell_mmc, 1, mem, irq); | ||
132 | if (ret) { | ||
133 | clk_disable(priv->clk); | ||
134 | clk_put(priv->clk); | ||
135 | kfree(priv); | ||
136 | } | ||
137 | |||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | static int sh_mobile_sdhi_remove(struct platform_device *pdev) | ||
142 | { | ||
143 | struct sh_mobile_sdhi *priv = platform_get_drvdata(pdev); | ||
144 | |||
145 | mfd_remove_devices(&pdev->dev); | ||
146 | clk_disable(priv->clk); | ||
147 | clk_put(priv->clk); | ||
148 | kfree(priv); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static struct platform_driver sh_mobile_sdhi_driver = { | ||
154 | .driver = { | ||
155 | .name = "sh_mobile_sdhi", | ||
156 | .owner = THIS_MODULE, | ||
157 | }, | ||
158 | .probe = sh_mobile_sdhi_probe, | ||
159 | .remove = __devexit_p(sh_mobile_sdhi_remove), | ||
160 | }; | ||
161 | |||
162 | static int __init sh_mobile_sdhi_init(void) | ||
163 | { | ||
164 | return platform_driver_register(&sh_mobile_sdhi_driver); | ||
165 | } | ||
166 | |||
167 | static void __exit sh_mobile_sdhi_exit(void) | ||
168 | { | ||
169 | platform_driver_unregister(&sh_mobile_sdhi_driver); | ||
170 | } | ||
171 | |||
172 | module_init(sh_mobile_sdhi_init); | ||
173 | module_exit(sh_mobile_sdhi_exit); | ||
174 | |||
175 | MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); | ||
176 | MODULE_AUTHOR("Magnus Damm"); | ||
177 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index bc9275c12133..df3702c1756d 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include <linux/sm501-regs.h> | 26 | #include <linux/sm501-regs.h> |
27 | #include <linux/serial_8250.h> | 27 | #include <linux/serial_8250.h> |
28 | 28 | ||
29 | #include <asm/io.h> | 29 | #include <linux/io.h> |
30 | 30 | ||
31 | struct sm501_device { | 31 | struct sm501_device { |
32 | struct list_head list; | 32 | struct list_head list; |
@@ -133,10 +133,10 @@ static unsigned long decode_div(unsigned long pll2, unsigned long val, | |||
133 | 133 | ||
134 | static void sm501_dump_clk(struct sm501_devdata *sm) | 134 | static void sm501_dump_clk(struct sm501_devdata *sm) |
135 | { | 135 | { |
136 | unsigned long misct = readl(sm->regs + SM501_MISC_TIMING); | 136 | unsigned long misct = smc501_readl(sm->regs + SM501_MISC_TIMING); |
137 | unsigned long pm0 = readl(sm->regs + SM501_POWER_MODE_0_CLOCK); | 137 | unsigned long pm0 = smc501_readl(sm->regs + SM501_POWER_MODE_0_CLOCK); |
138 | unsigned long pm1 = readl(sm->regs + SM501_POWER_MODE_1_CLOCK); | 138 | unsigned long pm1 = smc501_readl(sm->regs + SM501_POWER_MODE_1_CLOCK); |
139 | unsigned long pmc = readl(sm->regs + SM501_POWER_MODE_CONTROL); | 139 | unsigned long pmc = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL); |
140 | unsigned long sdclk0, sdclk1; | 140 | unsigned long sdclk0, sdclk1; |
141 | unsigned long pll2 = 0; | 141 | unsigned long pll2 = 0; |
142 | 142 | ||
@@ -193,29 +193,29 @@ static void sm501_dump_regs(struct sm501_devdata *sm) | |||
193 | void __iomem *regs = sm->regs; | 193 | void __iomem *regs = sm->regs; |
194 | 194 | ||
195 | dev_info(sm->dev, "System Control %08x\n", | 195 | dev_info(sm->dev, "System Control %08x\n", |
196 | readl(regs + SM501_SYSTEM_CONTROL)); | 196 | smc501_readl(regs + SM501_SYSTEM_CONTROL)); |
197 | dev_info(sm->dev, "Misc Control %08x\n", | 197 | dev_info(sm->dev, "Misc Control %08x\n", |
198 | readl(regs + SM501_MISC_CONTROL)); | 198 | smc501_readl(regs + SM501_MISC_CONTROL)); |
199 | dev_info(sm->dev, "GPIO Control Low %08x\n", | 199 | dev_info(sm->dev, "GPIO Control Low %08x\n", |
200 | readl(regs + SM501_GPIO31_0_CONTROL)); | 200 | smc501_readl(regs + SM501_GPIO31_0_CONTROL)); |
201 | dev_info(sm->dev, "GPIO Control Hi %08x\n", | 201 | dev_info(sm->dev, "GPIO Control Hi %08x\n", |
202 | readl(regs + SM501_GPIO63_32_CONTROL)); | 202 | smc501_readl(regs + SM501_GPIO63_32_CONTROL)); |
203 | dev_info(sm->dev, "DRAM Control %08x\n", | 203 | dev_info(sm->dev, "DRAM Control %08x\n", |
204 | readl(regs + SM501_DRAM_CONTROL)); | 204 | smc501_readl(regs + SM501_DRAM_CONTROL)); |
205 | dev_info(sm->dev, "Arbitration Ctrl %08x\n", | 205 | dev_info(sm->dev, "Arbitration Ctrl %08x\n", |
206 | readl(regs + SM501_ARBTRTN_CONTROL)); | 206 | smc501_readl(regs + SM501_ARBTRTN_CONTROL)); |
207 | dev_info(sm->dev, "Misc Timing %08x\n", | 207 | dev_info(sm->dev, "Misc Timing %08x\n", |
208 | readl(regs + SM501_MISC_TIMING)); | 208 | smc501_readl(regs + SM501_MISC_TIMING)); |
209 | } | 209 | } |
210 | 210 | ||
211 | static void sm501_dump_gate(struct sm501_devdata *sm) | 211 | static void sm501_dump_gate(struct sm501_devdata *sm) |
212 | { | 212 | { |
213 | dev_info(sm->dev, "CurrentGate %08x\n", | 213 | dev_info(sm->dev, "CurrentGate %08x\n", |
214 | readl(sm->regs + SM501_CURRENT_GATE)); | 214 | smc501_readl(sm->regs + SM501_CURRENT_GATE)); |
215 | dev_info(sm->dev, "CurrentClock %08x\n", | 215 | dev_info(sm->dev, "CurrentClock %08x\n", |
216 | readl(sm->regs + SM501_CURRENT_CLOCK)); | 216 | smc501_readl(sm->regs + SM501_CURRENT_CLOCK)); |
217 | dev_info(sm->dev, "PowerModeControl %08x\n", | 217 | dev_info(sm->dev, "PowerModeControl %08x\n", |
218 | readl(sm->regs + SM501_POWER_MODE_CONTROL)); | 218 | smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL)); |
219 | } | 219 | } |
220 | 220 | ||
221 | #else | 221 | #else |
@@ -231,7 +231,7 @@ static inline void sm501_dump_clk(struct sm501_devdata *sm) { } | |||
231 | 231 | ||
232 | static void sm501_sync_regs(struct sm501_devdata *sm) | 232 | static void sm501_sync_regs(struct sm501_devdata *sm) |
233 | { | 233 | { |
234 | readl(sm->regs); | 234 | smc501_readl(sm->regs); |
235 | } | 235 | } |
236 | 236 | ||
237 | static inline void sm501_mdelay(struct sm501_devdata *sm, unsigned int delay) | 237 | static inline void sm501_mdelay(struct sm501_devdata *sm, unsigned int delay) |
@@ -261,11 +261,11 @@ int sm501_misc_control(struct device *dev, | |||
261 | 261 | ||
262 | spin_lock_irqsave(&sm->reg_lock, save); | 262 | spin_lock_irqsave(&sm->reg_lock, save); |
263 | 263 | ||
264 | misc = readl(sm->regs + SM501_MISC_CONTROL); | 264 | misc = smc501_readl(sm->regs + SM501_MISC_CONTROL); |
265 | to = (misc & ~clear) | set; | 265 | to = (misc & ~clear) | set; |
266 | 266 | ||
267 | if (to != misc) { | 267 | if (to != misc) { |
268 | writel(to, sm->regs + SM501_MISC_CONTROL); | 268 | smc501_writel(to, sm->regs + SM501_MISC_CONTROL); |
269 | sm501_sync_regs(sm); | 269 | sm501_sync_regs(sm); |
270 | 270 | ||
271 | dev_dbg(sm->dev, "MISC_CONTROL %08lx\n", misc); | 271 | dev_dbg(sm->dev, "MISC_CONTROL %08lx\n", misc); |
@@ -294,11 +294,11 @@ unsigned long sm501_modify_reg(struct device *dev, | |||
294 | 294 | ||
295 | spin_lock_irqsave(&sm->reg_lock, save); | 295 | spin_lock_irqsave(&sm->reg_lock, save); |
296 | 296 | ||
297 | data = readl(sm->regs + reg); | 297 | data = smc501_readl(sm->regs + reg); |
298 | data |= set; | 298 | data |= set; |
299 | data &= ~clear; | 299 | data &= ~clear; |
300 | 300 | ||
301 | writel(data, sm->regs + reg); | 301 | smc501_writel(data, sm->regs + reg); |
302 | sm501_sync_regs(sm); | 302 | sm501_sync_regs(sm); |
303 | 303 | ||
304 | spin_unlock_irqrestore(&sm->reg_lock, save); | 304 | spin_unlock_irqrestore(&sm->reg_lock, save); |
@@ -322,9 +322,9 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to) | |||
322 | 322 | ||
323 | mutex_lock(&sm->clock_lock); | 323 | mutex_lock(&sm->clock_lock); |
324 | 324 | ||
325 | mode = readl(sm->regs + SM501_POWER_MODE_CONTROL); | 325 | mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL); |
326 | gate = readl(sm->regs + SM501_CURRENT_GATE); | 326 | gate = smc501_readl(sm->regs + SM501_CURRENT_GATE); |
327 | clock = readl(sm->regs + SM501_CURRENT_CLOCK); | 327 | clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK); |
328 | 328 | ||
329 | mode &= 3; /* get current power mode */ | 329 | mode &= 3; /* get current power mode */ |
330 | 330 | ||
@@ -356,14 +356,14 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to) | |||
356 | 356 | ||
357 | switch (mode) { | 357 | switch (mode) { |
358 | case 1: | 358 | case 1: |
359 | writel(gate, sm->regs + SM501_POWER_MODE_0_GATE); | 359 | smc501_writel(gate, sm->regs + SM501_POWER_MODE_0_GATE); |
360 | writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK); | 360 | smc501_writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK); |
361 | mode = 0; | 361 | mode = 0; |
362 | break; | 362 | break; |
363 | case 2: | 363 | case 2: |
364 | case 0: | 364 | case 0: |
365 | writel(gate, sm->regs + SM501_POWER_MODE_1_GATE); | 365 | smc501_writel(gate, sm->regs + SM501_POWER_MODE_1_GATE); |
366 | writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK); | 366 | smc501_writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK); |
367 | mode = 1; | 367 | mode = 1; |
368 | break; | 368 | break; |
369 | 369 | ||
@@ -372,7 +372,7 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to) | |||
372 | goto already; | 372 | goto already; |
373 | } | 373 | } |
374 | 374 | ||
375 | writel(mode, sm->regs + SM501_POWER_MODE_CONTROL); | 375 | smc501_writel(mode, sm->regs + SM501_POWER_MODE_CONTROL); |
376 | sm501_sync_regs(sm); | 376 | sm501_sync_regs(sm); |
377 | 377 | ||
378 | dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n", | 378 | dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n", |
@@ -519,9 +519,9 @@ unsigned long sm501_set_clock(struct device *dev, | |||
519 | unsigned long req_freq) | 519 | unsigned long req_freq) |
520 | { | 520 | { |
521 | struct sm501_devdata *sm = dev_get_drvdata(dev); | 521 | struct sm501_devdata *sm = dev_get_drvdata(dev); |
522 | unsigned long mode = readl(sm->regs + SM501_POWER_MODE_CONTROL); | 522 | unsigned long mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL); |
523 | unsigned long gate = readl(sm->regs + SM501_CURRENT_GATE); | 523 | unsigned long gate = smc501_readl(sm->regs + SM501_CURRENT_GATE); |
524 | unsigned long clock = readl(sm->regs + SM501_CURRENT_CLOCK); | 524 | unsigned long clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK); |
525 | unsigned char reg; | 525 | unsigned char reg; |
526 | unsigned int pll_reg = 0; | 526 | unsigned int pll_reg = 0; |
527 | unsigned long sm501_freq; /* the actual frequency achieved */ | 527 | unsigned long sm501_freq; /* the actual frequency achieved */ |
@@ -592,9 +592,9 @@ unsigned long sm501_set_clock(struct device *dev, | |||
592 | 592 | ||
593 | mutex_lock(&sm->clock_lock); | 593 | mutex_lock(&sm->clock_lock); |
594 | 594 | ||
595 | mode = readl(sm->regs + SM501_POWER_MODE_CONTROL); | 595 | mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL); |
596 | gate = readl(sm->regs + SM501_CURRENT_GATE); | 596 | gate = smc501_readl(sm->regs + SM501_CURRENT_GATE); |
597 | clock = readl(sm->regs + SM501_CURRENT_CLOCK); | 597 | clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK); |
598 | 598 | ||
599 | clock = clock & ~(0xFF << clksrc); | 599 | clock = clock & ~(0xFF << clksrc); |
600 | clock |= reg<<clksrc; | 600 | clock |= reg<<clksrc; |
@@ -603,14 +603,14 @@ unsigned long sm501_set_clock(struct device *dev, | |||
603 | 603 | ||
604 | switch (mode) { | 604 | switch (mode) { |
605 | case 1: | 605 | case 1: |
606 | writel(gate, sm->regs + SM501_POWER_MODE_0_GATE); | 606 | smc501_writel(gate, sm->regs + SM501_POWER_MODE_0_GATE); |
607 | writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK); | 607 | smc501_writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK); |
608 | mode = 0; | 608 | mode = 0; |
609 | break; | 609 | break; |
610 | case 2: | 610 | case 2: |
611 | case 0: | 611 | case 0: |
612 | writel(gate, sm->regs + SM501_POWER_MODE_1_GATE); | 612 | smc501_writel(gate, sm->regs + SM501_POWER_MODE_1_GATE); |
613 | writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK); | 613 | smc501_writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK); |
614 | mode = 1; | 614 | mode = 1; |
615 | break; | 615 | break; |
616 | 616 | ||
@@ -619,10 +619,11 @@ unsigned long sm501_set_clock(struct device *dev, | |||
619 | return -1; | 619 | return -1; |
620 | } | 620 | } |
621 | 621 | ||
622 | writel(mode, sm->regs + SM501_POWER_MODE_CONTROL); | 622 | smc501_writel(mode, sm->regs + SM501_POWER_MODE_CONTROL); |
623 | 623 | ||
624 | if (pll_reg) | 624 | if (pll_reg) |
625 | writel(pll_reg, sm->regs + SM501_PROGRAMMABLE_PLL_CONTROL); | 625 | smc501_writel(pll_reg, |
626 | sm->regs + SM501_PROGRAMMABLE_PLL_CONTROL); | ||
626 | 627 | ||
627 | sm501_sync_regs(sm); | 628 | sm501_sync_regs(sm); |
628 | 629 | ||
@@ -745,11 +746,8 @@ static int sm501_register_device(struct sm501_devdata *sm, | |||
745 | int ret; | 746 | int ret; |
746 | 747 | ||
747 | for (ptr = 0; ptr < pdev->num_resources; ptr++) { | 748 | for (ptr = 0; ptr < pdev->num_resources; ptr++) { |
748 | printk(KERN_DEBUG "%s[%d] flags %08lx: %08llx..%08llx\n", | 749 | printk(KERN_DEBUG "%s[%d] %pR\n", |
749 | pdev->name, ptr, | 750 | pdev->name, ptr, &pdev->resource[ptr]); |
750 | pdev->resource[ptr].flags, | ||
751 | (unsigned long long)pdev->resource[ptr].start, | ||
752 | (unsigned long long)pdev->resource[ptr].end); | ||
753 | } | 751 | } |
754 | 752 | ||
755 | ret = platform_device_register(pdev); | 753 | ret = platform_device_register(pdev); |
@@ -905,7 +903,7 @@ static int sm501_gpio_get(struct gpio_chip *chip, unsigned offset) | |||
905 | struct sm501_gpio_chip *smgpio = to_sm501_gpio(chip); | 903 | struct sm501_gpio_chip *smgpio = to_sm501_gpio(chip); |
906 | unsigned long result; | 904 | unsigned long result; |
907 | 905 | ||
908 | result = readl(smgpio->regbase + SM501_GPIO_DATA_LOW); | 906 | result = smc501_readl(smgpio->regbase + SM501_GPIO_DATA_LOW); |
909 | result >>= offset; | 907 | result >>= offset; |
910 | 908 | ||
911 | return result & 1UL; | 909 | return result & 1UL; |
@@ -918,13 +916,13 @@ static void sm501_gpio_ensure_gpio(struct sm501_gpio_chip *smchip, | |||
918 | 916 | ||
919 | /* check and modify if this pin is not set as gpio. */ | 917 | /* check and modify if this pin is not set as gpio. */ |
920 | 918 | ||
921 | if (readl(smchip->control) & bit) { | 919 | if (smc501_readl(smchip->control) & bit) { |
922 | dev_info(sm501_gpio_to_dev(smchip->ourgpio)->dev, | 920 | dev_info(sm501_gpio_to_dev(smchip->ourgpio)->dev, |
923 | "changing mode of gpio, bit %08lx\n", bit); | 921 | "changing mode of gpio, bit %08lx\n", bit); |
924 | 922 | ||
925 | ctrl = readl(smchip->control); | 923 | ctrl = smc501_readl(smchip->control); |
926 | ctrl &= ~bit; | 924 | ctrl &= ~bit; |
927 | writel(ctrl, smchip->control); | 925 | smc501_writel(ctrl, smchip->control); |
928 | 926 | ||
929 | sm501_sync_regs(sm501_gpio_to_dev(smchip->ourgpio)); | 927 | sm501_sync_regs(sm501_gpio_to_dev(smchip->ourgpio)); |
930 | } | 928 | } |
@@ -945,10 +943,10 @@ static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |||
945 | 943 | ||
946 | spin_lock_irqsave(&smgpio->lock, save); | 944 | spin_lock_irqsave(&smgpio->lock, save); |
947 | 945 | ||
948 | val = readl(regs + SM501_GPIO_DATA_LOW) & ~bit; | 946 | val = smc501_readl(regs + SM501_GPIO_DATA_LOW) & ~bit; |
949 | if (value) | 947 | if (value) |
950 | val |= bit; | 948 | val |= bit; |
951 | writel(val, regs); | 949 | smc501_writel(val, regs); |
952 | 950 | ||
953 | sm501_sync_regs(sm501_gpio_to_dev(smgpio)); | 951 | sm501_sync_regs(sm501_gpio_to_dev(smgpio)); |
954 | sm501_gpio_ensure_gpio(smchip, bit); | 952 | sm501_gpio_ensure_gpio(smchip, bit); |
@@ -970,8 +968,8 @@ static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset) | |||
970 | 968 | ||
971 | spin_lock_irqsave(&smgpio->lock, save); | 969 | spin_lock_irqsave(&smgpio->lock, save); |
972 | 970 | ||
973 | ddr = readl(regs + SM501_GPIO_DDR_LOW); | 971 | ddr = smc501_readl(regs + SM501_GPIO_DDR_LOW); |
974 | writel(ddr & ~bit, regs + SM501_GPIO_DDR_LOW); | 972 | smc501_writel(ddr & ~bit, regs + SM501_GPIO_DDR_LOW); |
975 | 973 | ||
976 | sm501_sync_regs(sm501_gpio_to_dev(smgpio)); | 974 | sm501_sync_regs(sm501_gpio_to_dev(smgpio)); |
977 | sm501_gpio_ensure_gpio(smchip, bit); | 975 | sm501_gpio_ensure_gpio(smchip, bit); |
@@ -997,18 +995,18 @@ static int sm501_gpio_output(struct gpio_chip *chip, | |||
997 | 995 | ||
998 | spin_lock_irqsave(&smgpio->lock, save); | 996 | spin_lock_irqsave(&smgpio->lock, save); |
999 | 997 | ||
1000 | val = readl(regs + SM501_GPIO_DATA_LOW); | 998 | val = smc501_readl(regs + SM501_GPIO_DATA_LOW); |
1001 | if (value) | 999 | if (value) |
1002 | val |= bit; | 1000 | val |= bit; |
1003 | else | 1001 | else |
1004 | val &= ~bit; | 1002 | val &= ~bit; |
1005 | writel(val, regs); | 1003 | smc501_writel(val, regs); |
1006 | 1004 | ||
1007 | ddr = readl(regs + SM501_GPIO_DDR_LOW); | 1005 | ddr = smc501_readl(regs + SM501_GPIO_DDR_LOW); |
1008 | writel(ddr | bit, regs + SM501_GPIO_DDR_LOW); | 1006 | smc501_writel(ddr | bit, regs + SM501_GPIO_DDR_LOW); |
1009 | 1007 | ||
1010 | sm501_sync_regs(sm501_gpio_to_dev(smgpio)); | 1008 | sm501_sync_regs(sm501_gpio_to_dev(smgpio)); |
1011 | writel(val, regs + SM501_GPIO_DATA_LOW); | 1009 | smc501_writel(val, regs + SM501_GPIO_DATA_LOW); |
1012 | 1010 | ||
1013 | sm501_sync_regs(sm501_gpio_to_dev(smgpio)); | 1011 | sm501_sync_regs(sm501_gpio_to_dev(smgpio)); |
1014 | spin_unlock_irqrestore(&smgpio->lock, save); | 1012 | spin_unlock_irqrestore(&smgpio->lock, save); |
@@ -1234,7 +1232,7 @@ static ssize_t sm501_dbg_regs(struct device *dev, | |||
1234 | 1232 | ||
1235 | for (reg = 0x00; reg < 0x70; reg += 4) { | 1233 | for (reg = 0x00; reg < 0x70; reg += 4) { |
1236 | ret = sprintf(ptr, "%08x = %08x\n", | 1234 | ret = sprintf(ptr, "%08x = %08x\n", |
1237 | reg, readl(sm->regs + reg)); | 1235 | reg, smc501_readl(sm->regs + reg)); |
1238 | ptr += ret; | 1236 | ptr += ret; |
1239 | } | 1237 | } |
1240 | 1238 | ||
@@ -1258,10 +1256,10 @@ static inline void sm501_init_reg(struct sm501_devdata *sm, | |||
1258 | { | 1256 | { |
1259 | unsigned long tmp; | 1257 | unsigned long tmp; |
1260 | 1258 | ||
1261 | tmp = readl(sm->regs + reg); | 1259 | tmp = smc501_readl(sm->regs + reg); |
1262 | tmp &= ~r->mask; | 1260 | tmp &= ~r->mask; |
1263 | tmp |= r->set; | 1261 | tmp |= r->set; |
1264 | writel(tmp, sm->regs + reg); | 1262 | smc501_writel(tmp, sm->regs + reg); |
1265 | } | 1263 | } |
1266 | 1264 | ||
1267 | /* sm501_init_regs | 1265 | /* sm501_init_regs |
@@ -1302,7 +1300,7 @@ static void sm501_init_regs(struct sm501_devdata *sm, | |||
1302 | 1300 | ||
1303 | static int sm501_check_clocks(struct sm501_devdata *sm) | 1301 | static int sm501_check_clocks(struct sm501_devdata *sm) |
1304 | { | 1302 | { |
1305 | unsigned long pwrmode = readl(sm->regs + SM501_CURRENT_CLOCK); | 1303 | unsigned long pwrmode = smc501_readl(sm->regs + SM501_CURRENT_CLOCK); |
1306 | unsigned long msrc = (pwrmode & SM501_POWERMODE_M_SRC); | 1304 | unsigned long msrc = (pwrmode & SM501_POWERMODE_M_SRC); |
1307 | unsigned long m1src = (pwrmode & SM501_POWERMODE_M1_SRC); | 1305 | unsigned long m1src = (pwrmode & SM501_POWERMODE_M1_SRC); |
1308 | 1306 | ||
@@ -1337,7 +1335,7 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm) | |||
1337 | 1335 | ||
1338 | INIT_LIST_HEAD(&sm->devices); | 1336 | INIT_LIST_HEAD(&sm->devices); |
1339 | 1337 | ||
1340 | devid = readl(sm->regs + SM501_DEVICEID); | 1338 | devid = smc501_readl(sm->regs + SM501_DEVICEID); |
1341 | 1339 | ||
1342 | if ((devid & SM501_DEVICEID_IDMASK) != SM501_DEVICEID_SM501) { | 1340 | if ((devid & SM501_DEVICEID_IDMASK) != SM501_DEVICEID_SM501) { |
1343 | dev_err(sm->dev, "incorrect device id %08lx\n", devid); | 1341 | dev_err(sm->dev, "incorrect device id %08lx\n", devid); |
@@ -1345,9 +1343,9 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm) | |||
1345 | } | 1343 | } |
1346 | 1344 | ||
1347 | /* disable irqs */ | 1345 | /* disable irqs */ |
1348 | writel(0, sm->regs + SM501_IRQ_MASK); | 1346 | smc501_writel(0, sm->regs + SM501_IRQ_MASK); |
1349 | 1347 | ||
1350 | dramctrl = readl(sm->regs + SM501_DRAM_CONTROL); | 1348 | dramctrl = smc501_readl(sm->regs + SM501_DRAM_CONTROL); |
1351 | mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7]; | 1349 | mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7]; |
1352 | 1350 | ||
1353 | dev_info(sm->dev, "SM501 At %p: Version %08lx, %ld Mb, IRQ %d\n", | 1351 | dev_info(sm->dev, "SM501 At %p: Version %08lx, %ld Mb, IRQ %d\n", |
@@ -1379,7 +1377,7 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm) | |||
1379 | sm501_register_gpio(sm); | 1377 | sm501_register_gpio(sm); |
1380 | } | 1378 | } |
1381 | 1379 | ||
1382 | if (pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) { | 1380 | if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) { |
1383 | if (!sm501_gpio_isregistered(sm)) | 1381 | if (!sm501_gpio_isregistered(sm)) |
1384 | dev_err(sm->dev, "no gpio available for i2c gpio.\n"); | 1382 | dev_err(sm->dev, "no gpio available for i2c gpio.\n"); |
1385 | else | 1383 | else |
@@ -1424,6 +1422,7 @@ static int __devinit sm501_plat_probe(struct platform_device *dev) | |||
1424 | 1422 | ||
1425 | sm->io_res = platform_get_resource(dev, IORESOURCE_MEM, 1); | 1423 | sm->io_res = platform_get_resource(dev, IORESOURCE_MEM, 1); |
1426 | sm->mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0); | 1424 | sm->mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0); |
1425 | |||
1427 | if (sm->io_res == NULL || sm->mem_res == NULL) { | 1426 | if (sm->io_res == NULL || sm->mem_res == NULL) { |
1428 | dev_err(&dev->dev, "failed to get IO resource\n"); | 1427 | dev_err(&dev->dev, "failed to get IO resource\n"); |
1429 | ret = -ENOENT; | 1428 | ret = -ENOENT; |
@@ -1492,7 +1491,7 @@ static int sm501_plat_suspend(struct platform_device *pdev, pm_message_t state) | |||
1492 | struct sm501_devdata *sm = platform_get_drvdata(pdev); | 1491 | struct sm501_devdata *sm = platform_get_drvdata(pdev); |
1493 | 1492 | ||
1494 | sm->in_suspend = 1; | 1493 | sm->in_suspend = 1; |
1495 | sm->pm_misc = readl(sm->regs + SM501_MISC_CONTROL); | 1494 | sm->pm_misc = smc501_readl(sm->regs + SM501_MISC_CONTROL); |
1496 | 1495 | ||
1497 | sm501_dump_regs(sm); | 1496 | sm501_dump_regs(sm); |
1498 | 1497 | ||
@@ -1516,9 +1515,9 @@ static int sm501_plat_resume(struct platform_device *pdev) | |||
1516 | 1515 | ||
1517 | /* check to see if we are in the same state as when suspended */ | 1516 | /* check to see if we are in the same state as when suspended */ |
1518 | 1517 | ||
1519 | if (readl(sm->regs + SM501_MISC_CONTROL) != sm->pm_misc) { | 1518 | if (smc501_readl(sm->regs + SM501_MISC_CONTROL) != sm->pm_misc) { |
1520 | dev_info(sm->dev, "SM501_MISC_CONTROL changed over sleep\n"); | 1519 | dev_info(sm->dev, "SM501_MISC_CONTROL changed over sleep\n"); |
1521 | writel(sm->pm_misc, sm->regs + SM501_MISC_CONTROL); | 1520 | smc501_writel(sm->pm_misc, sm->regs + SM501_MISC_CONTROL); |
1522 | 1521 | ||
1523 | /* our suspend causes the controller state to change, | 1522 | /* our suspend causes the controller state to change, |
1524 | * either by something attempting setup, power loss, | 1523 | * either by something attempting setup, power loss, |
@@ -1737,10 +1736,16 @@ static struct pci_driver sm501_pci_driver = { | |||
1737 | 1736 | ||
1738 | MODULE_ALIAS("platform:sm501"); | 1737 | MODULE_ALIAS("platform:sm501"); |
1739 | 1738 | ||
1739 | static struct of_device_id __devinitdata of_sm501_match_tbl[] = { | ||
1740 | { .compatible = "smi,sm501", }, | ||
1741 | { /* end */ } | ||
1742 | }; | ||
1743 | |||
1740 | static struct platform_driver sm501_plat_driver = { | 1744 | static struct platform_driver sm501_plat_driver = { |
1741 | .driver = { | 1745 | .driver = { |
1742 | .name = "sm501", | 1746 | .name = "sm501", |
1743 | .owner = THIS_MODULE, | 1747 | .owner = THIS_MODULE, |
1748 | .of_match_table = of_sm501_match_tbl, | ||
1744 | }, | 1749 | }, |
1745 | .probe = sm501_plat_probe, | 1750 | .probe = sm501_plat_probe, |
1746 | .remove = sm501_plat_remove, | 1751 | .remove = sm501_plat_remove, |
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 0754c5e91995..7ab7746631d4 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c | |||
@@ -699,16 +699,16 @@ static irqreturn_t stmpe_irq(int irq, void *data) | |||
699 | return IRQ_HANDLED; | 699 | return IRQ_HANDLED; |
700 | } | 700 | } |
701 | 701 | ||
702 | static void stmpe_irq_lock(unsigned int irq) | 702 | static void stmpe_irq_lock(struct irq_data *data) |
703 | { | 703 | { |
704 | struct stmpe *stmpe = get_irq_chip_data(irq); | 704 | struct stmpe *stmpe = irq_data_get_irq_chip_data(data); |
705 | 705 | ||
706 | mutex_lock(&stmpe->irq_lock); | 706 | mutex_lock(&stmpe->irq_lock); |
707 | } | 707 | } |
708 | 708 | ||
709 | static void stmpe_irq_sync_unlock(unsigned int irq) | 709 | static void stmpe_irq_sync_unlock(struct irq_data *data) |
710 | { | 710 | { |
711 | struct stmpe *stmpe = get_irq_chip_data(irq); | 711 | struct stmpe *stmpe = irq_data_get_irq_chip_data(data); |
712 | struct stmpe_variant_info *variant = stmpe->variant; | 712 | struct stmpe_variant_info *variant = stmpe->variant; |
713 | int num = DIV_ROUND_UP(variant->num_irqs, 8); | 713 | int num = DIV_ROUND_UP(variant->num_irqs, 8); |
714 | int i; | 714 | int i; |
@@ -727,20 +727,20 @@ static void stmpe_irq_sync_unlock(unsigned int irq) | |||
727 | mutex_unlock(&stmpe->irq_lock); | 727 | mutex_unlock(&stmpe->irq_lock); |
728 | } | 728 | } |
729 | 729 | ||
730 | static void stmpe_irq_mask(unsigned int irq) | 730 | static void stmpe_irq_mask(struct irq_data *data) |
731 | { | 731 | { |
732 | struct stmpe *stmpe = get_irq_chip_data(irq); | 732 | struct stmpe *stmpe = irq_data_get_irq_chip_data(data); |
733 | int offset = irq - stmpe->irq_base; | 733 | int offset = data->irq - stmpe->irq_base; |
734 | int regoffset = offset / 8; | 734 | int regoffset = offset / 8; |
735 | int mask = 1 << (offset % 8); | 735 | int mask = 1 << (offset % 8); |
736 | 736 | ||
737 | stmpe->ier[regoffset] &= ~mask; | 737 | stmpe->ier[regoffset] &= ~mask; |
738 | } | 738 | } |
739 | 739 | ||
740 | static void stmpe_irq_unmask(unsigned int irq) | 740 | static void stmpe_irq_unmask(struct irq_data *data) |
741 | { | 741 | { |
742 | struct stmpe *stmpe = get_irq_chip_data(irq); | 742 | struct stmpe *stmpe = irq_data_get_irq_chip_data(data); |
743 | int offset = irq - stmpe->irq_base; | 743 | int offset = data->irq - stmpe->irq_base; |
744 | int regoffset = offset / 8; | 744 | int regoffset = offset / 8; |
745 | int mask = 1 << (offset % 8); | 745 | int mask = 1 << (offset % 8); |
746 | 746 | ||
@@ -749,10 +749,10 @@ static void stmpe_irq_unmask(unsigned int irq) | |||
749 | 749 | ||
750 | static struct irq_chip stmpe_irq_chip = { | 750 | static struct irq_chip stmpe_irq_chip = { |
751 | .name = "stmpe", | 751 | .name = "stmpe", |
752 | .bus_lock = stmpe_irq_lock, | 752 | .irq_bus_lock = stmpe_irq_lock, |
753 | .bus_sync_unlock = stmpe_irq_sync_unlock, | 753 | .irq_bus_sync_unlock = stmpe_irq_sync_unlock, |
754 | .mask = stmpe_irq_mask, | 754 | .irq_mask = stmpe_irq_mask, |
755 | .unmask = stmpe_irq_unmask, | 755 | .irq_unmask = stmpe_irq_unmask, |
756 | }; | 756 | }; |
757 | 757 | ||
758 | static int __devinit stmpe_irq_init(struct stmpe *stmpe) | 758 | static int __devinit stmpe_irq_init(struct stmpe *stmpe) |
@@ -762,14 +762,14 @@ static int __devinit stmpe_irq_init(struct stmpe *stmpe) | |||
762 | int irq; | 762 | int irq; |
763 | 763 | ||
764 | for (irq = base; irq < base + num_irqs; irq++) { | 764 | for (irq = base; irq < base + num_irqs; irq++) { |
765 | set_irq_chip_data(irq, stmpe); | 765 | irq_set_chip_data(irq, stmpe); |
766 | set_irq_chip_and_handler(irq, &stmpe_irq_chip, | 766 | irq_set_chip_and_handler(irq, &stmpe_irq_chip, |
767 | handle_edge_irq); | 767 | handle_edge_irq); |
768 | set_irq_nested_thread(irq, 1); | 768 | irq_set_nested_thread(irq, 1); |
769 | #ifdef CONFIG_ARM | 769 | #ifdef CONFIG_ARM |
770 | set_irq_flags(irq, IRQF_VALID); | 770 | set_irq_flags(irq, IRQF_VALID); |
771 | #else | 771 | #else |
772 | set_irq_noprobe(irq); | 772 | irq_set_noprobe(irq); |
773 | #endif | 773 | #endif |
774 | } | 774 | } |
775 | 775 | ||
@@ -786,8 +786,8 @@ static void stmpe_irq_remove(struct stmpe *stmpe) | |||
786 | #ifdef CONFIG_ARM | 786 | #ifdef CONFIG_ARM |
787 | set_irq_flags(irq, 0); | 787 | set_irq_flags(irq, 0); |
788 | #endif | 788 | #endif |
789 | set_irq_chip_and_handler(irq, NULL, NULL); | 789 | irq_set_chip_and_handler(irq, NULL, NULL); |
790 | set_irq_chip_data(irq, NULL); | 790 | irq_set_chip_data(irq, NULL); |
791 | } | 791 | } |
792 | } | 792 | } |
793 | 793 | ||
@@ -873,6 +873,28 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe) | |||
873 | return ret; | 873 | return ret; |
874 | } | 874 | } |
875 | 875 | ||
876 | #ifdef CONFIG_PM | ||
877 | static int stmpe_suspend(struct device *dev) | ||
878 | { | ||
879 | struct i2c_client *i2c = to_i2c_client(dev); | ||
880 | |||
881 | if (device_may_wakeup(&i2c->dev)) | ||
882 | enable_irq_wake(i2c->irq); | ||
883 | |||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | static int stmpe_resume(struct device *dev) | ||
888 | { | ||
889 | struct i2c_client *i2c = to_i2c_client(dev); | ||
890 | |||
891 | if (device_may_wakeup(&i2c->dev)) | ||
892 | disable_irq_wake(i2c->irq); | ||
893 | |||
894 | return 0; | ||
895 | } | ||
896 | #endif | ||
897 | |||
876 | static int __devinit stmpe_probe(struct i2c_client *i2c, | 898 | static int __devinit stmpe_probe(struct i2c_client *i2c, |
877 | const struct i2c_device_id *id) | 899 | const struct i2c_device_id *id) |
878 | { | 900 | { |
@@ -960,9 +982,19 @@ static const struct i2c_device_id stmpe_id[] = { | |||
960 | }; | 982 | }; |
961 | MODULE_DEVICE_TABLE(i2c, stmpe_id); | 983 | MODULE_DEVICE_TABLE(i2c, stmpe_id); |
962 | 984 | ||
985 | #ifdef CONFIG_PM | ||
986 | static const struct dev_pm_ops stmpe_dev_pm_ops = { | ||
987 | .suspend = stmpe_suspend, | ||
988 | .resume = stmpe_resume, | ||
989 | }; | ||
990 | #endif | ||
991 | |||
963 | static struct i2c_driver stmpe_driver = { | 992 | static struct i2c_driver stmpe_driver = { |
964 | .driver.name = "stmpe", | 993 | .driver.name = "stmpe", |
965 | .driver.owner = THIS_MODULE, | 994 | .driver.owner = THIS_MODULE, |
995 | #ifdef CONFIG_PM | ||
996 | .driver.pm = &stmpe_dev_pm_ops, | ||
997 | #endif | ||
966 | .probe = stmpe_probe, | 998 | .probe = stmpe_probe, |
967 | .remove = __devexit_p(stmpe_remove), | 999 | .remove = __devexit_p(stmpe_remove), |
968 | .id_table = stmpe_id, | 1000 | .id_table = stmpe_id, |
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 006c121f3f0d..91ad21ef7721 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c | |||
@@ -170,7 +170,8 @@ static struct mfd_cell t7l66xb_cells[] = { | |||
170 | .name = "tmio-mmc", | 170 | .name = "tmio-mmc", |
171 | .enable = t7l66xb_mmc_enable, | 171 | .enable = t7l66xb_mmc_enable, |
172 | .disable = t7l66xb_mmc_disable, | 172 | .disable = t7l66xb_mmc_disable, |
173 | .driver_data = &t7166xb_mmc_data, | 173 | .platform_data = &t7166xb_mmc_data, |
174 | .pdata_size = sizeof(t7166xb_mmc_data), | ||
174 | .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources), | 175 | .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources), |
175 | .resources = t7l66xb_mmc_resources, | 176 | .resources = t7l66xb_mmc_resources, |
176 | }, | 177 | }, |
@@ -186,7 +187,7 @@ static struct mfd_cell t7l66xb_cells[] = { | |||
186 | /* Handle the T7L66XB interrupt mux */ | 187 | /* Handle the T7L66XB interrupt mux */ |
187 | static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc) | 188 | static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc) |
188 | { | 189 | { |
189 | struct t7l66xb *t7l66xb = get_irq_data(irq); | 190 | struct t7l66xb *t7l66xb = irq_get_handler_data(irq); |
190 | unsigned int isr; | 191 | unsigned int isr; |
191 | unsigned int i, irq_base; | 192 | unsigned int i, irq_base; |
192 | 193 | ||
@@ -199,37 +200,37 @@ static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc) | |||
199 | generic_handle_irq(irq_base + i); | 200 | generic_handle_irq(irq_base + i); |
200 | } | 201 | } |
201 | 202 | ||
202 | static void t7l66xb_irq_mask(unsigned int irq) | 203 | static void t7l66xb_irq_mask(struct irq_data *data) |
203 | { | 204 | { |
204 | struct t7l66xb *t7l66xb = get_irq_chip_data(irq); | 205 | struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data); |
205 | unsigned long flags; | 206 | unsigned long flags; |
206 | u8 imr; | 207 | u8 imr; |
207 | 208 | ||
208 | spin_lock_irqsave(&t7l66xb->lock, flags); | 209 | spin_lock_irqsave(&t7l66xb->lock, flags); |
209 | imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); | 210 | imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); |
210 | imr |= 1 << (irq - t7l66xb->irq_base); | 211 | imr |= 1 << (data->irq - t7l66xb->irq_base); |
211 | tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); | 212 | tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); |
212 | spin_unlock_irqrestore(&t7l66xb->lock, flags); | 213 | spin_unlock_irqrestore(&t7l66xb->lock, flags); |
213 | } | 214 | } |
214 | 215 | ||
215 | static void t7l66xb_irq_unmask(unsigned int irq) | 216 | static void t7l66xb_irq_unmask(struct irq_data *data) |
216 | { | 217 | { |
217 | struct t7l66xb *t7l66xb = get_irq_chip_data(irq); | 218 | struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data); |
218 | unsigned long flags; | 219 | unsigned long flags; |
219 | u8 imr; | 220 | u8 imr; |
220 | 221 | ||
221 | spin_lock_irqsave(&t7l66xb->lock, flags); | 222 | spin_lock_irqsave(&t7l66xb->lock, flags); |
222 | imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); | 223 | imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); |
223 | imr &= ~(1 << (irq - t7l66xb->irq_base)); | 224 | imr &= ~(1 << (data->irq - t7l66xb->irq_base)); |
224 | tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); | 225 | tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); |
225 | spin_unlock_irqrestore(&t7l66xb->lock, flags); | 226 | spin_unlock_irqrestore(&t7l66xb->lock, flags); |
226 | } | 227 | } |
227 | 228 | ||
228 | static struct irq_chip t7l66xb_chip = { | 229 | static struct irq_chip t7l66xb_chip = { |
229 | .name = "t7l66xb", | 230 | .name = "t7l66xb", |
230 | .ack = t7l66xb_irq_mask, | 231 | .irq_ack = t7l66xb_irq_mask, |
231 | .mask = t7l66xb_irq_mask, | 232 | .irq_mask = t7l66xb_irq_mask, |
232 | .unmask = t7l66xb_irq_unmask, | 233 | .irq_unmask = t7l66xb_irq_unmask, |
233 | }; | 234 | }; |
234 | 235 | ||
235 | /*--------------------------------------------------------------------------*/ | 236 | /*--------------------------------------------------------------------------*/ |
@@ -243,17 +244,16 @@ static void t7l66xb_attach_irq(struct platform_device *dev) | |||
243 | irq_base = t7l66xb->irq_base; | 244 | irq_base = t7l66xb->irq_base; |
244 | 245 | ||
245 | for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { | 246 | for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { |
246 | set_irq_chip(irq, &t7l66xb_chip); | 247 | irq_set_chip_and_handler(irq, &t7l66xb_chip, handle_level_irq); |
247 | set_irq_chip_data(irq, t7l66xb); | 248 | irq_set_chip_data(irq, t7l66xb); |
248 | set_irq_handler(irq, handle_level_irq); | ||
249 | #ifdef CONFIG_ARM | 249 | #ifdef CONFIG_ARM |
250 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 250 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
251 | #endif | 251 | #endif |
252 | } | 252 | } |
253 | 253 | ||
254 | set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); | 254 | irq_set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); |
255 | set_irq_data(t7l66xb->irq, t7l66xb); | 255 | irq_set_handler_data(t7l66xb->irq, t7l66xb); |
256 | set_irq_chained_handler(t7l66xb->irq, t7l66xb_irq); | 256 | irq_set_chained_handler(t7l66xb->irq, t7l66xb_irq); |
257 | } | 257 | } |
258 | 258 | ||
259 | static void t7l66xb_detach_irq(struct platform_device *dev) | 259 | static void t7l66xb_detach_irq(struct platform_device *dev) |
@@ -263,15 +263,15 @@ static void t7l66xb_detach_irq(struct platform_device *dev) | |||
263 | 263 | ||
264 | irq_base = t7l66xb->irq_base; | 264 | irq_base = t7l66xb->irq_base; |
265 | 265 | ||
266 | set_irq_chained_handler(t7l66xb->irq, NULL); | 266 | irq_set_chained_handler(t7l66xb->irq, NULL); |
267 | set_irq_data(t7l66xb->irq, NULL); | 267 | irq_set_handler_data(t7l66xb->irq, NULL); |
268 | 268 | ||
269 | for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { | 269 | for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { |
270 | #ifdef CONFIG_ARM | 270 | #ifdef CONFIG_ARM |
271 | set_irq_flags(irq, 0); | 271 | set_irq_flags(irq, 0); |
272 | #endif | 272 | #endif |
273 | set_irq_chip(irq, NULL); | 273 | irq_set_chip(irq, NULL); |
274 | set_irq_chip_data(irq, NULL); | 274 | irq_set_chip_data(irq, NULL); |
275 | } | 275 | } |
276 | } | 276 | } |
277 | 277 | ||
@@ -383,16 +383,8 @@ static int t7l66xb_probe(struct platform_device *dev) | |||
383 | 383 | ||
384 | t7l66xb_attach_irq(dev); | 384 | t7l66xb_attach_irq(dev); |
385 | 385 | ||
386 | t7l66xb_cells[T7L66XB_CELL_NAND].driver_data = pdata->nand_data; | 386 | t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = pdata->nand_data; |
387 | t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = | 387 | t7l66xb_cells[T7L66XB_CELL_NAND].pdata_size = sizeof(*pdata->nand_data); |
388 | &t7l66xb_cells[T7L66XB_CELL_NAND]; | ||
389 | t7l66xb_cells[T7L66XB_CELL_NAND].data_size = | ||
390 | sizeof(t7l66xb_cells[T7L66XB_CELL_NAND]); | ||
391 | |||
392 | t7l66xb_cells[T7L66XB_CELL_MMC].platform_data = | ||
393 | &t7l66xb_cells[T7L66XB_CELL_MMC]; | ||
394 | t7l66xb_cells[T7L66XB_CELL_MMC].data_size = | ||
395 | sizeof(t7l66xb_cells[T7L66XB_CELL_MMC]); | ||
396 | 388 | ||
397 | ret = mfd_add_devices(&dev->dev, dev->id, | 389 | ret = mfd_add_devices(&dev->dev, dev->id, |
398 | t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), | 390 | t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), |
diff --git a/drivers/mfd/tc35892.c b/drivers/mfd/tc35892.c deleted file mode 100644 index e619e2a55997..000000000000 --- a/drivers/mfd/tc35892.c +++ /dev/null | |||
@@ -1,345 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * License Terms: GNU General Public License, version 2 | ||
5 | * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson | ||
6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/irq.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/mfd/core.h> | ||
15 | #include <linux/mfd/tc35892.h> | ||
16 | |||
17 | /** | ||
18 | * tc35892_reg_read() - read a single TC35892 register | ||
19 | * @tc35892: Device to read from | ||
20 | * @reg: Register to read | ||
21 | */ | ||
22 | int tc35892_reg_read(struct tc35892 *tc35892, u8 reg) | ||
23 | { | ||
24 | int ret; | ||
25 | |||
26 | ret = i2c_smbus_read_byte_data(tc35892->i2c, reg); | ||
27 | if (ret < 0) | ||
28 | dev_err(tc35892->dev, "failed to read reg %#x: %d\n", | ||
29 | reg, ret); | ||
30 | |||
31 | return ret; | ||
32 | } | ||
33 | EXPORT_SYMBOL_GPL(tc35892_reg_read); | ||
34 | |||
35 | /** | ||
36 | * tc35892_reg_read() - write a single TC35892 register | ||
37 | * @tc35892: Device to write to | ||
38 | * @reg: Register to read | ||
39 | * @data: Value to write | ||
40 | */ | ||
41 | int tc35892_reg_write(struct tc35892 *tc35892, u8 reg, u8 data) | ||
42 | { | ||
43 | int ret; | ||
44 | |||
45 | ret = i2c_smbus_write_byte_data(tc35892->i2c, reg, data); | ||
46 | if (ret < 0) | ||
47 | dev_err(tc35892->dev, "failed to write reg %#x: %d\n", | ||
48 | reg, ret); | ||
49 | |||
50 | return ret; | ||
51 | } | ||
52 | EXPORT_SYMBOL_GPL(tc35892_reg_write); | ||
53 | |||
54 | /** | ||
55 | * tc35892_block_read() - read multiple TC35892 registers | ||
56 | * @tc35892: Device to read from | ||
57 | * @reg: First register | ||
58 | * @length: Number of registers | ||
59 | * @values: Buffer to write to | ||
60 | */ | ||
61 | int tc35892_block_read(struct tc35892 *tc35892, u8 reg, u8 length, u8 *values) | ||
62 | { | ||
63 | int ret; | ||
64 | |||
65 | ret = i2c_smbus_read_i2c_block_data(tc35892->i2c, reg, length, values); | ||
66 | if (ret < 0) | ||
67 | dev_err(tc35892->dev, "failed to read regs %#x: %d\n", | ||
68 | reg, ret); | ||
69 | |||
70 | return ret; | ||
71 | } | ||
72 | EXPORT_SYMBOL_GPL(tc35892_block_read); | ||
73 | |||
74 | /** | ||
75 | * tc35892_block_write() - write multiple TC35892 registers | ||
76 | * @tc35892: Device to write to | ||
77 | * @reg: First register | ||
78 | * @length: Number of registers | ||
79 | * @values: Values to write | ||
80 | */ | ||
81 | int tc35892_block_write(struct tc35892 *tc35892, u8 reg, u8 length, | ||
82 | const u8 *values) | ||
83 | { | ||
84 | int ret; | ||
85 | |||
86 | ret = i2c_smbus_write_i2c_block_data(tc35892->i2c, reg, length, | ||
87 | values); | ||
88 | if (ret < 0) | ||
89 | dev_err(tc35892->dev, "failed to write regs %#x: %d\n", | ||
90 | reg, ret); | ||
91 | |||
92 | return ret; | ||
93 | } | ||
94 | EXPORT_SYMBOL_GPL(tc35892_block_write); | ||
95 | |||
96 | /** | ||
97 | * tc35892_set_bits() - set the value of a bitfield in a TC35892 register | ||
98 | * @tc35892: Device to write to | ||
99 | * @reg: Register to write | ||
100 | * @mask: Mask of bits to set | ||
101 | * @values: Value to set | ||
102 | */ | ||
103 | int tc35892_set_bits(struct tc35892 *tc35892, u8 reg, u8 mask, u8 val) | ||
104 | { | ||
105 | int ret; | ||
106 | |||
107 | mutex_lock(&tc35892->lock); | ||
108 | |||
109 | ret = tc35892_reg_read(tc35892, reg); | ||
110 | if (ret < 0) | ||
111 | goto out; | ||
112 | |||
113 | ret &= ~mask; | ||
114 | ret |= val; | ||
115 | |||
116 | ret = tc35892_reg_write(tc35892, reg, ret); | ||
117 | |||
118 | out: | ||
119 | mutex_unlock(&tc35892->lock); | ||
120 | return ret; | ||
121 | } | ||
122 | EXPORT_SYMBOL_GPL(tc35892_set_bits); | ||
123 | |||
124 | static struct resource gpio_resources[] = { | ||
125 | { | ||
126 | .start = TC35892_INT_GPIIRQ, | ||
127 | .end = TC35892_INT_GPIIRQ, | ||
128 | .flags = IORESOURCE_IRQ, | ||
129 | }, | ||
130 | }; | ||
131 | |||
132 | static struct mfd_cell tc35892_devs[] = { | ||
133 | { | ||
134 | .name = "tc35892-gpio", | ||
135 | .num_resources = ARRAY_SIZE(gpio_resources), | ||
136 | .resources = &gpio_resources[0], | ||
137 | }, | ||
138 | }; | ||
139 | |||
140 | static irqreturn_t tc35892_irq(int irq, void *data) | ||
141 | { | ||
142 | struct tc35892 *tc35892 = data; | ||
143 | int status; | ||
144 | |||
145 | status = tc35892_reg_read(tc35892, TC35892_IRQST); | ||
146 | if (status < 0) | ||
147 | return IRQ_NONE; | ||
148 | |||
149 | while (status) { | ||
150 | int bit = __ffs(status); | ||
151 | |||
152 | handle_nested_irq(tc35892->irq_base + bit); | ||
153 | status &= ~(1 << bit); | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * A dummy read or write (to any register) appears to be necessary to | ||
158 | * have the last interrupt clear (for example, GPIO IC write) take | ||
159 | * effect. | ||
160 | */ | ||
161 | tc35892_reg_read(tc35892, TC35892_IRQST); | ||
162 | |||
163 | return IRQ_HANDLED; | ||
164 | } | ||
165 | |||
166 | static void tc35892_irq_dummy(unsigned int irq) | ||
167 | { | ||
168 | /* No mask/unmask at this level */ | ||
169 | } | ||
170 | |||
171 | static struct irq_chip tc35892_irq_chip = { | ||
172 | .name = "tc35892", | ||
173 | .mask = tc35892_irq_dummy, | ||
174 | .unmask = tc35892_irq_dummy, | ||
175 | }; | ||
176 | |||
177 | static int tc35892_irq_init(struct tc35892 *tc35892) | ||
178 | { | ||
179 | int base = tc35892->irq_base; | ||
180 | int irq; | ||
181 | |||
182 | for (irq = base; irq < base + TC35892_NR_INTERNAL_IRQS; irq++) { | ||
183 | set_irq_chip_data(irq, tc35892); | ||
184 | set_irq_chip_and_handler(irq, &tc35892_irq_chip, | ||
185 | handle_edge_irq); | ||
186 | set_irq_nested_thread(irq, 1); | ||
187 | #ifdef CONFIG_ARM | ||
188 | set_irq_flags(irq, IRQF_VALID); | ||
189 | #else | ||
190 | set_irq_noprobe(irq); | ||
191 | #endif | ||
192 | } | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static void tc35892_irq_remove(struct tc35892 *tc35892) | ||
198 | { | ||
199 | int base = tc35892->irq_base; | ||
200 | int irq; | ||
201 | |||
202 | for (irq = base; irq < base + TC35892_NR_INTERNAL_IRQS; irq++) { | ||
203 | #ifdef CONFIG_ARM | ||
204 | set_irq_flags(irq, 0); | ||
205 | #endif | ||
206 | set_irq_chip_and_handler(irq, NULL, NULL); | ||
207 | set_irq_chip_data(irq, NULL); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | static int tc35892_chip_init(struct tc35892 *tc35892) | ||
212 | { | ||
213 | int manf, ver, ret; | ||
214 | |||
215 | manf = tc35892_reg_read(tc35892, TC35892_MANFCODE); | ||
216 | if (manf < 0) | ||
217 | return manf; | ||
218 | |||
219 | ver = tc35892_reg_read(tc35892, TC35892_VERSION); | ||
220 | if (ver < 0) | ||
221 | return ver; | ||
222 | |||
223 | if (manf != TC35892_MANFCODE_MAGIC) { | ||
224 | dev_err(tc35892->dev, "unknown manufacturer: %#x\n", manf); | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | |||
228 | dev_info(tc35892->dev, "manufacturer: %#x, version: %#x\n", manf, ver); | ||
229 | |||
230 | /* Put everything except the IRQ module into reset */ | ||
231 | ret = tc35892_reg_write(tc35892, TC35892_RSTCTRL, | ||
232 | TC35892_RSTCTRL_TIMRST | ||
233 | | TC35892_RSTCTRL_ROTRST | ||
234 | | TC35892_RSTCTRL_KBDRST | ||
235 | | TC35892_RSTCTRL_GPIRST); | ||
236 | if (ret < 0) | ||
237 | return ret; | ||
238 | |||
239 | /* Clear the reset interrupt. */ | ||
240 | return tc35892_reg_write(tc35892, TC35892_RSTINTCLR, 0x1); | ||
241 | } | ||
242 | |||
243 | static int __devinit tc35892_probe(struct i2c_client *i2c, | ||
244 | const struct i2c_device_id *id) | ||
245 | { | ||
246 | struct tc35892_platform_data *pdata = i2c->dev.platform_data; | ||
247 | struct tc35892 *tc35892; | ||
248 | int ret; | ||
249 | |||
250 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | ||
251 | | I2C_FUNC_SMBUS_I2C_BLOCK)) | ||
252 | return -EIO; | ||
253 | |||
254 | tc35892 = kzalloc(sizeof(struct tc35892), GFP_KERNEL); | ||
255 | if (!tc35892) | ||
256 | return -ENOMEM; | ||
257 | |||
258 | mutex_init(&tc35892->lock); | ||
259 | |||
260 | tc35892->dev = &i2c->dev; | ||
261 | tc35892->i2c = i2c; | ||
262 | tc35892->pdata = pdata; | ||
263 | tc35892->irq_base = pdata->irq_base; | ||
264 | tc35892->num_gpio = id->driver_data; | ||
265 | |||
266 | i2c_set_clientdata(i2c, tc35892); | ||
267 | |||
268 | ret = tc35892_chip_init(tc35892); | ||
269 | if (ret) | ||
270 | goto out_free; | ||
271 | |||
272 | ret = tc35892_irq_init(tc35892); | ||
273 | if (ret) | ||
274 | goto out_free; | ||
275 | |||
276 | ret = request_threaded_irq(tc35892->i2c->irq, NULL, tc35892_irq, | ||
277 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
278 | "tc35892", tc35892); | ||
279 | if (ret) { | ||
280 | dev_err(tc35892->dev, "failed to request IRQ: %d\n", ret); | ||
281 | goto out_removeirq; | ||
282 | } | ||
283 | |||
284 | ret = mfd_add_devices(tc35892->dev, -1, tc35892_devs, | ||
285 | ARRAY_SIZE(tc35892_devs), NULL, | ||
286 | tc35892->irq_base); | ||
287 | if (ret) { | ||
288 | dev_err(tc35892->dev, "failed to add children\n"); | ||
289 | goto out_freeirq; | ||
290 | } | ||
291 | |||
292 | return 0; | ||
293 | |||
294 | out_freeirq: | ||
295 | free_irq(tc35892->i2c->irq, tc35892); | ||
296 | out_removeirq: | ||
297 | tc35892_irq_remove(tc35892); | ||
298 | out_free: | ||
299 | kfree(tc35892); | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | static int __devexit tc35892_remove(struct i2c_client *client) | ||
304 | { | ||
305 | struct tc35892 *tc35892 = i2c_get_clientdata(client); | ||
306 | |||
307 | mfd_remove_devices(tc35892->dev); | ||
308 | |||
309 | free_irq(tc35892->i2c->irq, tc35892); | ||
310 | tc35892_irq_remove(tc35892); | ||
311 | |||
312 | kfree(tc35892); | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static const struct i2c_device_id tc35892_id[] = { | ||
318 | { "tc35892", 24 }, | ||
319 | { } | ||
320 | }; | ||
321 | MODULE_DEVICE_TABLE(i2c, tc35892_id); | ||
322 | |||
323 | static struct i2c_driver tc35892_driver = { | ||
324 | .driver.name = "tc35892", | ||
325 | .driver.owner = THIS_MODULE, | ||
326 | .probe = tc35892_probe, | ||
327 | .remove = __devexit_p(tc35892_remove), | ||
328 | .id_table = tc35892_id, | ||
329 | }; | ||
330 | |||
331 | static int __init tc35892_init(void) | ||
332 | { | ||
333 | return i2c_add_driver(&tc35892_driver); | ||
334 | } | ||
335 | subsys_initcall(tc35892_init); | ||
336 | |||
337 | static void __exit tc35892_exit(void) | ||
338 | { | ||
339 | i2c_del_driver(&tc35892_driver); | ||
340 | } | ||
341 | module_exit(tc35892_exit); | ||
342 | |||
343 | MODULE_LICENSE("GPL v2"); | ||
344 | MODULE_DESCRIPTION("TC35892 MFD core driver"); | ||
345 | MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); | ||
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c new file mode 100644 index 000000000000..c27e515b0722 --- /dev/null +++ b/drivers/mfd/tc3589x.c | |||
@@ -0,0 +1,422 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * License Terms: GNU General Public License, version 2 | ||
5 | * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson | ||
6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/irq.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/mfd/core.h> | ||
15 | #include <linux/mfd/tc3589x.h> | ||
16 | |||
17 | #define TC3589x_CLKMODE_MODCTL_SLEEP 0x0 | ||
18 | #define TC3589x_CLKMODE_MODCTL_OPERATION (1 << 0) | ||
19 | |||
20 | /** | ||
21 | * tc3589x_reg_read() - read a single TC3589x register | ||
22 | * @tc3589x: Device to read from | ||
23 | * @reg: Register to read | ||
24 | */ | ||
25 | int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg) | ||
26 | { | ||
27 | int ret; | ||
28 | |||
29 | ret = i2c_smbus_read_byte_data(tc3589x->i2c, reg); | ||
30 | if (ret < 0) | ||
31 | dev_err(tc3589x->dev, "failed to read reg %#x: %d\n", | ||
32 | reg, ret); | ||
33 | |||
34 | return ret; | ||
35 | } | ||
36 | EXPORT_SYMBOL_GPL(tc3589x_reg_read); | ||
37 | |||
38 | /** | ||
39 | * tc3589x_reg_read() - write a single TC3589x register | ||
40 | * @tc3589x: Device to write to | ||
41 | * @reg: Register to read | ||
42 | * @data: Value to write | ||
43 | */ | ||
44 | int tc3589x_reg_write(struct tc3589x *tc3589x, u8 reg, u8 data) | ||
45 | { | ||
46 | int ret; | ||
47 | |||
48 | ret = i2c_smbus_write_byte_data(tc3589x->i2c, reg, data); | ||
49 | if (ret < 0) | ||
50 | dev_err(tc3589x->dev, "failed to write reg %#x: %d\n", | ||
51 | reg, ret); | ||
52 | |||
53 | return ret; | ||
54 | } | ||
55 | EXPORT_SYMBOL_GPL(tc3589x_reg_write); | ||
56 | |||
57 | /** | ||
58 | * tc3589x_block_read() - read multiple TC3589x registers | ||
59 | * @tc3589x: Device to read from | ||
60 | * @reg: First register | ||
61 | * @length: Number of registers | ||
62 | * @values: Buffer to write to | ||
63 | */ | ||
64 | int tc3589x_block_read(struct tc3589x *tc3589x, u8 reg, u8 length, u8 *values) | ||
65 | { | ||
66 | int ret; | ||
67 | |||
68 | ret = i2c_smbus_read_i2c_block_data(tc3589x->i2c, reg, length, values); | ||
69 | if (ret < 0) | ||
70 | dev_err(tc3589x->dev, "failed to read regs %#x: %d\n", | ||
71 | reg, ret); | ||
72 | |||
73 | return ret; | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(tc3589x_block_read); | ||
76 | |||
77 | /** | ||
78 | * tc3589x_block_write() - write multiple TC3589x registers | ||
79 | * @tc3589x: Device to write to | ||
80 | * @reg: First register | ||
81 | * @length: Number of registers | ||
82 | * @values: Values to write | ||
83 | */ | ||
84 | int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length, | ||
85 | const u8 *values) | ||
86 | { | ||
87 | int ret; | ||
88 | |||
89 | ret = i2c_smbus_write_i2c_block_data(tc3589x->i2c, reg, length, | ||
90 | values); | ||
91 | if (ret < 0) | ||
92 | dev_err(tc3589x->dev, "failed to write regs %#x: %d\n", | ||
93 | reg, ret); | ||
94 | |||
95 | return ret; | ||
96 | } | ||
97 | EXPORT_SYMBOL_GPL(tc3589x_block_write); | ||
98 | |||
99 | /** | ||
100 | * tc3589x_set_bits() - set the value of a bitfield in a TC3589x register | ||
101 | * @tc3589x: Device to write to | ||
102 | * @reg: Register to write | ||
103 | * @mask: Mask of bits to set | ||
104 | * @values: Value to set | ||
105 | */ | ||
106 | int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val) | ||
107 | { | ||
108 | int ret; | ||
109 | |||
110 | mutex_lock(&tc3589x->lock); | ||
111 | |||
112 | ret = tc3589x_reg_read(tc3589x, reg); | ||
113 | if (ret < 0) | ||
114 | goto out; | ||
115 | |||
116 | ret &= ~mask; | ||
117 | ret |= val; | ||
118 | |||
119 | ret = tc3589x_reg_write(tc3589x, reg, ret); | ||
120 | |||
121 | out: | ||
122 | mutex_unlock(&tc3589x->lock); | ||
123 | return ret; | ||
124 | } | ||
125 | EXPORT_SYMBOL_GPL(tc3589x_set_bits); | ||
126 | |||
127 | static struct resource gpio_resources[] = { | ||
128 | { | ||
129 | .start = TC3589x_INT_GPIIRQ, | ||
130 | .end = TC3589x_INT_GPIIRQ, | ||
131 | .flags = IORESOURCE_IRQ, | ||
132 | }, | ||
133 | }; | ||
134 | |||
135 | static struct resource keypad_resources[] = { | ||
136 | { | ||
137 | .start = TC3589x_INT_KBDIRQ, | ||
138 | .end = TC3589x_INT_KBDIRQ, | ||
139 | .flags = IORESOURCE_IRQ, | ||
140 | }, | ||
141 | }; | ||
142 | |||
143 | static struct mfd_cell tc3589x_dev_gpio[] = { | ||
144 | { | ||
145 | .name = "tc3589x-gpio", | ||
146 | .num_resources = ARRAY_SIZE(gpio_resources), | ||
147 | .resources = &gpio_resources[0], | ||
148 | }, | ||
149 | }; | ||
150 | |||
151 | static struct mfd_cell tc3589x_dev_keypad[] = { | ||
152 | { | ||
153 | .name = "tc3589x-keypad", | ||
154 | .num_resources = ARRAY_SIZE(keypad_resources), | ||
155 | .resources = &keypad_resources[0], | ||
156 | }, | ||
157 | }; | ||
158 | |||
159 | static irqreturn_t tc3589x_irq(int irq, void *data) | ||
160 | { | ||
161 | struct tc3589x *tc3589x = data; | ||
162 | int status; | ||
163 | |||
164 | again: | ||
165 | status = tc3589x_reg_read(tc3589x, TC3589x_IRQST); | ||
166 | if (status < 0) | ||
167 | return IRQ_NONE; | ||
168 | |||
169 | while (status) { | ||
170 | int bit = __ffs(status); | ||
171 | |||
172 | handle_nested_irq(tc3589x->irq_base + bit); | ||
173 | status &= ~(1 << bit); | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * A dummy read or write (to any register) appears to be necessary to | ||
178 | * have the last interrupt clear (for example, GPIO IC write) take | ||
179 | * effect. In such a case, recheck for any interrupt which is still | ||
180 | * pending. | ||
181 | */ | ||
182 | status = tc3589x_reg_read(tc3589x, TC3589x_IRQST); | ||
183 | if (status) | ||
184 | goto again; | ||
185 | |||
186 | return IRQ_HANDLED; | ||
187 | } | ||
188 | |||
189 | static int tc3589x_irq_init(struct tc3589x *tc3589x) | ||
190 | { | ||
191 | int base = tc3589x->irq_base; | ||
192 | int irq; | ||
193 | |||
194 | for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { | ||
195 | irq_set_chip_data(irq, tc3589x); | ||
196 | irq_set_chip_and_handler(irq, &dummy_irq_chip, | ||
197 | handle_edge_irq); | ||
198 | irq_set_nested_thread(irq, 1); | ||
199 | #ifdef CONFIG_ARM | ||
200 | set_irq_flags(irq, IRQF_VALID); | ||
201 | #else | ||
202 | irq_set_noprobe(irq); | ||
203 | #endif | ||
204 | } | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static void tc3589x_irq_remove(struct tc3589x *tc3589x) | ||
210 | { | ||
211 | int base = tc3589x->irq_base; | ||
212 | int irq; | ||
213 | |||
214 | for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { | ||
215 | #ifdef CONFIG_ARM | ||
216 | set_irq_flags(irq, 0); | ||
217 | #endif | ||
218 | irq_set_chip_and_handler(irq, NULL, NULL); | ||
219 | irq_set_chip_data(irq, NULL); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | static int tc3589x_chip_init(struct tc3589x *tc3589x) | ||
224 | { | ||
225 | int manf, ver, ret; | ||
226 | |||
227 | manf = tc3589x_reg_read(tc3589x, TC3589x_MANFCODE); | ||
228 | if (manf < 0) | ||
229 | return manf; | ||
230 | |||
231 | ver = tc3589x_reg_read(tc3589x, TC3589x_VERSION); | ||
232 | if (ver < 0) | ||
233 | return ver; | ||
234 | |||
235 | if (manf != TC3589x_MANFCODE_MAGIC) { | ||
236 | dev_err(tc3589x->dev, "unknown manufacturer: %#x\n", manf); | ||
237 | return -EINVAL; | ||
238 | } | ||
239 | |||
240 | dev_info(tc3589x->dev, "manufacturer: %#x, version: %#x\n", manf, ver); | ||
241 | |||
242 | /* | ||
243 | * Put everything except the IRQ module into reset; | ||
244 | * also spare the GPIO module for any pin initialization | ||
245 | * done during pre-kernel boot | ||
246 | */ | ||
247 | ret = tc3589x_reg_write(tc3589x, TC3589x_RSTCTRL, | ||
248 | TC3589x_RSTCTRL_TIMRST | ||
249 | | TC3589x_RSTCTRL_ROTRST | ||
250 | | TC3589x_RSTCTRL_KBDRST); | ||
251 | if (ret < 0) | ||
252 | return ret; | ||
253 | |||
254 | /* Clear the reset interrupt. */ | ||
255 | return tc3589x_reg_write(tc3589x, TC3589x_RSTINTCLR, 0x1); | ||
256 | } | ||
257 | |||
258 | static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) | ||
259 | { | ||
260 | int ret = 0; | ||
261 | unsigned int blocks = tc3589x->pdata->block; | ||
262 | |||
263 | if (blocks & TC3589x_BLOCK_GPIO) { | ||
264 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio, | ||
265 | ARRAY_SIZE(tc3589x_dev_gpio), NULL, | ||
266 | tc3589x->irq_base); | ||
267 | if (ret) { | ||
268 | dev_err(tc3589x->dev, "failed to add gpio child\n"); | ||
269 | return ret; | ||
270 | } | ||
271 | dev_info(tc3589x->dev, "added gpio block\n"); | ||
272 | } | ||
273 | |||
274 | if (blocks & TC3589x_BLOCK_KEYPAD) { | ||
275 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad, | ||
276 | ARRAY_SIZE(tc3589x_dev_keypad), NULL, | ||
277 | tc3589x->irq_base); | ||
278 | if (ret) { | ||
279 | dev_err(tc3589x->dev, "failed to keypad child\n"); | ||
280 | return ret; | ||
281 | } | ||
282 | dev_info(tc3589x->dev, "added keypad block\n"); | ||
283 | } | ||
284 | |||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | static int __devinit tc3589x_probe(struct i2c_client *i2c, | ||
289 | const struct i2c_device_id *id) | ||
290 | { | ||
291 | struct tc3589x_platform_data *pdata = i2c->dev.platform_data; | ||
292 | struct tc3589x *tc3589x; | ||
293 | int ret; | ||
294 | |||
295 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | ||
296 | | I2C_FUNC_SMBUS_I2C_BLOCK)) | ||
297 | return -EIO; | ||
298 | |||
299 | tc3589x = kzalloc(sizeof(struct tc3589x), GFP_KERNEL); | ||
300 | if (!tc3589x) | ||
301 | return -ENOMEM; | ||
302 | |||
303 | mutex_init(&tc3589x->lock); | ||
304 | |||
305 | tc3589x->dev = &i2c->dev; | ||
306 | tc3589x->i2c = i2c; | ||
307 | tc3589x->pdata = pdata; | ||
308 | tc3589x->irq_base = pdata->irq_base; | ||
309 | tc3589x->num_gpio = id->driver_data; | ||
310 | |||
311 | i2c_set_clientdata(i2c, tc3589x); | ||
312 | |||
313 | ret = tc3589x_chip_init(tc3589x); | ||
314 | if (ret) | ||
315 | goto out_free; | ||
316 | |||
317 | ret = tc3589x_irq_init(tc3589x); | ||
318 | if (ret) | ||
319 | goto out_free; | ||
320 | |||
321 | ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq, | ||
322 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
323 | "tc3589x", tc3589x); | ||
324 | if (ret) { | ||
325 | dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); | ||
326 | goto out_removeirq; | ||
327 | } | ||
328 | |||
329 | ret = tc3589x_device_init(tc3589x); | ||
330 | if (ret) { | ||
331 | dev_err(tc3589x->dev, "failed to add child devices\n"); | ||
332 | goto out_freeirq; | ||
333 | } | ||
334 | |||
335 | return 0; | ||
336 | |||
337 | out_freeirq: | ||
338 | free_irq(tc3589x->i2c->irq, tc3589x); | ||
339 | out_removeirq: | ||
340 | tc3589x_irq_remove(tc3589x); | ||
341 | out_free: | ||
342 | kfree(tc3589x); | ||
343 | return ret; | ||
344 | } | ||
345 | |||
346 | static int __devexit tc3589x_remove(struct i2c_client *client) | ||
347 | { | ||
348 | struct tc3589x *tc3589x = i2c_get_clientdata(client); | ||
349 | |||
350 | mfd_remove_devices(tc3589x->dev); | ||
351 | |||
352 | free_irq(tc3589x->i2c->irq, tc3589x); | ||
353 | tc3589x_irq_remove(tc3589x); | ||
354 | |||
355 | kfree(tc3589x); | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int tc3589x_suspend(struct device *dev) | ||
361 | { | ||
362 | struct tc3589x *tc3589x = dev_get_drvdata(dev); | ||
363 | struct i2c_client *client = tc3589x->i2c; | ||
364 | int ret = 0; | ||
365 | |||
366 | /* put the system to sleep mode */ | ||
367 | if (!device_may_wakeup(&client->dev)) | ||
368 | ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE, | ||
369 | TC3589x_CLKMODE_MODCTL_SLEEP); | ||
370 | |||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | static int tc3589x_resume(struct device *dev) | ||
375 | { | ||
376 | struct tc3589x *tc3589x = dev_get_drvdata(dev); | ||
377 | struct i2c_client *client = tc3589x->i2c; | ||
378 | int ret = 0; | ||
379 | |||
380 | /* enable the system into operation */ | ||
381 | if (!device_may_wakeup(&client->dev)) | ||
382 | ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE, | ||
383 | TC3589x_CLKMODE_MODCTL_OPERATION); | ||
384 | |||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | static const SIMPLE_DEV_PM_OPS(tc3589x_dev_pm_ops, tc3589x_suspend, | ||
389 | tc3589x_resume); | ||
390 | |||
391 | static const struct i2c_device_id tc3589x_id[] = { | ||
392 | { "tc3589x", 24 }, | ||
393 | { } | ||
394 | }; | ||
395 | MODULE_DEVICE_TABLE(i2c, tc3589x_id); | ||
396 | |||
397 | static struct i2c_driver tc3589x_driver = { | ||
398 | .driver.name = "tc3589x", | ||
399 | .driver.owner = THIS_MODULE, | ||
400 | #ifdef CONFIG_PM | ||
401 | .driver.pm = &tc3589x_dev_pm_ops, | ||
402 | #endif | ||
403 | .probe = tc3589x_probe, | ||
404 | .remove = __devexit_p(tc3589x_remove), | ||
405 | .id_table = tc3589x_id, | ||
406 | }; | ||
407 | |||
408 | static int __init tc3589x_init(void) | ||
409 | { | ||
410 | return i2c_add_driver(&tc3589x_driver); | ||
411 | } | ||
412 | subsys_initcall(tc3589x_init); | ||
413 | |||
414 | static void __exit tc3589x_exit(void) | ||
415 | { | ||
416 | i2c_del_driver(&tc3589x_driver); | ||
417 | } | ||
418 | module_exit(tc3589x_exit); | ||
419 | |||
420 | MODULE_LICENSE("GPL v2"); | ||
421 | MODULE_DESCRIPTION("TC3589x MFD core driver"); | ||
422 | MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); | ||
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index 6315f63f017d..ad715bf49cac 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c | |||
@@ -131,7 +131,8 @@ static struct mfd_cell tc6387xb_cells[] = { | |||
131 | .name = "tmio-mmc", | 131 | .name = "tmio-mmc", |
132 | .enable = tc6387xb_mmc_enable, | 132 | .enable = tc6387xb_mmc_enable, |
133 | .disable = tc6387xb_mmc_disable, | 133 | .disable = tc6387xb_mmc_disable, |
134 | .driver_data = &tc6387xb_mmc_data, | 134 | .platform_data = &tc6387xb_mmc_data, |
135 | .pdata_size = sizeof(tc6387xb_mmc_data), | ||
135 | .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources), | 136 | .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources), |
136 | .resources = tc6387xb_mmc_resources, | 137 | .resources = tc6387xb_mmc_resources, |
137 | }, | 138 | }, |
@@ -190,11 +191,6 @@ static int __devinit tc6387xb_probe(struct platform_device *dev) | |||
190 | 191 | ||
191 | printk(KERN_INFO "Toshiba tc6387xb initialised\n"); | 192 | printk(KERN_INFO "Toshiba tc6387xb initialised\n"); |
192 | 193 | ||
193 | tc6387xb_cells[TC6387XB_CELL_MMC].platform_data = | ||
194 | &tc6387xb_cells[TC6387XB_CELL_MMC]; | ||
195 | tc6387xb_cells[TC6387XB_CELL_MMC].data_size = | ||
196 | sizeof(tc6387xb_cells[TC6387XB_CELL_MMC]); | ||
197 | |||
198 | ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, | 194 | ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, |
199 | ARRAY_SIZE(tc6387xb_cells), iomem, irq); | 195 | ARRAY_SIZE(tc6387xb_cells), iomem, irq); |
200 | 196 | ||
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index ef6c42c8917a..9612264f0e6d 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c | |||
@@ -155,7 +155,7 @@ static struct resource __devinitdata tc6393xb_nand_resources[] = { | |||
155 | }, | 155 | }, |
156 | }; | 156 | }; |
157 | 157 | ||
158 | static struct resource __devinitdata tc6393xb_mmc_resources[] = { | 158 | static struct resource tc6393xb_mmc_resources[] = { |
159 | { | 159 | { |
160 | .start = 0x800, | 160 | .start = 0x800, |
161 | .end = 0x9ff, | 161 | .end = 0x9ff, |
@@ -393,7 +393,8 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = { | |||
393 | .name = "tmio-mmc", | 393 | .name = "tmio-mmc", |
394 | .enable = tc6393xb_mmc_enable, | 394 | .enable = tc6393xb_mmc_enable, |
395 | .resume = tc6393xb_mmc_resume, | 395 | .resume = tc6393xb_mmc_resume, |
396 | .driver_data = &tc6393xb_mmc_data, | 396 | .platform_data = &tc6393xb_mmc_data, |
397 | .pdata_size = sizeof(tc6393xb_mmc_data), | ||
397 | .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), | 398 | .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), |
398 | .resources = tc6393xb_mmc_resources, | 399 | .resources = tc6393xb_mmc_resources, |
399 | }, | 400 | }, |
@@ -513,7 +514,7 @@ static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb, int gpio_base) | |||
513 | static void | 514 | static void |
514 | tc6393xb_irq(unsigned int irq, struct irq_desc *desc) | 515 | tc6393xb_irq(unsigned int irq, struct irq_desc *desc) |
515 | { | 516 | { |
516 | struct tc6393xb *tc6393xb = get_irq_data(irq); | 517 | struct tc6393xb *tc6393xb = irq_get_handler_data(irq); |
517 | unsigned int isr; | 518 | unsigned int isr; |
518 | unsigned int i, irq_base; | 519 | unsigned int i, irq_base; |
519 | 520 | ||
@@ -527,41 +528,41 @@ tc6393xb_irq(unsigned int irq, struct irq_desc *desc) | |||
527 | } | 528 | } |
528 | } | 529 | } |
529 | 530 | ||
530 | static void tc6393xb_irq_ack(unsigned int irq) | 531 | static void tc6393xb_irq_ack(struct irq_data *data) |
531 | { | 532 | { |
532 | } | 533 | } |
533 | 534 | ||
534 | static void tc6393xb_irq_mask(unsigned int irq) | 535 | static void tc6393xb_irq_mask(struct irq_data *data) |
535 | { | 536 | { |
536 | struct tc6393xb *tc6393xb = get_irq_chip_data(irq); | 537 | struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data); |
537 | unsigned long flags; | 538 | unsigned long flags; |
538 | u8 imr; | 539 | u8 imr; |
539 | 540 | ||
540 | spin_lock_irqsave(&tc6393xb->lock, flags); | 541 | spin_lock_irqsave(&tc6393xb->lock, flags); |
541 | imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); | 542 | imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); |
542 | imr |= 1 << (irq - tc6393xb->irq_base); | 543 | imr |= 1 << (data->irq - tc6393xb->irq_base); |
543 | tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); | 544 | tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); |
544 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | 545 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
545 | } | 546 | } |
546 | 547 | ||
547 | static void tc6393xb_irq_unmask(unsigned int irq) | 548 | static void tc6393xb_irq_unmask(struct irq_data *data) |
548 | { | 549 | { |
549 | struct tc6393xb *tc6393xb = get_irq_chip_data(irq); | 550 | struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data); |
550 | unsigned long flags; | 551 | unsigned long flags; |
551 | u8 imr; | 552 | u8 imr; |
552 | 553 | ||
553 | spin_lock_irqsave(&tc6393xb->lock, flags); | 554 | spin_lock_irqsave(&tc6393xb->lock, flags); |
554 | imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); | 555 | imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); |
555 | imr &= ~(1 << (irq - tc6393xb->irq_base)); | 556 | imr &= ~(1 << (data->irq - tc6393xb->irq_base)); |
556 | tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); | 557 | tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); |
557 | spin_unlock_irqrestore(&tc6393xb->lock, flags); | 558 | spin_unlock_irqrestore(&tc6393xb->lock, flags); |
558 | } | 559 | } |
559 | 560 | ||
560 | static struct irq_chip tc6393xb_chip = { | 561 | static struct irq_chip tc6393xb_chip = { |
561 | .name = "tc6393xb", | 562 | .name = "tc6393xb", |
562 | .ack = tc6393xb_irq_ack, | 563 | .irq_ack = tc6393xb_irq_ack, |
563 | .mask = tc6393xb_irq_mask, | 564 | .irq_mask = tc6393xb_irq_mask, |
564 | .unmask = tc6393xb_irq_unmask, | 565 | .irq_unmask = tc6393xb_irq_unmask, |
565 | }; | 566 | }; |
566 | 567 | ||
567 | static void tc6393xb_attach_irq(struct platform_device *dev) | 568 | static void tc6393xb_attach_irq(struct platform_device *dev) |
@@ -572,15 +573,14 @@ static void tc6393xb_attach_irq(struct platform_device *dev) | |||
572 | irq_base = tc6393xb->irq_base; | 573 | irq_base = tc6393xb->irq_base; |
573 | 574 | ||
574 | for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { | 575 | for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { |
575 | set_irq_chip(irq, &tc6393xb_chip); | 576 | irq_set_chip_and_handler(irq, &tc6393xb_chip, handle_edge_irq); |
576 | set_irq_chip_data(irq, tc6393xb); | 577 | irq_set_chip_data(irq, tc6393xb); |
577 | set_irq_handler(irq, handle_edge_irq); | ||
578 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 578 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
579 | } | 579 | } |
580 | 580 | ||
581 | set_irq_type(tc6393xb->irq, IRQ_TYPE_EDGE_FALLING); | 581 | irq_set_irq_type(tc6393xb->irq, IRQ_TYPE_EDGE_FALLING); |
582 | set_irq_data(tc6393xb->irq, tc6393xb); | 582 | irq_set_handler_data(tc6393xb->irq, tc6393xb); |
583 | set_irq_chained_handler(tc6393xb->irq, tc6393xb_irq); | 583 | irq_set_chained_handler(tc6393xb->irq, tc6393xb_irq); |
584 | } | 584 | } |
585 | 585 | ||
586 | static void tc6393xb_detach_irq(struct platform_device *dev) | 586 | static void tc6393xb_detach_irq(struct platform_device *dev) |
@@ -588,15 +588,15 @@ static void tc6393xb_detach_irq(struct platform_device *dev) | |||
588 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | 588 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
589 | unsigned int irq, irq_base; | 589 | unsigned int irq, irq_base; |
590 | 590 | ||
591 | set_irq_chained_handler(tc6393xb->irq, NULL); | 591 | irq_set_chained_handler(tc6393xb->irq, NULL); |
592 | set_irq_data(tc6393xb->irq, NULL); | 592 | irq_set_handler_data(tc6393xb->irq, NULL); |
593 | 593 | ||
594 | irq_base = tc6393xb->irq_base; | 594 | irq_base = tc6393xb->irq_base; |
595 | 595 | ||
596 | for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { | 596 | for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { |
597 | set_irq_flags(irq, 0); | 597 | set_irq_flags(irq, 0); |
598 | set_irq_chip(irq, NULL); | 598 | irq_set_chip(irq, NULL); |
599 | set_irq_chip_data(irq, NULL); | 599 | irq_set_chip_data(irq, NULL); |
600 | } | 600 | } |
601 | } | 601 | } |
602 | 602 | ||
@@ -693,27 +693,11 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) | |||
693 | goto err_setup; | 693 | goto err_setup; |
694 | } | 694 | } |
695 | 695 | ||
696 | tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; | 696 | tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = tcpd->nand_data; |
697 | tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = | 697 | tc6393xb_cells[TC6393XB_CELL_NAND].pdata_size = |
698 | &tc6393xb_cells[TC6393XB_CELL_NAND]; | 698 | sizeof(*tcpd->nand_data); |
699 | tc6393xb_cells[TC6393XB_CELL_NAND].data_size = | 699 | tc6393xb_cells[TC6393XB_CELL_FB].platform_data = tcpd->fb_data; |
700 | sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]); | 700 | tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data); |
701 | |||
702 | tc6393xb_cells[TC6393XB_CELL_MMC].platform_data = | ||
703 | &tc6393xb_cells[TC6393XB_CELL_MMC]; | ||
704 | tc6393xb_cells[TC6393XB_CELL_MMC].data_size = | ||
705 | sizeof(tc6393xb_cells[TC6393XB_CELL_MMC]); | ||
706 | |||
707 | tc6393xb_cells[TC6393XB_CELL_OHCI].platform_data = | ||
708 | &tc6393xb_cells[TC6393XB_CELL_OHCI]; | ||
709 | tc6393xb_cells[TC6393XB_CELL_OHCI].data_size = | ||
710 | sizeof(tc6393xb_cells[TC6393XB_CELL_OHCI]); | ||
711 | |||
712 | tc6393xb_cells[TC6393XB_CELL_FB].driver_data = tcpd->fb_data; | ||
713 | tc6393xb_cells[TC6393XB_CELL_FB].platform_data = | ||
714 | &tc6393xb_cells[TC6393XB_CELL_FB]; | ||
715 | tc6393xb_cells[TC6393XB_CELL_FB].data_size = | ||
716 | sizeof(tc6393xb_cells[TC6393XB_CELL_FB]); | ||
717 | 701 | ||
718 | ret = mfd_add_devices(&dev->dev, dev->id, | 702 | ret = mfd_add_devices(&dev->dev, dev->id, |
719 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), | 703 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), |
diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c new file mode 100644 index 000000000000..af9ab0e5ca64 --- /dev/null +++ b/drivers/mfd/ti-ssp.c | |||
@@ -0,0 +1,476 @@ | |||
1 | /* | ||
2 | * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments Inc | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include <linux/errno.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/wait.h> | ||
28 | #include <linux/clk.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/device.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/delay.h> | ||
34 | #include <linux/io.h> | ||
35 | #include <linux/mfd/core.h> | ||
36 | #include <linux/mfd/ti_ssp.h> | ||
37 | |||
38 | /* Register Offsets */ | ||
39 | #define REG_REV 0x00 | ||
40 | #define REG_IOSEL_1 0x04 | ||
41 | #define REG_IOSEL_2 0x08 | ||
42 | #define REG_PREDIV 0x0c | ||
43 | #define REG_INTR_ST 0x10 | ||
44 | #define REG_INTR_EN 0x14 | ||
45 | #define REG_TEST_CTRL 0x18 | ||
46 | |||
47 | /* Per port registers */ | ||
48 | #define PORT_CFG_2 0x00 | ||
49 | #define PORT_ADDR 0x04 | ||
50 | #define PORT_DATA 0x08 | ||
51 | #define PORT_CFG_1 0x0c | ||
52 | #define PORT_STATE 0x10 | ||
53 | |||
54 | #define SSP_PORT_CONFIG_MASK (SSP_EARLY_DIN | SSP_DELAY_DOUT) | ||
55 | #define SSP_PORT_CLKRATE_MASK 0x0f | ||
56 | |||
57 | #define SSP_SEQRAM_WR_EN BIT(4) | ||
58 | #define SSP_SEQRAM_RD_EN BIT(5) | ||
59 | #define SSP_START BIT(15) | ||
60 | #define SSP_BUSY BIT(10) | ||
61 | #define SSP_PORT_ASL BIT(7) | ||
62 | #define SSP_PORT_CFO1 BIT(6) | ||
63 | |||
64 | #define SSP_PORT_SEQRAM_SIZE 32 | ||
65 | |||
66 | static const int ssp_port_base[] = {0x040, 0x080}; | ||
67 | static const int ssp_port_seqram[] = {0x100, 0x180}; | ||
68 | |||
69 | struct ti_ssp { | ||
70 | struct resource *res; | ||
71 | struct device *dev; | ||
72 | void __iomem *regs; | ||
73 | spinlock_t lock; | ||
74 | struct clk *clk; | ||
75 | int irq; | ||
76 | wait_queue_head_t wqh; | ||
77 | |||
78 | /* | ||
79 | * Some of the iosel2 register bits always read-back as 0, we need to | ||
80 | * remember these values so that we don't clobber previously set | ||
81 | * values. | ||
82 | */ | ||
83 | u32 iosel2; | ||
84 | }; | ||
85 | |||
86 | static inline struct ti_ssp *dev_to_ssp(struct device *dev) | ||
87 | { | ||
88 | return dev_get_drvdata(dev->parent); | ||
89 | } | ||
90 | |||
91 | static inline int dev_to_port(struct device *dev) | ||
92 | { | ||
93 | return to_platform_device(dev)->id; | ||
94 | } | ||
95 | |||
96 | /* Register Access Helpers, rmw() functions need to run locked */ | ||
97 | static inline u32 ssp_read(struct ti_ssp *ssp, int reg) | ||
98 | { | ||
99 | return __raw_readl(ssp->regs + reg); | ||
100 | } | ||
101 | |||
102 | static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val) | ||
103 | { | ||
104 | __raw_writel(val, ssp->regs + reg); | ||
105 | } | ||
106 | |||
107 | static inline void ssp_rmw(struct ti_ssp *ssp, int reg, u32 mask, u32 bits) | ||
108 | { | ||
109 | ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~mask) | bits); | ||
110 | } | ||
111 | |||
112 | static inline u32 ssp_port_read(struct ti_ssp *ssp, int port, int reg) | ||
113 | { | ||
114 | return ssp_read(ssp, ssp_port_base[port] + reg); | ||
115 | } | ||
116 | |||
117 | static inline void ssp_port_write(struct ti_ssp *ssp, int port, int reg, | ||
118 | u32 val) | ||
119 | { | ||
120 | ssp_write(ssp, ssp_port_base[port] + reg, val); | ||
121 | } | ||
122 | |||
123 | static inline void ssp_port_rmw(struct ti_ssp *ssp, int port, int reg, | ||
124 | u32 mask, u32 bits) | ||
125 | { | ||
126 | ssp_rmw(ssp, ssp_port_base[port] + reg, mask, bits); | ||
127 | } | ||
128 | |||
129 | static inline void ssp_port_clr_bits(struct ti_ssp *ssp, int port, int reg, | ||
130 | u32 bits) | ||
131 | { | ||
132 | ssp_port_rmw(ssp, port, reg, bits, 0); | ||
133 | } | ||
134 | |||
135 | static inline void ssp_port_set_bits(struct ti_ssp *ssp, int port, int reg, | ||
136 | u32 bits) | ||
137 | { | ||
138 | ssp_port_rmw(ssp, port, reg, 0, bits); | ||
139 | } | ||
140 | |||
141 | /* Called to setup port clock mode, caller must hold ssp->lock */ | ||
142 | static int __set_mode(struct ti_ssp *ssp, int port, int mode) | ||
143 | { | ||
144 | mode &= SSP_PORT_CONFIG_MASK; | ||
145 | ssp_port_rmw(ssp, port, PORT_CFG_1, SSP_PORT_CONFIG_MASK, mode); | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | int ti_ssp_set_mode(struct device *dev, int mode) | ||
151 | { | ||
152 | struct ti_ssp *ssp = dev_to_ssp(dev); | ||
153 | int port = dev_to_port(dev); | ||
154 | int ret; | ||
155 | |||
156 | spin_lock(&ssp->lock); | ||
157 | ret = __set_mode(ssp, port, mode); | ||
158 | spin_unlock(&ssp->lock); | ||
159 | |||
160 | return ret; | ||
161 | } | ||
162 | EXPORT_SYMBOL(ti_ssp_set_mode); | ||
163 | |||
164 | /* Called to setup iosel2, caller must hold ssp->lock */ | ||
165 | static void __set_iosel2(struct ti_ssp *ssp, u32 mask, u32 val) | ||
166 | { | ||
167 | ssp->iosel2 = (ssp->iosel2 & ~mask) | val; | ||
168 | ssp_write(ssp, REG_IOSEL_2, ssp->iosel2); | ||
169 | } | ||
170 | |||
171 | /* Called to setup port iosel, caller must hold ssp->lock */ | ||
172 | static void __set_iosel(struct ti_ssp *ssp, int port, u32 iosel) | ||
173 | { | ||
174 | unsigned val, shift = port ? 16 : 0; | ||
175 | |||
176 | /* IOSEL1 gets the least significant 16 bits */ | ||
177 | val = ssp_read(ssp, REG_IOSEL_1); | ||
178 | val &= 0xffff << (port ? 0 : 16); | ||
179 | val |= (iosel & 0xffff) << (port ? 16 : 0); | ||
180 | ssp_write(ssp, REG_IOSEL_1, val); | ||
181 | |||
182 | /* IOSEL2 gets the most significant 16 bits */ | ||
183 | val = (iosel >> 16) & 0x7; | ||
184 | __set_iosel2(ssp, 0x7 << shift, val << shift); | ||
185 | } | ||
186 | |||
187 | int ti_ssp_set_iosel(struct device *dev, u32 iosel) | ||
188 | { | ||
189 | struct ti_ssp *ssp = dev_to_ssp(dev); | ||
190 | int port = dev_to_port(dev); | ||
191 | |||
192 | spin_lock(&ssp->lock); | ||
193 | __set_iosel(ssp, port, iosel); | ||
194 | spin_unlock(&ssp->lock); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | EXPORT_SYMBOL(ti_ssp_set_iosel); | ||
199 | |||
200 | int ti_ssp_load(struct device *dev, int offs, u32* prog, int len) | ||
201 | { | ||
202 | struct ti_ssp *ssp = dev_to_ssp(dev); | ||
203 | int port = dev_to_port(dev); | ||
204 | int i; | ||
205 | |||
206 | if (len > SSP_PORT_SEQRAM_SIZE) | ||
207 | return -ENOSPC; | ||
208 | |||
209 | spin_lock(&ssp->lock); | ||
210 | |||
211 | /* Enable SeqRAM access */ | ||
212 | ssp_port_set_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN); | ||
213 | |||
214 | /* Copy code */ | ||
215 | for (i = 0; i < len; i++) { | ||
216 | __raw_writel(prog[i], ssp->regs + offs + 4*i + | ||
217 | ssp_port_seqram[port]); | ||
218 | } | ||
219 | |||
220 | /* Disable SeqRAM access */ | ||
221 | ssp_port_clr_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN); | ||
222 | |||
223 | spin_unlock(&ssp->lock); | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | EXPORT_SYMBOL(ti_ssp_load); | ||
228 | |||
229 | int ti_ssp_raw_read(struct device *dev) | ||
230 | { | ||
231 | struct ti_ssp *ssp = dev_to_ssp(dev); | ||
232 | int port = dev_to_port(dev); | ||
233 | int shift = port ? 27 : 11; | ||
234 | |||
235 | return (ssp_read(ssp, REG_IOSEL_2) >> shift) & 0xf; | ||
236 | } | ||
237 | EXPORT_SYMBOL(ti_ssp_raw_read); | ||
238 | |||
239 | int ti_ssp_raw_write(struct device *dev, u32 val) | ||
240 | { | ||
241 | struct ti_ssp *ssp = dev_to_ssp(dev); | ||
242 | int port = dev_to_port(dev), shift; | ||
243 | |||
244 | spin_lock(&ssp->lock); | ||
245 | |||
246 | shift = port ? 22 : 6; | ||
247 | val &= 0xf; | ||
248 | __set_iosel2(ssp, 0xf << shift, val << shift); | ||
249 | |||
250 | spin_unlock(&ssp->lock); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | EXPORT_SYMBOL(ti_ssp_raw_write); | ||
255 | |||
256 | static inline int __xfer_done(struct ti_ssp *ssp, int port) | ||
257 | { | ||
258 | return !(ssp_port_read(ssp, port, PORT_CFG_1) & SSP_BUSY); | ||
259 | } | ||
260 | |||
261 | int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output) | ||
262 | { | ||
263 | struct ti_ssp *ssp = dev_to_ssp(dev); | ||
264 | int port = dev_to_port(dev); | ||
265 | int ret; | ||
266 | |||
267 | if (pc & ~(0x3f)) | ||
268 | return -EINVAL; | ||
269 | |||
270 | /* Grab ssp->lock to serialize rmw on ssp registers */ | ||
271 | spin_lock(&ssp->lock); | ||
272 | |||
273 | ssp_port_write(ssp, port, PORT_ADDR, input >> 16); | ||
274 | ssp_port_write(ssp, port, PORT_DATA, input & 0xffff); | ||
275 | ssp_port_rmw(ssp, port, PORT_CFG_1, 0x3f, pc); | ||
276 | |||
277 | /* grab wait queue head lock to avoid race with the isr */ | ||
278 | spin_lock_irq(&ssp->wqh.lock); | ||
279 | |||
280 | /* kick off sequence execution in hardware */ | ||
281 | ssp_port_set_bits(ssp, port, PORT_CFG_1, SSP_START); | ||
282 | |||
283 | /* drop ssp lock; no register writes beyond this */ | ||
284 | spin_unlock(&ssp->lock); | ||
285 | |||
286 | ret = wait_event_interruptible_locked_irq(ssp->wqh, | ||
287 | __xfer_done(ssp, port)); | ||
288 | spin_unlock_irq(&ssp->wqh.lock); | ||
289 | |||
290 | if (ret < 0) | ||
291 | return ret; | ||
292 | |||
293 | if (output) { | ||
294 | *output = (ssp_port_read(ssp, port, PORT_ADDR) << 16) | | ||
295 | (ssp_port_read(ssp, port, PORT_DATA) & 0xffff); | ||
296 | } | ||
297 | |||
298 | ret = ssp_port_read(ssp, port, PORT_STATE) & 0x3f; /* stop address */ | ||
299 | |||
300 | return ret; | ||
301 | } | ||
302 | EXPORT_SYMBOL(ti_ssp_run); | ||
303 | |||
304 | static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data) | ||
305 | { | ||
306 | struct ti_ssp *ssp = dev_data; | ||
307 | |||
308 | spin_lock(&ssp->wqh.lock); | ||
309 | |||
310 | ssp_write(ssp, REG_INTR_ST, 0x3); | ||
311 | wake_up_locked(&ssp->wqh); | ||
312 | |||
313 | spin_unlock(&ssp->wqh.lock); | ||
314 | |||
315 | return IRQ_HANDLED; | ||
316 | } | ||
317 | |||
318 | static int __devinit ti_ssp_probe(struct platform_device *pdev) | ||
319 | { | ||
320 | static struct ti_ssp *ssp; | ||
321 | const struct ti_ssp_data *pdata = pdev->dev.platform_data; | ||
322 | int error = 0, prediv = 0xff, id; | ||
323 | unsigned long sysclk; | ||
324 | struct device *dev = &pdev->dev; | ||
325 | struct mfd_cell cells[2]; | ||
326 | |||
327 | ssp = kzalloc(sizeof(*ssp), GFP_KERNEL); | ||
328 | if (!ssp) { | ||
329 | dev_err(dev, "cannot allocate device info\n"); | ||
330 | return -ENOMEM; | ||
331 | } | ||
332 | |||
333 | ssp->dev = dev; | ||
334 | dev_set_drvdata(dev, ssp); | ||
335 | |||
336 | ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
337 | if (!ssp->res) { | ||
338 | error = -ENODEV; | ||
339 | dev_err(dev, "cannot determine register area\n"); | ||
340 | goto error_res; | ||
341 | } | ||
342 | |||
343 | if (!request_mem_region(ssp->res->start, resource_size(ssp->res), | ||
344 | pdev->name)) { | ||
345 | error = -ENOMEM; | ||
346 | dev_err(dev, "cannot claim register memory\n"); | ||
347 | goto error_res; | ||
348 | } | ||
349 | |||
350 | ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res)); | ||
351 | if (!ssp->regs) { | ||
352 | error = -ENOMEM; | ||
353 | dev_err(dev, "cannot map register memory\n"); | ||
354 | goto error_map; | ||
355 | } | ||
356 | |||
357 | ssp->clk = clk_get(dev, NULL); | ||
358 | if (IS_ERR(ssp->clk)) { | ||
359 | error = PTR_ERR(ssp->clk); | ||
360 | dev_err(dev, "cannot claim device clock\n"); | ||
361 | goto error_clk; | ||
362 | } | ||
363 | |||
364 | ssp->irq = platform_get_irq(pdev, 0); | ||
365 | if (ssp->irq < 0) { | ||
366 | error = -ENODEV; | ||
367 | dev_err(dev, "unknown irq\n"); | ||
368 | goto error_irq; | ||
369 | } | ||
370 | |||
371 | error = request_threaded_irq(ssp->irq, NULL, ti_ssp_interrupt, 0, | ||
372 | dev_name(dev), ssp); | ||
373 | if (error < 0) { | ||
374 | dev_err(dev, "cannot acquire irq\n"); | ||
375 | goto error_irq; | ||
376 | } | ||
377 | |||
378 | spin_lock_init(&ssp->lock); | ||
379 | init_waitqueue_head(&ssp->wqh); | ||
380 | |||
381 | /* Power on and initialize SSP */ | ||
382 | error = clk_enable(ssp->clk); | ||
383 | if (error) { | ||
384 | dev_err(dev, "cannot enable device clock\n"); | ||
385 | goto error_enable; | ||
386 | } | ||
387 | |||
388 | /* Reset registers to a sensible known state */ | ||
389 | ssp_write(ssp, REG_IOSEL_1, 0); | ||
390 | ssp_write(ssp, REG_IOSEL_2, 0); | ||
391 | ssp_write(ssp, REG_INTR_EN, 0x3); | ||
392 | ssp_write(ssp, REG_INTR_ST, 0x3); | ||
393 | ssp_write(ssp, REG_TEST_CTRL, 0); | ||
394 | ssp_port_write(ssp, 0, PORT_CFG_1, SSP_PORT_ASL); | ||
395 | ssp_port_write(ssp, 1, PORT_CFG_1, SSP_PORT_ASL); | ||
396 | ssp_port_write(ssp, 0, PORT_CFG_2, SSP_PORT_CFO1); | ||
397 | ssp_port_write(ssp, 1, PORT_CFG_2, SSP_PORT_CFO1); | ||
398 | |||
399 | sysclk = clk_get_rate(ssp->clk); | ||
400 | if (pdata && pdata->out_clock) | ||
401 | prediv = (sysclk / pdata->out_clock) - 1; | ||
402 | prediv = clamp(prediv, 0, 0xff); | ||
403 | ssp_rmw(ssp, REG_PREDIV, 0xff, prediv); | ||
404 | |||
405 | memset(cells, 0, sizeof(cells)); | ||
406 | for (id = 0; id < 2; id++) { | ||
407 | const struct ti_ssp_dev_data *data = &pdata->dev_data[id]; | ||
408 | |||
409 | cells[id].id = id; | ||
410 | cells[id].name = data->dev_name; | ||
411 | cells[id].platform_data = data->pdata; | ||
412 | cells[id].data_size = data->pdata_size; | ||
413 | } | ||
414 | |||
415 | error = mfd_add_devices(dev, 0, cells, 2, NULL, 0); | ||
416 | if (error < 0) { | ||
417 | dev_err(dev, "cannot add mfd cells\n"); | ||
418 | goto error_enable; | ||
419 | } | ||
420 | |||
421 | return 0; | ||
422 | |||
423 | error_enable: | ||
424 | free_irq(ssp->irq, ssp); | ||
425 | error_irq: | ||
426 | clk_put(ssp->clk); | ||
427 | error_clk: | ||
428 | iounmap(ssp->regs); | ||
429 | error_map: | ||
430 | release_mem_region(ssp->res->start, resource_size(ssp->res)); | ||
431 | error_res: | ||
432 | kfree(ssp); | ||
433 | return error; | ||
434 | } | ||
435 | |||
436 | static int __devexit ti_ssp_remove(struct platform_device *pdev) | ||
437 | { | ||
438 | struct device *dev = &pdev->dev; | ||
439 | struct ti_ssp *ssp = dev_get_drvdata(dev); | ||
440 | |||
441 | mfd_remove_devices(dev); | ||
442 | clk_disable(ssp->clk); | ||
443 | free_irq(ssp->irq, ssp); | ||
444 | clk_put(ssp->clk); | ||
445 | iounmap(ssp->regs); | ||
446 | release_mem_region(ssp->res->start, resource_size(ssp->res)); | ||
447 | kfree(ssp); | ||
448 | dev_set_drvdata(dev, NULL); | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static struct platform_driver ti_ssp_driver = { | ||
453 | .probe = ti_ssp_probe, | ||
454 | .remove = __devexit_p(ti_ssp_remove), | ||
455 | .driver = { | ||
456 | .name = "ti-ssp", | ||
457 | .owner = THIS_MODULE, | ||
458 | } | ||
459 | }; | ||
460 | |||
461 | static int __init ti_ssp_init(void) | ||
462 | { | ||
463 | return platform_driver_register(&ti_ssp_driver); | ||
464 | } | ||
465 | module_init(ti_ssp_init); | ||
466 | |||
467 | static void __exit ti_ssp_exit(void) | ||
468 | { | ||
469 | platform_driver_unregister(&ti_ssp_driver); | ||
470 | } | ||
471 | module_exit(ti_ssp_exit); | ||
472 | |||
473 | MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver"); | ||
474 | MODULE_AUTHOR("Cyril Chemparathy"); | ||
475 | MODULE_LICENSE("GPL"); | ||
476 | MODULE_ALIAS("platform:ti-ssp"); | ||
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index ac5995026c88..69272e4e3459 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c | |||
@@ -40,9 +40,12 @@ | |||
40 | #include <linux/spi/mc33880.h> | 40 | #include <linux/spi/mc33880.h> |
41 | 41 | ||
42 | #include <media/timb_radio.h> | 42 | #include <media/timb_radio.h> |
43 | #include <media/timb_video.h> | ||
43 | 44 | ||
44 | #include <linux/timb_dma.h> | 45 | #include <linux/timb_dma.h> |
45 | 46 | ||
47 | #include <linux/ks8842.h> | ||
48 | |||
46 | #include "timberdale.h" | 49 | #include "timberdale.h" |
47 | 50 | ||
48 | #define DRIVER_NAME "timberdale" | 51 | #define DRIVER_NAME "timberdale" |
@@ -161,6 +164,12 @@ static const __devinitconst struct resource timberdale_spi_resources[] = { | |||
161 | }, | 164 | }, |
162 | }; | 165 | }; |
163 | 166 | ||
167 | static __devinitdata struct ks8842_platform_data | ||
168 | timberdale_ks8842_platform_data = { | ||
169 | .rx_dma_channel = DMA_ETH_RX, | ||
170 | .tx_dma_channel = DMA_ETH_TX | ||
171 | }; | ||
172 | |||
164 | static const __devinitconst struct resource timberdale_eth_resources[] = { | 173 | static const __devinitconst struct resource timberdale_eth_resources[] = { |
165 | { | 174 | { |
166 | .start = ETHOFFSET, | 175 | .start = ETHOFFSET, |
@@ -238,7 +247,23 @@ static const __devinitconst struct resource timberdale_uartlite_resources[] = { | |||
238 | }, | 247 | }, |
239 | }; | 248 | }; |
240 | 249 | ||
241 | static const __devinitconst struct resource timberdale_radio_resources[] = { | 250 | static __devinitdata struct i2c_board_info timberdale_adv7180_i2c_board_info = { |
251 | /* Requires jumper JP9 to be off */ | ||
252 | I2C_BOARD_INFO("adv7180", 0x42 >> 1), | ||
253 | .irq = IRQ_TIMBERDALE_ADV7180 | ||
254 | }; | ||
255 | |||
256 | static __devinitdata struct timb_video_platform_data | ||
257 | timberdale_video_platform_data = { | ||
258 | .dma_channel = DMA_VIDEO_RX, | ||
259 | .i2c_adapter = 0, | ||
260 | .encoder = { | ||
261 | .info = &timberdale_adv7180_i2c_board_info | ||
262 | } | ||
263 | }; | ||
264 | |||
265 | static const __devinitconst struct resource | ||
266 | timberdale_radio_resources[] = { | ||
242 | { | 267 | { |
243 | .start = RDSOFFSET, | 268 | .start = RDSOFFSET, |
244 | .end = RDSEND, | 269 | .end = RDSEND, |
@@ -263,15 +288,25 @@ static __devinitdata struct timb_radio_platform_data | |||
263 | timberdale_radio_platform_data = { | 288 | timberdale_radio_platform_data = { |
264 | .i2c_adapter = 0, | 289 | .i2c_adapter = 0, |
265 | .tuner = { | 290 | .tuner = { |
266 | .module_name = "tef6862", | ||
267 | .info = &timberdale_tef6868_i2c_board_info | 291 | .info = &timberdale_tef6868_i2c_board_info |
268 | }, | 292 | }, |
269 | .dsp = { | 293 | .dsp = { |
270 | .module_name = "saa7706h", | ||
271 | .info = &timberdale_saa7706_i2c_board_info | 294 | .info = &timberdale_saa7706_i2c_board_info |
272 | } | 295 | } |
273 | }; | 296 | }; |
274 | 297 | ||
298 | static const __devinitconst struct resource timberdale_video_resources[] = { | ||
299 | { | ||
300 | .start = LOGIWOFFSET, | ||
301 | .end = LOGIWEND, | ||
302 | .flags = IORESOURCE_MEM, | ||
303 | }, | ||
304 | /* | ||
305 | note that the "frame buffer" is located in DMA area | ||
306 | starting at 0x1200000 | ||
307 | */ | ||
308 | }; | ||
309 | |||
275 | static __devinitdata struct timb_dma_platform_data timb_dma_platform_data = { | 310 | static __devinitdata struct timb_dma_platform_data timb_dma_platform_data = { |
276 | .nr_channels = 10, | 311 | .nr_channels = 10, |
277 | .channels = { | 312 | .channels = { |
@@ -350,7 +385,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { | |||
350 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), | 385 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), |
351 | .resources = timberdale_dma_resources, | 386 | .resources = timberdale_dma_resources, |
352 | .platform_data = &timb_dma_platform_data, | 387 | .platform_data = &timb_dma_platform_data, |
353 | .data_size = sizeof(timb_dma_platform_data), | 388 | .pdata_size = sizeof(timb_dma_platform_data), |
354 | }, | 389 | }, |
355 | { | 390 | { |
356 | .name = "timb-uart", | 391 | .name = "timb-uart", |
@@ -362,33 +397,42 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { | |||
362 | .num_resources = ARRAY_SIZE(timberdale_xiic_resources), | 397 | .num_resources = ARRAY_SIZE(timberdale_xiic_resources), |
363 | .resources = timberdale_xiic_resources, | 398 | .resources = timberdale_xiic_resources, |
364 | .platform_data = &timberdale_xiic_platform_data, | 399 | .platform_data = &timberdale_xiic_platform_data, |
365 | .data_size = sizeof(timberdale_xiic_platform_data), | 400 | .pdata_size = sizeof(timberdale_xiic_platform_data), |
366 | }, | 401 | }, |
367 | { | 402 | { |
368 | .name = "timb-gpio", | 403 | .name = "timb-gpio", |
369 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), | 404 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), |
370 | .resources = timberdale_gpio_resources, | 405 | .resources = timberdale_gpio_resources, |
371 | .platform_data = &timberdale_gpio_platform_data, | 406 | .platform_data = &timberdale_gpio_platform_data, |
372 | .data_size = sizeof(timberdale_gpio_platform_data), | 407 | .pdata_size = sizeof(timberdale_gpio_platform_data), |
408 | }, | ||
409 | { | ||
410 | .name = "timb-video", | ||
411 | .num_resources = ARRAY_SIZE(timberdale_video_resources), | ||
412 | .resources = timberdale_video_resources, | ||
413 | .platform_data = &timberdale_video_platform_data, | ||
414 | .pdata_size = sizeof(timberdale_video_platform_data), | ||
373 | }, | 415 | }, |
374 | { | 416 | { |
375 | .name = "timb-radio", | 417 | .name = "timb-radio", |
376 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), | 418 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), |
377 | .resources = timberdale_radio_resources, | 419 | .resources = timberdale_radio_resources, |
378 | .platform_data = &timberdale_radio_platform_data, | 420 | .platform_data = &timberdale_radio_platform_data, |
379 | .data_size = sizeof(timberdale_radio_platform_data), | 421 | .pdata_size = sizeof(timberdale_radio_platform_data), |
380 | }, | 422 | }, |
381 | { | 423 | { |
382 | .name = "xilinx_spi", | 424 | .name = "xilinx_spi", |
383 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), | 425 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), |
384 | .resources = timberdale_spi_resources, | 426 | .resources = timberdale_spi_resources, |
385 | .platform_data = &timberdale_xspi_platform_data, | 427 | .platform_data = &timberdale_xspi_platform_data, |
386 | .data_size = sizeof(timberdale_xspi_platform_data), | 428 | .pdata_size = sizeof(timberdale_xspi_platform_data), |
387 | }, | 429 | }, |
388 | { | 430 | { |
389 | .name = "ks8842", | 431 | .name = "ks8842", |
390 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), | 432 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), |
391 | .resources = timberdale_eth_resources, | 433 | .resources = timberdale_eth_resources, |
434 | .platform_data = &timberdale_ks8842_platform_data, | ||
435 | .pdata_size = sizeof(timberdale_ks8842_platform_data), | ||
392 | }, | 436 | }, |
393 | }; | 437 | }; |
394 | 438 | ||
@@ -398,7 +442,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { | |||
398 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), | 442 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), |
399 | .resources = timberdale_dma_resources, | 443 | .resources = timberdale_dma_resources, |
400 | .platform_data = &timb_dma_platform_data, | 444 | .platform_data = &timb_dma_platform_data, |
401 | .data_size = sizeof(timb_dma_platform_data), | 445 | .pdata_size = sizeof(timb_dma_platform_data), |
402 | }, | 446 | }, |
403 | { | 447 | { |
404 | .name = "timb-uart", | 448 | .name = "timb-uart", |
@@ -415,14 +459,14 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { | |||
415 | .num_resources = ARRAY_SIZE(timberdale_xiic_resources), | 459 | .num_resources = ARRAY_SIZE(timberdale_xiic_resources), |
416 | .resources = timberdale_xiic_resources, | 460 | .resources = timberdale_xiic_resources, |
417 | .platform_data = &timberdale_xiic_platform_data, | 461 | .platform_data = &timberdale_xiic_platform_data, |
418 | .data_size = sizeof(timberdale_xiic_platform_data), | 462 | .pdata_size = sizeof(timberdale_xiic_platform_data), |
419 | }, | 463 | }, |
420 | { | 464 | { |
421 | .name = "timb-gpio", | 465 | .name = "timb-gpio", |
422 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), | 466 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), |
423 | .resources = timberdale_gpio_resources, | 467 | .resources = timberdale_gpio_resources, |
424 | .platform_data = &timberdale_gpio_platform_data, | 468 | .platform_data = &timberdale_gpio_platform_data, |
425 | .data_size = sizeof(timberdale_gpio_platform_data), | 469 | .pdata_size = sizeof(timberdale_gpio_platform_data), |
426 | }, | 470 | }, |
427 | { | 471 | { |
428 | .name = "timb-mlogicore", | 472 | .name = "timb-mlogicore", |
@@ -430,23 +474,32 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { | |||
430 | .resources = timberdale_mlogicore_resources, | 474 | .resources = timberdale_mlogicore_resources, |
431 | }, | 475 | }, |
432 | { | 476 | { |
477 | .name = "timb-video", | ||
478 | .num_resources = ARRAY_SIZE(timberdale_video_resources), | ||
479 | .resources = timberdale_video_resources, | ||
480 | .platform_data = &timberdale_video_platform_data, | ||
481 | .pdata_size = sizeof(timberdale_video_platform_data), | ||
482 | }, | ||
483 | { | ||
433 | .name = "timb-radio", | 484 | .name = "timb-radio", |
434 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), | 485 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), |
435 | .resources = timberdale_radio_resources, | 486 | .resources = timberdale_radio_resources, |
436 | .platform_data = &timberdale_radio_platform_data, | 487 | .platform_data = &timberdale_radio_platform_data, |
437 | .data_size = sizeof(timberdale_radio_platform_data), | 488 | .pdata_size = sizeof(timberdale_radio_platform_data), |
438 | }, | 489 | }, |
439 | { | 490 | { |
440 | .name = "xilinx_spi", | 491 | .name = "xilinx_spi", |
441 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), | 492 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), |
442 | .resources = timberdale_spi_resources, | 493 | .resources = timberdale_spi_resources, |
443 | .platform_data = &timberdale_xspi_platform_data, | 494 | .platform_data = &timberdale_xspi_platform_data, |
444 | .data_size = sizeof(timberdale_xspi_platform_data), | 495 | .pdata_size = sizeof(timberdale_xspi_platform_data), |
445 | }, | 496 | }, |
446 | { | 497 | { |
447 | .name = "ks8842", | 498 | .name = "ks8842", |
448 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), | 499 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), |
449 | .resources = timberdale_eth_resources, | 500 | .resources = timberdale_eth_resources, |
501 | .platform_data = &timberdale_ks8842_platform_data, | ||
502 | .pdata_size = sizeof(timberdale_ks8842_platform_data), | ||
450 | }, | 503 | }, |
451 | }; | 504 | }; |
452 | 505 | ||
@@ -456,7 +509,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { | |||
456 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), | 509 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), |
457 | .resources = timberdale_dma_resources, | 510 | .resources = timberdale_dma_resources, |
458 | .platform_data = &timb_dma_platform_data, | 511 | .platform_data = &timb_dma_platform_data, |
459 | .data_size = sizeof(timb_dma_platform_data), | 512 | .pdata_size = sizeof(timb_dma_platform_data), |
460 | }, | 513 | }, |
461 | { | 514 | { |
462 | .name = "timb-uart", | 515 | .name = "timb-uart", |
@@ -468,28 +521,35 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { | |||
468 | .num_resources = ARRAY_SIZE(timberdale_xiic_resources), | 521 | .num_resources = ARRAY_SIZE(timberdale_xiic_resources), |
469 | .resources = timberdale_xiic_resources, | 522 | .resources = timberdale_xiic_resources, |
470 | .platform_data = &timberdale_xiic_platform_data, | 523 | .platform_data = &timberdale_xiic_platform_data, |
471 | .data_size = sizeof(timberdale_xiic_platform_data), | 524 | .pdata_size = sizeof(timberdale_xiic_platform_data), |
472 | }, | 525 | }, |
473 | { | 526 | { |
474 | .name = "timb-gpio", | 527 | .name = "timb-gpio", |
475 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), | 528 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), |
476 | .resources = timberdale_gpio_resources, | 529 | .resources = timberdale_gpio_resources, |
477 | .platform_data = &timberdale_gpio_platform_data, | 530 | .platform_data = &timberdale_gpio_platform_data, |
478 | .data_size = sizeof(timberdale_gpio_platform_data), | 531 | .pdata_size = sizeof(timberdale_gpio_platform_data), |
532 | }, | ||
533 | { | ||
534 | .name = "timb-video", | ||
535 | .num_resources = ARRAY_SIZE(timberdale_video_resources), | ||
536 | .resources = timberdale_video_resources, | ||
537 | .platform_data = &timberdale_video_platform_data, | ||
538 | .pdata_size = sizeof(timberdale_video_platform_data), | ||
479 | }, | 539 | }, |
480 | { | 540 | { |
481 | .name = "timb-radio", | 541 | .name = "timb-radio", |
482 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), | 542 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), |
483 | .resources = timberdale_radio_resources, | 543 | .resources = timberdale_radio_resources, |
484 | .platform_data = &timberdale_radio_platform_data, | 544 | .platform_data = &timberdale_radio_platform_data, |
485 | .data_size = sizeof(timberdale_radio_platform_data), | 545 | .pdata_size = sizeof(timberdale_radio_platform_data), |
486 | }, | 546 | }, |
487 | { | 547 | { |
488 | .name = "xilinx_spi", | 548 | .name = "xilinx_spi", |
489 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), | 549 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), |
490 | .resources = timberdale_spi_resources, | 550 | .resources = timberdale_spi_resources, |
491 | .platform_data = &timberdale_xspi_platform_data, | 551 | .platform_data = &timberdale_xspi_platform_data, |
492 | .data_size = sizeof(timberdale_xspi_platform_data), | 552 | .pdata_size = sizeof(timberdale_xspi_platform_data), |
493 | }, | 553 | }, |
494 | }; | 554 | }; |
495 | 555 | ||
@@ -499,7 +559,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { | |||
499 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), | 559 | .num_resources = ARRAY_SIZE(timberdale_dma_resources), |
500 | .resources = timberdale_dma_resources, | 560 | .resources = timberdale_dma_resources, |
501 | .platform_data = &timb_dma_platform_data, | 561 | .platform_data = &timb_dma_platform_data, |
502 | .data_size = sizeof(timb_dma_platform_data), | 562 | .pdata_size = sizeof(timb_dma_platform_data), |
503 | }, | 563 | }, |
504 | { | 564 | { |
505 | .name = "timb-uart", | 565 | .name = "timb-uart", |
@@ -511,33 +571,42 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { | |||
511 | .num_resources = ARRAY_SIZE(timberdale_ocores_resources), | 571 | .num_resources = ARRAY_SIZE(timberdale_ocores_resources), |
512 | .resources = timberdale_ocores_resources, | 572 | .resources = timberdale_ocores_resources, |
513 | .platform_data = &timberdale_ocores_platform_data, | 573 | .platform_data = &timberdale_ocores_platform_data, |
514 | .data_size = sizeof(timberdale_ocores_platform_data), | 574 | .pdata_size = sizeof(timberdale_ocores_platform_data), |
515 | }, | 575 | }, |
516 | { | 576 | { |
517 | .name = "timb-gpio", | 577 | .name = "timb-gpio", |
518 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), | 578 | .num_resources = ARRAY_SIZE(timberdale_gpio_resources), |
519 | .resources = timberdale_gpio_resources, | 579 | .resources = timberdale_gpio_resources, |
520 | .platform_data = &timberdale_gpio_platform_data, | 580 | .platform_data = &timberdale_gpio_platform_data, |
521 | .data_size = sizeof(timberdale_gpio_platform_data), | 581 | .pdata_size = sizeof(timberdale_gpio_platform_data), |
582 | }, | ||
583 | { | ||
584 | .name = "timb-video", | ||
585 | .num_resources = ARRAY_SIZE(timberdale_video_resources), | ||
586 | .resources = timberdale_video_resources, | ||
587 | .platform_data = &timberdale_video_platform_data, | ||
588 | .pdata_size = sizeof(timberdale_video_platform_data), | ||
522 | }, | 589 | }, |
523 | { | 590 | { |
524 | .name = "timb-radio", | 591 | .name = "timb-radio", |
525 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), | 592 | .num_resources = ARRAY_SIZE(timberdale_radio_resources), |
526 | .resources = timberdale_radio_resources, | 593 | .resources = timberdale_radio_resources, |
527 | .platform_data = &timberdale_radio_platform_data, | 594 | .platform_data = &timberdale_radio_platform_data, |
528 | .data_size = sizeof(timberdale_radio_platform_data), | 595 | .pdata_size = sizeof(timberdale_radio_platform_data), |
529 | }, | 596 | }, |
530 | { | 597 | { |
531 | .name = "xilinx_spi", | 598 | .name = "xilinx_spi", |
532 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), | 599 | .num_resources = ARRAY_SIZE(timberdale_spi_resources), |
533 | .resources = timberdale_spi_resources, | 600 | .resources = timberdale_spi_resources, |
534 | .platform_data = &timberdale_xspi_platform_data, | 601 | .platform_data = &timberdale_xspi_platform_data, |
535 | .data_size = sizeof(timberdale_xspi_platform_data), | 602 | .pdata_size = sizeof(timberdale_xspi_platform_data), |
536 | }, | 603 | }, |
537 | { | 604 | { |
538 | .name = "ks8842", | 605 | .name = "ks8842", |
539 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), | 606 | .num_resources = ARRAY_SIZE(timberdale_eth_resources), |
540 | .resources = timberdale_eth_resources, | 607 | .resources = timberdale_eth_resources, |
608 | .platform_data = &timberdale_ks8842_platform_data, | ||
609 | .pdata_size = sizeof(timberdale_ks8842_platform_data), | ||
541 | }, | 610 | }, |
542 | }; | 611 | }; |
543 | 612 | ||
diff --git a/drivers/mfd/timberdale.h b/drivers/mfd/timberdale.h index c11bf6ebfe00..4412acd826fa 100644 --- a/drivers/mfd/timberdale.h +++ b/drivers/mfd/timberdale.h | |||
@@ -23,7 +23,7 @@ | |||
23 | #ifndef MFD_TIMBERDALE_H | 23 | #ifndef MFD_TIMBERDALE_H |
24 | #define MFD_TIMBERDALE_H | 24 | #define MFD_TIMBERDALE_H |
25 | 25 | ||
26 | #define DRV_VERSION "0.2" | 26 | #define DRV_VERSION "0.3" |
27 | 27 | ||
28 | /* This driver only support versions >= 3.8 and < 4.0 */ | 28 | /* This driver only support versions >= 3.8 and < 4.0 */ |
29 | #define TIMB_SUPPORTED_MAJOR 3 | 29 | #define TIMB_SUPPORTED_MAJOR 3 |
diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c new file mode 100644 index 000000000000..a293b978e27c --- /dev/null +++ b/drivers/mfd/tps6105x.c | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * Core driver for TPS61050/61052 boost converters, used for while LED | ||
3 | * driving, audio power amplification, white LED flash, and generic | ||
4 | * boost conversion. Additionally it provides a 1-bit GPIO pin (out or in) | ||
5 | * and a flash synchronization pin to synchronize flash events when used as | ||
6 | * flashgun. | ||
7 | * | ||
8 | * Copyright (C) 2011 ST-Ericsson SA | ||
9 | * Written on behalf of Linaro for ST-Ericsson | ||
10 | * | ||
11 | * Author: Linus Walleij <linus.walleij@linaro.org> | ||
12 | * | ||
13 | * License terms: GNU General Public License (GPL) version 2 | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/mutex.h> | ||
20 | #include <linux/gpio.h> | ||
21 | #include <linux/spinlock.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/err.h> | ||
24 | #include <linux/regulator/driver.h> | ||
25 | #include <linux/mfd/core.h> | ||
26 | #include <linux/mfd/tps6105x.h> | ||
27 | |||
28 | int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value) | ||
29 | { | ||
30 | int ret; | ||
31 | |||
32 | ret = mutex_lock_interruptible(&tps6105x->lock); | ||
33 | if (ret) | ||
34 | return ret; | ||
35 | ret = i2c_smbus_write_byte_data(tps6105x->client, reg, value); | ||
36 | mutex_unlock(&tps6105x->lock); | ||
37 | if (ret < 0) | ||
38 | return ret; | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | EXPORT_SYMBOL(tps6105x_set); | ||
43 | |||
44 | int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf) | ||
45 | { | ||
46 | int ret; | ||
47 | |||
48 | ret = mutex_lock_interruptible(&tps6105x->lock); | ||
49 | if (ret) | ||
50 | return ret; | ||
51 | ret = i2c_smbus_read_byte_data(tps6105x->client, reg); | ||
52 | mutex_unlock(&tps6105x->lock); | ||
53 | if (ret < 0) | ||
54 | return ret; | ||
55 | |||
56 | *buf = ret; | ||
57 | return 0; | ||
58 | } | ||
59 | EXPORT_SYMBOL(tps6105x_get); | ||
60 | |||
61 | /* | ||
62 | * Masks off the bits in the mask and sets the bits in the bitvalues | ||
63 | * parameter in one atomic operation | ||
64 | */ | ||
65 | int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg, | ||
66 | u8 bitmask, u8 bitvalues) | ||
67 | { | ||
68 | int ret; | ||
69 | u8 regval; | ||
70 | |||
71 | ret = mutex_lock_interruptible(&tps6105x->lock); | ||
72 | if (ret) | ||
73 | return ret; | ||
74 | ret = i2c_smbus_read_byte_data(tps6105x->client, reg); | ||
75 | if (ret < 0) | ||
76 | goto fail; | ||
77 | regval = ret; | ||
78 | regval = (~bitmask & regval) | (bitmask & bitvalues); | ||
79 | ret = i2c_smbus_write_byte_data(tps6105x->client, reg, regval); | ||
80 | fail: | ||
81 | mutex_unlock(&tps6105x->lock); | ||
82 | if (ret < 0) | ||
83 | return ret; | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | EXPORT_SYMBOL(tps6105x_mask_and_set); | ||
88 | |||
89 | static int __devinit tps6105x_startup(struct tps6105x *tps6105x) | ||
90 | { | ||
91 | int ret; | ||
92 | u8 regval; | ||
93 | |||
94 | ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val); | ||
95 | if (ret) | ||
96 | return ret; | ||
97 | switch (regval >> TPS6105X_REG0_MODE_SHIFT) { | ||
98 | case TPS6105X_REG0_MODE_SHUTDOWN: | ||
99 | dev_info(&tps6105x->client->dev, | ||
100 | "TPS6105x found in SHUTDOWN mode\n"); | ||
101 | break; | ||
102 | case TPS6105X_REG0_MODE_TORCH: | ||
103 | dev_info(&tps6105x->client->dev, | ||
104 | "TPS6105x found in TORCH mode\n"); | ||
105 | break; | ||
106 | case TPS6105X_REG0_MODE_TORCH_FLASH: | ||
107 | dev_info(&tps6105x->client->dev, | ||
108 | "TPS6105x found in FLASH mode\n"); | ||
109 | break; | ||
110 | case TPS6105X_REG0_MODE_VOLTAGE: | ||
111 | dev_info(&tps6105x->client->dev, | ||
112 | "TPS6105x found in VOLTAGE mode\n"); | ||
113 | break; | ||
114 | default: | ||
115 | break; | ||
116 | } | ||
117 | |||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * MFD cells - we have one cell which is selected operation | ||
123 | * mode, and we always have a GPIO cell. | ||
124 | */ | ||
125 | static struct mfd_cell tps6105x_cells[] = { | ||
126 | { | ||
127 | /* name will be runtime assigned */ | ||
128 | .id = -1, | ||
129 | }, | ||
130 | { | ||
131 | .name = "tps6105x-gpio", | ||
132 | .id = -1, | ||
133 | }, | ||
134 | }; | ||
135 | |||
136 | static int __devinit tps6105x_probe(struct i2c_client *client, | ||
137 | const struct i2c_device_id *id) | ||
138 | { | ||
139 | struct tps6105x *tps6105x; | ||
140 | struct tps6105x_platform_data *pdata; | ||
141 | int ret; | ||
142 | int i; | ||
143 | |||
144 | tps6105x = kmalloc(sizeof(*tps6105x), GFP_KERNEL); | ||
145 | if (!tps6105x) | ||
146 | return -ENOMEM; | ||
147 | |||
148 | i2c_set_clientdata(client, tps6105x); | ||
149 | tps6105x->client = client; | ||
150 | pdata = client->dev.platform_data; | ||
151 | tps6105x->pdata = pdata; | ||
152 | mutex_init(&tps6105x->lock); | ||
153 | |||
154 | ret = tps6105x_startup(tps6105x); | ||
155 | if (ret) { | ||
156 | dev_err(&client->dev, "chip initialization failed\n"); | ||
157 | goto fail; | ||
158 | } | ||
159 | |||
160 | /* Remove warning texts when you implement new cell drivers */ | ||
161 | switch (pdata->mode) { | ||
162 | case TPS6105X_MODE_SHUTDOWN: | ||
163 | dev_info(&client->dev, | ||
164 | "present, not used for anything, only GPIO\n"); | ||
165 | break; | ||
166 | case TPS6105X_MODE_TORCH: | ||
167 | tps6105x_cells[0].name = "tps6105x-leds"; | ||
168 | dev_warn(&client->dev, | ||
169 | "torch mode is unsupported\n"); | ||
170 | break; | ||
171 | case TPS6105X_MODE_TORCH_FLASH: | ||
172 | tps6105x_cells[0].name = "tps6105x-flash"; | ||
173 | dev_warn(&client->dev, | ||
174 | "flash mode is unsupported\n"); | ||
175 | break; | ||
176 | case TPS6105X_MODE_VOLTAGE: | ||
177 | tps6105x_cells[0].name ="tps6105x-regulator"; | ||
178 | break; | ||
179 | default: | ||
180 | break; | ||
181 | } | ||
182 | |||
183 | /* Set up and register the platform devices. */ | ||
184 | for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) { | ||
185 | /* One state holder for all drivers, this is simple */ | ||
186 | tps6105x_cells[i].platform_data = tps6105x; | ||
187 | tps6105x_cells[i].pdata_size = sizeof(*tps6105x); | ||
188 | } | ||
189 | |||
190 | ret = mfd_add_devices(&client->dev, 0, tps6105x_cells, | ||
191 | ARRAY_SIZE(tps6105x_cells), NULL, 0); | ||
192 | if (ret) | ||
193 | goto fail; | ||
194 | |||
195 | return 0; | ||
196 | |||
197 | fail: | ||
198 | kfree(tps6105x); | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static int __devexit tps6105x_remove(struct i2c_client *client) | ||
203 | { | ||
204 | struct tps6105x *tps6105x = i2c_get_clientdata(client); | ||
205 | |||
206 | mfd_remove_devices(&client->dev); | ||
207 | |||
208 | /* Put chip in shutdown mode */ | ||
209 | tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0, | ||
210 | TPS6105X_REG0_MODE_MASK, | ||
211 | TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT); | ||
212 | |||
213 | kfree(tps6105x); | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static const struct i2c_device_id tps6105x_id[] = { | ||
218 | { "tps61050", 0 }, | ||
219 | { "tps61052", 0 }, | ||
220 | { } | ||
221 | }; | ||
222 | MODULE_DEVICE_TABLE(i2c, tps6105x_id); | ||
223 | |||
224 | static struct i2c_driver tps6105x_driver = { | ||
225 | .driver = { | ||
226 | .name = "tps6105x", | ||
227 | }, | ||
228 | .probe = tps6105x_probe, | ||
229 | .remove = __devexit_p(tps6105x_remove), | ||
230 | .id_table = tps6105x_id, | ||
231 | }; | ||
232 | |||
233 | static int __init tps6105x_init(void) | ||
234 | { | ||
235 | return i2c_add_driver(&tps6105x_driver); | ||
236 | } | ||
237 | subsys_initcall(tps6105x_init); | ||
238 | |||
239 | static void __exit tps6105x_exit(void) | ||
240 | { | ||
241 | i2c_del_driver(&tps6105x_driver); | ||
242 | } | ||
243 | module_exit(tps6105x_exit); | ||
244 | |||
245 | MODULE_AUTHOR("Linus Walleij"); | ||
246 | MODULE_DESCRIPTION("TPS6105x White LED Boost Converter Driver"); | ||
247 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index d0016b67d125..93d5fdf020c7 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c | |||
@@ -34,7 +34,7 @@ | |||
34 | 34 | ||
35 | #include <linux/i2c/tps65010.h> | 35 | #include <linux/i2c/tps65010.h> |
36 | 36 | ||
37 | #include <asm/gpio.h> | 37 | #include <linux/gpio.h> |
38 | 38 | ||
39 | 39 | ||
40 | /*-------------------------------------------------------------------------*/ | 40 | /*-------------------------------------------------------------------------*/ |
@@ -242,7 +242,7 @@ static int dbg_show(struct seq_file *s, void *_) | |||
242 | seq_printf(s, "mask2 %s\n", buf); | 242 | seq_printf(s, "mask2 %s\n", buf); |
243 | /* ignore ackint2 */ | 243 | /* ignore ackint2 */ |
244 | 244 | ||
245 | (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); | 245 | schedule_delayed_work(&tps->work, POWER_POLL_DELAY); |
246 | 246 | ||
247 | 247 | ||
248 | /* VMAIN voltage, enable lowpower, etc */ | 248 | /* VMAIN voltage, enable lowpower, etc */ |
@@ -400,7 +400,7 @@ static void tps65010_interrupt(struct tps65010 *tps) | |||
400 | && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC))) | 400 | && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC))) |
401 | poll = 1; | 401 | poll = 1; |
402 | if (poll) | 402 | if (poll) |
403 | (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); | 403 | schedule_delayed_work(&tps->work, POWER_POLL_DELAY); |
404 | 404 | ||
405 | /* also potentially gpio-in rise or fall */ | 405 | /* also potentially gpio-in rise or fall */ |
406 | } | 406 | } |
@@ -410,7 +410,7 @@ static void tps65010_work(struct work_struct *work) | |||
410 | { | 410 | { |
411 | struct tps65010 *tps; | 411 | struct tps65010 *tps; |
412 | 412 | ||
413 | tps = container_of(work, struct tps65010, work.work); | 413 | tps = container_of(to_delayed_work(work), struct tps65010, work); |
414 | mutex_lock(&tps->lock); | 414 | mutex_lock(&tps->lock); |
415 | 415 | ||
416 | tps65010_interrupt(tps); | 416 | tps65010_interrupt(tps); |
@@ -448,7 +448,7 @@ static irqreturn_t tps65010_irq(int irq, void *_tps) | |||
448 | 448 | ||
449 | disable_irq_nosync(irq); | 449 | disable_irq_nosync(irq); |
450 | set_bit(FLAG_IRQ_ENABLE, &tps->flags); | 450 | set_bit(FLAG_IRQ_ENABLE, &tps->flags); |
451 | (void) schedule_work(&tps->work.work); | 451 | schedule_delayed_work(&tps->work, 0); |
452 | return IRQ_HANDLED; | 452 | return IRQ_HANDLED; |
453 | } | 453 | } |
454 | 454 | ||
@@ -527,8 +527,7 @@ static int __exit tps65010_remove(struct i2c_client *client) | |||
527 | } | 527 | } |
528 | if (client->irq > 0) | 528 | if (client->irq > 0) |
529 | free_irq(client->irq, tps); | 529 | free_irq(client->irq, tps); |
530 | cancel_delayed_work(&tps->work); | 530 | cancel_delayed_work_sync(&tps->work); |
531 | flush_scheduled_work(); | ||
532 | debugfs_remove(tps->file); | 531 | debugfs_remove(tps->file); |
533 | kfree(tps); | 532 | kfree(tps); |
534 | the_tps = NULL; | 533 | the_tps = NULL; |
@@ -720,7 +719,7 @@ int tps65010_set_vbus_draw(unsigned mA) | |||
720 | && test_and_set_bit( | 719 | && test_and_set_bit( |
721 | FLAG_VBUS_CHANGED, &the_tps->flags)) { | 720 | FLAG_VBUS_CHANGED, &the_tps->flags)) { |
722 | /* gadget drivers call this in_irq() */ | 721 | /* gadget drivers call this in_irq() */ |
723 | (void) schedule_work(&the_tps->work.work); | 722 | schedule_delayed_work(&the_tps->work, 0); |
724 | } | 723 | } |
725 | local_irq_restore(flags); | 724 | local_irq_restore(flags); |
726 | 725 | ||
diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c index fc0197649281..33ba7723c967 100644 --- a/drivers/mfd/tps6507x.c +++ b/drivers/mfd/tps6507x.c | |||
@@ -68,7 +68,7 @@ static int tps6507x_i2c_write_device(struct tps6507x_dev *tps6507x, char reg, | |||
68 | u8 msg[TPS6507X_MAX_REGISTER + 1]; | 68 | u8 msg[TPS6507X_MAX_REGISTER + 1]; |
69 | int ret; | 69 | int ret; |
70 | 70 | ||
71 | if (bytes > (TPS6507X_MAX_REGISTER + 1)) | 71 | if (bytes > TPS6507X_MAX_REGISTER) |
72 | return -EINVAL; | 72 | return -EINVAL; |
73 | 73 | ||
74 | msg[0] = reg; | 74 | msg[0] = reg; |
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 4cde31e6a252..bba26d96c240 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c | |||
@@ -15,6 +15,8 @@ | |||
15 | * published by the Free Software Foundation. | 15 | * published by the Free Software Foundation. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/irq.h> | ||
18 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
19 | #include <linux/module.h> | 21 | #include <linux/module.h> |
20 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
@@ -29,9 +31,62 @@ | |||
29 | #define TPS6586X_GPIOSET1 0x5d | 31 | #define TPS6586X_GPIOSET1 0x5d |
30 | #define TPS6586X_GPIOSET2 0x5e | 32 | #define TPS6586X_GPIOSET2 0x5e |
31 | 33 | ||
34 | /* interrupt control registers */ | ||
35 | #define TPS6586X_INT_ACK1 0xb5 | ||
36 | #define TPS6586X_INT_ACK2 0xb6 | ||
37 | #define TPS6586X_INT_ACK3 0xb7 | ||
38 | #define TPS6586X_INT_ACK4 0xb8 | ||
39 | |||
40 | /* interrupt mask registers */ | ||
41 | #define TPS6586X_INT_MASK1 0xb0 | ||
42 | #define TPS6586X_INT_MASK2 0xb1 | ||
43 | #define TPS6586X_INT_MASK3 0xb2 | ||
44 | #define TPS6586X_INT_MASK4 0xb3 | ||
45 | #define TPS6586X_INT_MASK5 0xb4 | ||
46 | |||
32 | /* device id */ | 47 | /* device id */ |
33 | #define TPS6586X_VERSIONCRC 0xcd | 48 | #define TPS6586X_VERSIONCRC 0xcd |
34 | #define TPS658621A_VERSIONCRC 0x15 | 49 | |
50 | struct tps6586x_irq_data { | ||
51 | u8 mask_reg; | ||
52 | u8 mask_mask; | ||
53 | }; | ||
54 | |||
55 | #define TPS6586X_IRQ(_reg, _mask) \ | ||
56 | { \ | ||
57 | .mask_reg = (_reg) - TPS6586X_INT_MASK1, \ | ||
58 | .mask_mask = (_mask), \ | ||
59 | } | ||
60 | |||
61 | static const struct tps6586x_irq_data tps6586x_irqs[] = { | ||
62 | [TPS6586X_INT_PLDO_0] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 0), | ||
63 | [TPS6586X_INT_PLDO_1] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 1), | ||
64 | [TPS6586X_INT_PLDO_2] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 2), | ||
65 | [TPS6586X_INT_PLDO_3] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 3), | ||
66 | [TPS6586X_INT_PLDO_4] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 4), | ||
67 | [TPS6586X_INT_PLDO_5] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 5), | ||
68 | [TPS6586X_INT_PLDO_6] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 6), | ||
69 | [TPS6586X_INT_PLDO_7] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 7), | ||
70 | [TPS6586X_INT_COMP_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 0), | ||
71 | [TPS6586X_INT_ADC] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 1), | ||
72 | [TPS6586X_INT_PLDO_8] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 2), | ||
73 | [TPS6586X_INT_PLDO_9] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 3), | ||
74 | [TPS6586X_INT_PSM_0] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 4), | ||
75 | [TPS6586X_INT_PSM_1] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 5), | ||
76 | [TPS6586X_INT_PSM_2] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 6), | ||
77 | [TPS6586X_INT_PSM_3] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 7), | ||
78 | [TPS6586X_INT_RTC_ALM1] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 4), | ||
79 | [TPS6586X_INT_ACUSB_OVP] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 0x03), | ||
80 | [TPS6586X_INT_USB_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 2), | ||
81 | [TPS6586X_INT_AC_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 3), | ||
82 | [TPS6586X_INT_BAT_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK3, 1 << 0), | ||
83 | [TPS6586X_INT_CHG_STAT] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 0xfc), | ||
84 | [TPS6586X_INT_CHG_TEMP] = TPS6586X_IRQ(TPS6586X_INT_MASK3, 0x06), | ||
85 | [TPS6586X_INT_PP] = TPS6586X_IRQ(TPS6586X_INT_MASK3, 0xf0), | ||
86 | [TPS6586X_INT_RESUME] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 5), | ||
87 | [TPS6586X_INT_LOW_SYS] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 6), | ||
88 | [TPS6586X_INT_RTC_ALM2] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 1), | ||
89 | }; | ||
35 | 90 | ||
36 | struct tps6586x { | 91 | struct tps6586x { |
37 | struct mutex lock; | 92 | struct mutex lock; |
@@ -39,6 +94,12 @@ struct tps6586x { | |||
39 | struct i2c_client *client; | 94 | struct i2c_client *client; |
40 | 95 | ||
41 | struct gpio_chip gpio; | 96 | struct gpio_chip gpio; |
97 | struct irq_chip irq_chip; | ||
98 | struct mutex irq_lock; | ||
99 | int irq_base; | ||
100 | u32 irq_en; | ||
101 | u8 mask_cache[5]; | ||
102 | u8 mask_reg[5]; | ||
42 | }; | 103 | }; |
43 | 104 | ||
44 | static inline int __tps6586x_read(struct i2c_client *client, | 105 | static inline int __tps6586x_read(struct i2c_client *client, |
@@ -89,12 +150,12 @@ static inline int __tps6586x_write(struct i2c_client *client, | |||
89 | static inline int __tps6586x_writes(struct i2c_client *client, int reg, | 150 | static inline int __tps6586x_writes(struct i2c_client *client, int reg, |
90 | int len, uint8_t *val) | 151 | int len, uint8_t *val) |
91 | { | 152 | { |
92 | int ret; | 153 | int ret, i; |
93 | 154 | ||
94 | ret = i2c_smbus_write_i2c_block_data(client, reg, len, val); | 155 | for (i = 0; i < len; i++) { |
95 | if (ret < 0) { | 156 | ret = __tps6586x_write(client, reg + i, *(val + i)); |
96 | dev_err(&client->dev, "failed writings to 0x%02x\n", reg); | 157 | if (ret < 0) |
97 | return ret; | 158 | return ret; |
98 | } | 159 | } |
99 | 160 | ||
100 | return 0; | 161 | return 0; |
@@ -209,8 +270,8 @@ static void tps6586x_gpio_set(struct gpio_chip *chip, unsigned offset, | |||
209 | { | 270 | { |
210 | struct tps6586x *tps6586x = container_of(chip, struct tps6586x, gpio); | 271 | struct tps6586x *tps6586x = container_of(chip, struct tps6586x, gpio); |
211 | 272 | ||
212 | __tps6586x_write(tps6586x->client, TPS6586X_GPIOSET2, | 273 | tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET2, |
213 | value << offset); | 274 | value << offset, 1 << offset); |
214 | } | 275 | } |
215 | 276 | ||
216 | static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset, | 277 | static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset, |
@@ -227,12 +288,10 @@ static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset, | |||
227 | return tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET1, val, mask); | 288 | return tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET1, val, mask); |
228 | } | 289 | } |
229 | 290 | ||
230 | static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base) | 291 | static int tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base) |
231 | { | 292 | { |
232 | int ret; | ||
233 | |||
234 | if (!gpio_base) | 293 | if (!gpio_base) |
235 | return; | 294 | return 0; |
236 | 295 | ||
237 | tps6586x->gpio.owner = THIS_MODULE; | 296 | tps6586x->gpio.owner = THIS_MODULE; |
238 | tps6586x->gpio.label = tps6586x->client->name; | 297 | tps6586x->gpio.label = tps6586x->client->name; |
@@ -246,9 +305,7 @@ static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base) | |||
246 | tps6586x->gpio.set = tps6586x_gpio_set; | 305 | tps6586x->gpio.set = tps6586x_gpio_set; |
247 | tps6586x->gpio.get = tps6586x_gpio_get; | 306 | tps6586x->gpio.get = tps6586x_gpio_get; |
248 | 307 | ||
249 | ret = gpiochip_add(&tps6586x->gpio); | 308 | return gpiochip_add(&tps6586x->gpio); |
250 | if (ret) | ||
251 | dev_warn(tps6586x->dev, "GPIO registration failed: %d\n", ret); | ||
252 | } | 309 | } |
253 | 310 | ||
254 | static int __remove_subdev(struct device *dev, void *unused) | 311 | static int __remove_subdev(struct device *dev, void *unused) |
@@ -262,6 +319,129 @@ static int tps6586x_remove_subdevs(struct tps6586x *tps6586x) | |||
262 | return device_for_each_child(tps6586x->dev, NULL, __remove_subdev); | 319 | return device_for_each_child(tps6586x->dev, NULL, __remove_subdev); |
263 | } | 320 | } |
264 | 321 | ||
322 | static void tps6586x_irq_lock(struct irq_data *data) | ||
323 | { | ||
324 | struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data); | ||
325 | |||
326 | mutex_lock(&tps6586x->irq_lock); | ||
327 | } | ||
328 | |||
329 | static void tps6586x_irq_enable(struct irq_data *irq_data) | ||
330 | { | ||
331 | struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data); | ||
332 | unsigned int __irq = irq_data->irq - tps6586x->irq_base; | ||
333 | const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; | ||
334 | |||
335 | tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask; | ||
336 | tps6586x->irq_en |= (1 << __irq); | ||
337 | } | ||
338 | |||
339 | static void tps6586x_irq_disable(struct irq_data *irq_data) | ||
340 | { | ||
341 | struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data); | ||
342 | |||
343 | unsigned int __irq = irq_data->irq - tps6586x->irq_base; | ||
344 | const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; | ||
345 | |||
346 | tps6586x->mask_reg[data->mask_reg] |= data->mask_mask; | ||
347 | tps6586x->irq_en &= ~(1 << __irq); | ||
348 | } | ||
349 | |||
350 | static void tps6586x_irq_sync_unlock(struct irq_data *data) | ||
351 | { | ||
352 | struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data); | ||
353 | int i; | ||
354 | |||
355 | for (i = 0; i < ARRAY_SIZE(tps6586x->mask_reg); i++) { | ||
356 | if (tps6586x->mask_reg[i] != tps6586x->mask_cache[i]) { | ||
357 | if (!WARN_ON(tps6586x_write(tps6586x->dev, | ||
358 | TPS6586X_INT_MASK1 + i, | ||
359 | tps6586x->mask_reg[i]))) | ||
360 | tps6586x->mask_cache[i] = tps6586x->mask_reg[i]; | ||
361 | } | ||
362 | } | ||
363 | |||
364 | mutex_unlock(&tps6586x->irq_lock); | ||
365 | } | ||
366 | |||
367 | static irqreturn_t tps6586x_irq(int irq, void *data) | ||
368 | { | ||
369 | struct tps6586x *tps6586x = data; | ||
370 | u32 acks; | ||
371 | int ret = 0; | ||
372 | |||
373 | ret = tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, | ||
374 | sizeof(acks), (uint8_t *)&acks); | ||
375 | |||
376 | if (ret < 0) { | ||
377 | dev_err(tps6586x->dev, "failed to read interrupt status\n"); | ||
378 | return IRQ_NONE; | ||
379 | } | ||
380 | |||
381 | acks = le32_to_cpu(acks); | ||
382 | |||
383 | while (acks) { | ||
384 | int i = __ffs(acks); | ||
385 | |||
386 | if (tps6586x->irq_en & (1 << i)) | ||
387 | handle_nested_irq(tps6586x->irq_base + i); | ||
388 | |||
389 | acks &= ~(1 << i); | ||
390 | } | ||
391 | |||
392 | return IRQ_HANDLED; | ||
393 | } | ||
394 | |||
395 | static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq, | ||
396 | int irq_base) | ||
397 | { | ||
398 | int i, ret; | ||
399 | u8 tmp[4]; | ||
400 | |||
401 | if (!irq_base) { | ||
402 | dev_warn(tps6586x->dev, "No interrupt support on IRQ base\n"); | ||
403 | return -EINVAL; | ||
404 | } | ||
405 | |||
406 | mutex_init(&tps6586x->irq_lock); | ||
407 | for (i = 0; i < 5; i++) { | ||
408 | tps6586x->mask_cache[i] = 0xff; | ||
409 | tps6586x->mask_reg[i] = 0xff; | ||
410 | tps6586x_write(tps6586x->dev, TPS6586X_INT_MASK1 + i, 0xff); | ||
411 | } | ||
412 | |||
413 | tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, sizeof(tmp), tmp); | ||
414 | |||
415 | tps6586x->irq_base = irq_base; | ||
416 | |||
417 | tps6586x->irq_chip.name = "tps6586x"; | ||
418 | tps6586x->irq_chip.irq_enable = tps6586x_irq_enable; | ||
419 | tps6586x->irq_chip.irq_disable = tps6586x_irq_disable; | ||
420 | tps6586x->irq_chip.irq_bus_lock = tps6586x_irq_lock; | ||
421 | tps6586x->irq_chip.irq_bus_sync_unlock = tps6586x_irq_sync_unlock; | ||
422 | |||
423 | for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) { | ||
424 | int __irq = i + tps6586x->irq_base; | ||
425 | irq_set_chip_data(__irq, tps6586x); | ||
426 | irq_set_chip_and_handler(__irq, &tps6586x->irq_chip, | ||
427 | handle_simple_irq); | ||
428 | irq_set_nested_thread(__irq, 1); | ||
429 | #ifdef CONFIG_ARM | ||
430 | set_irq_flags(__irq, IRQF_VALID); | ||
431 | #endif | ||
432 | } | ||
433 | |||
434 | ret = request_threaded_irq(irq, NULL, tps6586x_irq, IRQF_ONESHOT, | ||
435 | "tps6586x", tps6586x); | ||
436 | |||
437 | if (!ret) { | ||
438 | device_init_wakeup(tps6586x->dev, 1); | ||
439 | enable_irq_wake(irq); | ||
440 | } | ||
441 | |||
442 | return ret; | ||
443 | } | ||
444 | |||
265 | static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x, | 445 | static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x, |
266 | struct tps6586x_platform_data *pdata) | 446 | struct tps6586x_platform_data *pdata) |
267 | { | 447 | { |
@@ -273,13 +453,19 @@ static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x, | |||
273 | subdev = &pdata->subdevs[i]; | 453 | subdev = &pdata->subdevs[i]; |
274 | 454 | ||
275 | pdev = platform_device_alloc(subdev->name, subdev->id); | 455 | pdev = platform_device_alloc(subdev->name, subdev->id); |
456 | if (!pdev) { | ||
457 | ret = -ENOMEM; | ||
458 | goto failed; | ||
459 | } | ||
276 | 460 | ||
277 | pdev->dev.parent = tps6586x->dev; | 461 | pdev->dev.parent = tps6586x->dev; |
278 | pdev->dev.platform_data = subdev->platform_data; | 462 | pdev->dev.platform_data = subdev->platform_data; |
279 | 463 | ||
280 | ret = platform_device_add(pdev); | 464 | ret = platform_device_add(pdev); |
281 | if (ret) | 465 | if (ret) { |
466 | platform_device_put(pdev); | ||
282 | goto failed; | 467 | goto failed; |
468 | } | ||
283 | } | 469 | } |
284 | return 0; | 470 | return 0; |
285 | 471 | ||
@@ -306,10 +492,7 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, | |||
306 | return -EIO; | 492 | return -EIO; |
307 | } | 493 | } |
308 | 494 | ||
309 | if (ret != TPS658621A_VERSIONCRC) { | 495 | dev_info(&client->dev, "VERSIONCRC is %02x\n", ret); |
310 | dev_err(&client->dev, "Unsupported chip ID: %x\n", ret); | ||
311 | return -ENODEV; | ||
312 | } | ||
313 | 496 | ||
314 | tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL); | 497 | tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL); |
315 | if (tps6586x == NULL) | 498 | if (tps6586x == NULL) |
@@ -321,23 +504,62 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, | |||
321 | 504 | ||
322 | mutex_init(&tps6586x->lock); | 505 | mutex_init(&tps6586x->lock); |
323 | 506 | ||
507 | if (client->irq) { | ||
508 | ret = tps6586x_irq_init(tps6586x, client->irq, | ||
509 | pdata->irq_base); | ||
510 | if (ret) { | ||
511 | dev_err(&client->dev, "IRQ init failed: %d\n", ret); | ||
512 | goto err_irq_init; | ||
513 | } | ||
514 | } | ||
515 | |||
516 | ret = tps6586x_gpio_init(tps6586x, pdata->gpio_base); | ||
517 | if (ret) { | ||
518 | dev_err(&client->dev, "GPIO registration failed: %d\n", ret); | ||
519 | goto err_gpio_init; | ||
520 | } | ||
521 | |||
324 | ret = tps6586x_add_subdevs(tps6586x, pdata); | 522 | ret = tps6586x_add_subdevs(tps6586x, pdata); |
325 | if (ret) { | 523 | if (ret) { |
326 | dev_err(&client->dev, "add devices failed: %d\n", ret); | 524 | dev_err(&client->dev, "add devices failed: %d\n", ret); |
327 | goto err_add_devs; | 525 | goto err_add_devs; |
328 | } | 526 | } |
329 | 527 | ||
330 | tps6586x_gpio_init(tps6586x, pdata->gpio_base); | ||
331 | |||
332 | return 0; | 528 | return 0; |
333 | 529 | ||
334 | err_add_devs: | 530 | err_add_devs: |
531 | if (pdata->gpio_base) { | ||
532 | ret = gpiochip_remove(&tps6586x->gpio); | ||
533 | if (ret) | ||
534 | dev_err(&client->dev, "Can't remove gpio chip: %d\n", | ||
535 | ret); | ||
536 | } | ||
537 | err_gpio_init: | ||
538 | if (client->irq) | ||
539 | free_irq(client->irq, tps6586x); | ||
540 | err_irq_init: | ||
335 | kfree(tps6586x); | 541 | kfree(tps6586x); |
336 | return ret; | 542 | return ret; |
337 | } | 543 | } |
338 | 544 | ||
339 | static int __devexit tps6586x_i2c_remove(struct i2c_client *client) | 545 | static int __devexit tps6586x_i2c_remove(struct i2c_client *client) |
340 | { | 546 | { |
547 | struct tps6586x *tps6586x = i2c_get_clientdata(client); | ||
548 | struct tps6586x_platform_data *pdata = client->dev.platform_data; | ||
549 | int ret; | ||
550 | |||
551 | if (client->irq) | ||
552 | free_irq(client->irq, tps6586x); | ||
553 | |||
554 | if (pdata->gpio_base) { | ||
555 | ret = gpiochip_remove(&tps6586x->gpio); | ||
556 | if (ret) | ||
557 | dev_err(&client->dev, "Can't remove gpio chip: %d\n", | ||
558 | ret); | ||
559 | } | ||
560 | |||
561 | tps6586x_remove_subdevs(tps6586x); | ||
562 | kfree(tps6586x); | ||
341 | return 0; | 563 | return 0; |
342 | } | 564 | } |
343 | 565 | ||
@@ -372,4 +594,3 @@ module_exit(tps6586x_exit); | |||
372 | MODULE_DESCRIPTION("TPS6586X core driver"); | 594 | MODULE_DESCRIPTION("TPS6586X core driver"); |
373 | MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); | 595 | MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); |
374 | MODULE_LICENSE("GPL"); | 596 | MODULE_LICENSE("GPL"); |
375 | |||
diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c new file mode 100644 index 000000000000..2bfad5c86cc7 --- /dev/null +++ b/drivers/mfd/tps65910-irq.c | |||
@@ -0,0 +1,218 @@ | |||
1 | /* | ||
2 | * tps65910-irq.c -- TI TPS6591x | ||
3 | * | ||
4 | * Copyright 2010 Texas Instruments Inc. | ||
5 | * | ||
6 | * Author: Graeme Gregory <gg@slimlogic.co.uk> | ||
7 | * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/bug.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/irq.h> | ||
23 | #include <linux/gpio.h> | ||
24 | #include <linux/mfd/tps65910.h> | ||
25 | |||
26 | static inline int irq_to_tps65910_irq(struct tps65910 *tps65910, | ||
27 | int irq) | ||
28 | { | ||
29 | return (irq - tps65910->irq_base); | ||
30 | } | ||
31 | |||
32 | /* | ||
33 | * This is a threaded IRQ handler so can access I2C/SPI. Since all | ||
34 | * interrupts are clear on read the IRQ line will be reasserted and | ||
35 | * the physical IRQ will be handled again if another interrupt is | ||
36 | * asserted while we run - in the normal course of events this is a | ||
37 | * rare occurrence so we save I2C/SPI reads. We're also assuming that | ||
38 | * it's rare to get lots of interrupts firing simultaneously so try to | ||
39 | * minimise I/O. | ||
40 | */ | ||
41 | static irqreturn_t tps65910_irq(int irq, void *irq_data) | ||
42 | { | ||
43 | struct tps65910 *tps65910 = irq_data; | ||
44 | u32 irq_sts; | ||
45 | u32 irq_mask; | ||
46 | u8 reg; | ||
47 | int i; | ||
48 | |||
49 | tps65910->read(tps65910, TPS65910_INT_STS, 1, ®); | ||
50 | irq_sts = reg; | ||
51 | tps65910->read(tps65910, TPS65910_INT_STS2, 1, ®); | ||
52 | irq_sts |= reg << 8; | ||
53 | switch (tps65910_chip_id(tps65910)) { | ||
54 | case TPS65911: | ||
55 | tps65910->read(tps65910, TPS65910_INT_STS3, 1, ®); | ||
56 | irq_sts |= reg << 16; | ||
57 | } | ||
58 | |||
59 | tps65910->read(tps65910, TPS65910_INT_MSK, 1, ®); | ||
60 | irq_mask = reg; | ||
61 | tps65910->read(tps65910, TPS65910_INT_MSK2, 1, ®); | ||
62 | irq_mask |= reg << 8; | ||
63 | switch (tps65910_chip_id(tps65910)) { | ||
64 | case TPS65911: | ||
65 | tps65910->read(tps65910, TPS65910_INT_MSK3, 1, ®); | ||
66 | irq_mask |= reg << 16; | ||
67 | } | ||
68 | |||
69 | irq_sts &= ~irq_mask; | ||
70 | |||
71 | if (!irq_sts) | ||
72 | return IRQ_NONE; | ||
73 | |||
74 | for (i = 0; i < tps65910->irq_num; i++) { | ||
75 | |||
76 | if (!(irq_sts & (1 << i))) | ||
77 | continue; | ||
78 | |||
79 | handle_nested_irq(tps65910->irq_base + i); | ||
80 | } | ||
81 | |||
82 | /* Write the STS register back to clear IRQs we handled */ | ||
83 | reg = irq_sts & 0xFF; | ||
84 | irq_sts >>= 8; | ||
85 | tps65910->write(tps65910, TPS65910_INT_STS, 1, ®); | ||
86 | reg = irq_sts & 0xFF; | ||
87 | tps65910->write(tps65910, TPS65910_INT_STS2, 1, ®); | ||
88 | switch (tps65910_chip_id(tps65910)) { | ||
89 | case TPS65911: | ||
90 | reg = irq_sts >> 8; | ||
91 | tps65910->write(tps65910, TPS65910_INT_STS3, 1, ®); | ||
92 | } | ||
93 | |||
94 | return IRQ_HANDLED; | ||
95 | } | ||
96 | |||
97 | static void tps65910_irq_lock(struct irq_data *data) | ||
98 | { | ||
99 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
100 | |||
101 | mutex_lock(&tps65910->irq_lock); | ||
102 | } | ||
103 | |||
104 | static void tps65910_irq_sync_unlock(struct irq_data *data) | ||
105 | { | ||
106 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
107 | u32 reg_mask; | ||
108 | u8 reg; | ||
109 | |||
110 | tps65910->read(tps65910, TPS65910_INT_MSK, 1, ®); | ||
111 | reg_mask = reg; | ||
112 | tps65910->read(tps65910, TPS65910_INT_MSK2, 1, ®); | ||
113 | reg_mask |= reg << 8; | ||
114 | switch (tps65910_chip_id(tps65910)) { | ||
115 | case TPS65911: | ||
116 | tps65910->read(tps65910, TPS65910_INT_MSK3, 1, ®); | ||
117 | reg_mask |= reg << 16; | ||
118 | } | ||
119 | |||
120 | if (tps65910->irq_mask != reg_mask) { | ||
121 | reg = tps65910->irq_mask & 0xFF; | ||
122 | tps65910->write(tps65910, TPS65910_INT_MSK, 1, ®); | ||
123 | reg = tps65910->irq_mask >> 8 & 0xFF; | ||
124 | tps65910->write(tps65910, TPS65910_INT_MSK2, 1, ®); | ||
125 | switch (tps65910_chip_id(tps65910)) { | ||
126 | case TPS65911: | ||
127 | reg = tps65910->irq_mask >> 16; | ||
128 | tps65910->write(tps65910, TPS65910_INT_MSK3, 1, ®); | ||
129 | } | ||
130 | } | ||
131 | mutex_unlock(&tps65910->irq_lock); | ||
132 | } | ||
133 | |||
134 | static void tps65910_irq_enable(struct irq_data *data) | ||
135 | { | ||
136 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
137 | |||
138 | tps65910->irq_mask &= ~( 1 << irq_to_tps65910_irq(tps65910, data->irq)); | ||
139 | } | ||
140 | |||
141 | static void tps65910_irq_disable(struct irq_data *data) | ||
142 | { | ||
143 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
144 | |||
145 | tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq)); | ||
146 | } | ||
147 | |||
148 | static struct irq_chip tps65910_irq_chip = { | ||
149 | .name = "tps65910", | ||
150 | .irq_bus_lock = tps65910_irq_lock, | ||
151 | .irq_bus_sync_unlock = tps65910_irq_sync_unlock, | ||
152 | .irq_disable = tps65910_irq_disable, | ||
153 | .irq_enable = tps65910_irq_enable, | ||
154 | }; | ||
155 | |||
156 | int tps65910_irq_init(struct tps65910 *tps65910, int irq, | ||
157 | struct tps65910_platform_data *pdata) | ||
158 | { | ||
159 | int ret, cur_irq; | ||
160 | int flags = IRQF_ONESHOT; | ||
161 | |||
162 | if (!irq) { | ||
163 | dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n"); | ||
164 | return -EINVAL; | ||
165 | } | ||
166 | |||
167 | if (!pdata || !pdata->irq_base) { | ||
168 | dev_warn(tps65910->dev, "No interrupt support, no IRQ base\n"); | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | |||
172 | tps65910->irq_mask = 0xFFFFFF; | ||
173 | |||
174 | mutex_init(&tps65910->irq_lock); | ||
175 | tps65910->chip_irq = irq; | ||
176 | tps65910->irq_base = pdata->irq_base; | ||
177 | |||
178 | switch (tps65910_chip_id(tps65910)) { | ||
179 | case TPS65910: | ||
180 | tps65910->irq_num = TPS65910_NUM_IRQ; | ||
181 | case TPS65911: | ||
182 | tps65910->irq_num = TPS65911_NUM_IRQ; | ||
183 | } | ||
184 | |||
185 | /* Register with genirq */ | ||
186 | for (cur_irq = tps65910->irq_base; | ||
187 | cur_irq < tps65910->irq_num + tps65910->irq_base; | ||
188 | cur_irq++) { | ||
189 | irq_set_chip_data(cur_irq, tps65910); | ||
190 | irq_set_chip_and_handler(cur_irq, &tps65910_irq_chip, | ||
191 | handle_edge_irq); | ||
192 | irq_set_nested_thread(cur_irq, 1); | ||
193 | |||
194 | /* ARM needs us to explicitly flag the IRQ as valid | ||
195 | * and will set them noprobe when we do so. */ | ||
196 | #ifdef CONFIG_ARM | ||
197 | set_irq_flags(cur_irq, IRQF_VALID); | ||
198 | #else | ||
199 | irq_set_noprobe(cur_irq); | ||
200 | #endif | ||
201 | } | ||
202 | |||
203 | ret = request_threaded_irq(irq, NULL, tps65910_irq, flags, | ||
204 | "tps65910", tps65910); | ||
205 | |||
206 | irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); | ||
207 | |||
208 | if (ret != 0) | ||
209 | dev_err(tps65910->dev, "Failed to request IRQ: %d\n", ret); | ||
210 | |||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | int tps65910_irq_exit(struct tps65910 *tps65910) | ||
215 | { | ||
216 | free_irq(tps65910->chip_irq, tps65910); | ||
217 | return 0; | ||
218 | } | ||
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c new file mode 100644 index 000000000000..2229e66d80db --- /dev/null +++ b/drivers/mfd/tps65910.c | |||
@@ -0,0 +1,229 @@ | |||
1 | /* | ||
2 | * tps65910.c -- TI TPS6591x | ||
3 | * | ||
4 | * Copyright 2010 Texas Instruments Inc. | ||
5 | * | ||
6 | * Author: Graeme Gregory <gg@slimlogic.co.uk> | ||
7 | * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/moduleparam.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/mfd/core.h> | ||
23 | #include <linux/mfd/tps65910.h> | ||
24 | |||
25 | static struct mfd_cell tps65910s[] = { | ||
26 | { | ||
27 | .name = "tps65910-pmic", | ||
28 | }, | ||
29 | { | ||
30 | .name = "tps65910-rtc", | ||
31 | }, | ||
32 | { | ||
33 | .name = "tps65910-power", | ||
34 | }, | ||
35 | }; | ||
36 | |||
37 | |||
38 | static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, | ||
39 | int bytes, void *dest) | ||
40 | { | ||
41 | struct i2c_client *i2c = tps65910->i2c_client; | ||
42 | struct i2c_msg xfer[2]; | ||
43 | int ret; | ||
44 | |||
45 | /* Write register */ | ||
46 | xfer[0].addr = i2c->addr; | ||
47 | xfer[0].flags = 0; | ||
48 | xfer[0].len = 1; | ||
49 | xfer[0].buf = ® | ||
50 | |||
51 | /* Read data */ | ||
52 | xfer[1].addr = i2c->addr; | ||
53 | xfer[1].flags = I2C_M_RD; | ||
54 | xfer[1].len = bytes; | ||
55 | xfer[1].buf = dest; | ||
56 | |||
57 | ret = i2c_transfer(i2c->adapter, xfer, 2); | ||
58 | if (ret == 2) | ||
59 | ret = 0; | ||
60 | else if (ret >= 0) | ||
61 | ret = -EIO; | ||
62 | |||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg, | ||
67 | int bytes, void *src) | ||
68 | { | ||
69 | struct i2c_client *i2c = tps65910->i2c_client; | ||
70 | /* we add 1 byte for device register */ | ||
71 | u8 msg[TPS65910_MAX_REGISTER + 1]; | ||
72 | int ret; | ||
73 | |||
74 | if (bytes > TPS65910_MAX_REGISTER) | ||
75 | return -EINVAL; | ||
76 | |||
77 | msg[0] = reg; | ||
78 | memcpy(&msg[1], src, bytes); | ||
79 | |||
80 | ret = i2c_master_send(i2c, msg, bytes + 1); | ||
81 | if (ret < 0) | ||
82 | return ret; | ||
83 | if (ret != bytes + 1) | ||
84 | return -EIO; | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask) | ||
89 | { | ||
90 | u8 data; | ||
91 | int err; | ||
92 | |||
93 | mutex_lock(&tps65910->io_mutex); | ||
94 | err = tps65910_i2c_read(tps65910, reg, 1, &data); | ||
95 | if (err) { | ||
96 | dev_err(tps65910->dev, "read from reg %x failed\n", reg); | ||
97 | goto out; | ||
98 | } | ||
99 | |||
100 | data |= mask; | ||
101 | err = tps65910_i2c_write(tps65910, reg, 1, &data); | ||
102 | if (err) | ||
103 | dev_err(tps65910->dev, "write to reg %x failed\n", reg); | ||
104 | |||
105 | out: | ||
106 | mutex_unlock(&tps65910->io_mutex); | ||
107 | return err; | ||
108 | } | ||
109 | EXPORT_SYMBOL_GPL(tps65910_set_bits); | ||
110 | |||
111 | int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask) | ||
112 | { | ||
113 | u8 data; | ||
114 | int err; | ||
115 | |||
116 | mutex_lock(&tps65910->io_mutex); | ||
117 | err = tps65910_i2c_read(tps65910, reg, 1, &data); | ||
118 | if (err) { | ||
119 | dev_err(tps65910->dev, "read from reg %x failed\n", reg); | ||
120 | goto out; | ||
121 | } | ||
122 | |||
123 | data &= mask; | ||
124 | err = tps65910_i2c_write(tps65910, reg, 1, &data); | ||
125 | if (err) | ||
126 | dev_err(tps65910->dev, "write to reg %x failed\n", reg); | ||
127 | |||
128 | out: | ||
129 | mutex_unlock(&tps65910->io_mutex); | ||
130 | return err; | ||
131 | } | ||
132 | EXPORT_SYMBOL_GPL(tps65910_clear_bits); | ||
133 | |||
134 | static int tps65910_i2c_probe(struct i2c_client *i2c, | ||
135 | const struct i2c_device_id *id) | ||
136 | { | ||
137 | struct tps65910 *tps65910; | ||
138 | struct tps65910_board *pmic_plat_data; | ||
139 | struct tps65910_platform_data *init_data; | ||
140 | int ret = 0; | ||
141 | |||
142 | pmic_plat_data = dev_get_platdata(&i2c->dev); | ||
143 | if (!pmic_plat_data) | ||
144 | return -EINVAL; | ||
145 | |||
146 | init_data = kzalloc(sizeof(struct tps65910_platform_data), GFP_KERNEL); | ||
147 | if (init_data == NULL) | ||
148 | return -ENOMEM; | ||
149 | |||
150 | init_data->irq = pmic_plat_data->irq; | ||
151 | init_data->irq_base = pmic_plat_data->irq; | ||
152 | |||
153 | tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL); | ||
154 | if (tps65910 == NULL) | ||
155 | return -ENOMEM; | ||
156 | |||
157 | i2c_set_clientdata(i2c, tps65910); | ||
158 | tps65910->dev = &i2c->dev; | ||
159 | tps65910->i2c_client = i2c; | ||
160 | tps65910->id = id->driver_data; | ||
161 | tps65910->read = tps65910_i2c_read; | ||
162 | tps65910->write = tps65910_i2c_write; | ||
163 | mutex_init(&tps65910->io_mutex); | ||
164 | |||
165 | ret = mfd_add_devices(tps65910->dev, -1, | ||
166 | tps65910s, ARRAY_SIZE(tps65910s), | ||
167 | NULL, 0); | ||
168 | if (ret < 0) | ||
169 | goto err; | ||
170 | |||
171 | tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base); | ||
172 | |||
173 | ret = tps65910_irq_init(tps65910, init_data->irq, init_data); | ||
174 | if (ret < 0) | ||
175 | goto err; | ||
176 | |||
177 | return ret; | ||
178 | |||
179 | err: | ||
180 | mfd_remove_devices(tps65910->dev); | ||
181 | kfree(tps65910); | ||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | static int tps65910_i2c_remove(struct i2c_client *i2c) | ||
186 | { | ||
187 | struct tps65910 *tps65910 = i2c_get_clientdata(i2c); | ||
188 | |||
189 | mfd_remove_devices(tps65910->dev); | ||
190 | kfree(tps65910); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static const struct i2c_device_id tps65910_i2c_id[] = { | ||
196 | { "tps65910", TPS65910 }, | ||
197 | { "tps65911", TPS65911 }, | ||
198 | { } | ||
199 | }; | ||
200 | MODULE_DEVICE_TABLE(i2c, tps65910_i2c_id); | ||
201 | |||
202 | |||
203 | static struct i2c_driver tps65910_i2c_driver = { | ||
204 | .driver = { | ||
205 | .name = "tps65910", | ||
206 | .owner = THIS_MODULE, | ||
207 | }, | ||
208 | .probe = tps65910_i2c_probe, | ||
209 | .remove = tps65910_i2c_remove, | ||
210 | .id_table = tps65910_i2c_id, | ||
211 | }; | ||
212 | |||
213 | static int __init tps65910_i2c_init(void) | ||
214 | { | ||
215 | return i2c_add_driver(&tps65910_i2c_driver); | ||
216 | } | ||
217 | /* init early so consumer devices can complete system boot */ | ||
218 | subsys_initcall(tps65910_i2c_init); | ||
219 | |||
220 | static void __exit tps65910_i2c_exit(void) | ||
221 | { | ||
222 | i2c_del_driver(&tps65910_i2c_driver); | ||
223 | } | ||
224 | module_exit(tps65910_i2c_exit); | ||
225 | |||
226 | MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); | ||
227 | MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>"); | ||
228 | MODULE_DESCRIPTION("TPS6591x chip family multi-function driver"); | ||
229 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c new file mode 100644 index 000000000000..283ac6759757 --- /dev/null +++ b/drivers/mfd/tps65911-comparator.c | |||
@@ -0,0 +1,188 @@ | |||
1 | /* | ||
2 | * tps65910.c -- TI TPS6591x | ||
3 | * | ||
4 | * Copyright 2010 Texas Instruments Inc. | ||
5 | * | ||
6 | * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/debugfs.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/mfd/tps65910.h> | ||
24 | |||
25 | #define COMP 0 | ||
26 | #define COMP1 1 | ||
27 | #define COMP2 2 | ||
28 | |||
29 | /* Comparator 1 voltage selection table in milivolts */ | ||
30 | static const u16 COMP_VSEL_TABLE[] = { | ||
31 | 0, 2500, 2500, 2500, 2500, 2550, 2600, 2650, | ||
32 | 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050, | ||
33 | 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450, | ||
34 | 3500, | ||
35 | }; | ||
36 | |||
37 | struct comparator { | ||
38 | const char *name; | ||
39 | int reg; | ||
40 | int uV_max; | ||
41 | const u16 *vsel_table; | ||
42 | }; | ||
43 | |||
44 | static struct comparator tps_comparators[] = { | ||
45 | { | ||
46 | .name = "COMP1", | ||
47 | .reg = TPS65911_VMBCH, | ||
48 | .uV_max = 3500, | ||
49 | .vsel_table = COMP_VSEL_TABLE, | ||
50 | }, | ||
51 | { | ||
52 | .name = "COMP2", | ||
53 | .reg = TPS65911_VMBCH2, | ||
54 | .uV_max = 3500, | ||
55 | .vsel_table = COMP_VSEL_TABLE, | ||
56 | }, | ||
57 | }; | ||
58 | |||
59 | static int comp_threshold_set(struct tps65910 *tps65910, int id, int voltage) | ||
60 | { | ||
61 | struct comparator tps_comp = tps_comparators[id]; | ||
62 | int curr_voltage = 0; | ||
63 | int ret; | ||
64 | u8 index = 0, val; | ||
65 | |||
66 | if (id == COMP) | ||
67 | return 0; | ||
68 | |||
69 | while (curr_voltage < tps_comp.uV_max) { | ||
70 | curr_voltage = tps_comp.vsel_table[index]; | ||
71 | if (curr_voltage >= voltage) | ||
72 | break; | ||
73 | else if (curr_voltage < voltage) | ||
74 | index ++; | ||
75 | } | ||
76 | |||
77 | if (curr_voltage > tps_comp.uV_max) | ||
78 | return -EINVAL; | ||
79 | |||
80 | val = index << 1; | ||
81 | ret = tps65910->write(tps65910, tps_comp.reg, 1, &val); | ||
82 | |||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | static int comp_threshold_get(struct tps65910 *tps65910, int id) | ||
87 | { | ||
88 | struct comparator tps_comp = tps_comparators[id]; | ||
89 | int ret; | ||
90 | u8 val; | ||
91 | |||
92 | if (id == COMP) | ||
93 | return 0; | ||
94 | |||
95 | ret = tps65910->read(tps65910, tps_comp.reg, 1, &val); | ||
96 | if (ret < 0) | ||
97 | return ret; | ||
98 | |||
99 | val >>= 1; | ||
100 | return tps_comp.vsel_table[val]; | ||
101 | } | ||
102 | |||
103 | static ssize_t comp_threshold_show(struct device *dev, | ||
104 | struct device_attribute *attr, char *buf) | ||
105 | { | ||
106 | struct tps65910 *tps65910 = dev_get_drvdata(dev->parent); | ||
107 | struct attribute comp_attr = attr->attr; | ||
108 | int id, uVolt; | ||
109 | |||
110 | if (!strcmp(comp_attr.name, "comp1_threshold")) | ||
111 | id = COMP1; | ||
112 | else if (!strcmp(comp_attr.name, "comp2_threshold")) | ||
113 | id = COMP2; | ||
114 | else | ||
115 | return -EINVAL; | ||
116 | |||
117 | uVolt = comp_threshold_get(tps65910, id); | ||
118 | |||
119 | return sprintf(buf, "%d\n", uVolt); | ||
120 | } | ||
121 | |||
122 | static DEVICE_ATTR(comp1_threshold, S_IRUGO, comp_threshold_show, NULL); | ||
123 | static DEVICE_ATTR(comp2_threshold, S_IRUGO, comp_threshold_show, NULL); | ||
124 | |||
125 | static __devinit int tps65911_comparator_probe(struct platform_device *pdev) | ||
126 | { | ||
127 | struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); | ||
128 | struct tps65910_board *pdata = dev_get_platdata(tps65910->dev); | ||
129 | int ret; | ||
130 | |||
131 | ret = comp_threshold_set(tps65910, COMP1, pdata->vmbch_threshold); | ||
132 | if (ret < 0) { | ||
133 | dev_err(&pdev->dev, "cannot set COMP1 threshold\n"); | ||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | ret = comp_threshold_set(tps65910, COMP2, pdata->vmbch2_threshold); | ||
138 | if (ret < 0) { | ||
139 | dev_err(&pdev->dev, "cannot set COMP2 theshold\n"); | ||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | /* Create sysfs entry */ | ||
144 | ret = device_create_file(&pdev->dev, &dev_attr_comp1_threshold); | ||
145 | if (ret < 0) | ||
146 | dev_err(&pdev->dev, "failed to add COMP1 sysfs file\n"); | ||
147 | |||
148 | ret = device_create_file(&pdev->dev, &dev_attr_comp2_threshold); | ||
149 | if (ret < 0) | ||
150 | dev_err(&pdev->dev, "failed to add COMP2 sysfs file\n"); | ||
151 | |||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | static __devexit int tps65911_comparator_remove(struct platform_device *pdev) | ||
156 | { | ||
157 | struct tps65910 *tps65910; | ||
158 | |||
159 | tps65910 = dev_get_drvdata(pdev->dev.parent); | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static struct platform_driver tps65911_comparator_driver = { | ||
165 | .driver = { | ||
166 | .name = "tps65911-comparator", | ||
167 | .owner = THIS_MODULE, | ||
168 | }, | ||
169 | .probe = tps65911_comparator_probe, | ||
170 | .remove = __devexit_p(tps65911_comparator_remove), | ||
171 | }; | ||
172 | |||
173 | static int __init tps65911_comparator_init(void) | ||
174 | { | ||
175 | return platform_driver_register(&tps65911_comparator_driver); | ||
176 | } | ||
177 | subsys_initcall(tps65911_comparator_init); | ||
178 | |||
179 | static void __exit tps65911_comparator_exit(void) | ||
180 | { | ||
181 | platform_driver_unregister(&tps65911_comparator_driver); | ||
182 | } | ||
183 | module_exit(tps65911_comparator_exit); | ||
184 | |||
185 | MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>"); | ||
186 | MODULE_DESCRIPTION("TPS65911 comparator driver"); | ||
187 | MODULE_LICENSE("GPL v2"); | ||
188 | MODULE_ALIAS("platform:tps65911-comparator"); | ||
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 720e099e506d..b8f2a4e7f6e7 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c | |||
@@ -95,7 +95,8 @@ | |||
95 | #define twl_has_rtc() false | 95 | #define twl_has_rtc() false |
96 | #endif | 96 | #endif |
97 | 97 | ||
98 | #if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE) | 98 | #if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE) ||\ |
99 | defined(CONFIG_TWL6030_USB) || defined(CONFIG_TWL6030_USB_MODULE) | ||
99 | #define twl_has_usb() true | 100 | #define twl_has_usb() true |
100 | #else | 101 | #else |
101 | #define twl_has_usb() false | 102 | #define twl_has_usb() false |
@@ -115,6 +116,12 @@ | |||
115 | #define twl_has_codec() false | 116 | #define twl_has_codec() false |
116 | #endif | 117 | #endif |
117 | 118 | ||
119 | #if defined(CONFIG_CHARGER_TWL4030) || defined(CONFIG_CHARGER_TWL4030_MODULE) | ||
120 | #define twl_has_bci() true | ||
121 | #else | ||
122 | #define twl_has_bci() false | ||
123 | #endif | ||
124 | |||
118 | /* Triton Core internal information (BEGIN) */ | 125 | /* Triton Core internal information (BEGIN) */ |
119 | 126 | ||
120 | /* Last - for index max*/ | 127 | /* Last - for index max*/ |
@@ -191,6 +198,7 @@ | |||
191 | #define TWL6030_BASEADD_GASGAUGE 0x00C0 | 198 | #define TWL6030_BASEADD_GASGAUGE 0x00C0 |
192 | #define TWL6030_BASEADD_PIH 0x00D0 | 199 | #define TWL6030_BASEADD_PIH 0x00D0 |
193 | #define TWL6030_BASEADD_CHARGER 0x00E0 | 200 | #define TWL6030_BASEADD_CHARGER 0x00E0 |
201 | #define TWL6025_BASEADD_CHARGER 0x00DA | ||
194 | 202 | ||
195 | /* subchip/slave 2 0x4A - DFT */ | 203 | /* subchip/slave 2 0x4A - DFT */ |
196 | #define TWL6030_BASEADD_DIEID 0x00C0 | 204 | #define TWL6030_BASEADD_DIEID 0x00C0 |
@@ -202,12 +210,6 @@ | |||
202 | 210 | ||
203 | /* Few power values */ | 211 | /* Few power values */ |
204 | #define R_CFG_BOOT 0x05 | 212 | #define R_CFG_BOOT 0x05 |
205 | #define R_PROTECT_KEY 0x0E | ||
206 | |||
207 | /* access control values for R_PROTECT_KEY */ | ||
208 | #define KEY_UNLOCK1 0xce | ||
209 | #define KEY_UNLOCK2 0xec | ||
210 | #define KEY_LOCK 0x00 | ||
211 | 213 | ||
212 | /* some fields in R_CFG_BOOT */ | 214 | /* some fields in R_CFG_BOOT */ |
213 | #define HFCLK_FREQ_19p2_MHZ (1 << 0) | 215 | #define HFCLK_FREQ_19p2_MHZ (1 << 0) |
@@ -228,6 +230,9 @@ | |||
228 | /* is driver active, bound to a chip? */ | 230 | /* is driver active, bound to a chip? */ |
229 | static bool inuse; | 231 | static bool inuse; |
230 | 232 | ||
233 | /* TWL IDCODE Register value */ | ||
234 | static u32 twl_idcode; | ||
235 | |||
231 | static unsigned int twl_id; | 236 | static unsigned int twl_id; |
232 | unsigned int twl_rev(void) | 237 | unsigned int twl_rev(void) |
233 | { | 238 | { |
@@ -255,7 +260,7 @@ struct twl_mapping { | |||
255 | unsigned char sid; /* Slave ID */ | 260 | unsigned char sid; /* Slave ID */ |
256 | unsigned char base; /* base address */ | 261 | unsigned char base; /* base address */ |
257 | }; | 262 | }; |
258 | struct twl_mapping *twl_map; | 263 | static struct twl_mapping *twl_map; |
259 | 264 | ||
260 | static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { | 265 | static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = { |
261 | /* | 266 | /* |
@@ -327,6 +332,7 @@ static struct twl_mapping twl6030_map[] = { | |||
327 | 332 | ||
328 | { SUB_CHIP_ID0, TWL6030_BASEADD_RTC }, | 333 | { SUB_CHIP_ID0, TWL6030_BASEADD_RTC }, |
329 | { SUB_CHIP_ID0, TWL6030_BASEADD_MEM }, | 334 | { SUB_CHIP_ID0, TWL6030_BASEADD_MEM }, |
335 | { SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER }, | ||
330 | }; | 336 | }; |
331 | 337 | ||
332 | /*----------------------------------------------------------------------*/ | 338 | /*----------------------------------------------------------------------*/ |
@@ -486,6 +492,58 @@ EXPORT_SYMBOL(twl_i2c_read_u8); | |||
486 | 492 | ||
487 | /*----------------------------------------------------------------------*/ | 493 | /*----------------------------------------------------------------------*/ |
488 | 494 | ||
495 | /** | ||
496 | * twl_read_idcode_register - API to read the IDCODE register. | ||
497 | * | ||
498 | * Unlocks the IDCODE register and read the 32 bit value. | ||
499 | */ | ||
500 | static int twl_read_idcode_register(void) | ||
501 | { | ||
502 | int err; | ||
503 | |||
504 | err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, TWL_EEPROM_R_UNLOCK, | ||
505 | REG_UNLOCK_TEST_REG); | ||
506 | if (err) { | ||
507 | pr_err("TWL4030 Unable to unlock IDCODE registers -%d\n", err); | ||
508 | goto fail; | ||
509 | } | ||
510 | |||
511 | err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_idcode), | ||
512 | REG_IDCODE_7_0, 4); | ||
513 | if (err) { | ||
514 | pr_err("TWL4030: unable to read IDCODE -%d\n", err); | ||
515 | goto fail; | ||
516 | } | ||
517 | |||
518 | err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, 0x0, REG_UNLOCK_TEST_REG); | ||
519 | if (err) | ||
520 | pr_err("TWL4030 Unable to relock IDCODE registers -%d\n", err); | ||
521 | fail: | ||
522 | return err; | ||
523 | } | ||
524 | |||
525 | /** | ||
526 | * twl_get_type - API to get TWL Si type. | ||
527 | * | ||
528 | * Api to get the TWL Si type from IDCODE value. | ||
529 | */ | ||
530 | int twl_get_type(void) | ||
531 | { | ||
532 | return TWL_SIL_TYPE(twl_idcode); | ||
533 | } | ||
534 | EXPORT_SYMBOL_GPL(twl_get_type); | ||
535 | |||
536 | /** | ||
537 | * twl_get_version - API to get TWL Si version. | ||
538 | * | ||
539 | * Api to get the TWL Si version from IDCODE value. | ||
540 | */ | ||
541 | int twl_get_version(void) | ||
542 | { | ||
543 | return TWL_SIL_REV(twl_idcode); | ||
544 | } | ||
545 | EXPORT_SYMBOL_GPL(twl_get_version); | ||
546 | |||
489 | static struct device * | 547 | static struct device * |
490 | add_numbered_child(unsigned chip, const char *name, int num, | 548 | add_numbered_child(unsigned chip, const char *name, int num, |
491 | void *pdata, unsigned pdata_len, | 549 | void *pdata, unsigned pdata_len, |
@@ -548,7 +606,7 @@ static inline struct device *add_child(unsigned chip, const char *name, | |||
548 | static struct device * | 606 | static struct device * |
549 | add_regulator_linked(int num, struct regulator_init_data *pdata, | 607 | add_regulator_linked(int num, struct regulator_init_data *pdata, |
550 | struct regulator_consumer_supply *consumers, | 608 | struct regulator_consumer_supply *consumers, |
551 | unsigned num_consumers) | 609 | unsigned num_consumers, unsigned long features) |
552 | { | 610 | { |
553 | unsigned sub_chip_id; | 611 | unsigned sub_chip_id; |
554 | /* regulator framework demands init_data ... */ | 612 | /* regulator framework demands init_data ... */ |
@@ -560,6 +618,8 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, | |||
560 | pdata->num_consumer_supplies = num_consumers; | 618 | pdata->num_consumer_supplies = num_consumers; |
561 | } | 619 | } |
562 | 620 | ||
621 | pdata->driver_data = (void *)features; | ||
622 | |||
563 | /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ | 623 | /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ |
564 | sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid; | 624 | sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid; |
565 | return add_numbered_child(sub_chip_id, "twl_reg", num, | 625 | return add_numbered_child(sub_chip_id, "twl_reg", num, |
@@ -567,9 +627,10 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, | |||
567 | } | 627 | } |
568 | 628 | ||
569 | static struct device * | 629 | static struct device * |
570 | add_regulator(int num, struct regulator_init_data *pdata) | 630 | add_regulator(int num, struct regulator_init_data *pdata, |
631 | unsigned long features) | ||
571 | { | 632 | { |
572 | return add_regulator_linked(num, pdata, NULL, 0); | 633 | return add_regulator_linked(num, pdata, NULL, 0, features); |
573 | } | 634 | } |
574 | 635 | ||
575 | /* | 636 | /* |
@@ -649,17 +710,20 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
649 | }; | 710 | }; |
650 | 711 | ||
651 | child = add_regulator_linked(TWL4030_REG_VUSB1V5, | 712 | child = add_regulator_linked(TWL4030_REG_VUSB1V5, |
652 | &usb_fixed, &usb1v5, 1); | 713 | &usb_fixed, &usb1v5, 1, |
714 | features); | ||
653 | if (IS_ERR(child)) | 715 | if (IS_ERR(child)) |
654 | return PTR_ERR(child); | 716 | return PTR_ERR(child); |
655 | 717 | ||
656 | child = add_regulator_linked(TWL4030_REG_VUSB1V8, | 718 | child = add_regulator_linked(TWL4030_REG_VUSB1V8, |
657 | &usb_fixed, &usb1v8, 1); | 719 | &usb_fixed, &usb1v8, 1, |
720 | features); | ||
658 | if (IS_ERR(child)) | 721 | if (IS_ERR(child)) |
659 | return PTR_ERR(child); | 722 | return PTR_ERR(child); |
660 | 723 | ||
661 | child = add_regulator_linked(TWL4030_REG_VUSB3V1, | 724 | child = add_regulator_linked(TWL4030_REG_VUSB3V1, |
662 | &usb_fixed, &usb3v1, 1); | 725 | &usb_fixed, &usb3v1, 1, |
726 | features); | ||
663 | if (IS_ERR(child)) | 727 | if (IS_ERR(child)) |
664 | return PTR_ERR(child); | 728 | return PTR_ERR(child); |
665 | 729 | ||
@@ -682,14 +746,69 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
682 | usb3v1.dev = child; | 746 | usb3v1.dev = child; |
683 | } | 747 | } |
684 | } | 748 | } |
749 | if (twl_has_usb() && pdata->usb && twl_class_is_6030()) { | ||
750 | |||
751 | static struct regulator_consumer_supply usb3v3; | ||
752 | int regulator; | ||
753 | |||
754 | if (twl_has_regulator()) { | ||
755 | /* this is a template that gets copied */ | ||
756 | struct regulator_init_data usb_fixed = { | ||
757 | .constraints.valid_modes_mask = | ||
758 | REGULATOR_MODE_NORMAL | ||
759 | | REGULATOR_MODE_STANDBY, | ||
760 | .constraints.valid_ops_mask = | ||
761 | REGULATOR_CHANGE_MODE | ||
762 | | REGULATOR_CHANGE_STATUS, | ||
763 | }; | ||
764 | |||
765 | if (features & TWL6025_SUBCLASS) { | ||
766 | usb3v3.supply = "ldousb"; | ||
767 | regulator = TWL6025_REG_LDOUSB; | ||
768 | } else { | ||
769 | usb3v3.supply = "vusb"; | ||
770 | regulator = TWL6030_REG_VUSB; | ||
771 | } | ||
772 | child = add_regulator_linked(regulator, &usb_fixed, | ||
773 | &usb3v3, 1, | ||
774 | features); | ||
775 | if (IS_ERR(child)) | ||
776 | return PTR_ERR(child); | ||
777 | } | ||
778 | |||
779 | pdata->usb->features = features; | ||
780 | |||
781 | child = add_child(0, "twl6030_usb", | ||
782 | pdata->usb, sizeof(*pdata->usb), | ||
783 | true, | ||
784 | /* irq1 = VBUS_PRES, irq0 = USB ID */ | ||
785 | pdata->irq_base + USBOTG_INTR_OFFSET, | ||
786 | pdata->irq_base + USB_PRES_INTR_OFFSET); | ||
787 | |||
788 | if (IS_ERR(child)) | ||
789 | return PTR_ERR(child); | ||
790 | /* we need to connect regulators to this transceiver */ | ||
791 | if (twl_has_regulator() && child) | ||
792 | usb3v3.dev = child; | ||
793 | } else if (twl_has_regulator() && twl_class_is_6030()) { | ||
794 | if (features & TWL6025_SUBCLASS) | ||
795 | child = add_regulator(TWL6025_REG_LDOUSB, | ||
796 | pdata->ldousb, features); | ||
797 | else | ||
798 | child = add_regulator(TWL6030_REG_VUSB, | ||
799 | pdata->vusb, features); | ||
800 | |||
801 | if (IS_ERR(child)) | ||
802 | return PTR_ERR(child); | ||
803 | } | ||
685 | 804 | ||
686 | if (twl_has_watchdog()) { | 805 | if (twl_has_watchdog() && twl_class_is_4030()) { |
687 | child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0); | 806 | child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0); |
688 | if (IS_ERR(child)) | 807 | if (IS_ERR(child)) |
689 | return PTR_ERR(child); | 808 | return PTR_ERR(child); |
690 | } | 809 | } |
691 | 810 | ||
692 | if (twl_has_pwrbutton()) { | 811 | if (twl_has_pwrbutton() && twl_class_is_4030()) { |
693 | child = add_child(1, "twl4030_pwrbutton", | 812 | child = add_child(1, "twl4030_pwrbutton", |
694 | NULL, 0, true, pdata->irq_base + 8 + 0, 0); | 813 | NULL, 0, true, pdata->irq_base + 8 + 0, 0); |
695 | if (IS_ERR(child)) | 814 | if (IS_ERR(child)) |
@@ -698,17 +817,17 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
698 | 817 | ||
699 | if (twl_has_codec() && pdata->codec && twl_class_is_4030()) { | 818 | if (twl_has_codec() && pdata->codec && twl_class_is_4030()) { |
700 | sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; | 819 | sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; |
701 | child = add_child(sub_chip_id, "twl4030_codec", | 820 | child = add_child(sub_chip_id, "twl4030-audio", |
702 | pdata->codec, sizeof(*pdata->codec), | 821 | pdata->codec, sizeof(*pdata->codec), |
703 | false, 0, 0); | 822 | false, 0, 0); |
704 | if (IS_ERR(child)) | 823 | if (IS_ERR(child)) |
705 | return PTR_ERR(child); | 824 | return PTR_ERR(child); |
706 | } | 825 | } |
707 | 826 | ||
708 | /* Phoenix*/ | 827 | /* Phoenix codec driver is probed directly atm */ |
709 | if (twl_has_codec() && pdata->codec && twl_class_is_6030()) { | 828 | if (twl_has_codec() && pdata->codec && twl_class_is_6030()) { |
710 | sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; | 829 | sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; |
711 | child = add_child(sub_chip_id, "twl6040_codec", | 830 | child = add_child(sub_chip_id, "twl6040-codec", |
712 | pdata->codec, sizeof(*pdata->codec), | 831 | pdata->codec, sizeof(*pdata->codec), |
713 | false, 0, 0); | 832 | false, 0, 0); |
714 | if (IS_ERR(child)) | 833 | if (IS_ERR(child)) |
@@ -717,46 +836,55 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
717 | 836 | ||
718 | /* twl4030 regulators */ | 837 | /* twl4030 regulators */ |
719 | if (twl_has_regulator() && twl_class_is_4030()) { | 838 | if (twl_has_regulator() && twl_class_is_4030()) { |
720 | child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1); | 839 | child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1, |
840 | features); | ||
721 | if (IS_ERR(child)) | 841 | if (IS_ERR(child)) |
722 | return PTR_ERR(child); | 842 | return PTR_ERR(child); |
723 | 843 | ||
724 | child = add_regulator(TWL4030_REG_VIO, pdata->vio); | 844 | child = add_regulator(TWL4030_REG_VIO, pdata->vio, |
845 | features); | ||
725 | if (IS_ERR(child)) | 846 | if (IS_ERR(child)) |
726 | return PTR_ERR(child); | 847 | return PTR_ERR(child); |
727 | 848 | ||
728 | child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1); | 849 | child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1, |
850 | features); | ||
729 | if (IS_ERR(child)) | 851 | if (IS_ERR(child)) |
730 | return PTR_ERR(child); | 852 | return PTR_ERR(child); |
731 | 853 | ||
732 | child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2); | 854 | child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2, |
855 | features); | ||
733 | if (IS_ERR(child)) | 856 | if (IS_ERR(child)) |
734 | return PTR_ERR(child); | 857 | return PTR_ERR(child); |
735 | 858 | ||
736 | child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1); | 859 | child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1, |
860 | features); | ||
737 | if (IS_ERR(child)) | 861 | if (IS_ERR(child)) |
738 | return PTR_ERR(child); | 862 | return PTR_ERR(child); |
739 | 863 | ||
740 | child = add_regulator(TWL4030_REG_VDAC, pdata->vdac); | 864 | child = add_regulator(TWL4030_REG_VDAC, pdata->vdac, |
865 | features); | ||
741 | if (IS_ERR(child)) | 866 | if (IS_ERR(child)) |
742 | return PTR_ERR(child); | 867 | return PTR_ERR(child); |
743 | 868 | ||
744 | child = add_regulator((features & TWL4030_VAUX2) | 869 | child = add_regulator((features & TWL4030_VAUX2) |
745 | ? TWL4030_REG_VAUX2_4030 | 870 | ? TWL4030_REG_VAUX2_4030 |
746 | : TWL4030_REG_VAUX2, | 871 | : TWL4030_REG_VAUX2, |
747 | pdata->vaux2); | 872 | pdata->vaux2, features); |
748 | if (IS_ERR(child)) | 873 | if (IS_ERR(child)) |
749 | return PTR_ERR(child); | 874 | return PTR_ERR(child); |
750 | 875 | ||
751 | child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1); | 876 | child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1, |
877 | features); | ||
752 | if (IS_ERR(child)) | 878 | if (IS_ERR(child)) |
753 | return PTR_ERR(child); | 879 | return PTR_ERR(child); |
754 | 880 | ||
755 | child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2); | 881 | child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2, |
882 | features); | ||
756 | if (IS_ERR(child)) | 883 | if (IS_ERR(child)) |
757 | return PTR_ERR(child); | 884 | return PTR_ERR(child); |
758 | 885 | ||
759 | child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig); | 886 | child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig, |
887 | features); | ||
760 | if (IS_ERR(child)) | 888 | if (IS_ERR(child)) |
761 | return PTR_ERR(child); | 889 | return PTR_ERR(child); |
762 | } | 890 | } |
@@ -764,70 +892,161 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | |||
764 | /* maybe add LDOs that are omitted on cost-reduced parts */ | 892 | /* maybe add LDOs that are omitted on cost-reduced parts */ |
765 | if (twl_has_regulator() && !(features & TPS_SUBSET) | 893 | if (twl_has_regulator() && !(features & TPS_SUBSET) |
766 | && twl_class_is_4030()) { | 894 | && twl_class_is_4030()) { |
767 | child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2); | 895 | child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2, |
896 | features); | ||
768 | if (IS_ERR(child)) | 897 | if (IS_ERR(child)) |
769 | return PTR_ERR(child); | 898 | return PTR_ERR(child); |
770 | 899 | ||
771 | child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2); | 900 | child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2, |
901 | features); | ||
772 | if (IS_ERR(child)) | 902 | if (IS_ERR(child)) |
773 | return PTR_ERR(child); | 903 | return PTR_ERR(child); |
774 | 904 | ||
775 | child = add_regulator(TWL4030_REG_VSIM, pdata->vsim); | 905 | child = add_regulator(TWL4030_REG_VSIM, pdata->vsim, |
906 | features); | ||
776 | if (IS_ERR(child)) | 907 | if (IS_ERR(child)) |
777 | return PTR_ERR(child); | 908 | return PTR_ERR(child); |
778 | 909 | ||
779 | child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1); | 910 | child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1, |
911 | features); | ||
780 | if (IS_ERR(child)) | 912 | if (IS_ERR(child)) |
781 | return PTR_ERR(child); | 913 | return PTR_ERR(child); |
782 | 914 | ||
783 | child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3); | 915 | child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3, |
916 | features); | ||
784 | if (IS_ERR(child)) | 917 | if (IS_ERR(child)) |
785 | return PTR_ERR(child); | 918 | return PTR_ERR(child); |
786 | 919 | ||
787 | child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4); | 920 | child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4, |
921 | features); | ||
788 | if (IS_ERR(child)) | 922 | if (IS_ERR(child)) |
789 | return PTR_ERR(child); | 923 | return PTR_ERR(child); |
790 | } | 924 | } |
791 | 925 | ||
792 | /* twl6030 regulators */ | 926 | /* twl6030 regulators */ |
927 | if (twl_has_regulator() && twl_class_is_6030() && | ||
928 | !(features & TWL6025_SUBCLASS)) { | ||
929 | child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc, | ||
930 | features); | ||
931 | if (IS_ERR(child)) | ||
932 | return PTR_ERR(child); | ||
933 | |||
934 | child = add_regulator(TWL6030_REG_VPP, pdata->vpp, | ||
935 | features); | ||
936 | if (IS_ERR(child)) | ||
937 | return PTR_ERR(child); | ||
938 | |||
939 | child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim, | ||
940 | features); | ||
941 | if (IS_ERR(child)) | ||
942 | return PTR_ERR(child); | ||
943 | |||
944 | child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio, | ||
945 | features); | ||
946 | if (IS_ERR(child)) | ||
947 | return PTR_ERR(child); | ||
948 | |||
949 | child = add_regulator(TWL6030_REG_VDAC, pdata->vdac, | ||
950 | features); | ||
951 | if (IS_ERR(child)) | ||
952 | return PTR_ERR(child); | ||
953 | |||
954 | child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1, | ||
955 | features); | ||
956 | if (IS_ERR(child)) | ||
957 | return PTR_ERR(child); | ||
958 | |||
959 | child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2, | ||
960 | features); | ||
961 | if (IS_ERR(child)) | ||
962 | return PTR_ERR(child); | ||
963 | |||
964 | child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3, | ||
965 | features); | ||
966 | if (IS_ERR(child)) | ||
967 | return PTR_ERR(child); | ||
968 | |||
969 | child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg, | ||
970 | features); | ||
971 | if (IS_ERR(child)) | ||
972 | return PTR_ERR(child); | ||
973 | } | ||
974 | |||
975 | /* 6030 and 6025 share this regulator */ | ||
793 | if (twl_has_regulator() && twl_class_is_6030()) { | 976 | if (twl_has_regulator() && twl_class_is_6030()) { |
794 | child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc); | 977 | child = add_regulator(TWL6030_REG_VANA, pdata->vana, |
978 | features); | ||
795 | if (IS_ERR(child)) | 979 | if (IS_ERR(child)) |
796 | return PTR_ERR(child); | 980 | return PTR_ERR(child); |
981 | } | ||
797 | 982 | ||
798 | child = add_regulator(TWL6030_REG_VPP, pdata->vpp); | 983 | /* twl6025 regulators */ |
984 | if (twl_has_regulator() && twl_class_is_6030() && | ||
985 | (features & TWL6025_SUBCLASS)) { | ||
986 | child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5, | ||
987 | features); | ||
799 | if (IS_ERR(child)) | 988 | if (IS_ERR(child)) |
800 | return PTR_ERR(child); | 989 | return PTR_ERR(child); |
801 | 990 | ||
802 | child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim); | 991 | child = add_regulator(TWL6025_REG_LDO1, pdata->ldo1, |
992 | features); | ||
803 | if (IS_ERR(child)) | 993 | if (IS_ERR(child)) |
804 | return PTR_ERR(child); | 994 | return PTR_ERR(child); |
805 | 995 | ||
806 | child = add_regulator(TWL6030_REG_VANA, pdata->vana); | 996 | child = add_regulator(TWL6025_REG_LDO7, pdata->ldo7, |
997 | features); | ||
807 | if (IS_ERR(child)) | 998 | if (IS_ERR(child)) |
808 | return PTR_ERR(child); | 999 | return PTR_ERR(child); |
809 | 1000 | ||
810 | child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio); | 1001 | child = add_regulator(TWL6025_REG_LDO6, pdata->ldo6, |
1002 | features); | ||
811 | if (IS_ERR(child)) | 1003 | if (IS_ERR(child)) |
812 | return PTR_ERR(child); | 1004 | return PTR_ERR(child); |
813 | 1005 | ||
814 | child = add_regulator(TWL6030_REG_VDAC, pdata->vdac); | 1006 | child = add_regulator(TWL6025_REG_LDOLN, pdata->ldoln, |
1007 | features); | ||
815 | if (IS_ERR(child)) | 1008 | if (IS_ERR(child)) |
816 | return PTR_ERR(child); | 1009 | return PTR_ERR(child); |
817 | 1010 | ||
818 | child = add_regulator(TWL6030_REG_VUSB, pdata->vusb); | 1011 | child = add_regulator(TWL6025_REG_LDO2, pdata->ldo2, |
1012 | features); | ||
819 | if (IS_ERR(child)) | 1013 | if (IS_ERR(child)) |
820 | return PTR_ERR(child); | 1014 | return PTR_ERR(child); |
821 | 1015 | ||
822 | child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1); | 1016 | child = add_regulator(TWL6025_REG_LDO4, pdata->ldo4, |
1017 | features); | ||
823 | if (IS_ERR(child)) | 1018 | if (IS_ERR(child)) |
824 | return PTR_ERR(child); | 1019 | return PTR_ERR(child); |
825 | 1020 | ||
826 | child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2); | 1021 | child = add_regulator(TWL6025_REG_LDO3, pdata->ldo3, |
1022 | features); | ||
827 | if (IS_ERR(child)) | 1023 | if (IS_ERR(child)) |
828 | return PTR_ERR(child); | 1024 | return PTR_ERR(child); |
829 | 1025 | ||
830 | child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3); | 1026 | child = add_regulator(TWL6025_REG_SMPS3, pdata->smps3, |
1027 | features); | ||
1028 | if (IS_ERR(child)) | ||
1029 | return PTR_ERR(child); | ||
1030 | |||
1031 | child = add_regulator(TWL6025_REG_SMPS4, pdata->smps4, | ||
1032 | features); | ||
1033 | if (IS_ERR(child)) | ||
1034 | return PTR_ERR(child); | ||
1035 | |||
1036 | child = add_regulator(TWL6025_REG_VIO, pdata->vio6025, | ||
1037 | features); | ||
1038 | if (IS_ERR(child)) | ||
1039 | return PTR_ERR(child); | ||
1040 | |||
1041 | } | ||
1042 | |||
1043 | if (twl_has_bci() && pdata->bci && | ||
1044 | !(features & (TPS_SUBSET | TWL5031))) { | ||
1045 | child = add_child(3, "twl4030_bci", | ||
1046 | pdata->bci, sizeof(*pdata->bci), false, | ||
1047 | /* irq0 = CHG_PRES, irq1 = BCI */ | ||
1048 | pdata->irq_base + BCI_PRES_INTR_OFFSET, | ||
1049 | pdata->irq_base + BCI_INTR_OFFSET); | ||
831 | if (IS_ERR(child)) | 1050 | if (IS_ERR(child)) |
832 | return PTR_ERR(child); | 1051 | return PTR_ERR(child); |
833 | } | 1052 | } |
@@ -846,8 +1065,8 @@ static inline int __init protect_pm_master(void) | |||
846 | { | 1065 | { |
847 | int e = 0; | 1066 | int e = 0; |
848 | 1067 | ||
849 | e = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_LOCK, | 1068 | e = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, |
850 | R_PROTECT_KEY); | 1069 | TWL4030_PM_MASTER_PROTECT_KEY); |
851 | return e; | 1070 | return e; |
852 | } | 1071 | } |
853 | 1072 | ||
@@ -855,10 +1074,13 @@ static inline int __init unprotect_pm_master(void) | |||
855 | { | 1074 | { |
856 | int e = 0; | 1075 | int e = 0; |
857 | 1076 | ||
858 | e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK1, | 1077 | e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, |
859 | R_PROTECT_KEY); | 1078 | TWL4030_PM_MASTER_KEY_CFG1, |
860 | e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK2, | 1079 | TWL4030_PM_MASTER_PROTECT_KEY); |
861 | R_PROTECT_KEY); | 1080 | e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, |
1081 | TWL4030_PM_MASTER_KEY_CFG2, | ||
1082 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
1083 | |||
862 | return e; | 1084 | return e; |
863 | } | 1085 | } |
864 | 1086 | ||
@@ -955,13 +1177,14 @@ static int twl_remove(struct i2c_client *client) | |||
955 | } | 1177 | } |
956 | 1178 | ||
957 | /* NOTE: this driver only handles a single twl4030/tps659x0 chip */ | 1179 | /* NOTE: this driver only handles a single twl4030/tps659x0 chip */ |
958 | static int __init | 1180 | static int __devinit |
959 | twl_probe(struct i2c_client *client, const struct i2c_device_id *id) | 1181 | twl_probe(struct i2c_client *client, const struct i2c_device_id *id) |
960 | { | 1182 | { |
961 | int status; | 1183 | int status; |
962 | unsigned i; | 1184 | unsigned i; |
963 | struct twl4030_platform_data *pdata = client->dev.platform_data; | 1185 | struct twl4030_platform_data *pdata = client->dev.platform_data; |
964 | u8 temp; | 1186 | u8 temp; |
1187 | int ret = 0; | ||
965 | 1188 | ||
966 | if (!pdata) { | 1189 | if (!pdata) { |
967 | dev_dbg(&client->dev, "no platform data?\n"); | 1190 | dev_dbg(&client->dev, "no platform data?\n"); |
@@ -1008,6 +1231,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
1008 | /* setup clock framework */ | 1231 | /* setup clock framework */ |
1009 | clocks_init(&client->dev, pdata->clock); | 1232 | clocks_init(&client->dev, pdata->clock); |
1010 | 1233 | ||
1234 | /* read TWL IDCODE Register */ | ||
1235 | if (twl_id == TWL4030_CLASS_ID) { | ||
1236 | ret = twl_read_idcode_register(); | ||
1237 | WARN(ret < 0, "Error: reading twl_idcode register value\n"); | ||
1238 | } | ||
1239 | |||
1011 | /* load power event scripts */ | 1240 | /* load power event scripts */ |
1012 | if (twl_has_power() && pdata->power) | 1241 | if (twl_has_power() && pdata->power) |
1013 | twl4030_power_init(pdata->power); | 1242 | twl4030_power_init(pdata->power); |
@@ -1056,6 +1285,7 @@ static const struct i2c_device_id twl_ids[] = { | |||
1056 | { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */ | 1285 | { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */ |
1057 | { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */ | 1286 | { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */ |
1058 | { "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */ | 1287 | { "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */ |
1288 | { "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */ | ||
1059 | { /* end of list */ }, | 1289 | { /* end of list */ }, |
1060 | }; | 1290 | }; |
1061 | MODULE_DEVICE_TABLE(i2c, twl_ids); | 1291 | MODULE_DEVICE_TABLE(i2c, twl_ids); |
diff --git a/drivers/mfd/twl-core.h b/drivers/mfd/twl-core.h new file mode 100644 index 000000000000..8c50a556e986 --- /dev/null +++ b/drivers/mfd/twl-core.h | |||
@@ -0,0 +1,10 @@ | |||
1 | #ifndef __TWL_CORE_H__ | ||
2 | #define __TWL_CORE_H__ | ||
3 | |||
4 | extern int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); | ||
5 | extern int twl6030_exit_irq(void); | ||
6 | extern int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); | ||
7 | extern int twl4030_exit_irq(void); | ||
8 | extern int twl4030_init_chip_irq(const char *chip); | ||
9 | |||
10 | #endif /* __TWL_CORE_H__ */ | ||
diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c index add6f67d8032..2bf4136464c1 100644 --- a/drivers/mfd/twl4030-codec.c +++ b/drivers/mfd/twl4030-codec.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * MFD driver for twl4030 codec submodule | 2 | * MFD driver for twl4030 codec submodule |
3 | * | 3 | * |
4 | * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com> | 4 | * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> |
5 | * | 5 | * |
6 | * Copyright: (C) 2009 Nokia Corporation | 6 | * Copyright: (C) 2009 Nokia Corporation |
7 | * | 7 | * |
@@ -207,16 +207,16 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) | |||
207 | 207 | ||
208 | if (pdata->audio) { | 208 | if (pdata->audio) { |
209 | cell = &codec->cells[childs]; | 209 | cell = &codec->cells[childs]; |
210 | cell->name = "twl4030_codec_audio"; | 210 | cell->name = "twl4030-codec"; |
211 | cell->platform_data = pdata->audio; | 211 | cell->platform_data = pdata->audio; |
212 | cell->data_size = sizeof(*pdata->audio); | 212 | cell->pdata_size = sizeof(*pdata->audio); |
213 | childs++; | 213 | childs++; |
214 | } | 214 | } |
215 | if (pdata->vibra) { | 215 | if (pdata->vibra) { |
216 | cell = &codec->cells[childs]; | 216 | cell = &codec->cells[childs]; |
217 | cell->name = "twl4030_codec_vibra"; | 217 | cell->name = "twl4030-vibra"; |
218 | cell->platform_data = pdata->vibra; | 218 | cell->platform_data = pdata->vibra; |
219 | cell->data_size = sizeof(*pdata->vibra); | 219 | cell->pdata_size = sizeof(*pdata->vibra); |
220 | childs++; | 220 | childs++; |
221 | } | 221 | } |
222 | 222 | ||
@@ -249,14 +249,14 @@ static int __devexit twl4030_codec_remove(struct platform_device *pdev) | |||
249 | return 0; | 249 | return 0; |
250 | } | 250 | } |
251 | 251 | ||
252 | MODULE_ALIAS("platform:twl4030_codec"); | 252 | MODULE_ALIAS("platform:twl4030-audio"); |
253 | 253 | ||
254 | static struct platform_driver twl4030_codec_driver = { | 254 | static struct platform_driver twl4030_codec_driver = { |
255 | .probe = twl4030_codec_probe, | 255 | .probe = twl4030_codec_probe, |
256 | .remove = __devexit_p(twl4030_codec_remove), | 256 | .remove = __devexit_p(twl4030_codec_remove), |
257 | .driver = { | 257 | .driver = { |
258 | .owner = THIS_MODULE, | 258 | .owner = THIS_MODULE, |
259 | .name = "twl4030_codec", | 259 | .name = "twl4030-audio", |
260 | }, | 260 | }, |
261 | }; | 261 | }; |
262 | 262 | ||
@@ -272,6 +272,6 @@ static void __devexit twl4030_codec_exit(void) | |||
272 | } | 272 | } |
273 | module_exit(twl4030_codec_exit); | 273 | module_exit(twl4030_codec_exit); |
274 | 274 | ||
275 | MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>"); | 275 | MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); |
276 | MODULE_LICENSE("GPL"); | 276 | MODULE_LICENSE("GPL"); |
277 | 277 | ||
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index 097f24d8bceb..8a7ee3139b86 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c | |||
@@ -35,6 +35,7 @@ | |||
35 | 35 | ||
36 | #include <linux/i2c/twl.h> | 36 | #include <linux/i2c/twl.h> |
37 | 37 | ||
38 | #include "twl-core.h" | ||
38 | 39 | ||
39 | /* | 40 | /* |
40 | * TWL4030 IRQ handling has two stages in hardware, and thus in software. | 41 | * TWL4030 IRQ handling has two stages in hardware, and thus in software. |
@@ -78,7 +79,7 @@ struct sih { | |||
78 | u8 irq_lines; /* number of supported irq lines */ | 79 | u8 irq_lines; /* number of supported irq lines */ |
79 | 80 | ||
80 | /* SIR ignored -- set interrupt, for testing only */ | 81 | /* SIR ignored -- set interrupt, for testing only */ |
81 | struct irq_data { | 82 | struct sih_irq_data { |
82 | u8 isr_offset; | 83 | u8 isr_offset; |
83 | u8 imr_offset; | 84 | u8 imr_offset; |
84 | } mask[2]; | 85 | } mask[2]; |
@@ -144,6 +145,7 @@ static const struct sih sih_modules_twl4030[6] = { | |||
144 | .name = "bci", | 145 | .name = "bci", |
145 | .module = TWL4030_MODULE_INTERRUPTS, | 146 | .module = TWL4030_MODULE_INTERRUPTS, |
146 | .control_offset = TWL4030_INTERRUPTS_BCISIHCTRL, | 147 | .control_offset = TWL4030_INTERRUPTS_BCISIHCTRL, |
148 | .set_cor = true, | ||
147 | .bits = 12, | 149 | .bits = 12, |
148 | .bytes_ixr = 2, | 150 | .bytes_ixr = 2, |
149 | .edr_offset = TWL4030_INTERRUPTS_BCIEDR1, | 151 | .edr_offset = TWL4030_INTERRUPTS_BCIEDR1, |
@@ -318,24 +320,8 @@ static int twl4030_irq_thread(void *data) | |||
318 | for (module_irq = twl4030_irq_base; | 320 | for (module_irq = twl4030_irq_base; |
319 | pih_isr; | 321 | pih_isr; |
320 | pih_isr >>= 1, module_irq++) { | 322 | pih_isr >>= 1, module_irq++) { |
321 | if (pih_isr & 0x1) { | 323 | if (pih_isr & 0x1) |
322 | struct irq_desc *d = irq_to_desc(module_irq); | 324 | generic_handle_irq(module_irq); |
323 | |||
324 | if (!d) { | ||
325 | pr_err("twl4030: Invalid SIH IRQ: %d\n", | ||
326 | module_irq); | ||
327 | return -EINVAL; | ||
328 | } | ||
329 | |||
330 | /* These can't be masked ... always warn | ||
331 | * if we get any surprises. | ||
332 | */ | ||
333 | if (d->status & IRQ_DISABLED) | ||
334 | note_interrupt(module_irq, d, | ||
335 | IRQ_NONE); | ||
336 | else | ||
337 | d->handle_irq(module_irq, d); | ||
338 | } | ||
339 | } | 325 | } |
340 | local_irq_enable(); | 326 | local_irq_enable(); |
341 | 327 | ||
@@ -408,7 +394,7 @@ static int twl4030_init_sih_modules(unsigned line) | |||
408 | * set Clear-On-Read (COR) bit. | 394 | * set Clear-On-Read (COR) bit. |
409 | * | 395 | * |
410 | * NOTE that sometimes COR polarity is documented as being | 396 | * NOTE that sometimes COR polarity is documented as being |
411 | * inverted: for MADC and BCI, COR=1 means "clear on write". | 397 | * inverted: for MADC, COR=1 means "clear on write". |
412 | * And for PWR_INT it's not documented... | 398 | * And for PWR_INT it's not documented... |
413 | */ | 399 | */ |
414 | if (sih->set_cor) { | 400 | if (sih->set_cor) { |
@@ -468,7 +454,7 @@ static inline void activate_irq(int irq) | |||
468 | set_irq_flags(irq, IRQF_VALID); | 454 | set_irq_flags(irq, IRQF_VALID); |
469 | #else | 455 | #else |
470 | /* same effect on other architectures */ | 456 | /* same effect on other architectures */ |
471 | set_irq_noprobe(irq); | 457 | irq_set_noprobe(irq); |
472 | #endif | 458 | #endif |
473 | } | 459 | } |
474 | 460 | ||
@@ -558,24 +544,18 @@ static void twl4030_sih_do_edge(struct work_struct *work) | |||
558 | /* Modify only the bits we know must change */ | 544 | /* Modify only the bits we know must change */ |
559 | while (edge_change) { | 545 | while (edge_change) { |
560 | int i = fls(edge_change) - 1; | 546 | int i = fls(edge_change) - 1; |
561 | struct irq_desc *d = irq_to_desc(i + agent->irq_base); | 547 | struct irq_data *idata = irq_get_irq_data(i + agent->irq_base); |
562 | int byte = 1 + (i >> 2); | 548 | int byte = 1 + (i >> 2); |
563 | int off = (i & 0x3) * 2; | 549 | int off = (i & 0x3) * 2; |
564 | 550 | unsigned int type; | |
565 | if (!d) { | ||
566 | pr_err("twl4030: Invalid IRQ: %d\n", | ||
567 | i + agent->irq_base); | ||
568 | return; | ||
569 | } | ||
570 | 551 | ||
571 | bytes[byte] &= ~(0x03 << off); | 552 | bytes[byte] &= ~(0x03 << off); |
572 | 553 | ||
573 | raw_spin_lock_irq(&d->lock); | 554 | type = irqd_get_trigger_type(idata); |
574 | if (d->status & IRQ_TYPE_EDGE_RISING) | 555 | if (type & IRQ_TYPE_EDGE_RISING) |
575 | bytes[byte] |= BIT(off + 1); | 556 | bytes[byte] |= BIT(off + 1); |
576 | if (d->status & IRQ_TYPE_EDGE_FALLING) | 557 | if (type & IRQ_TYPE_EDGE_FALLING) |
577 | bytes[byte] |= BIT(off + 0); | 558 | bytes[byte] |= BIT(off + 0); |
578 | raw_spin_unlock_irq(&d->lock); | ||
579 | 559 | ||
580 | edge_change &= ~BIT(i); | 560 | edge_change &= ~BIT(i); |
581 | } | 561 | } |
@@ -597,49 +577,41 @@ static void twl4030_sih_do_edge(struct work_struct *work) | |||
597 | * completion, potentially including some re-ordering, of these requests. | 577 | * completion, potentially including some re-ordering, of these requests. |
598 | */ | 578 | */ |
599 | 579 | ||
600 | static void twl4030_sih_mask(unsigned irq) | 580 | static void twl4030_sih_mask(struct irq_data *data) |
601 | { | 581 | { |
602 | struct sih_agent *sih = get_irq_chip_data(irq); | 582 | struct sih_agent *sih = irq_data_get_irq_chip_data(data); |
603 | unsigned long flags; | 583 | unsigned long flags; |
604 | 584 | ||
605 | spin_lock_irqsave(&sih_agent_lock, flags); | 585 | spin_lock_irqsave(&sih_agent_lock, flags); |
606 | sih->imr |= BIT(irq - sih->irq_base); | 586 | sih->imr |= BIT(data->irq - sih->irq_base); |
607 | sih->imr_change_pending = true; | 587 | sih->imr_change_pending = true; |
608 | queue_work(wq, &sih->mask_work); | 588 | queue_work(wq, &sih->mask_work); |
609 | spin_unlock_irqrestore(&sih_agent_lock, flags); | 589 | spin_unlock_irqrestore(&sih_agent_lock, flags); |
610 | } | 590 | } |
611 | 591 | ||
612 | static void twl4030_sih_unmask(unsigned irq) | 592 | static void twl4030_sih_unmask(struct irq_data *data) |
613 | { | 593 | { |
614 | struct sih_agent *sih = get_irq_chip_data(irq); | 594 | struct sih_agent *sih = irq_data_get_irq_chip_data(data); |
615 | unsigned long flags; | 595 | unsigned long flags; |
616 | 596 | ||
617 | spin_lock_irqsave(&sih_agent_lock, flags); | 597 | spin_lock_irqsave(&sih_agent_lock, flags); |
618 | sih->imr &= ~BIT(irq - sih->irq_base); | 598 | sih->imr &= ~BIT(data->irq - sih->irq_base); |
619 | sih->imr_change_pending = true; | 599 | sih->imr_change_pending = true; |
620 | queue_work(wq, &sih->mask_work); | 600 | queue_work(wq, &sih->mask_work); |
621 | spin_unlock_irqrestore(&sih_agent_lock, flags); | 601 | spin_unlock_irqrestore(&sih_agent_lock, flags); |
622 | } | 602 | } |
623 | 603 | ||
624 | static int twl4030_sih_set_type(unsigned irq, unsigned trigger) | 604 | static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger) |
625 | { | 605 | { |
626 | struct sih_agent *sih = get_irq_chip_data(irq); | 606 | struct sih_agent *sih = irq_data_get_irq_chip_data(data); |
627 | struct irq_desc *desc = irq_to_desc(irq); | ||
628 | unsigned long flags; | 607 | unsigned long flags; |
629 | 608 | ||
630 | if (!desc) { | ||
631 | pr_err("twl4030: Invalid IRQ: %d\n", irq); | ||
632 | return -EINVAL; | ||
633 | } | ||
634 | |||
635 | if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) | 609 | if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) |
636 | return -EINVAL; | 610 | return -EINVAL; |
637 | 611 | ||
638 | spin_lock_irqsave(&sih_agent_lock, flags); | 612 | spin_lock_irqsave(&sih_agent_lock, flags); |
639 | if ((desc->status & IRQ_TYPE_SENSE_MASK) != trigger) { | 613 | if (irqd_get_trigger_type(data) != trigger) { |
640 | desc->status &= ~IRQ_TYPE_SENSE_MASK; | 614 | sih->edge_change |= BIT(data->irq - sih->irq_base); |
641 | desc->status |= trigger; | ||
642 | sih->edge_change |= BIT(irq - sih->irq_base); | ||
643 | queue_work(wq, &sih->edge_work); | 615 | queue_work(wq, &sih->edge_work); |
644 | } | 616 | } |
645 | spin_unlock_irqrestore(&sih_agent_lock, flags); | 617 | spin_unlock_irqrestore(&sih_agent_lock, flags); |
@@ -648,9 +620,9 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger) | |||
648 | 620 | ||
649 | static struct irq_chip twl4030_sih_irq_chip = { | 621 | static struct irq_chip twl4030_sih_irq_chip = { |
650 | .name = "twl4030", | 622 | .name = "twl4030", |
651 | .mask = twl4030_sih_mask, | 623 | .irq_mask = twl4030_sih_mask, |
652 | .unmask = twl4030_sih_unmask, | 624 | .irq_unmask = twl4030_sih_unmask, |
653 | .set_type = twl4030_sih_set_type, | 625 | .irq_set_type = twl4030_sih_set_type, |
654 | }; | 626 | }; |
655 | 627 | ||
656 | /*----------------------------------------------------------------------*/ | 628 | /*----------------------------------------------------------------------*/ |
@@ -678,7 +650,7 @@ static inline int sih_read_isr(const struct sih *sih) | |||
678 | */ | 650 | */ |
679 | static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc) | 651 | static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc) |
680 | { | 652 | { |
681 | struct sih_agent *agent = get_irq_data(irq); | 653 | struct sih_agent *agent = irq_get_handler_data(irq); |
682 | const struct sih *sih = agent->sih; | 654 | const struct sih *sih = agent->sih; |
683 | int isr; | 655 | int isr; |
684 | 656 | ||
@@ -752,9 +724,9 @@ int twl4030_sih_setup(int module) | |||
752 | for (i = 0; i < sih->bits; i++) { | 724 | for (i = 0; i < sih->bits; i++) { |
753 | irq = irq_base + i; | 725 | irq = irq_base + i; |
754 | 726 | ||
755 | set_irq_chip_and_handler(irq, &twl4030_sih_irq_chip, | 727 | irq_set_chip_and_handler(irq, &twl4030_sih_irq_chip, |
756 | handle_edge_irq); | 728 | handle_edge_irq); |
757 | set_irq_chip_data(irq, agent); | 729 | irq_set_chip_data(irq, agent); |
758 | activate_irq(irq); | 730 | activate_irq(irq); |
759 | } | 731 | } |
760 | 732 | ||
@@ -763,8 +735,8 @@ int twl4030_sih_setup(int module) | |||
763 | 735 | ||
764 | /* replace generic PIH handler (handle_simple_irq) */ | 736 | /* replace generic PIH handler (handle_simple_irq) */ |
765 | irq = sih_mod + twl4030_irq_base; | 737 | irq = sih_mod + twl4030_irq_base; |
766 | set_irq_data(irq, agent); | 738 | irq_set_handler_data(irq, agent); |
767 | set_irq_chained_handler(irq, handle_twl4030_sih); | 739 | irq_set_chained_handler(irq, handle_twl4030_sih); |
768 | 740 | ||
769 | pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name, | 741 | pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name, |
770 | irq, irq_base, twl4030_irq_next - 1); | 742 | irq, irq_base, twl4030_irq_next - 1); |
@@ -810,11 +782,11 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | |||
810 | twl4030_irq_chip = dummy_irq_chip; | 782 | twl4030_irq_chip = dummy_irq_chip; |
811 | twl4030_irq_chip.name = "twl4030"; | 783 | twl4030_irq_chip.name = "twl4030"; |
812 | 784 | ||
813 | twl4030_sih_irq_chip.ack = dummy_irq_chip.ack; | 785 | twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack; |
814 | 786 | ||
815 | for (i = irq_base; i < irq_end; i++) { | 787 | for (i = irq_base; i < irq_end; i++) { |
816 | set_irq_chip_and_handler(i, &twl4030_irq_chip, | 788 | irq_set_chip_and_handler(i, &twl4030_irq_chip, |
817 | handle_simple_irq); | 789 | handle_simple_irq); |
818 | activate_irq(i); | 790 | activate_irq(i); |
819 | } | 791 | } |
820 | twl4030_irq_next = i; | 792 | twl4030_irq_next = i; |
@@ -854,7 +826,7 @@ fail_rqirq: | |||
854 | /* clean up twl4030_sih_setup */ | 826 | /* clean up twl4030_sih_setup */ |
855 | fail: | 827 | fail: |
856 | for (i = irq_base; i < irq_end; i++) | 828 | for (i = irq_base; i < irq_end; i++) |
857 | set_irq_chip_and_handler(i, NULL, NULL); | 829 | irq_set_chip_and_handler(i, NULL, NULL); |
858 | destroy_workqueue(wq); | 830 | destroy_workqueue(wq); |
859 | wq = NULL; | 831 | wq = NULL; |
860 | return status; | 832 | return status; |
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c new file mode 100644 index 000000000000..3941ddcf15fe --- /dev/null +++ b/drivers/mfd/twl4030-madc.c | |||
@@ -0,0 +1,802 @@ | |||
1 | /* | ||
2 | * | ||
3 | * TWL4030 MADC module driver-This driver monitors the real time | ||
4 | * conversion of analog signals like battery temperature, | ||
5 | * battery type, battery level etc. | ||
6 | * | ||
7 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
8 | * J Keerthy <j-keerthy@ti.com> | ||
9 | * | ||
10 | * Based on twl4030-madc.c | ||
11 | * Copyright (C) 2008 Nokia Corporation | ||
12 | * Mikko Ylinen <mikko.k.ylinen@nokia.com> | ||
13 | * | ||
14 | * Amit Kucheria <amit.kucheria@canonical.com> | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or | ||
17 | * modify it under the terms of the GNU General Public License | ||
18 | * version 2 as published by the Free Software Foundation. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, but | ||
21 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
23 | * General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
28 | * 02110-1301 USA | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <linux/init.h> | ||
33 | #include <linux/device.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/delay.h> | ||
37 | #include <linux/platform_device.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/i2c/twl.h> | ||
40 | #include <linux/i2c/twl4030-madc.h> | ||
41 | #include <linux/module.h> | ||
42 | #include <linux/stddef.h> | ||
43 | #include <linux/mutex.h> | ||
44 | #include <linux/bitops.h> | ||
45 | #include <linux/jiffies.h> | ||
46 | #include <linux/types.h> | ||
47 | #include <linux/gfp.h> | ||
48 | #include <linux/err.h> | ||
49 | |||
50 | /* | ||
51 | * struct twl4030_madc_data - a container for madc info | ||
52 | * @dev - pointer to device structure for madc | ||
53 | * @lock - mutex protecting this data structure | ||
54 | * @requests - Array of request struct corresponding to SW1, SW2 and RT | ||
55 | * @imr - Interrupt mask register of MADC | ||
56 | * @isr - Interrupt status register of MADC | ||
57 | */ | ||
58 | struct twl4030_madc_data { | ||
59 | struct device *dev; | ||
60 | struct mutex lock; /* mutex protecting this data structure */ | ||
61 | struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS]; | ||
62 | int imr; | ||
63 | int isr; | ||
64 | }; | ||
65 | |||
66 | static struct twl4030_madc_data *twl4030_madc; | ||
67 | |||
68 | struct twl4030_prescale_divider_ratios { | ||
69 | s16 numerator; | ||
70 | s16 denominator; | ||
71 | }; | ||
72 | |||
73 | static const struct twl4030_prescale_divider_ratios | ||
74 | twl4030_divider_ratios[16] = { | ||
75 | {1, 1}, /* CHANNEL 0 No Prescaler */ | ||
76 | {1, 1}, /* CHANNEL 1 No Prescaler */ | ||
77 | {6, 10}, /* CHANNEL 2 */ | ||
78 | {6, 10}, /* CHANNEL 3 */ | ||
79 | {6, 10}, /* CHANNEL 4 */ | ||
80 | {6, 10}, /* CHANNEL 5 */ | ||
81 | {6, 10}, /* CHANNEL 6 */ | ||
82 | {6, 10}, /* CHANNEL 7 */ | ||
83 | {3, 14}, /* CHANNEL 8 */ | ||
84 | {1, 3}, /* CHANNEL 9 */ | ||
85 | {1, 1}, /* CHANNEL 10 No Prescaler */ | ||
86 | {15, 100}, /* CHANNEL 11 */ | ||
87 | {1, 4}, /* CHANNEL 12 */ | ||
88 | {1, 1}, /* CHANNEL 13 Reserved channels */ | ||
89 | {1, 1}, /* CHANNEL 14 Reseved channels */ | ||
90 | {5, 11}, /* CHANNEL 15 */ | ||
91 | }; | ||
92 | |||
93 | |||
94 | /* | ||
95 | * Conversion table from -3 to 55 degree Celcius | ||
96 | */ | ||
97 | static int therm_tbl[] = { | ||
98 | 30800, 29500, 28300, 27100, | ||
99 | 26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900, | ||
100 | 17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100, | ||
101 | 11600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310, | ||
102 | 8020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830, | ||
103 | 5640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170, | ||
104 | 4040, 3910, 3790, 3670, 3550 | ||
105 | }; | ||
106 | |||
107 | /* | ||
108 | * Structure containing the registers | ||
109 | * of different conversion methods supported by MADC. | ||
110 | * Hardware or RT real time conversion request initiated by external host | ||
111 | * processor for RT Signal conversions. | ||
112 | * External host processors can also request for non RT conversions | ||
113 | * SW1 and SW2 software conversions also called asynchronous or GPC request. | ||
114 | */ | ||
115 | static | ||
116 | const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = { | ||
117 | [TWL4030_MADC_RT] = { | ||
118 | .sel = TWL4030_MADC_RTSELECT_LSB, | ||
119 | .avg = TWL4030_MADC_RTAVERAGE_LSB, | ||
120 | .rbase = TWL4030_MADC_RTCH0_LSB, | ||
121 | }, | ||
122 | [TWL4030_MADC_SW1] = { | ||
123 | .sel = TWL4030_MADC_SW1SELECT_LSB, | ||
124 | .avg = TWL4030_MADC_SW1AVERAGE_LSB, | ||
125 | .rbase = TWL4030_MADC_GPCH0_LSB, | ||
126 | .ctrl = TWL4030_MADC_CTRL_SW1, | ||
127 | }, | ||
128 | [TWL4030_MADC_SW2] = { | ||
129 | .sel = TWL4030_MADC_SW2SELECT_LSB, | ||
130 | .avg = TWL4030_MADC_SW2AVERAGE_LSB, | ||
131 | .rbase = TWL4030_MADC_GPCH0_LSB, | ||
132 | .ctrl = TWL4030_MADC_CTRL_SW2, | ||
133 | }, | ||
134 | }; | ||
135 | |||
136 | /* | ||
137 | * Function to read a particular channel value. | ||
138 | * @madc - pointer to struct twl4030_madc_data | ||
139 | * @reg - lsb of ADC Channel | ||
140 | * If the i2c read fails it returns an error else returns 0. | ||
141 | */ | ||
142 | static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg) | ||
143 | { | ||
144 | u8 msb, lsb; | ||
145 | int ret; | ||
146 | /* | ||
147 | * For each ADC channel, we have MSB and LSB register pair. MSB address | ||
148 | * is always LSB address+1. reg parameter is the address of LSB register | ||
149 | */ | ||
150 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &msb, reg + 1); | ||
151 | if (ret) { | ||
152 | dev_err(madc->dev, "unable to read MSB register 0x%X\n", | ||
153 | reg + 1); | ||
154 | return ret; | ||
155 | } | ||
156 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &lsb, reg); | ||
157 | if (ret) { | ||
158 | dev_err(madc->dev, "unable to read LSB register 0x%X\n", reg); | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | return (int)(((msb << 8) | lsb) >> 6); | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * Return battery temperature | ||
167 | * Or < 0 on failure. | ||
168 | */ | ||
169 | static int twl4030battery_temperature(int raw_volt) | ||
170 | { | ||
171 | u8 val; | ||
172 | int temp, curr, volt, res, ret; | ||
173 | |||
174 | volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R; | ||
175 | /* Getting and calculating the supply current in micro ampers */ | ||
176 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val, | ||
177 | REG_BCICTL2); | ||
178 | if (ret < 0) | ||
179 | return ret; | ||
180 | curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10; | ||
181 | /* Getting and calculating the thermistor resistance in ohms */ | ||
182 | res = volt * 1000 / curr; | ||
183 | /* calculating temperature */ | ||
184 | for (temp = 58; temp >= 0; temp--) { | ||
185 | int actual = therm_tbl[temp]; | ||
186 | |||
187 | if ((actual - res) >= 0) | ||
188 | break; | ||
189 | } | ||
190 | |||
191 | return temp + 1; | ||
192 | } | ||
193 | |||
194 | static int twl4030battery_current(int raw_volt) | ||
195 | { | ||
196 | int ret; | ||
197 | u8 val; | ||
198 | |||
199 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val, | ||
200 | TWL4030_BCI_BCICTL1); | ||
201 | if (ret) | ||
202 | return ret; | ||
203 | if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */ | ||
204 | return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1; | ||
205 | else /* slope of 0.88 mV/mA */ | ||
206 | return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2; | ||
207 | } | ||
208 | /* | ||
209 | * Function to read channel values | ||
210 | * @madc - pointer to twl4030_madc_data struct | ||
211 | * @reg_base - Base address of the first channel | ||
212 | * @Channels - 16 bit bitmap. If the bit is set, channel value is read | ||
213 | * @buf - The channel values are stored here. if read fails error | ||
214 | * value is stored | ||
215 | * Returns the number of successfully read channels. | ||
216 | */ | ||
217 | static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, | ||
218 | u8 reg_base, unsigned | ||
219 | long channels, int *buf) | ||
220 | { | ||
221 | int count = 0, count_req = 0, i; | ||
222 | u8 reg; | ||
223 | |||
224 | for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) { | ||
225 | reg = reg_base + 2 * i; | ||
226 | buf[i] = twl4030_madc_channel_raw_read(madc, reg); | ||
227 | if (buf[i] < 0) { | ||
228 | dev_err(madc->dev, | ||
229 | "Unable to read register 0x%X\n", reg); | ||
230 | count_req++; | ||
231 | continue; | ||
232 | } | ||
233 | switch (i) { | ||
234 | case 10: | ||
235 | buf[i] = twl4030battery_current(buf[i]); | ||
236 | if (buf[i] < 0) { | ||
237 | dev_err(madc->dev, "err reading current\n"); | ||
238 | count_req++; | ||
239 | } else { | ||
240 | count++; | ||
241 | buf[i] = buf[i] - 750; | ||
242 | } | ||
243 | break; | ||
244 | case 1: | ||
245 | buf[i] = twl4030battery_temperature(buf[i]); | ||
246 | if (buf[i] < 0) { | ||
247 | dev_err(madc->dev, "err reading temperature\n"); | ||
248 | count_req++; | ||
249 | } else { | ||
250 | buf[i] -= 3; | ||
251 | count++; | ||
252 | } | ||
253 | break; | ||
254 | default: | ||
255 | count++; | ||
256 | /* Analog Input (V) = conv_result * step_size / R | ||
257 | * conv_result = decimal value of 10-bit conversion | ||
258 | * result | ||
259 | * step size = 1.5 / (2 ^ 10 -1) | ||
260 | * R = Prescaler ratio for input channels. | ||
261 | * Result given in mV hence multiplied by 1000. | ||
262 | */ | ||
263 | buf[i] = (buf[i] * 3 * 1000 * | ||
264 | twl4030_divider_ratios[i].denominator) | ||
265 | / (2 * 1023 * | ||
266 | twl4030_divider_ratios[i].numerator); | ||
267 | } | ||
268 | } | ||
269 | if (count_req) | ||
270 | dev_err(madc->dev, "%d channel conversion failed\n", count_req); | ||
271 | |||
272 | return count; | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * Enables irq. | ||
277 | * @madc - pointer to twl4030_madc_data struct | ||
278 | * @id - irq number to be enabled | ||
279 | * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2 | ||
280 | * corresponding to RT, SW1, SW2 conversion requests. | ||
281 | * If the i2c read fails it returns an error else returns 0. | ||
282 | */ | ||
283 | static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id) | ||
284 | { | ||
285 | u8 val; | ||
286 | int ret; | ||
287 | |||
288 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr); | ||
289 | if (ret) { | ||
290 | dev_err(madc->dev, "unable to read imr register 0x%X\n", | ||
291 | madc->imr); | ||
292 | return ret; | ||
293 | } | ||
294 | val &= ~(1 << id); | ||
295 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr); | ||
296 | if (ret) { | ||
297 | dev_err(madc->dev, | ||
298 | "unable to write imr register 0x%X\n", madc->imr); | ||
299 | return ret; | ||
300 | |||
301 | } | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * Disables irq. | ||
308 | * @madc - pointer to twl4030_madc_data struct | ||
309 | * @id - irq number to be disabled | ||
310 | * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2 | ||
311 | * corresponding to RT, SW1, SW2 conversion requests. | ||
312 | * Returns error if i2c read/write fails. | ||
313 | */ | ||
314 | static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id) | ||
315 | { | ||
316 | u8 val; | ||
317 | int ret; | ||
318 | |||
319 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr); | ||
320 | if (ret) { | ||
321 | dev_err(madc->dev, "unable to read imr register 0x%X\n", | ||
322 | madc->imr); | ||
323 | return ret; | ||
324 | } | ||
325 | val |= (1 << id); | ||
326 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr); | ||
327 | if (ret) { | ||
328 | dev_err(madc->dev, | ||
329 | "unable to write imr register 0x%X\n", madc->imr); | ||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) | ||
337 | { | ||
338 | struct twl4030_madc_data *madc = _madc; | ||
339 | const struct twl4030_madc_conversion_method *method; | ||
340 | u8 isr_val, imr_val; | ||
341 | int i, len, ret; | ||
342 | struct twl4030_madc_request *r; | ||
343 | |||
344 | mutex_lock(&madc->lock); | ||
345 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr); | ||
346 | if (ret) { | ||
347 | dev_err(madc->dev, "unable to read isr register 0x%X\n", | ||
348 | madc->isr); | ||
349 | goto err_i2c; | ||
350 | } | ||
351 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr); | ||
352 | if (ret) { | ||
353 | dev_err(madc->dev, "unable to read imr register 0x%X\n", | ||
354 | madc->imr); | ||
355 | goto err_i2c; | ||
356 | } | ||
357 | isr_val &= ~imr_val; | ||
358 | for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { | ||
359 | if (!(isr_val & (1 << i))) | ||
360 | continue; | ||
361 | ret = twl4030_madc_disable_irq(madc, i); | ||
362 | if (ret < 0) | ||
363 | dev_dbg(madc->dev, "Disable interrupt failed%d\n", i); | ||
364 | madc->requests[i].result_pending = 1; | ||
365 | } | ||
366 | for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { | ||
367 | r = &madc->requests[i]; | ||
368 | /* No pending results for this method, move to next one */ | ||
369 | if (!r->result_pending) | ||
370 | continue; | ||
371 | method = &twl4030_conversion_methods[r->method]; | ||
372 | /* Read results */ | ||
373 | len = twl4030_madc_read_channels(madc, method->rbase, | ||
374 | r->channels, r->rbuf); | ||
375 | /* Return results to caller */ | ||
376 | if (r->func_cb != NULL) { | ||
377 | r->func_cb(len, r->channels, r->rbuf); | ||
378 | r->func_cb = NULL; | ||
379 | } | ||
380 | /* Free request */ | ||
381 | r->result_pending = 0; | ||
382 | r->active = 0; | ||
383 | } | ||
384 | mutex_unlock(&madc->lock); | ||
385 | |||
386 | return IRQ_HANDLED; | ||
387 | |||
388 | err_i2c: | ||
389 | /* | ||
390 | * In case of error check whichever request is active | ||
391 | * and service the same. | ||
392 | */ | ||
393 | for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { | ||
394 | r = &madc->requests[i]; | ||
395 | if (r->active == 0) | ||
396 | continue; | ||
397 | method = &twl4030_conversion_methods[r->method]; | ||
398 | /* Read results */ | ||
399 | len = twl4030_madc_read_channels(madc, method->rbase, | ||
400 | r->channels, r->rbuf); | ||
401 | /* Return results to caller */ | ||
402 | if (r->func_cb != NULL) { | ||
403 | r->func_cb(len, r->channels, r->rbuf); | ||
404 | r->func_cb = NULL; | ||
405 | } | ||
406 | /* Free request */ | ||
407 | r->result_pending = 0; | ||
408 | r->active = 0; | ||
409 | } | ||
410 | mutex_unlock(&madc->lock); | ||
411 | |||
412 | return IRQ_HANDLED; | ||
413 | } | ||
414 | |||
415 | static int twl4030_madc_set_irq(struct twl4030_madc_data *madc, | ||
416 | struct twl4030_madc_request *req) | ||
417 | { | ||
418 | struct twl4030_madc_request *p; | ||
419 | int ret; | ||
420 | |||
421 | p = &madc->requests[req->method]; | ||
422 | memcpy(p, req, sizeof(*req)); | ||
423 | ret = twl4030_madc_enable_irq(madc, req->method); | ||
424 | if (ret < 0) { | ||
425 | dev_err(madc->dev, "enable irq failed!!\n"); | ||
426 | return ret; | ||
427 | } | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | /* | ||
433 | * Function which enables the madc conversion | ||
434 | * by writing to the control register. | ||
435 | * @madc - pointer to twl4030_madc_data struct | ||
436 | * @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1 | ||
437 | * corresponding to RT SW1 or SW2 conversion methods. | ||
438 | * Returns 0 if succeeds else a negative error value | ||
439 | */ | ||
440 | static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc, | ||
441 | int conv_method) | ||
442 | { | ||
443 | const struct twl4030_madc_conversion_method *method; | ||
444 | int ret = 0; | ||
445 | method = &twl4030_conversion_methods[conv_method]; | ||
446 | switch (conv_method) { | ||
447 | case TWL4030_MADC_SW1: | ||
448 | case TWL4030_MADC_SW2: | ||
449 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, | ||
450 | TWL4030_MADC_SW_START, method->ctrl); | ||
451 | if (ret) { | ||
452 | dev_err(madc->dev, | ||
453 | "unable to write ctrl register 0x%X\n", | ||
454 | method->ctrl); | ||
455 | return ret; | ||
456 | } | ||
457 | break; | ||
458 | default: | ||
459 | break; | ||
460 | } | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | /* | ||
466 | * Function that waits for conversion to be ready | ||
467 | * @madc - pointer to twl4030_madc_data struct | ||
468 | * @timeout_ms - timeout value in milliseconds | ||
469 | * @status_reg - ctrl register | ||
470 | * returns 0 if succeeds else a negative error value | ||
471 | */ | ||
472 | static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc, | ||
473 | unsigned int timeout_ms, | ||
474 | u8 status_reg) | ||
475 | { | ||
476 | unsigned long timeout; | ||
477 | int ret; | ||
478 | |||
479 | timeout = jiffies + msecs_to_jiffies(timeout_ms); | ||
480 | do { | ||
481 | u8 reg; | ||
482 | |||
483 | ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, ®, status_reg); | ||
484 | if (ret) { | ||
485 | dev_err(madc->dev, | ||
486 | "unable to read status register 0x%X\n", | ||
487 | status_reg); | ||
488 | return ret; | ||
489 | } | ||
490 | if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW)) | ||
491 | return 0; | ||
492 | usleep_range(500, 2000); | ||
493 | } while (!time_after(jiffies, timeout)); | ||
494 | dev_err(madc->dev, "conversion timeout!\n"); | ||
495 | |||
496 | return -EAGAIN; | ||
497 | } | ||
498 | |||
499 | /* | ||
500 | * An exported function which can be called from other kernel drivers. | ||
501 | * @req twl4030_madc_request structure | ||
502 | * req->rbuf will be filled with read values of channels based on the | ||
503 | * channel index. If a particular channel reading fails there will | ||
504 | * be a negative error value in the corresponding array element. | ||
505 | * returns 0 if succeeds else error value | ||
506 | */ | ||
507 | int twl4030_madc_conversion(struct twl4030_madc_request *req) | ||
508 | { | ||
509 | const struct twl4030_madc_conversion_method *method; | ||
510 | u8 ch_msb, ch_lsb; | ||
511 | int ret; | ||
512 | |||
513 | if (!req) | ||
514 | return -EINVAL; | ||
515 | mutex_lock(&twl4030_madc->lock); | ||
516 | if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) { | ||
517 | ret = -EINVAL; | ||
518 | goto out; | ||
519 | } | ||
520 | /* Do we have a conversion request ongoing */ | ||
521 | if (twl4030_madc->requests[req->method].active) { | ||
522 | ret = -EBUSY; | ||
523 | goto out; | ||
524 | } | ||
525 | ch_msb = (req->channels >> 8) & 0xff; | ||
526 | ch_lsb = req->channels & 0xff; | ||
527 | method = &twl4030_conversion_methods[req->method]; | ||
528 | /* Select channels to be converted */ | ||
529 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_msb, method->sel + 1); | ||
530 | if (ret) { | ||
531 | dev_err(twl4030_madc->dev, | ||
532 | "unable to write sel register 0x%X\n", method->sel + 1); | ||
533 | return ret; | ||
534 | } | ||
535 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel); | ||
536 | if (ret) { | ||
537 | dev_err(twl4030_madc->dev, | ||
538 | "unable to write sel register 0x%X\n", method->sel + 1); | ||
539 | return ret; | ||
540 | } | ||
541 | /* Select averaging for all channels if do_avg is set */ | ||
542 | if (req->do_avg) { | ||
543 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, | ||
544 | ch_msb, method->avg + 1); | ||
545 | if (ret) { | ||
546 | dev_err(twl4030_madc->dev, | ||
547 | "unable to write avg register 0x%X\n", | ||
548 | method->avg + 1); | ||
549 | return ret; | ||
550 | } | ||
551 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, | ||
552 | ch_lsb, method->avg); | ||
553 | if (ret) { | ||
554 | dev_err(twl4030_madc->dev, | ||
555 | "unable to write sel reg 0x%X\n", | ||
556 | method->sel + 1); | ||
557 | return ret; | ||
558 | } | ||
559 | } | ||
560 | if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) { | ||
561 | ret = twl4030_madc_set_irq(twl4030_madc, req); | ||
562 | if (ret < 0) | ||
563 | goto out; | ||
564 | ret = twl4030_madc_start_conversion(twl4030_madc, req->method); | ||
565 | if (ret < 0) | ||
566 | goto out; | ||
567 | twl4030_madc->requests[req->method].active = 1; | ||
568 | ret = 0; | ||
569 | goto out; | ||
570 | } | ||
571 | /* With RT method we should not be here anymore */ | ||
572 | if (req->method == TWL4030_MADC_RT) { | ||
573 | ret = -EINVAL; | ||
574 | goto out; | ||
575 | } | ||
576 | ret = twl4030_madc_start_conversion(twl4030_madc, req->method); | ||
577 | if (ret < 0) | ||
578 | goto out; | ||
579 | twl4030_madc->requests[req->method].active = 1; | ||
580 | /* Wait until conversion is ready (ctrl register returns EOC) */ | ||
581 | ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl); | ||
582 | if (ret) { | ||
583 | twl4030_madc->requests[req->method].active = 0; | ||
584 | goto out; | ||
585 | } | ||
586 | ret = twl4030_madc_read_channels(twl4030_madc, method->rbase, | ||
587 | req->channels, req->rbuf); | ||
588 | twl4030_madc->requests[req->method].active = 0; | ||
589 | |||
590 | out: | ||
591 | mutex_unlock(&twl4030_madc->lock); | ||
592 | |||
593 | return ret; | ||
594 | } | ||
595 | EXPORT_SYMBOL_GPL(twl4030_madc_conversion); | ||
596 | |||
597 | /* | ||
598 | * Return channel value | ||
599 | * Or < 0 on failure. | ||
600 | */ | ||
601 | int twl4030_get_madc_conversion(int channel_no) | ||
602 | { | ||
603 | struct twl4030_madc_request req; | ||
604 | int temp = 0; | ||
605 | int ret; | ||
606 | |||
607 | req.channels = (1 << channel_no); | ||
608 | req.method = TWL4030_MADC_SW2; | ||
609 | req.active = 0; | ||
610 | req.func_cb = NULL; | ||
611 | ret = twl4030_madc_conversion(&req); | ||
612 | if (ret < 0) | ||
613 | return ret; | ||
614 | if (req.rbuf[channel_no] > 0) | ||
615 | temp = req.rbuf[channel_no]; | ||
616 | |||
617 | return temp; | ||
618 | } | ||
619 | EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion); | ||
620 | |||
621 | /* | ||
622 | * Function to enable or disable bias current for | ||
623 | * main battery type reading or temperature sensing | ||
624 | * @madc - pointer to twl4030_madc_data struct | ||
625 | * @chan - can be one of the two values | ||
626 | * TWL4030_BCI_ITHEN - Enables bias current for main battery type reading | ||
627 | * TWL4030_BCI_TYPEN - Enables bias current for main battery temperature | ||
628 | * sensing | ||
629 | * @on - enable or disable chan. | ||
630 | */ | ||
631 | static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc, | ||
632 | int chan, int on) | ||
633 | { | ||
634 | int ret; | ||
635 | u8 regval; | ||
636 | |||
637 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, | ||
638 | ®val, TWL4030_BCI_BCICTL1); | ||
639 | if (ret) { | ||
640 | dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X", | ||
641 | TWL4030_BCI_BCICTL1); | ||
642 | return ret; | ||
643 | } | ||
644 | if (on) | ||
645 | regval |= chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN; | ||
646 | else | ||
647 | regval &= chan ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN; | ||
648 | ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, | ||
649 | regval, TWL4030_BCI_BCICTL1); | ||
650 | if (ret) { | ||
651 | dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n", | ||
652 | TWL4030_BCI_BCICTL1); | ||
653 | return ret; | ||
654 | } | ||
655 | |||
656 | return 0; | ||
657 | } | ||
658 | |||
659 | /* | ||
660 | * Function that sets MADC software power on bit to enable MADC | ||
661 | * @madc - pointer to twl4030_madc_data struct | ||
662 | * @on - Enable or disable MADC software powen on bit. | ||
663 | * returns error if i2c read/write fails else 0 | ||
664 | */ | ||
665 | static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on) | ||
666 | { | ||
667 | u8 regval; | ||
668 | int ret; | ||
669 | |||
670 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, | ||
671 | ®val, TWL4030_MADC_CTRL1); | ||
672 | if (ret) { | ||
673 | dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n", | ||
674 | TWL4030_MADC_CTRL1); | ||
675 | return ret; | ||
676 | } | ||
677 | if (on) | ||
678 | regval |= TWL4030_MADC_MADCON; | ||
679 | else | ||
680 | regval &= ~TWL4030_MADC_MADCON; | ||
681 | ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1); | ||
682 | if (ret) { | ||
683 | dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n", | ||
684 | TWL4030_MADC_CTRL1); | ||
685 | return ret; | ||
686 | } | ||
687 | |||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | /* | ||
692 | * Initialize MADC and request for threaded irq | ||
693 | */ | ||
694 | static int __devinit twl4030_madc_probe(struct platform_device *pdev) | ||
695 | { | ||
696 | struct twl4030_madc_data *madc; | ||
697 | struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data; | ||
698 | int ret; | ||
699 | u8 regval; | ||
700 | |||
701 | if (!pdata) { | ||
702 | dev_err(&pdev->dev, "platform_data not available\n"); | ||
703 | return -EINVAL; | ||
704 | } | ||
705 | madc = kzalloc(sizeof(*madc), GFP_KERNEL); | ||
706 | if (!madc) | ||
707 | return -ENOMEM; | ||
708 | |||
709 | /* | ||
710 | * Phoenix provides 2 interrupt lines. The first one is connected to | ||
711 | * the OMAP. The other one can be connected to the other processor such | ||
712 | * as modem. Hence two separate ISR and IMR registers. | ||
713 | */ | ||
714 | madc->imr = (pdata->irq_line == 1) ? | ||
715 | TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2; | ||
716 | madc->isr = (pdata->irq_line == 1) ? | ||
717 | TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2; | ||
718 | ret = twl4030_madc_set_power(madc, 1); | ||
719 | if (ret < 0) | ||
720 | goto err_power; | ||
721 | ret = twl4030_madc_set_current_generator(madc, 0, 1); | ||
722 | if (ret < 0) | ||
723 | goto err_current_generator; | ||
724 | |||
725 | ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, | ||
726 | ®val, TWL4030_BCI_BCICTL1); | ||
727 | if (ret) { | ||
728 | dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n", | ||
729 | TWL4030_BCI_BCICTL1); | ||
730 | goto err_i2c; | ||
731 | } | ||
732 | regval |= TWL4030_BCI_MESBAT; | ||
733 | ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, | ||
734 | regval, TWL4030_BCI_BCICTL1); | ||
735 | if (ret) { | ||
736 | dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n", | ||
737 | TWL4030_BCI_BCICTL1); | ||
738 | goto err_i2c; | ||
739 | } | ||
740 | platform_set_drvdata(pdev, madc); | ||
741 | mutex_init(&madc->lock); | ||
742 | ret = request_threaded_irq(platform_get_irq(pdev, 0), NULL, | ||
743 | twl4030_madc_threaded_irq_handler, | ||
744 | IRQF_TRIGGER_RISING, "twl4030_madc", madc); | ||
745 | if (ret) { | ||
746 | dev_dbg(&pdev->dev, "could not request irq\n"); | ||
747 | goto err_irq; | ||
748 | } | ||
749 | twl4030_madc = madc; | ||
750 | return 0; | ||
751 | err_irq: | ||
752 | platform_set_drvdata(pdev, NULL); | ||
753 | err_i2c: | ||
754 | twl4030_madc_set_current_generator(madc, 0, 0); | ||
755 | err_current_generator: | ||
756 | twl4030_madc_set_power(madc, 0); | ||
757 | err_power: | ||
758 | kfree(madc); | ||
759 | |||
760 | return ret; | ||
761 | } | ||
762 | |||
763 | static int __devexit twl4030_madc_remove(struct platform_device *pdev) | ||
764 | { | ||
765 | struct twl4030_madc_data *madc = platform_get_drvdata(pdev); | ||
766 | |||
767 | free_irq(platform_get_irq(pdev, 0), madc); | ||
768 | platform_set_drvdata(pdev, NULL); | ||
769 | twl4030_madc_set_current_generator(madc, 0, 0); | ||
770 | twl4030_madc_set_power(madc, 0); | ||
771 | kfree(madc); | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | static struct platform_driver twl4030_madc_driver = { | ||
777 | .probe = twl4030_madc_probe, | ||
778 | .remove = __exit_p(twl4030_madc_remove), | ||
779 | .driver = { | ||
780 | .name = "twl4030_madc", | ||
781 | .owner = THIS_MODULE, | ||
782 | }, | ||
783 | }; | ||
784 | |||
785 | static int __init twl4030_madc_init(void) | ||
786 | { | ||
787 | return platform_driver_register(&twl4030_madc_driver); | ||
788 | } | ||
789 | |||
790 | module_init(twl4030_madc_init); | ||
791 | |||
792 | static void __exit twl4030_madc_exit(void) | ||
793 | { | ||
794 | platform_driver_unregister(&twl4030_madc_driver); | ||
795 | } | ||
796 | |||
797 | module_exit(twl4030_madc_exit); | ||
798 | |||
799 | MODULE_DESCRIPTION("TWL4030 ADC driver"); | ||
800 | MODULE_LICENSE("GPL"); | ||
801 | MODULE_AUTHOR("J Keerthy"); | ||
802 | MODULE_ALIAS("platform:twl4030_madc"); | ||
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 7efa8789a3a2..a764676f0922 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c | |||
@@ -63,10 +63,6 @@ static u8 twl4030_start_script_address = 0x2b; | |||
63 | #define R_MEMORY_ADDRESS PHY_TO_OFF_PM_MASTER(0x59) | 63 | #define R_MEMORY_ADDRESS PHY_TO_OFF_PM_MASTER(0x59) |
64 | #define R_MEMORY_DATA PHY_TO_OFF_PM_MASTER(0x5a) | 64 | #define R_MEMORY_DATA PHY_TO_OFF_PM_MASTER(0x5a) |
65 | 65 | ||
66 | #define R_PROTECT_KEY 0x0E | ||
67 | #define R_KEY_1 0xC0 | ||
68 | #define R_KEY_2 0x0C | ||
69 | |||
70 | /* resource configuration registers | 66 | /* resource configuration registers |
71 | <RESOURCE>_DEV_GRP at address 'n+0' | 67 | <RESOURCE>_DEV_GRP at address 'n+0' |
72 | <RESOURCE>_TYPE at address 'n+1' | 68 | <RESOURCE>_TYPE at address 'n+1' |
@@ -124,7 +120,7 @@ static u8 res_config_addrs[] = { | |||
124 | [RES_HFCLKOUT] = 0x8b, | 120 | [RES_HFCLKOUT] = 0x8b, |
125 | [RES_32KCLKOUT] = 0x8e, | 121 | [RES_32KCLKOUT] = 0x8e, |
126 | [RES_RESET] = 0x91, | 122 | [RES_RESET] = 0x91, |
127 | [RES_Main_Ref] = 0x94, | 123 | [RES_MAIN_REF] = 0x94, |
128 | }; | 124 | }; |
129 | 125 | ||
130 | static int __init twl4030_write_script_byte(u8 address, u8 byte) | 126 | static int __init twl4030_write_script_byte(u8 address, u8 byte) |
@@ -451,12 +447,13 @@ static int __init load_twl4030_script(struct twl4030_script *tscript, | |||
451 | if (err) | 447 | if (err) |
452 | goto out; | 448 | goto out; |
453 | } | 449 | } |
454 | if (tscript->flags & TWL4030_SLEEP_SCRIPT) | 450 | if (tscript->flags & TWL4030_SLEEP_SCRIPT) { |
455 | if (order) | 451 | if (!order) |
456 | pr_warning("TWL4030: Bad order of scripts (sleep "\ | 452 | pr_warning("TWL4030: Bad order of scripts (sleep "\ |
457 | "script before wakeup) Leads to boot"\ | 453 | "script before wakeup) Leads to boot"\ |
458 | "failure on some boards\n"); | 454 | "failure on some boards\n"); |
459 | err = twl4030_config_sleep_sequence(address); | 455 | err = twl4030_config_sleep_sequence(address); |
456 | } | ||
460 | out: | 457 | out: |
461 | return err; | 458 | return err; |
462 | } | 459 | } |
@@ -465,15 +462,17 @@ int twl4030_remove_script(u8 flags) | |||
465 | { | 462 | { |
466 | int err = 0; | 463 | int err = 0; |
467 | 464 | ||
468 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1, | 465 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, |
469 | R_PROTECT_KEY); | 466 | TWL4030_PM_MASTER_KEY_CFG1, |
467 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
470 | if (err) { | 468 | if (err) { |
471 | pr_err("twl4030: unable to unlock PROTECT_KEY\n"); | 469 | pr_err("twl4030: unable to unlock PROTECT_KEY\n"); |
472 | return err; | 470 | return err; |
473 | } | 471 | } |
474 | 472 | ||
475 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2, | 473 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, |
476 | R_PROTECT_KEY); | 474 | TWL4030_PM_MASTER_KEY_CFG2, |
475 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
477 | if (err) { | 476 | if (err) { |
478 | pr_err("twl4030: unable to unlock PROTECT_KEY\n"); | 477 | pr_err("twl4030: unable to unlock PROTECT_KEY\n"); |
479 | return err; | 478 | return err; |
@@ -486,9 +485,9 @@ int twl4030_remove_script(u8 flags) | |||
486 | return err; | 485 | return err; |
487 | } | 486 | } |
488 | if (flags & TWL4030_WAKEUP12_SCRIPT) { | 487 | if (flags & TWL4030_WAKEUP12_SCRIPT) { |
489 | if (err) | ||
490 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT, | 488 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT, |
491 | R_SEQ_ADD_S2A12); | 489 | R_SEQ_ADD_S2A12); |
490 | if (err) | ||
492 | return err; | 491 | return err; |
493 | } | 492 | } |
494 | if (flags & TWL4030_WAKEUP3_SCRIPT) { | 493 | if (flags & TWL4030_WAKEUP3_SCRIPT) { |
@@ -504,7 +503,8 @@ int twl4030_remove_script(u8 flags) | |||
504 | return err; | 503 | return err; |
505 | } | 504 | } |
506 | 505 | ||
507 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY); | 506 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, |
507 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
508 | if (err) | 508 | if (err) |
509 | pr_err("TWL4030 Unable to relock registers\n"); | 509 | pr_err("TWL4030 Unable to relock registers\n"); |
510 | 510 | ||
@@ -518,13 +518,15 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) | |||
518 | struct twl4030_resconfig *resconfig; | 518 | struct twl4030_resconfig *resconfig; |
519 | u8 address = twl4030_start_script_address; | 519 | u8 address = twl4030_start_script_address; |
520 | 520 | ||
521 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1, | 521 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, |
522 | R_PROTECT_KEY); | 522 | TWL4030_PM_MASTER_KEY_CFG1, |
523 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
523 | if (err) | 524 | if (err) |
524 | goto unlock; | 525 | goto unlock; |
525 | 526 | ||
526 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2, | 527 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, |
527 | R_PROTECT_KEY); | 528 | TWL4030_PM_MASTER_KEY_CFG2, |
529 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
528 | if (err) | 530 | if (err) |
529 | goto unlock; | 531 | goto unlock; |
530 | 532 | ||
@@ -546,7 +548,8 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) | |||
546 | } | 548 | } |
547 | } | 549 | } |
548 | 550 | ||
549 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY); | 551 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, |
552 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
550 | if (err) | 553 | if (err) |
551 | pr_err("TWL4030 Unable to relock registers\n"); | 554 | pr_err("TWL4030 Unable to relock registers\n"); |
552 | return; | 555 | return; |
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 10bf228ad626..eb3b5f88e566 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c | |||
@@ -36,6 +36,9 @@ | |||
36 | #include <linux/irq.h> | 36 | #include <linux/irq.h> |
37 | #include <linux/kthread.h> | 37 | #include <linux/kthread.h> |
38 | #include <linux/i2c/twl.h> | 38 | #include <linux/i2c/twl.h> |
39 | #include <linux/platform_device.h> | ||
40 | |||
41 | #include "twl-core.h" | ||
39 | 42 | ||
40 | /* | 43 | /* |
41 | * TWL6030 (unlike its predecessors, which had two level interrupt handling) | 44 | * TWL6030 (unlike its predecessors, which had two level interrupt handling) |
@@ -71,10 +74,10 @@ static int twl6030_interrupt_mapping[24] = { | |||
71 | USBOTG_INTR_OFFSET, /* Bit 16 ID_WKUP */ | 74 | USBOTG_INTR_OFFSET, /* Bit 16 ID_WKUP */ |
72 | USBOTG_INTR_OFFSET, /* Bit 17 VBUS_WKUP */ | 75 | USBOTG_INTR_OFFSET, /* Bit 17 VBUS_WKUP */ |
73 | USBOTG_INTR_OFFSET, /* Bit 18 ID */ | 76 | USBOTG_INTR_OFFSET, /* Bit 18 ID */ |
74 | USBOTG_INTR_OFFSET, /* Bit 19 VBUS */ | 77 | USB_PRES_INTR_OFFSET, /* Bit 19 VBUS */ |
75 | CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */ | 78 | CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */ |
76 | CHARGER_INTR_OFFSET, /* Bit 21 EXT_CHRG */ | 79 | CHARGERFAULT_INTR_OFFSET, /* Bit 21 EXT_CHRG */ |
77 | CHARGER_INTR_OFFSET, /* Bit 22 INT_CHRG */ | 80 | CHARGERFAULT_INTR_OFFSET, /* Bit 22 INT_CHRG */ |
78 | RSV_INTR_OFFSET, /* Bit 23 Reserved */ | 81 | RSV_INTR_OFFSET, /* Bit 23 Reserved */ |
79 | }; | 82 | }; |
80 | /*----------------------------------------------------------------------*/ | 83 | /*----------------------------------------------------------------------*/ |
@@ -125,27 +128,19 @@ static int twl6030_irq_thread(void *data) | |||
125 | 128 | ||
126 | sts.bytes[3] = 0; /* Only 24 bits are valid*/ | 129 | sts.bytes[3] = 0; /* Only 24 bits are valid*/ |
127 | 130 | ||
131 | /* | ||
132 | * Since VBUS status bit is not reliable for VBUS disconnect | ||
133 | * use CHARGER VBUS detection status bit instead. | ||
134 | */ | ||
135 | if (sts.bytes[2] & 0x10) | ||
136 | sts.bytes[2] |= 0x08; | ||
137 | |||
128 | for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) { | 138 | for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) { |
129 | local_irq_disable(); | 139 | local_irq_disable(); |
130 | if (sts.int_sts & 0x1) { | 140 | if (sts.int_sts & 0x1) { |
131 | int module_irq = twl6030_irq_base + | 141 | int module_irq = twl6030_irq_base + |
132 | twl6030_interrupt_mapping[i]; | 142 | twl6030_interrupt_mapping[i]; |
133 | struct irq_desc *d = irq_to_desc(module_irq); | 143 | generic_handle_irq(module_irq); |
134 | |||
135 | if (!d) { | ||
136 | pr_err("twl6030: Invalid SIH IRQ: %d\n", | ||
137 | module_irq); | ||
138 | return -EINVAL; | ||
139 | } | ||
140 | |||
141 | /* These can't be masked ... always warn | ||
142 | * if we get any surprises. | ||
143 | */ | ||
144 | if (d->status & IRQ_DISABLED) | ||
145 | note_interrupt(module_irq, d, | ||
146 | IRQ_NONE); | ||
147 | else | ||
148 | d->handle_irq(module_irq, d); | ||
149 | 144 | ||
150 | } | 145 | } |
151 | local_irq_enable(); | 146 | local_irq_enable(); |
@@ -188,7 +183,7 @@ static inline void activate_irq(int irq) | |||
188 | set_irq_flags(irq, IRQF_VALID); | 183 | set_irq_flags(irq, IRQF_VALID); |
189 | #else | 184 | #else |
190 | /* same effect on other architectures */ | 185 | /* same effect on other architectures */ |
191 | set_irq_noprobe(irq); | 186 | irq_set_noprobe(irq); |
192 | #endif | 187 | #endif |
193 | } | 188 | } |
194 | 189 | ||
@@ -223,6 +218,78 @@ int twl6030_interrupt_mask(u8 bit_mask, u8 offset) | |||
223 | } | 218 | } |
224 | EXPORT_SYMBOL(twl6030_interrupt_mask); | 219 | EXPORT_SYMBOL(twl6030_interrupt_mask); |
225 | 220 | ||
221 | int twl6030_mmc_card_detect_config(void) | ||
222 | { | ||
223 | int ret; | ||
224 | u8 reg_val = 0; | ||
225 | |||
226 | /* Unmasking the Card detect Interrupt line for MMC1 from Phoenix */ | ||
227 | twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, | ||
228 | REG_INT_MSK_LINE_B); | ||
229 | twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, | ||
230 | REG_INT_MSK_STS_B); | ||
231 | /* | ||
232 | * Initially Configuring MMC_CTRL for receiving interrupts & | ||
233 | * Card status on TWL6030 for MMC1 | ||
234 | */ | ||
235 | ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, TWL6030_MMCCTRL); | ||
236 | if (ret < 0) { | ||
237 | pr_err("twl6030: Failed to read MMCCTRL, error %d\n", ret); | ||
238 | return ret; | ||
239 | } | ||
240 | reg_val &= ~VMMC_AUTO_OFF; | ||
241 | reg_val |= SW_FC; | ||
242 | ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, TWL6030_MMCCTRL); | ||
243 | if (ret < 0) { | ||
244 | pr_err("twl6030: Failed to write MMCCTRL, error %d\n", ret); | ||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | /* Configuring PullUp-PullDown register */ | ||
249 | ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, | ||
250 | TWL6030_CFG_INPUT_PUPD3); | ||
251 | if (ret < 0) { | ||
252 | pr_err("twl6030: Failed to read CFG_INPUT_PUPD3, error %d\n", | ||
253 | ret); | ||
254 | return ret; | ||
255 | } | ||
256 | reg_val &= ~(MMC_PU | MMC_PD); | ||
257 | ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, | ||
258 | TWL6030_CFG_INPUT_PUPD3); | ||
259 | if (ret < 0) { | ||
260 | pr_err("twl6030: Failed to write CFG_INPUT_PUPD3, error %d\n", | ||
261 | ret); | ||
262 | return ret; | ||
263 | } | ||
264 | return 0; | ||
265 | } | ||
266 | EXPORT_SYMBOL(twl6030_mmc_card_detect_config); | ||
267 | |||
268 | int twl6030_mmc_card_detect(struct device *dev, int slot) | ||
269 | { | ||
270 | int ret = -EIO; | ||
271 | u8 read_reg = 0; | ||
272 | struct platform_device *pdev = to_platform_device(dev); | ||
273 | |||
274 | if (pdev->id) { | ||
275 | /* TWL6030 provide's Card detect support for | ||
276 | * only MMC1 controller. | ||
277 | */ | ||
278 | pr_err("Unknown MMC controller %d in %s\n", pdev->id, __func__); | ||
279 | return ret; | ||
280 | } | ||
281 | /* | ||
282 | * BIT0 of MMC_CTRL on TWL6030 provides card status for MMC1 | ||
283 | * 0 - Card not present ,1 - Card present | ||
284 | */ | ||
285 | ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, &read_reg, | ||
286 | TWL6030_MMCCTRL); | ||
287 | if (ret >= 0) | ||
288 | ret = read_reg & STS_MMC; | ||
289 | return ret; | ||
290 | } | ||
291 | EXPORT_SYMBOL(twl6030_mmc_card_detect); | ||
292 | |||
226 | int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | 293 | int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) |
227 | { | 294 | { |
228 | 295 | ||
@@ -250,11 +317,11 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | |||
250 | */ | 317 | */ |
251 | twl6030_irq_chip = dummy_irq_chip; | 318 | twl6030_irq_chip = dummy_irq_chip; |
252 | twl6030_irq_chip.name = "twl6030"; | 319 | twl6030_irq_chip.name = "twl6030"; |
253 | twl6030_irq_chip.set_type = NULL; | 320 | twl6030_irq_chip.irq_set_type = NULL; |
254 | 321 | ||
255 | for (i = irq_base; i < irq_end; i++) { | 322 | for (i = irq_base; i < irq_end; i++) { |
256 | set_irq_chip_and_handler(i, &twl6030_irq_chip, | 323 | irq_set_chip_and_handler(i, &twl6030_irq_chip, |
257 | handle_simple_irq); | 324 | handle_simple_irq); |
258 | activate_irq(i); | 325 | activate_irq(i); |
259 | } | 326 | } |
260 | 327 | ||
@@ -283,7 +350,7 @@ fail_irq: | |||
283 | 350 | ||
284 | fail_kthread: | 351 | fail_kthread: |
285 | for (i = irq_base; i < irq_end; i++) | 352 | for (i = irq_base; i < irq_end; i++) |
286 | set_irq_chip_and_handler(i, NULL, NULL); | 353 | irq_set_chip_and_handler(i, NULL, NULL); |
287 | return status; | 354 | return status; |
288 | } | 355 | } |
289 | 356 | ||
diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c index d73f84ba0f08..daf69527ed83 100644 --- a/drivers/mfd/ucb1400_core.c +++ b/drivers/mfd/ucb1400_core.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * Copyright: MontaVista Software, Inc. | 8 | * Copyright: MontaVista Software, Inc. |
9 | * | 9 | * |
10 | * Spliting done by: Marek Vasut <marek.vasut@gmail.com> | 10 | * Spliting done by: Marek Vasut <marek.vasut@gmail.com> |
11 | * If something doesnt work and it worked before spliting, e-mail me, | 11 | * If something doesn't work and it worked before spliting, e-mail me, |
12 | * dont bother Nicolas please ;-) | 12 | * dont bother Nicolas please ;-) |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 000cb414a78a..38ffbd50a0d2 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c | |||
@@ -60,6 +60,7 @@ static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x | |||
60 | input_report_abs(idev, ABS_X, x); | 60 | input_report_abs(idev, ABS_X, x); |
61 | input_report_abs(idev, ABS_Y, y); | 61 | input_report_abs(idev, ABS_Y, y); |
62 | input_report_abs(idev, ABS_PRESSURE, pressure); | 62 | input_report_abs(idev, ABS_PRESSURE, pressure); |
63 | input_report_key(idev, BTN_TOUCH, 1); | ||
63 | input_sync(idev); | 64 | input_sync(idev); |
64 | } | 65 | } |
65 | 66 | ||
@@ -68,6 +69,7 @@ static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) | |||
68 | struct input_dev *idev = ts->idev; | 69 | struct input_dev *idev = ts->idev; |
69 | 70 | ||
70 | input_report_abs(idev, ABS_PRESSURE, 0); | 71 | input_report_abs(idev, ABS_PRESSURE, 0); |
72 | input_report_key(idev, BTN_TOUCH, 0); | ||
71 | input_sync(idev); | 73 | input_sync(idev); |
72 | } | 74 | } |
73 | 75 | ||
@@ -384,13 +386,20 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) | |||
384 | idev->open = ucb1x00_ts_open; | 386 | idev->open = ucb1x00_ts_open; |
385 | idev->close = ucb1x00_ts_close; | 387 | idev->close = ucb1x00_ts_close; |
386 | 388 | ||
387 | __set_bit(EV_ABS, idev->evbit); | 389 | idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); |
388 | __set_bit(ABS_X, idev->absbit); | 390 | idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); |
389 | __set_bit(ABS_Y, idev->absbit); | ||
390 | __set_bit(ABS_PRESSURE, idev->absbit); | ||
391 | 391 | ||
392 | input_set_drvdata(idev, ts); | 392 | input_set_drvdata(idev, ts); |
393 | 393 | ||
394 | ucb1x00_adc_enable(ts->ucb); | ||
395 | ts->x_res = ucb1x00_ts_read_xres(ts); | ||
396 | ts->y_res = ucb1x00_ts_read_yres(ts); | ||
397 | ucb1x00_adc_disable(ts->ucb); | ||
398 | |||
399 | input_set_abs_params(idev, ABS_X, 0, ts->x_res, 0, 0); | ||
400 | input_set_abs_params(idev, ABS_Y, 0, ts->y_res, 0, 0); | ||
401 | input_set_abs_params(idev, ABS_PRESSURE, 0, 0, 0, 0); | ||
402 | |||
394 | err = input_register_device(idev); | 403 | err = input_register_device(idev); |
395 | if (err) | 404 | if (err) |
396 | goto fail; | 405 | goto fail; |
diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c new file mode 100644 index 000000000000..d698703dbd46 --- /dev/null +++ b/drivers/mfd/vx855.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * Linux multi-function-device driver (MFD) for the integrated peripherals | ||
3 | * of the VIA VX855 chipset | ||
4 | * | ||
5 | * Copyright (C) 2009 VIA Technologies, Inc. | ||
6 | * Copyright (C) 2010 One Laptop per Child | ||
7 | * Author: Harald Welte <HaraldWelte@viatech.com> | ||
8 | * All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License as | ||
12 | * published by the Free Software Foundation; either version 2 of | ||
13 | * the License, or (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
23 | * MA 02111-1307 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/pci.h> | ||
32 | #include <linux/mfd/core.h> | ||
33 | |||
34 | /* offset into pci config space indicating the 16bit register containing | ||
35 | * the power management IO space base */ | ||
36 | #define VX855_CFG_PMIO_OFFSET 0x88 | ||
37 | |||
38 | /* ACPI I/O Space registers */ | ||
39 | #define VX855_PMIO_ACPI 0x00 | ||
40 | #define VX855_PMIO_ACPI_LEN 0x0b | ||
41 | |||
42 | /* Processor Power Management */ | ||
43 | #define VX855_PMIO_PPM 0x10 | ||
44 | #define VX855_PMIO_PPM_LEN 0x08 | ||
45 | |||
46 | /* General Purpose Power Management */ | ||
47 | #define VX855_PMIO_GPPM 0x20 | ||
48 | #define VX855_PMIO_R_GPI 0x48 | ||
49 | #define VX855_PMIO_R_GPO 0x4c | ||
50 | #define VX855_PMIO_GPPM_LEN 0x33 | ||
51 | |||
52 | #define VSPIC_MMIO_SIZE 0x1000 | ||
53 | |||
54 | static struct resource vx855_gpio_resources[] = { | ||
55 | { | ||
56 | .flags = IORESOURCE_IO, | ||
57 | }, | ||
58 | { | ||
59 | .flags = IORESOURCE_IO, | ||
60 | }, | ||
61 | }; | ||
62 | |||
63 | static struct mfd_cell vx855_cells[] = { | ||
64 | { | ||
65 | .name = "vx855_gpio", | ||
66 | .num_resources = ARRAY_SIZE(vx855_gpio_resources), | ||
67 | .resources = vx855_gpio_resources, | ||
68 | |||
69 | /* we must ignore resource conflicts, for reasons outlined in | ||
70 | * the vx855_gpio driver */ | ||
71 | .ignore_resource_conflicts = true, | ||
72 | }, | ||
73 | }; | ||
74 | |||
75 | static __devinit int vx855_probe(struct pci_dev *pdev, | ||
76 | const struct pci_device_id *id) | ||
77 | { | ||
78 | int ret; | ||
79 | u16 gpio_io_offset; | ||
80 | |||
81 | ret = pci_enable_device(pdev); | ||
82 | if (ret) | ||
83 | return -ENODEV; | ||
84 | |||
85 | pci_read_config_word(pdev, VX855_CFG_PMIO_OFFSET, &gpio_io_offset); | ||
86 | if (!gpio_io_offset) { | ||
87 | dev_warn(&pdev->dev, | ||
88 | "BIOS did not assign PMIO base offset?!?\n"); | ||
89 | ret = -ENODEV; | ||
90 | goto out; | ||
91 | } | ||
92 | |||
93 | /* mask out the lowest seven bits, as they are always zero, but | ||
94 | * hardware returns them as 0x01 */ | ||
95 | gpio_io_offset &= 0xff80; | ||
96 | |||
97 | /* As the region identified here includes many non-GPIO things, we | ||
98 | * only work with the specific registers that concern us. */ | ||
99 | vx855_gpio_resources[0].start = gpio_io_offset + VX855_PMIO_R_GPI; | ||
100 | vx855_gpio_resources[0].end = vx855_gpio_resources[0].start + 3; | ||
101 | vx855_gpio_resources[1].start = gpio_io_offset + VX855_PMIO_R_GPO; | ||
102 | vx855_gpio_resources[1].end = vx855_gpio_resources[1].start + 3; | ||
103 | |||
104 | ret = mfd_add_devices(&pdev->dev, -1, vx855_cells, ARRAY_SIZE(vx855_cells), | ||
105 | NULL, 0); | ||
106 | |||
107 | /* we always return -ENODEV here in order to enable other | ||
108 | * drivers like old, not-yet-platform_device ported i2c-viapro */ | ||
109 | return -ENODEV; | ||
110 | out: | ||
111 | pci_disable_device(pdev); | ||
112 | return ret; | ||
113 | } | ||
114 | |||
115 | static void __devexit vx855_remove(struct pci_dev *pdev) | ||
116 | { | ||
117 | mfd_remove_devices(&pdev->dev); | ||
118 | pci_disable_device(pdev); | ||
119 | } | ||
120 | |||
121 | static struct pci_device_id vx855_pci_tbl[] = { | ||
122 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) }, | ||
123 | { 0, } | ||
124 | }; | ||
125 | MODULE_DEVICE_TABLE(pci, vx855_pci_tbl); | ||
126 | |||
127 | static struct pci_driver vx855_pci_driver = { | ||
128 | .name = "vx855", | ||
129 | .id_table = vx855_pci_tbl, | ||
130 | .probe = vx855_probe, | ||
131 | .remove = __devexit_p(vx855_remove), | ||
132 | }; | ||
133 | |||
134 | static int vx855_init(void) | ||
135 | { | ||
136 | return pci_register_driver(&vx855_pci_driver); | ||
137 | } | ||
138 | module_init(vx855_init); | ||
139 | |||
140 | static void vx855_exit(void) | ||
141 | { | ||
142 | pci_unregister_driver(&vx855_pci_driver); | ||
143 | } | ||
144 | module_exit(vx855_exit); | ||
145 | |||
146 | MODULE_LICENSE("GPL"); | ||
147 | MODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>"); | ||
148 | MODULE_DESCRIPTION("Driver for the VIA VX855 chipset"); | ||
diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c new file mode 100644 index 000000000000..d97a86945174 --- /dev/null +++ b/drivers/mfd/wl1273-core.c | |||
@@ -0,0 +1,290 @@ | |||
1 | /* | ||
2 | * MFD driver for wl1273 FM radio and audio codec submodules. | ||
3 | * | ||
4 | * Copyright (C) 2011 Nokia Corporation | ||
5 | * Author: Matti Aaltonen <matti.j.aaltonen@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/mfd/wl1273-core.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #define DRIVER_DESC "WL1273 FM Radio Core" | ||
27 | |||
28 | static const struct i2c_device_id wl1273_driver_id_table[] = { | ||
29 | { WL1273_FM_DRIVER_NAME, 0 }, | ||
30 | { } | ||
31 | }; | ||
32 | MODULE_DEVICE_TABLE(i2c, wl1273_driver_id_table); | ||
33 | |||
34 | static int wl1273_fm_read_reg(struct wl1273_core *core, u8 reg, u16 *value) | ||
35 | { | ||
36 | struct i2c_client *client = core->client; | ||
37 | u8 b[2]; | ||
38 | int r; | ||
39 | |||
40 | r = i2c_smbus_read_i2c_block_data(client, reg, sizeof(b), b); | ||
41 | if (r != 2) { | ||
42 | dev_err(&client->dev, "%s: Read: %d fails.\n", __func__, reg); | ||
43 | return -EREMOTEIO; | ||
44 | } | ||
45 | |||
46 | *value = (u16)b[0] << 8 | b[1]; | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static int wl1273_fm_write_cmd(struct wl1273_core *core, u8 cmd, u16 param) | ||
52 | { | ||
53 | struct i2c_client *client = core->client; | ||
54 | u8 buf[] = { (param >> 8) & 0xff, param & 0xff }; | ||
55 | int r; | ||
56 | |||
57 | r = i2c_smbus_write_i2c_block_data(client, cmd, sizeof(buf), buf); | ||
58 | if (r) { | ||
59 | dev_err(&client->dev, "%s: Cmd: %d fails.\n", __func__, cmd); | ||
60 | return r; | ||
61 | } | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int wl1273_fm_write_data(struct wl1273_core *core, u8 *data, u16 len) | ||
67 | { | ||
68 | struct i2c_client *client = core->client; | ||
69 | struct i2c_msg msg; | ||
70 | int r; | ||
71 | |||
72 | msg.addr = client->addr; | ||
73 | msg.flags = 0; | ||
74 | msg.buf = data; | ||
75 | msg.len = len; | ||
76 | |||
77 | r = i2c_transfer(client->adapter, &msg, 1); | ||
78 | if (r != 1) { | ||
79 | dev_err(&client->dev, "%s: write error.\n", __func__); | ||
80 | return -EREMOTEIO; | ||
81 | } | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * wl1273_fm_set_audio() - Set audio mode. | ||
88 | * @core: A pointer to the device struct. | ||
89 | * @new_mode: The new audio mode. | ||
90 | * | ||
91 | * Audio modes are WL1273_AUDIO_DIGITAL and WL1273_AUDIO_ANALOG. | ||
92 | */ | ||
93 | static int wl1273_fm_set_audio(struct wl1273_core *core, unsigned int new_mode) | ||
94 | { | ||
95 | int r = 0; | ||
96 | |||
97 | if (core->mode == WL1273_MODE_OFF || | ||
98 | core->mode == WL1273_MODE_SUSPENDED) | ||
99 | return -EPERM; | ||
100 | |||
101 | if (core->mode == WL1273_MODE_RX && new_mode == WL1273_AUDIO_DIGITAL) { | ||
102 | r = wl1273_fm_write_cmd(core, WL1273_PCM_MODE_SET, | ||
103 | WL1273_PCM_DEF_MODE); | ||
104 | if (r) | ||
105 | goto out; | ||
106 | |||
107 | r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET, | ||
108 | core->i2s_mode); | ||
109 | if (r) | ||
110 | goto out; | ||
111 | |||
112 | r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE, | ||
113 | WL1273_AUDIO_ENABLE_I2S); | ||
114 | if (r) | ||
115 | goto out; | ||
116 | |||
117 | } else if (core->mode == WL1273_MODE_RX && | ||
118 | new_mode == WL1273_AUDIO_ANALOG) { | ||
119 | r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE, | ||
120 | WL1273_AUDIO_ENABLE_ANALOG); | ||
121 | if (r) | ||
122 | goto out; | ||
123 | |||
124 | } else if (core->mode == WL1273_MODE_TX && | ||
125 | new_mode == WL1273_AUDIO_DIGITAL) { | ||
126 | r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET, | ||
127 | core->i2s_mode); | ||
128 | if (r) | ||
129 | goto out; | ||
130 | |||
131 | r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET, | ||
132 | WL1273_AUDIO_IO_SET_I2S); | ||
133 | if (r) | ||
134 | goto out; | ||
135 | |||
136 | } else if (core->mode == WL1273_MODE_TX && | ||
137 | new_mode == WL1273_AUDIO_ANALOG) { | ||
138 | r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET, | ||
139 | WL1273_AUDIO_IO_SET_ANALOG); | ||
140 | if (r) | ||
141 | goto out; | ||
142 | } | ||
143 | |||
144 | core->audio_mode = new_mode; | ||
145 | out: | ||
146 | return r; | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * wl1273_fm_set_volume() - Set volume. | ||
151 | * @core: A pointer to the device struct. | ||
152 | * @volume: The new volume value. | ||
153 | */ | ||
154 | static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume) | ||
155 | { | ||
156 | int r; | ||
157 | |||
158 | if (volume > WL1273_MAX_VOLUME) | ||
159 | return -EINVAL; | ||
160 | |||
161 | if (core->volume == volume) | ||
162 | return 0; | ||
163 | |||
164 | r = wl1273_fm_write_cmd(core, WL1273_VOLUME_SET, volume); | ||
165 | if (r) | ||
166 | return r; | ||
167 | |||
168 | core->volume = volume; | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int wl1273_core_remove(struct i2c_client *client) | ||
173 | { | ||
174 | struct wl1273_core *core = i2c_get_clientdata(client); | ||
175 | |||
176 | dev_dbg(&client->dev, "%s\n", __func__); | ||
177 | |||
178 | mfd_remove_devices(&client->dev); | ||
179 | kfree(core); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int __devinit wl1273_core_probe(struct i2c_client *client, | ||
185 | const struct i2c_device_id *id) | ||
186 | { | ||
187 | struct wl1273_fm_platform_data *pdata = client->dev.platform_data; | ||
188 | struct wl1273_core *core; | ||
189 | struct mfd_cell *cell; | ||
190 | int children = 0; | ||
191 | int r = 0; | ||
192 | |||
193 | dev_dbg(&client->dev, "%s\n", __func__); | ||
194 | |||
195 | if (!pdata) { | ||
196 | dev_err(&client->dev, "No platform data.\n"); | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | |||
200 | if (!(pdata->children & WL1273_RADIO_CHILD)) { | ||
201 | dev_err(&client->dev, "Cannot function without radio child.\n"); | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | |||
205 | core = kzalloc(sizeof(*core), GFP_KERNEL); | ||
206 | if (!core) | ||
207 | return -ENOMEM; | ||
208 | |||
209 | core->pdata = pdata; | ||
210 | core->client = client; | ||
211 | mutex_init(&core->lock); | ||
212 | |||
213 | i2c_set_clientdata(client, core); | ||
214 | |||
215 | dev_dbg(&client->dev, "%s: Have V4L2.\n", __func__); | ||
216 | |||
217 | cell = &core->cells[children]; | ||
218 | cell->name = "wl1273_fm_radio"; | ||
219 | cell->platform_data = &core; | ||
220 | cell->pdata_size = sizeof(core); | ||
221 | children++; | ||
222 | |||
223 | core->read = wl1273_fm_read_reg; | ||
224 | core->write = wl1273_fm_write_cmd; | ||
225 | core->write_data = wl1273_fm_write_data; | ||
226 | core->set_audio = wl1273_fm_set_audio; | ||
227 | core->set_volume = wl1273_fm_set_volume; | ||
228 | |||
229 | if (pdata->children & WL1273_CODEC_CHILD) { | ||
230 | cell = &core->cells[children]; | ||
231 | |||
232 | dev_dbg(&client->dev, "%s: Have codec.\n", __func__); | ||
233 | cell->name = "wl1273-codec"; | ||
234 | cell->platform_data = &core; | ||
235 | cell->pdata_size = sizeof(core); | ||
236 | children++; | ||
237 | } | ||
238 | |||
239 | dev_dbg(&client->dev, "%s: number of children: %d.\n", | ||
240 | __func__, children); | ||
241 | |||
242 | r = mfd_add_devices(&client->dev, -1, core->cells, | ||
243 | children, NULL, 0); | ||
244 | if (r) | ||
245 | goto err; | ||
246 | |||
247 | return 0; | ||
248 | |||
249 | err: | ||
250 | pdata->free_resources(); | ||
251 | kfree(core); | ||
252 | |||
253 | dev_dbg(&client->dev, "%s\n", __func__); | ||
254 | |||
255 | return r; | ||
256 | } | ||
257 | |||
258 | static struct i2c_driver wl1273_core_driver = { | ||
259 | .driver = { | ||
260 | .name = WL1273_FM_DRIVER_NAME, | ||
261 | }, | ||
262 | .probe = wl1273_core_probe, | ||
263 | .id_table = wl1273_driver_id_table, | ||
264 | .remove = __devexit_p(wl1273_core_remove), | ||
265 | }; | ||
266 | |||
267 | static int __init wl1273_core_init(void) | ||
268 | { | ||
269 | int r; | ||
270 | |||
271 | r = i2c_add_driver(&wl1273_core_driver); | ||
272 | if (r) { | ||
273 | pr_err(WL1273_FM_DRIVER_NAME | ||
274 | ": driver registration failed\n"); | ||
275 | return r; | ||
276 | } | ||
277 | |||
278 | return r; | ||
279 | } | ||
280 | |||
281 | static void __exit wl1273_core_exit(void) | ||
282 | { | ||
283 | i2c_del_driver(&wl1273_core_driver); | ||
284 | } | ||
285 | late_initcall(wl1273_core_init); | ||
286 | module_exit(wl1273_core_exit); | ||
287 | |||
288 | MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>"); | ||
289 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
290 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 1e7aaaf6cc6f..265f75fc6a25 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c | |||
@@ -14,7 +14,6 @@ | |||
14 | 14 | ||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/i2c.h> | ||
18 | #include <linux/bcd.h> | 17 | #include <linux/bcd.h> |
19 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
20 | #include <linux/mfd/core.h> | 19 | #include <linux/mfd/core.h> |
@@ -90,14 +89,6 @@ int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = { | |||
90 | }; | 89 | }; |
91 | EXPORT_SYMBOL_GPL(wm831x_isinkv_values); | 90 | EXPORT_SYMBOL_GPL(wm831x_isinkv_values); |
92 | 91 | ||
93 | enum wm831x_parent { | ||
94 | WM8310 = 0x8310, | ||
95 | WM8311 = 0x8311, | ||
96 | WM8312 = 0x8312, | ||
97 | WM8320 = 0x8320, | ||
98 | WM8321 = 0x8321, | ||
99 | }; | ||
100 | |||
101 | static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg) | 92 | static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg) |
102 | { | 93 | { |
103 | if (!wm831x->locked) | 94 | if (!wm831x->locked) |
@@ -1446,12 +1437,12 @@ static struct mfd_cell backlight_devs[] = { | |||
1446 | /* | 1437 | /* |
1447 | * Instantiate the generic non-control parts of the device. | 1438 | * Instantiate the generic non-control parts of the device. |
1448 | */ | 1439 | */ |
1449 | static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | 1440 | int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) |
1450 | { | 1441 | { |
1451 | struct wm831x_pdata *pdata = wm831x->dev->platform_data; | 1442 | struct wm831x_pdata *pdata = wm831x->dev->platform_data; |
1452 | int rev; | 1443 | int rev; |
1453 | enum wm831x_parent parent; | 1444 | enum wm831x_parent parent; |
1454 | int ret; | 1445 | int ret, i; |
1455 | 1446 | ||
1456 | mutex_init(&wm831x->io_lock); | 1447 | mutex_init(&wm831x->io_lock); |
1457 | mutex_init(&wm831x->key_lock); | 1448 | mutex_init(&wm831x->key_lock); |
@@ -1464,7 +1455,11 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
1464 | dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret); | 1455 | dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret); |
1465 | goto err; | 1456 | goto err; |
1466 | } | 1457 | } |
1467 | if (ret != 0x6204) { | 1458 | switch (ret) { |
1459 | case 0x6204: | ||
1460 | case 0x6246: | ||
1461 | break; | ||
1462 | default: | ||
1468 | dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret); | 1463 | dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret); |
1469 | ret = -EINVAL; | 1464 | ret = -EINVAL; |
1470 | goto err; | 1465 | goto err; |
@@ -1540,6 +1535,18 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
1540 | dev_info(wm831x->dev, "WM8321 revision %c\n", 'A' + rev); | 1535 | dev_info(wm831x->dev, "WM8321 revision %c\n", 'A' + rev); |
1541 | break; | 1536 | break; |
1542 | 1537 | ||
1538 | case WM8325: | ||
1539 | parent = WM8325; | ||
1540 | wm831x->num_gpio = 12; | ||
1541 | dev_info(wm831x->dev, "WM8325 revision %c\n", 'A' + rev); | ||
1542 | break; | ||
1543 | |||
1544 | case WM8326: | ||
1545 | parent = WM8326; | ||
1546 | wm831x->num_gpio = 12; | ||
1547 | dev_info(wm831x->dev, "WM8326 revision %c\n", 'A' + rev); | ||
1548 | break; | ||
1549 | |||
1543 | default: | 1550 | default: |
1544 | dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret); | 1551 | dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret); |
1545 | ret = -EINVAL; | 1552 | ret = -EINVAL; |
@@ -1574,6 +1581,17 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
1574 | } | 1581 | } |
1575 | } | 1582 | } |
1576 | 1583 | ||
1584 | if (pdata) { | ||
1585 | for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { | ||
1586 | if (!pdata->gpio_defaults[i]) | ||
1587 | continue; | ||
1588 | |||
1589 | wm831x_reg_write(wm831x, | ||
1590 | WM831X_GPIO1_CONTROL + i, | ||
1591 | pdata->gpio_defaults[i] & 0xffff); | ||
1592 | } | ||
1593 | } | ||
1594 | |||
1577 | ret = wm831x_irq_init(wm831x, irq); | 1595 | ret = wm831x_irq_init(wm831x, irq); |
1578 | if (ret != 0) | 1596 | if (ret != 0) |
1579 | goto err; | 1597 | goto err; |
@@ -1609,15 +1627,12 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
1609 | break; | 1627 | break; |
1610 | 1628 | ||
1611 | case WM8320: | 1629 | case WM8320: |
1612 | ret = mfd_add_devices(wm831x->dev, -1, | ||
1613 | wm8320_devs, ARRAY_SIZE(wm8320_devs), | ||
1614 | NULL, 0); | ||
1615 | break; | ||
1616 | |||
1617 | case WM8321: | 1630 | case WM8321: |
1631 | case WM8325: | ||
1632 | case WM8326: | ||
1618 | ret = mfd_add_devices(wm831x->dev, -1, | 1633 | ret = mfd_add_devices(wm831x->dev, -1, |
1619 | wm8320_devs, ARRAY_SIZE(wm8320_devs), | 1634 | wm8320_devs, ARRAY_SIZE(wm8320_devs), |
1620 | NULL, 0); | 1635 | NULL, wm831x->irq_base); |
1621 | break; | 1636 | break; |
1622 | 1637 | ||
1623 | default: | 1638 | default: |
@@ -1660,7 +1675,7 @@ err: | |||
1660 | return ret; | 1675 | return ret; |
1661 | } | 1676 | } |
1662 | 1677 | ||
1663 | static void wm831x_device_exit(struct wm831x *wm831x) | 1678 | void wm831x_device_exit(struct wm831x *wm831x) |
1664 | { | 1679 | { |
1665 | wm831x_otp_exit(wm831x); | 1680 | wm831x_otp_exit(wm831x); |
1666 | mfd_remove_devices(wm831x->dev); | 1681 | mfd_remove_devices(wm831x->dev); |
@@ -1670,7 +1685,7 @@ static void wm831x_device_exit(struct wm831x *wm831x) | |||
1670 | kfree(wm831x); | 1685 | kfree(wm831x); |
1671 | } | 1686 | } |
1672 | 1687 | ||
1673 | static int wm831x_device_suspend(struct wm831x *wm831x) | 1688 | int wm831x_device_suspend(struct wm831x *wm831x) |
1674 | { | 1689 | { |
1675 | int reg, mask; | 1690 | int reg, mask; |
1676 | 1691 | ||
@@ -1706,125 +1721,6 @@ static int wm831x_device_suspend(struct wm831x *wm831x) | |||
1706 | return 0; | 1721 | return 0; |
1707 | } | 1722 | } |
1708 | 1723 | ||
1709 | static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg, | 1724 | MODULE_DESCRIPTION("Core support for the WM831X AudioPlus PMIC"); |
1710 | int bytes, void *dest) | ||
1711 | { | ||
1712 | struct i2c_client *i2c = wm831x->control_data; | ||
1713 | int ret; | ||
1714 | u16 r = cpu_to_be16(reg); | ||
1715 | |||
1716 | ret = i2c_master_send(i2c, (unsigned char *)&r, 2); | ||
1717 | if (ret < 0) | ||
1718 | return ret; | ||
1719 | if (ret != 2) | ||
1720 | return -EIO; | ||
1721 | |||
1722 | ret = i2c_master_recv(i2c, dest, bytes); | ||
1723 | if (ret < 0) | ||
1724 | return ret; | ||
1725 | if (ret != bytes) | ||
1726 | return -EIO; | ||
1727 | return 0; | ||
1728 | } | ||
1729 | |||
1730 | /* Currently we allocate the write buffer on the stack; this is OK for | ||
1731 | * small writes - if we need to do large writes this will need to be | ||
1732 | * revised. | ||
1733 | */ | ||
1734 | static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg, | ||
1735 | int bytes, void *src) | ||
1736 | { | ||
1737 | struct i2c_client *i2c = wm831x->control_data; | ||
1738 | unsigned char msg[bytes + 2]; | ||
1739 | int ret; | ||
1740 | |||
1741 | reg = cpu_to_be16(reg); | ||
1742 | memcpy(&msg[0], ®, 2); | ||
1743 | memcpy(&msg[2], src, bytes); | ||
1744 | |||
1745 | ret = i2c_master_send(i2c, msg, bytes + 2); | ||
1746 | if (ret < 0) | ||
1747 | return ret; | ||
1748 | if (ret < bytes + 2) | ||
1749 | return -EIO; | ||
1750 | |||
1751 | return 0; | ||
1752 | } | ||
1753 | |||
1754 | static int wm831x_i2c_probe(struct i2c_client *i2c, | ||
1755 | const struct i2c_device_id *id) | ||
1756 | { | ||
1757 | struct wm831x *wm831x; | ||
1758 | |||
1759 | wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); | ||
1760 | if (wm831x == NULL) | ||
1761 | return -ENOMEM; | ||
1762 | |||
1763 | i2c_set_clientdata(i2c, wm831x); | ||
1764 | wm831x->dev = &i2c->dev; | ||
1765 | wm831x->control_data = i2c; | ||
1766 | wm831x->read_dev = wm831x_i2c_read_device; | ||
1767 | wm831x->write_dev = wm831x_i2c_write_device; | ||
1768 | |||
1769 | return wm831x_device_init(wm831x, id->driver_data, i2c->irq); | ||
1770 | } | ||
1771 | |||
1772 | static int wm831x_i2c_remove(struct i2c_client *i2c) | ||
1773 | { | ||
1774 | struct wm831x *wm831x = i2c_get_clientdata(i2c); | ||
1775 | |||
1776 | wm831x_device_exit(wm831x); | ||
1777 | |||
1778 | return 0; | ||
1779 | } | ||
1780 | |||
1781 | static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg) | ||
1782 | { | ||
1783 | struct wm831x *wm831x = i2c_get_clientdata(i2c); | ||
1784 | |||
1785 | return wm831x_device_suspend(wm831x); | ||
1786 | } | ||
1787 | |||
1788 | static const struct i2c_device_id wm831x_i2c_id[] = { | ||
1789 | { "wm8310", WM8310 }, | ||
1790 | { "wm8311", WM8311 }, | ||
1791 | { "wm8312", WM8312 }, | ||
1792 | { "wm8320", WM8320 }, | ||
1793 | { "wm8321", WM8321 }, | ||
1794 | { } | ||
1795 | }; | ||
1796 | MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); | ||
1797 | |||
1798 | |||
1799 | static struct i2c_driver wm831x_i2c_driver = { | ||
1800 | .driver = { | ||
1801 | .name = "wm831x", | ||
1802 | .owner = THIS_MODULE, | ||
1803 | }, | ||
1804 | .probe = wm831x_i2c_probe, | ||
1805 | .remove = wm831x_i2c_remove, | ||
1806 | .suspend = wm831x_i2c_suspend, | ||
1807 | .id_table = wm831x_i2c_id, | ||
1808 | }; | ||
1809 | |||
1810 | static int __init wm831x_i2c_init(void) | ||
1811 | { | ||
1812 | int ret; | ||
1813 | |||
1814 | ret = i2c_add_driver(&wm831x_i2c_driver); | ||
1815 | if (ret != 0) | ||
1816 | pr_err("Failed to register wm831x I2C driver: %d\n", ret); | ||
1817 | |||
1818 | return ret; | ||
1819 | } | ||
1820 | subsys_initcall(wm831x_i2c_init); | ||
1821 | |||
1822 | static void __exit wm831x_i2c_exit(void) | ||
1823 | { | ||
1824 | i2c_del_driver(&wm831x_i2c_driver); | ||
1825 | } | ||
1826 | module_exit(wm831x_i2c_exit); | ||
1827 | |||
1828 | MODULE_DESCRIPTION("I2C support for the WM831X AudioPlus PMIC"); | ||
1829 | MODULE_LICENSE("GPL"); | 1725 | MODULE_LICENSE("GPL"); |
1830 | MODULE_AUTHOR("Mark Brown"); | 1726 | MODULE_AUTHOR("Mark Brown"); |
diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c new file mode 100644 index 000000000000..a06cbc739716 --- /dev/null +++ b/drivers/mfd/wm831x-i2c.c | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | * wm831x-i2c.c -- I2C access for Wolfson WM831x PMICs | ||
3 | * | ||
4 | * Copyright 2009,2010 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/mfd/core.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include <linux/mfd/wm831x/core.h> | ||
23 | #include <linux/mfd/wm831x/pdata.h> | ||
24 | |||
25 | static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg, | ||
26 | int bytes, void *dest) | ||
27 | { | ||
28 | struct i2c_client *i2c = wm831x->control_data; | ||
29 | int ret; | ||
30 | u16 r = cpu_to_be16(reg); | ||
31 | |||
32 | ret = i2c_master_send(i2c, (unsigned char *)&r, 2); | ||
33 | if (ret < 0) | ||
34 | return ret; | ||
35 | if (ret != 2) | ||
36 | return -EIO; | ||
37 | |||
38 | ret = i2c_master_recv(i2c, dest, bytes); | ||
39 | if (ret < 0) | ||
40 | return ret; | ||
41 | if (ret != bytes) | ||
42 | return -EIO; | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | /* Currently we allocate the write buffer on the stack; this is OK for | ||
47 | * small writes - if we need to do large writes this will need to be | ||
48 | * revised. | ||
49 | */ | ||
50 | static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg, | ||
51 | int bytes, void *src) | ||
52 | { | ||
53 | struct i2c_client *i2c = wm831x->control_data; | ||
54 | struct i2c_msg xfer[2]; | ||
55 | int ret; | ||
56 | |||
57 | reg = cpu_to_be16(reg); | ||
58 | |||
59 | xfer[0].addr = i2c->addr; | ||
60 | xfer[0].flags = 0; | ||
61 | xfer[0].len = 2; | ||
62 | xfer[0].buf = (char *)® | ||
63 | |||
64 | xfer[1].addr = i2c->addr; | ||
65 | xfer[1].flags = I2C_M_NOSTART; | ||
66 | xfer[1].len = bytes; | ||
67 | xfer[1].buf = (char *)src; | ||
68 | |||
69 | ret = i2c_transfer(i2c->adapter, xfer, 2); | ||
70 | if (ret < 0) | ||
71 | return ret; | ||
72 | if (ret != 2) | ||
73 | return -EIO; | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static int wm831x_i2c_probe(struct i2c_client *i2c, | ||
79 | const struct i2c_device_id *id) | ||
80 | { | ||
81 | struct wm831x *wm831x; | ||
82 | |||
83 | wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); | ||
84 | if (wm831x == NULL) | ||
85 | return -ENOMEM; | ||
86 | |||
87 | i2c_set_clientdata(i2c, wm831x); | ||
88 | wm831x->dev = &i2c->dev; | ||
89 | wm831x->control_data = i2c; | ||
90 | wm831x->read_dev = wm831x_i2c_read_device; | ||
91 | wm831x->write_dev = wm831x_i2c_write_device; | ||
92 | |||
93 | return wm831x_device_init(wm831x, id->driver_data, i2c->irq); | ||
94 | } | ||
95 | |||
96 | static int wm831x_i2c_remove(struct i2c_client *i2c) | ||
97 | { | ||
98 | struct wm831x *wm831x = i2c_get_clientdata(i2c); | ||
99 | |||
100 | wm831x_device_exit(wm831x); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int wm831x_i2c_suspend(struct device *dev) | ||
106 | { | ||
107 | struct wm831x *wm831x = dev_get_drvdata(dev); | ||
108 | |||
109 | return wm831x_device_suspend(wm831x); | ||
110 | } | ||
111 | |||
112 | static const struct i2c_device_id wm831x_i2c_id[] = { | ||
113 | { "wm8310", WM8310 }, | ||
114 | { "wm8311", WM8311 }, | ||
115 | { "wm8312", WM8312 }, | ||
116 | { "wm8320", WM8320 }, | ||
117 | { "wm8321", WM8321 }, | ||
118 | { "wm8325", WM8325 }, | ||
119 | { "wm8326", WM8326 }, | ||
120 | { } | ||
121 | }; | ||
122 | MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); | ||
123 | |||
124 | static const struct dev_pm_ops wm831x_pm_ops = { | ||
125 | .suspend = wm831x_i2c_suspend, | ||
126 | }; | ||
127 | |||
128 | static struct i2c_driver wm831x_i2c_driver = { | ||
129 | .driver = { | ||
130 | .name = "wm831x", | ||
131 | .owner = THIS_MODULE, | ||
132 | .pm = &wm831x_pm_ops, | ||
133 | }, | ||
134 | .probe = wm831x_i2c_probe, | ||
135 | .remove = wm831x_i2c_remove, | ||
136 | .id_table = wm831x_i2c_id, | ||
137 | }; | ||
138 | |||
139 | static int __init wm831x_i2c_init(void) | ||
140 | { | ||
141 | int ret; | ||
142 | |||
143 | ret = i2c_add_driver(&wm831x_i2c_driver); | ||
144 | if (ret != 0) | ||
145 | pr_err("Failed to register wm831x I2C driver: %d\n", ret); | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | subsys_initcall(wm831x_i2c_init); | ||
150 | |||
151 | static void __exit wm831x_i2c_exit(void) | ||
152 | { | ||
153 | i2c_del_driver(&wm831x_i2c_driver); | ||
154 | } | ||
155 | module_exit(wm831x_i2c_exit); | ||
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index 294183b6260b..42b928ec891e 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c | |||
@@ -26,15 +26,6 @@ | |||
26 | 26 | ||
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | 28 | ||
29 | /* | ||
30 | * Since generic IRQs don't currently support interrupt controllers on | ||
31 | * interrupt driven buses we don't use genirq but instead provide an | ||
32 | * interface that looks very much like the standard ones. This leads | ||
33 | * to some bodges, including storing interrupt handler information in | ||
34 | * the static irq_data table we use to look up the data for individual | ||
35 | * interrupts, but hopefully won't last too long. | ||
36 | */ | ||
37 | |||
38 | struct wm831x_irq_data { | 29 | struct wm831x_irq_data { |
39 | int primary; | 30 | int primary; |
40 | int reg; | 31 | int reg; |
@@ -345,22 +336,26 @@ static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x, | |||
345 | return &wm831x_irqs[irq - wm831x->irq_base]; | 336 | return &wm831x_irqs[irq - wm831x->irq_base]; |
346 | } | 337 | } |
347 | 338 | ||
348 | static void wm831x_irq_lock(unsigned int irq) | 339 | static void wm831x_irq_lock(struct irq_data *data) |
349 | { | 340 | { |
350 | struct wm831x *wm831x = get_irq_chip_data(irq); | 341 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
351 | 342 | ||
352 | mutex_lock(&wm831x->irq_lock); | 343 | mutex_lock(&wm831x->irq_lock); |
353 | } | 344 | } |
354 | 345 | ||
355 | static void wm831x_irq_sync_unlock(unsigned int irq) | 346 | static void wm831x_irq_sync_unlock(struct irq_data *data) |
356 | { | 347 | { |
357 | struct wm831x *wm831x = get_irq_chip_data(irq); | 348 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
358 | int i; | 349 | int i; |
359 | 350 | ||
360 | for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { | 351 | for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { |
361 | /* If there's been a change in the mask write it back | 352 | /* If there's been a change in the mask write it back |
362 | * to the hardware. */ | 353 | * to the hardware. */ |
363 | if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) { | 354 | if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) { |
355 | dev_dbg(wm831x->dev, "IRQ mask sync: %x = %x\n", | ||
356 | WM831X_INTERRUPT_STATUS_1_MASK + i, | ||
357 | wm831x->irq_masks_cur[i]); | ||
358 | |||
364 | wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i]; | 359 | wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i]; |
365 | wm831x_reg_write(wm831x, | 360 | wm831x_reg_write(wm831x, |
366 | WM831X_INTERRUPT_STATUS_1_MASK + i, | 361 | WM831X_INTERRUPT_STATUS_1_MASK + i, |
@@ -371,28 +366,30 @@ static void wm831x_irq_sync_unlock(unsigned int irq) | |||
371 | mutex_unlock(&wm831x->irq_lock); | 366 | mutex_unlock(&wm831x->irq_lock); |
372 | } | 367 | } |
373 | 368 | ||
374 | static void wm831x_irq_unmask(unsigned int irq) | 369 | static void wm831x_irq_enable(struct irq_data *data) |
375 | { | 370 | { |
376 | struct wm831x *wm831x = get_irq_chip_data(irq); | 371 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
377 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq); | 372 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, |
373 | data->irq); | ||
378 | 374 | ||
379 | wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; | 375 | wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; |
380 | } | 376 | } |
381 | 377 | ||
382 | static void wm831x_irq_mask(unsigned int irq) | 378 | static void wm831x_irq_disable(struct irq_data *data) |
383 | { | 379 | { |
384 | struct wm831x *wm831x = get_irq_chip_data(irq); | 380 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
385 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq); | 381 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, |
382 | data->irq); | ||
386 | 383 | ||
387 | wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; | 384 | wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; |
388 | } | 385 | } |
389 | 386 | ||
390 | static int wm831x_irq_set_type(unsigned int irq, unsigned int type) | 387 | static int wm831x_irq_set_type(struct irq_data *data, unsigned int type) |
391 | { | 388 | { |
392 | struct wm831x *wm831x = get_irq_chip_data(irq); | 389 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
393 | int val; | 390 | int val, irq; |
394 | 391 | ||
395 | irq = irq - wm831x->irq_base; | 392 | irq = data->irq - wm831x->irq_base; |
396 | 393 | ||
397 | if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) { | 394 | if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) { |
398 | /* Ignore internal-only IRQs */ | 395 | /* Ignore internal-only IRQs */ |
@@ -421,12 +418,12 @@ static int wm831x_irq_set_type(unsigned int irq, unsigned int type) | |||
421 | } | 418 | } |
422 | 419 | ||
423 | static struct irq_chip wm831x_irq_chip = { | 420 | static struct irq_chip wm831x_irq_chip = { |
424 | .name = "wm831x", | 421 | .name = "wm831x", |
425 | .bus_lock = wm831x_irq_lock, | 422 | .irq_bus_lock = wm831x_irq_lock, |
426 | .bus_sync_unlock = wm831x_irq_sync_unlock, | 423 | .irq_bus_sync_unlock = wm831x_irq_sync_unlock, |
427 | .mask = wm831x_irq_mask, | 424 | .irq_disable = wm831x_irq_disable, |
428 | .unmask = wm831x_irq_unmask, | 425 | .irq_enable = wm831x_irq_enable, |
429 | .set_type = wm831x_irq_set_type, | 426 | .irq_set_type = wm831x_irq_set_type, |
430 | }; | 427 | }; |
431 | 428 | ||
432 | /* The processing of the primary interrupt occurs in a thread so that | 429 | /* The processing of the primary interrupt occurs in a thread so that |
@@ -447,6 +444,18 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) | |||
447 | goto out; | 444 | goto out; |
448 | } | 445 | } |
449 | 446 | ||
447 | /* The touch interrupts are visible in the primary register as | ||
448 | * an optimisation; open code this to avoid complicating the | ||
449 | * main handling loop and so we can also skip iterating the | ||
450 | * descriptors. | ||
451 | */ | ||
452 | if (primary & WM831X_TCHPD_INT) | ||
453 | handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD); | ||
454 | if (primary & WM831X_TCHDATA_INT) | ||
455 | handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA); | ||
456 | if (primary & (WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT)) | ||
457 | goto out; | ||
458 | |||
450 | for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { | 459 | for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { |
451 | int offset = wm831x_irqs[i].reg - 1; | 460 | int offset = wm831x_irqs[i].reg - 1; |
452 | 461 | ||
@@ -479,6 +488,9 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) | |||
479 | } | 488 | } |
480 | 489 | ||
481 | out: | 490 | out: |
491 | /* Touchscreen interrupts are handled specially in the driver */ | ||
492 | status_regs[0] &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT); | ||
493 | |||
482 | for (i = 0; i < ARRAY_SIZE(status_regs); i++) { | 494 | for (i = 0; i < ARRAY_SIZE(status_regs); i++) { |
483 | if (status_regs[i]) | 495 | if (status_regs[i]) |
484 | wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i, | 496 | wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i, |
@@ -503,18 +515,31 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) | |||
503 | 0xffff); | 515 | 0xffff); |
504 | } | 516 | } |
505 | 517 | ||
506 | if (!irq) { | ||
507 | dev_warn(wm831x->dev, | ||
508 | "No interrupt specified - functionality limited\n"); | ||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | if (!pdata || !pdata->irq_base) { | 518 | if (!pdata || !pdata->irq_base) { |
513 | dev_err(wm831x->dev, | 519 | dev_err(wm831x->dev, |
514 | "No interrupt base specified, no interrupts\n"); | 520 | "No interrupt base specified, no interrupts\n"); |
515 | return 0; | 521 | return 0; |
516 | } | 522 | } |
517 | 523 | ||
524 | if (pdata->irq_cmos) | ||
525 | i = 0; | ||
526 | else | ||
527 | i = WM831X_IRQ_OD; | ||
528 | |||
529 | wm831x_set_bits(wm831x, WM831X_IRQ_CONFIG, | ||
530 | WM831X_IRQ_OD, i); | ||
531 | |||
532 | /* Try to flag /IRQ as a wake source; there are a number of | ||
533 | * unconditional wake sources in the PMIC so this isn't | ||
534 | * conditional but we don't actually care *too* much if it | ||
535 | * fails. | ||
536 | */ | ||
537 | ret = enable_irq_wake(irq); | ||
538 | if (ret != 0) { | ||
539 | dev_warn(wm831x->dev, "Can't enable IRQ as wake source: %d\n", | ||
540 | ret); | ||
541 | } | ||
542 | |||
518 | wm831x->irq = irq; | 543 | wm831x->irq = irq; |
519 | wm831x->irq_base = pdata->irq_base; | 544 | wm831x->irq_base = pdata->irq_base; |
520 | 545 | ||
@@ -522,29 +547,36 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) | |||
522 | for (cur_irq = wm831x->irq_base; | 547 | for (cur_irq = wm831x->irq_base; |
523 | cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base; | 548 | cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base; |
524 | cur_irq++) { | 549 | cur_irq++) { |
525 | set_irq_chip_data(cur_irq, wm831x); | 550 | irq_set_chip_data(cur_irq, wm831x); |
526 | set_irq_chip_and_handler(cur_irq, &wm831x_irq_chip, | 551 | irq_set_chip_and_handler(cur_irq, &wm831x_irq_chip, |
527 | handle_edge_irq); | 552 | handle_edge_irq); |
528 | set_irq_nested_thread(cur_irq, 1); | 553 | irq_set_nested_thread(cur_irq, 1); |
529 | 554 | ||
530 | /* ARM needs us to explicitly flag the IRQ as valid | 555 | /* ARM needs us to explicitly flag the IRQ as valid |
531 | * and will set them noprobe when we do so. */ | 556 | * and will set them noprobe when we do so. */ |
532 | #ifdef CONFIG_ARM | 557 | #ifdef CONFIG_ARM |
533 | set_irq_flags(cur_irq, IRQF_VALID); | 558 | set_irq_flags(cur_irq, IRQF_VALID); |
534 | #else | 559 | #else |
535 | set_irq_noprobe(cur_irq); | 560 | irq_set_noprobe(cur_irq); |
536 | #endif | 561 | #endif |
537 | } | 562 | } |
538 | 563 | ||
539 | ret = request_threaded_irq(irq, NULL, wm831x_irq_thread, | 564 | if (irq) { |
540 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | 565 | ret = request_threaded_irq(irq, NULL, wm831x_irq_thread, |
541 | "wm831x", wm831x); | 566 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
542 | if (ret != 0) { | 567 | "wm831x", wm831x); |
543 | dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n", | 568 | if (ret != 0) { |
544 | irq, ret); | 569 | dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n", |
545 | return ret; | 570 | irq, ret); |
571 | return ret; | ||
572 | } | ||
573 | } else { | ||
574 | dev_warn(wm831x->dev, | ||
575 | "No interrupt specified - functionality limited\n"); | ||
546 | } | 576 | } |
547 | 577 | ||
578 | |||
579 | |||
548 | /* Enable top level interrupts, we mask at secondary level */ | 580 | /* Enable top level interrupts, we mask at secondary level */ |
549 | wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0); | 581 | wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0); |
550 | 582 | ||
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c new file mode 100644 index 000000000000..eed8e4f7a5a1 --- /dev/null +++ b/drivers/mfd/wm831x-spi.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* | ||
2 | * wm831x-spi.c -- SPI access for Wolfson WM831x PMICs | ||
3 | * | ||
4 | * Copyright 2009,2010 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/pm.h> | ||
18 | #include <linux/spi/spi.h> | ||
19 | |||
20 | #include <linux/mfd/wm831x/core.h> | ||
21 | |||
22 | static int wm831x_spi_read_device(struct wm831x *wm831x, unsigned short reg, | ||
23 | int bytes, void *dest) | ||
24 | { | ||
25 | u16 tx_val; | ||
26 | u16 *d = dest; | ||
27 | int r, ret; | ||
28 | |||
29 | /* Go register at a time */ | ||
30 | for (r = reg; r < reg + (bytes / 2); r++) { | ||
31 | tx_val = r | 0x8000; | ||
32 | |||
33 | ret = spi_write_then_read(wm831x->control_data, | ||
34 | (u8 *)&tx_val, 2, (u8 *)d, 2); | ||
35 | if (ret != 0) | ||
36 | return ret; | ||
37 | |||
38 | *d = be16_to_cpu(*d); | ||
39 | |||
40 | d++; | ||
41 | } | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static int wm831x_spi_write_device(struct wm831x *wm831x, unsigned short reg, | ||
47 | int bytes, void *src) | ||
48 | { | ||
49 | struct spi_device *spi = wm831x->control_data; | ||
50 | u16 *s = src; | ||
51 | u16 data[2]; | ||
52 | int ret, r; | ||
53 | |||
54 | /* Go register at a time */ | ||
55 | for (r = reg; r < reg + (bytes / 2); r++) { | ||
56 | data[0] = r; | ||
57 | data[1] = *s++; | ||
58 | |||
59 | ret = spi_write(spi, (char *)&data, sizeof(data)); | ||
60 | if (ret != 0) | ||
61 | return ret; | ||
62 | } | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int __devinit wm831x_spi_probe(struct spi_device *spi) | ||
68 | { | ||
69 | struct wm831x *wm831x; | ||
70 | enum wm831x_parent type; | ||
71 | |||
72 | /* Currently SPI support for ID tables is unmerged, we're faking it */ | ||
73 | if (strcmp(spi->modalias, "wm8310") == 0) | ||
74 | type = WM8310; | ||
75 | else if (strcmp(spi->modalias, "wm8311") == 0) | ||
76 | type = WM8311; | ||
77 | else if (strcmp(spi->modalias, "wm8312") == 0) | ||
78 | type = WM8312; | ||
79 | else if (strcmp(spi->modalias, "wm8320") == 0) | ||
80 | type = WM8320; | ||
81 | else if (strcmp(spi->modalias, "wm8321") == 0) | ||
82 | type = WM8321; | ||
83 | else if (strcmp(spi->modalias, "wm8325") == 0) | ||
84 | type = WM8325; | ||
85 | else if (strcmp(spi->modalias, "wm8326") == 0) | ||
86 | type = WM8326; | ||
87 | else { | ||
88 | dev_err(&spi->dev, "Unknown device type\n"); | ||
89 | return -EINVAL; | ||
90 | } | ||
91 | |||
92 | wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); | ||
93 | if (wm831x == NULL) | ||
94 | return -ENOMEM; | ||
95 | |||
96 | spi->bits_per_word = 16; | ||
97 | spi->mode = SPI_MODE_0; | ||
98 | |||
99 | dev_set_drvdata(&spi->dev, wm831x); | ||
100 | wm831x->dev = &spi->dev; | ||
101 | wm831x->control_data = spi; | ||
102 | wm831x->read_dev = wm831x_spi_read_device; | ||
103 | wm831x->write_dev = wm831x_spi_write_device; | ||
104 | |||
105 | return wm831x_device_init(wm831x, type, spi->irq); | ||
106 | } | ||
107 | |||
108 | static int __devexit wm831x_spi_remove(struct spi_device *spi) | ||
109 | { | ||
110 | struct wm831x *wm831x = dev_get_drvdata(&spi->dev); | ||
111 | |||
112 | wm831x_device_exit(wm831x); | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static int wm831x_spi_suspend(struct device *dev) | ||
118 | { | ||
119 | struct wm831x *wm831x = dev_get_drvdata(dev); | ||
120 | |||
121 | return wm831x_device_suspend(wm831x); | ||
122 | } | ||
123 | |||
124 | static const struct dev_pm_ops wm831x_spi_pm = { | ||
125 | .freeze = wm831x_spi_suspend, | ||
126 | .suspend = wm831x_spi_suspend, | ||
127 | }; | ||
128 | |||
129 | static struct spi_driver wm8310_spi_driver = { | ||
130 | .driver = { | ||
131 | .name = "wm8310", | ||
132 | .bus = &spi_bus_type, | ||
133 | .owner = THIS_MODULE, | ||
134 | .pm = &wm831x_spi_pm, | ||
135 | }, | ||
136 | .probe = wm831x_spi_probe, | ||
137 | .remove = __devexit_p(wm831x_spi_remove), | ||
138 | }; | ||
139 | |||
140 | static struct spi_driver wm8311_spi_driver = { | ||
141 | .driver = { | ||
142 | .name = "wm8311", | ||
143 | .bus = &spi_bus_type, | ||
144 | .owner = THIS_MODULE, | ||
145 | .pm = &wm831x_spi_pm, | ||
146 | }, | ||
147 | .probe = wm831x_spi_probe, | ||
148 | .remove = __devexit_p(wm831x_spi_remove), | ||
149 | }; | ||
150 | |||
151 | static struct spi_driver wm8312_spi_driver = { | ||
152 | .driver = { | ||
153 | .name = "wm8312", | ||
154 | .bus = &spi_bus_type, | ||
155 | .owner = THIS_MODULE, | ||
156 | .pm = &wm831x_spi_pm, | ||
157 | }, | ||
158 | .probe = wm831x_spi_probe, | ||
159 | .remove = __devexit_p(wm831x_spi_remove), | ||
160 | }; | ||
161 | |||
162 | static struct spi_driver wm8320_spi_driver = { | ||
163 | .driver = { | ||
164 | .name = "wm8320", | ||
165 | .bus = &spi_bus_type, | ||
166 | .owner = THIS_MODULE, | ||
167 | .pm = &wm831x_spi_pm, | ||
168 | }, | ||
169 | .probe = wm831x_spi_probe, | ||
170 | .remove = __devexit_p(wm831x_spi_remove), | ||
171 | }; | ||
172 | |||
173 | static struct spi_driver wm8321_spi_driver = { | ||
174 | .driver = { | ||
175 | .name = "wm8321", | ||
176 | .bus = &spi_bus_type, | ||
177 | .owner = THIS_MODULE, | ||
178 | .pm = &wm831x_spi_pm, | ||
179 | }, | ||
180 | .probe = wm831x_spi_probe, | ||
181 | .remove = __devexit_p(wm831x_spi_remove), | ||
182 | }; | ||
183 | |||
184 | static struct spi_driver wm8325_spi_driver = { | ||
185 | .driver = { | ||
186 | .name = "wm8325", | ||
187 | .bus = &spi_bus_type, | ||
188 | .owner = THIS_MODULE, | ||
189 | .pm = &wm831x_spi_pm, | ||
190 | }, | ||
191 | .probe = wm831x_spi_probe, | ||
192 | .remove = __devexit_p(wm831x_spi_remove), | ||
193 | }; | ||
194 | |||
195 | static struct spi_driver wm8326_spi_driver = { | ||
196 | .driver = { | ||
197 | .name = "wm8326", | ||
198 | .bus = &spi_bus_type, | ||
199 | .owner = THIS_MODULE, | ||
200 | .pm = &wm831x_spi_pm, | ||
201 | }, | ||
202 | .probe = wm831x_spi_probe, | ||
203 | .remove = __devexit_p(wm831x_spi_remove), | ||
204 | }; | ||
205 | |||
206 | static int __init wm831x_spi_init(void) | ||
207 | { | ||
208 | int ret; | ||
209 | |||
210 | ret = spi_register_driver(&wm8310_spi_driver); | ||
211 | if (ret != 0) | ||
212 | pr_err("Failed to register WM8310 SPI driver: %d\n", ret); | ||
213 | |||
214 | ret = spi_register_driver(&wm8311_spi_driver); | ||
215 | if (ret != 0) | ||
216 | pr_err("Failed to register WM8311 SPI driver: %d\n", ret); | ||
217 | |||
218 | ret = spi_register_driver(&wm8312_spi_driver); | ||
219 | if (ret != 0) | ||
220 | pr_err("Failed to register WM8312 SPI driver: %d\n", ret); | ||
221 | |||
222 | ret = spi_register_driver(&wm8320_spi_driver); | ||
223 | if (ret != 0) | ||
224 | pr_err("Failed to register WM8320 SPI driver: %d\n", ret); | ||
225 | |||
226 | ret = spi_register_driver(&wm8321_spi_driver); | ||
227 | if (ret != 0) | ||
228 | pr_err("Failed to register WM8321 SPI driver: %d\n", ret); | ||
229 | |||
230 | ret = spi_register_driver(&wm8325_spi_driver); | ||
231 | if (ret != 0) | ||
232 | pr_err("Failed to register WM8325 SPI driver: %d\n", ret); | ||
233 | |||
234 | ret = spi_register_driver(&wm8326_spi_driver); | ||
235 | if (ret != 0) | ||
236 | pr_err("Failed to register WM8326 SPI driver: %d\n", ret); | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | subsys_initcall(wm831x_spi_init); | ||
241 | |||
242 | static void __exit wm831x_spi_exit(void) | ||
243 | { | ||
244 | spi_unregister_driver(&wm8326_spi_driver); | ||
245 | spi_unregister_driver(&wm8325_spi_driver); | ||
246 | spi_unregister_driver(&wm8321_spi_driver); | ||
247 | spi_unregister_driver(&wm8320_spi_driver); | ||
248 | spi_unregister_driver(&wm8312_spi_driver); | ||
249 | spi_unregister_driver(&wm8311_spi_driver); | ||
250 | spi_unregister_driver(&wm8310_spi_driver); | ||
251 | } | ||
252 | module_exit(wm831x_spi_exit); | ||
253 | |||
254 | MODULE_DESCRIPTION("SPI support for WM831x/2x AudioPlus PMICs"); | ||
255 | MODULE_LICENSE("GPL"); | ||
256 | MODULE_AUTHOR("Mark Brown"); | ||
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c index f56c9adf9493..ed4b22a167b3 100644 --- a/drivers/mfd/wm8350-irq.c +++ b/drivers/mfd/wm8350-irq.c | |||
@@ -417,16 +417,16 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data) | |||
417 | return IRQ_HANDLED; | 417 | return IRQ_HANDLED; |
418 | } | 418 | } |
419 | 419 | ||
420 | static void wm8350_irq_lock(unsigned int irq) | 420 | static void wm8350_irq_lock(struct irq_data *data) |
421 | { | 421 | { |
422 | struct wm8350 *wm8350 = get_irq_chip_data(irq); | 422 | struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data); |
423 | 423 | ||
424 | mutex_lock(&wm8350->irq_lock); | 424 | mutex_lock(&wm8350->irq_lock); |
425 | } | 425 | } |
426 | 426 | ||
427 | static void wm8350_irq_sync_unlock(unsigned int irq) | 427 | static void wm8350_irq_sync_unlock(struct irq_data *data) |
428 | { | 428 | { |
429 | struct wm8350 *wm8350 = get_irq_chip_data(irq); | 429 | struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data); |
430 | int i; | 430 | int i; |
431 | 431 | ||
432 | for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) { | 432 | for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) { |
@@ -442,28 +442,30 @@ static void wm8350_irq_sync_unlock(unsigned int irq) | |||
442 | mutex_unlock(&wm8350->irq_lock); | 442 | mutex_unlock(&wm8350->irq_lock); |
443 | } | 443 | } |
444 | 444 | ||
445 | static void wm8350_irq_enable(unsigned int irq) | 445 | static void wm8350_irq_enable(struct irq_data *data) |
446 | { | 446 | { |
447 | struct wm8350 *wm8350 = get_irq_chip_data(irq); | 447 | struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data); |
448 | struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq); | 448 | struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, |
449 | data->irq); | ||
449 | 450 | ||
450 | wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask; | 451 | wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask; |
451 | } | 452 | } |
452 | 453 | ||
453 | static void wm8350_irq_disable(unsigned int irq) | 454 | static void wm8350_irq_disable(struct irq_data *data) |
454 | { | 455 | { |
455 | struct wm8350 *wm8350 = get_irq_chip_data(irq); | 456 | struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data); |
456 | struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq); | 457 | struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, |
458 | data->irq); | ||
457 | 459 | ||
458 | wm8350->irq_masks[irq_data->reg] |= irq_data->mask; | 460 | wm8350->irq_masks[irq_data->reg] |= irq_data->mask; |
459 | } | 461 | } |
460 | 462 | ||
461 | static struct irq_chip wm8350_irq_chip = { | 463 | static struct irq_chip wm8350_irq_chip = { |
462 | .name = "wm8350", | 464 | .name = "wm8350", |
463 | .bus_lock = wm8350_irq_lock, | 465 | .irq_bus_lock = wm8350_irq_lock, |
464 | .bus_sync_unlock = wm8350_irq_sync_unlock, | 466 | .irq_bus_sync_unlock = wm8350_irq_sync_unlock, |
465 | .disable = wm8350_irq_disable, | 467 | .irq_disable = wm8350_irq_disable, |
466 | .enable = wm8350_irq_enable, | 468 | .irq_enable = wm8350_irq_enable, |
467 | }; | 469 | }; |
468 | 470 | ||
469 | int wm8350_irq_init(struct wm8350 *wm8350, int irq, | 471 | int wm8350_irq_init(struct wm8350 *wm8350, int irq, |
@@ -516,17 +518,17 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq, | |||
516 | for (cur_irq = wm8350->irq_base; | 518 | for (cur_irq = wm8350->irq_base; |
517 | cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base; | 519 | cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base; |
518 | cur_irq++) { | 520 | cur_irq++) { |
519 | set_irq_chip_data(cur_irq, wm8350); | 521 | irq_set_chip_data(cur_irq, wm8350); |
520 | set_irq_chip_and_handler(cur_irq, &wm8350_irq_chip, | 522 | irq_set_chip_and_handler(cur_irq, &wm8350_irq_chip, |
521 | handle_edge_irq); | 523 | handle_edge_irq); |
522 | set_irq_nested_thread(cur_irq, 1); | 524 | irq_set_nested_thread(cur_irq, 1); |
523 | 525 | ||
524 | /* ARM needs us to explicitly flag the IRQ as valid | 526 | /* ARM needs us to explicitly flag the IRQ as valid |
525 | * and will set them noprobe when we do so. */ | 527 | * and will set them noprobe when we do so. */ |
526 | #ifdef CONFIG_ARM | 528 | #ifdef CONFIG_ARM |
527 | set_irq_flags(cur_irq, IRQF_VALID); | 529 | set_irq_flags(cur_irq, IRQF_VALID); |
528 | #else | 530 | #else |
529 | set_irq_noprobe(cur_irq); | 531 | irq_set_noprobe(cur_irq); |
530 | #endif | 532 | #endif |
531 | } | 533 | } |
532 | 534 | ||
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 1bfef4846b07..597f82edacaa 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c | |||
@@ -245,7 +245,8 @@ static int wm8400_register_codec(struct wm8400 *wm8400) | |||
245 | { | 245 | { |
246 | struct mfd_cell cell = { | 246 | struct mfd_cell cell = { |
247 | .name = "wm8400-codec", | 247 | .name = "wm8400-codec", |
248 | .driver_data = wm8400, | 248 | .platform_data = wm8400, |
249 | .pdata_size = sizeof(*wm8400), | ||
249 | }; | 250 | }; |
250 | 251 | ||
251 | return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0); | 252 | return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0); |
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index b3b2aaf89dbe..e198d40292e7 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
20 | #include <linux/mfd/core.h> | 20 | #include <linux/mfd/core.h> |
21 | #include <linux/pm_runtime.h> | ||
21 | #include <linux/regulator/consumer.h> | 22 | #include <linux/regulator/consumer.h> |
22 | #include <linux/regulator/machine.h> | 23 | #include <linux/regulator/machine.h> |
23 | 24 | ||
@@ -39,10 +40,8 @@ static int wm8994_read(struct wm8994 *wm8994, unsigned short reg, | |||
39 | return ret; | 40 | return ret; |
40 | 41 | ||
41 | for (i = 0; i < bytes / 2; i++) { | 42 | for (i = 0; i < bytes / 2; i++) { |
42 | buf[i] = be16_to_cpu(buf[i]); | ||
43 | |||
44 | dev_vdbg(wm8994->dev, "Read %04x from R%d(0x%x)\n", | 43 | dev_vdbg(wm8994->dev, "Read %04x from R%d(0x%x)\n", |
45 | buf[i], reg + i, reg + i); | 44 | be16_to_cpu(buf[i]), reg + i, reg + i); |
46 | } | 45 | } |
47 | 46 | ||
48 | return 0; | 47 | return 0; |
@@ -68,7 +67,7 @@ int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg) | |||
68 | if (ret < 0) | 67 | if (ret < 0) |
69 | return ret; | 68 | return ret; |
70 | else | 69 | else |
71 | return val; | 70 | return be16_to_cpu(val); |
72 | } | 71 | } |
73 | EXPORT_SYMBOL_GPL(wm8994_reg_read); | 72 | EXPORT_SYMBOL_GPL(wm8994_reg_read); |
74 | 73 | ||
@@ -78,7 +77,7 @@ EXPORT_SYMBOL_GPL(wm8994_reg_read); | |||
78 | * @wm8994: Device to read from | 77 | * @wm8994: Device to read from |
79 | * @reg: First register | 78 | * @reg: First register |
80 | * @count: Number of registers | 79 | * @count: Number of registers |
81 | * @buf: Buffer to fill. | 80 | * @buf: Buffer to fill. The data will be returned big endian. |
82 | */ | 81 | */ |
83 | int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, | 82 | int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, |
84 | int count, u16 *buf) | 83 | int count, u16 *buf) |
@@ -96,9 +95,9 @@ int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, | |||
96 | EXPORT_SYMBOL_GPL(wm8994_bulk_read); | 95 | EXPORT_SYMBOL_GPL(wm8994_bulk_read); |
97 | 96 | ||
98 | static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, | 97 | static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, |
99 | int bytes, void *src) | 98 | int bytes, const void *src) |
100 | { | 99 | { |
101 | u16 *buf = src; | 100 | const u16 *buf = src; |
102 | int i; | 101 | int i; |
103 | 102 | ||
104 | BUG_ON(bytes % 2); | 103 | BUG_ON(bytes % 2); |
@@ -106,9 +105,7 @@ static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, | |||
106 | 105 | ||
107 | for (i = 0; i < bytes / 2; i++) { | 106 | for (i = 0; i < bytes / 2; i++) { |
108 | dev_vdbg(wm8994->dev, "Write %04x to R%d(0x%x)\n", | 107 | dev_vdbg(wm8994->dev, "Write %04x to R%d(0x%x)\n", |
109 | buf[i], reg + i, reg + i); | 108 | be16_to_cpu(buf[i]), reg + i, reg + i); |
110 | |||
111 | buf[i] = cpu_to_be16(buf[i]); | ||
112 | } | 109 | } |
113 | 110 | ||
114 | return wm8994->write_dev(wm8994, reg, bytes, src); | 111 | return wm8994->write_dev(wm8994, reg, bytes, src); |
@@ -126,6 +123,8 @@ int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg, | |||
126 | { | 123 | { |
127 | int ret; | 124 | int ret; |
128 | 125 | ||
126 | val = cpu_to_be16(val); | ||
127 | |||
129 | mutex_lock(&wm8994->io_lock); | 128 | mutex_lock(&wm8994->io_lock); |
130 | 129 | ||
131 | ret = wm8994_write(wm8994, reg, 2, &val); | 130 | ret = wm8994_write(wm8994, reg, 2, &val); |
@@ -137,6 +136,29 @@ int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg, | |||
137 | EXPORT_SYMBOL_GPL(wm8994_reg_write); | 136 | EXPORT_SYMBOL_GPL(wm8994_reg_write); |
138 | 137 | ||
139 | /** | 138 | /** |
139 | * wm8994_bulk_write: Write multiple WM8994 registers | ||
140 | * | ||
141 | * @wm8994: Device to write to | ||
142 | * @reg: First register | ||
143 | * @count: Number of registers | ||
144 | * @buf: Buffer to write from. Data must be big-endian formatted. | ||
145 | */ | ||
146 | int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg, | ||
147 | int count, const u16 *buf) | ||
148 | { | ||
149 | int ret; | ||
150 | |||
151 | mutex_lock(&wm8994->io_lock); | ||
152 | |||
153 | ret = wm8994_write(wm8994, reg, count * 2, buf); | ||
154 | |||
155 | mutex_unlock(&wm8994->io_lock); | ||
156 | |||
157 | return ret; | ||
158 | } | ||
159 | EXPORT_SYMBOL_GPL(wm8994_bulk_write); | ||
160 | |||
161 | /** | ||
140 | * wm8994_set_bits: Set the value of a bitfield in a WM8994 register | 162 | * wm8994_set_bits: Set the value of a bitfield in a WM8994 register |
141 | * | 163 | * |
142 | * @wm8994: Device to write to. | 164 | * @wm8994: Device to write to. |
@@ -156,9 +178,13 @@ int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg, | |||
156 | if (ret < 0) | 178 | if (ret < 0) |
157 | goto out; | 179 | goto out; |
158 | 180 | ||
181 | r = be16_to_cpu(r); | ||
182 | |||
159 | r &= ~mask; | 183 | r &= ~mask; |
160 | r |= val; | 184 | r |= val; |
161 | 185 | ||
186 | r = cpu_to_be16(r); | ||
187 | |||
162 | ret = wm8994_write(wm8994, reg, 2, &r); | 188 | ret = wm8994_write(wm8994, reg, 2, &r); |
163 | 189 | ||
164 | out: | 190 | out: |
@@ -169,8 +195,16 @@ out: | |||
169 | EXPORT_SYMBOL_GPL(wm8994_set_bits); | 195 | EXPORT_SYMBOL_GPL(wm8994_set_bits); |
170 | 196 | ||
171 | static struct mfd_cell wm8994_regulator_devs[] = { | 197 | static struct mfd_cell wm8994_regulator_devs[] = { |
172 | { .name = "wm8994-ldo", .id = 1 }, | 198 | { |
173 | { .name = "wm8994-ldo", .id = 2 }, | 199 | .name = "wm8994-ldo", |
200 | .id = 1, | ||
201 | .pm_runtime_no_callbacks = true, | ||
202 | }, | ||
203 | { | ||
204 | .name = "wm8994-ldo", | ||
205 | .id = 2, | ||
206 | .pm_runtime_no_callbacks = true, | ||
207 | }, | ||
174 | }; | 208 | }; |
175 | 209 | ||
176 | static struct resource wm8994_codec_resources[] = { | 210 | static struct resource wm8994_codec_resources[] = { |
@@ -200,6 +234,7 @@ static struct mfd_cell wm8994_devs[] = { | |||
200 | .name = "wm8994-gpio", | 234 | .name = "wm8994-gpio", |
201 | .num_resources = ARRAY_SIZE(wm8994_gpio_resources), | 235 | .num_resources = ARRAY_SIZE(wm8994_gpio_resources), |
202 | .resources = wm8994_gpio_resources, | 236 | .resources = wm8994_gpio_resources, |
237 | .pm_runtime_no_callbacks = true, | ||
203 | }, | 238 | }, |
204 | }; | 239 | }; |
205 | 240 | ||
@@ -218,12 +253,34 @@ static const char *wm8994_main_supplies[] = { | |||
218 | "SPKVDD2", | 253 | "SPKVDD2", |
219 | }; | 254 | }; |
220 | 255 | ||
256 | static const char *wm8958_main_supplies[] = { | ||
257 | "DBVDD1", | ||
258 | "DBVDD2", | ||
259 | "DBVDD3", | ||
260 | "DCVDD", | ||
261 | "AVDD1", | ||
262 | "AVDD2", | ||
263 | "CPVDD", | ||
264 | "SPKVDD1", | ||
265 | "SPKVDD2", | ||
266 | }; | ||
267 | |||
221 | #ifdef CONFIG_PM | 268 | #ifdef CONFIG_PM |
222 | static int wm8994_device_suspend(struct device *dev) | 269 | static int wm8994_suspend(struct device *dev) |
223 | { | 270 | { |
224 | struct wm8994 *wm8994 = dev_get_drvdata(dev); | 271 | struct wm8994 *wm8994 = dev_get_drvdata(dev); |
225 | int ret; | 272 | int ret; |
226 | 273 | ||
274 | /* Don't actually go through with the suspend if the CODEC is | ||
275 | * still active (eg, for audio passthrough from CP. */ | ||
276 | ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_1); | ||
277 | if (ret < 0) { | ||
278 | dev_err(dev, "Failed to read power status: %d\n", ret); | ||
279 | } else if (ret & WM8994_VMID_SEL_MASK) { | ||
280 | dev_dbg(dev, "CODEC still active, ignoring suspend\n"); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
227 | /* GPIO configuration state is saved here since we may be configuring | 284 | /* GPIO configuration state is saved here since we may be configuring |
228 | * the GPIO alternate functions even if we're not using the gpiolib | 285 | * the GPIO alternate functions even if we're not using the gpiolib |
229 | * driver for them. | 286 | * driver for them. |
@@ -239,7 +296,14 @@ static int wm8994_device_suspend(struct device *dev) | |||
239 | if (ret < 0) | 296 | if (ret < 0) |
240 | dev_err(dev, "Failed to save LDO registers: %d\n", ret); | 297 | dev_err(dev, "Failed to save LDO registers: %d\n", ret); |
241 | 298 | ||
242 | ret = regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies), | 299 | /* Explicitly put the device into reset in case regulators |
300 | * don't get disabled in order to ensure consistent restart. | ||
301 | */ | ||
302 | wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET, 0x8994); | ||
303 | |||
304 | wm8994->suspended = true; | ||
305 | |||
306 | ret = regulator_bulk_disable(wm8994->num_supplies, | ||
243 | wm8994->supplies); | 307 | wm8994->supplies); |
244 | if (ret != 0) { | 308 | if (ret != 0) { |
245 | dev_err(dev, "Failed to disable supplies: %d\n", ret); | 309 | dev_err(dev, "Failed to disable supplies: %d\n", ret); |
@@ -249,12 +313,16 @@ static int wm8994_device_suspend(struct device *dev) | |||
249 | return 0; | 313 | return 0; |
250 | } | 314 | } |
251 | 315 | ||
252 | static int wm8994_device_resume(struct device *dev) | 316 | static int wm8994_resume(struct device *dev) |
253 | { | 317 | { |
254 | struct wm8994 *wm8994 = dev_get_drvdata(dev); | 318 | struct wm8994 *wm8994 = dev_get_drvdata(dev); |
255 | int ret; | 319 | int ret; |
256 | 320 | ||
257 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies), | 321 | /* We may have lied to the PM core about suspending */ |
322 | if (!wm8994->suspended) | ||
323 | return 0; | ||
324 | |||
325 | ret = regulator_bulk_enable(wm8994->num_supplies, | ||
258 | wm8994->supplies); | 326 | wm8994->supplies); |
259 | if (ret != 0) { | 327 | if (ret != 0) { |
260 | dev_err(dev, "Failed to enable supplies: %d\n", ret); | 328 | dev_err(dev, "Failed to enable supplies: %d\n", ret); |
@@ -276,6 +344,8 @@ static int wm8994_device_resume(struct device *dev) | |||
276 | if (ret < 0) | 344 | if (ret < 0) |
277 | dev_err(dev, "Failed to restore GPIO registers: %d\n", ret); | 345 | dev_err(dev, "Failed to restore GPIO registers: %d\n", ret); |
278 | 346 | ||
347 | wm8994->suspended = false; | ||
348 | |||
279 | return 0; | 349 | return 0; |
280 | } | 350 | } |
281 | #endif | 351 | #endif |
@@ -305,9 +375,10 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) | |||
305 | /* | 375 | /* |
306 | * Instantiate the generic non-control parts of the device. | 376 | * Instantiate the generic non-control parts of the device. |
307 | */ | 377 | */ |
308 | static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) | 378 | static int wm8994_device_init(struct wm8994 *wm8994, int irq) |
309 | { | 379 | { |
310 | struct wm8994_pdata *pdata = wm8994->dev->platform_data; | 380 | struct wm8994_pdata *pdata = wm8994->dev->platform_data; |
381 | const char *devname; | ||
311 | int ret, i; | 382 | int ret, i; |
312 | 383 | ||
313 | mutex_init(&wm8994->io_lock); | 384 | mutex_init(&wm8994->io_lock); |
@@ -323,25 +394,48 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) | |||
323 | goto err; | 394 | goto err; |
324 | } | 395 | } |
325 | 396 | ||
397 | switch (wm8994->type) { | ||
398 | case WM8994: | ||
399 | wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies); | ||
400 | break; | ||
401 | case WM8958: | ||
402 | wm8994->num_supplies = ARRAY_SIZE(wm8958_main_supplies); | ||
403 | break; | ||
404 | default: | ||
405 | BUG(); | ||
406 | return -EINVAL; | ||
407 | } | ||
408 | |||
326 | wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) * | 409 | wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) * |
327 | ARRAY_SIZE(wm8994_main_supplies), | 410 | wm8994->num_supplies, |
328 | GFP_KERNEL); | 411 | GFP_KERNEL); |
329 | if (!wm8994->supplies) { | 412 | if (!wm8994->supplies) { |
330 | ret = -ENOMEM; | 413 | ret = -ENOMEM; |
331 | goto err; | 414 | goto err; |
332 | } | 415 | } |
333 | 416 | ||
334 | for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++) | 417 | switch (wm8994->type) { |
335 | wm8994->supplies[i].supply = wm8994_main_supplies[i]; | 418 | case WM8994: |
336 | 419 | for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++) | |
337 | ret = regulator_bulk_get(wm8994->dev, ARRAY_SIZE(wm8994_main_supplies), | 420 | wm8994->supplies[i].supply = wm8994_main_supplies[i]; |
421 | break; | ||
422 | case WM8958: | ||
423 | for (i = 0; i < ARRAY_SIZE(wm8958_main_supplies); i++) | ||
424 | wm8994->supplies[i].supply = wm8958_main_supplies[i]; | ||
425 | break; | ||
426 | default: | ||
427 | BUG(); | ||
428 | return -EINVAL; | ||
429 | } | ||
430 | |||
431 | ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies, | ||
338 | wm8994->supplies); | 432 | wm8994->supplies); |
339 | if (ret != 0) { | 433 | if (ret != 0) { |
340 | dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret); | 434 | dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret); |
341 | goto err_supplies; | 435 | goto err_supplies; |
342 | } | 436 | } |
343 | 437 | ||
344 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies), | 438 | ret = regulator_bulk_enable(wm8994->num_supplies, |
345 | wm8994->supplies); | 439 | wm8994->supplies); |
346 | if (ret != 0) { | 440 | if (ret != 0) { |
347 | dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret); | 441 | dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret); |
@@ -353,7 +447,22 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) | |||
353 | dev_err(wm8994->dev, "Failed to read ID register\n"); | 447 | dev_err(wm8994->dev, "Failed to read ID register\n"); |
354 | goto err_enable; | 448 | goto err_enable; |
355 | } | 449 | } |
356 | if (ret != 0x8994) { | 450 | switch (ret) { |
451 | case 0x8994: | ||
452 | devname = "WM8994"; | ||
453 | if (wm8994->type != WM8994) | ||
454 | dev_warn(wm8994->dev, "Device registered as type %d\n", | ||
455 | wm8994->type); | ||
456 | wm8994->type = WM8994; | ||
457 | break; | ||
458 | case 0x8958: | ||
459 | devname = "WM8958"; | ||
460 | if (wm8994->type != WM8958) | ||
461 | dev_warn(wm8994->dev, "Device registered as type %d\n", | ||
462 | wm8994->type); | ||
463 | wm8994->type = WM8958; | ||
464 | break; | ||
465 | default: | ||
357 | dev_err(wm8994->dev, "Device is not a WM8994, ID is %x\n", | 466 | dev_err(wm8994->dev, "Device is not a WM8994, ID is %x\n", |
358 | ret); | 467 | ret); |
359 | ret = -EINVAL; | 468 | ret = -EINVAL; |
@@ -370,14 +479,16 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) | |||
370 | switch (ret) { | 479 | switch (ret) { |
371 | case 0: | 480 | case 0: |
372 | case 1: | 481 | case 1: |
373 | dev_warn(wm8994->dev, "revision %c not fully supported\n", | 482 | if (wm8994->type == WM8994) |
374 | 'A' + ret); | 483 | dev_warn(wm8994->dev, |
484 | "revision %c not fully supported\n", | ||
485 | 'A' + ret); | ||
375 | break; | 486 | break; |
376 | default: | 487 | default: |
377 | dev_info(wm8994->dev, "revision %c\n", 'A' + ret); | ||
378 | break; | 488 | break; |
379 | } | 489 | } |
380 | 490 | ||
491 | dev_info(wm8994->dev, "%s revision %c\n", devname, 'A' + ret); | ||
381 | 492 | ||
382 | if (pdata) { | 493 | if (pdata) { |
383 | wm8994->irq_base = pdata->irq_base; | 494 | wm8994->irq_base = pdata->irq_base; |
@@ -418,15 +529,18 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) | |||
418 | goto err_irq; | 529 | goto err_irq; |
419 | } | 530 | } |
420 | 531 | ||
532 | pm_runtime_enable(wm8994->dev); | ||
533 | pm_runtime_resume(wm8994->dev); | ||
534 | |||
421 | return 0; | 535 | return 0; |
422 | 536 | ||
423 | err_irq: | 537 | err_irq: |
424 | wm8994_irq_exit(wm8994); | 538 | wm8994_irq_exit(wm8994); |
425 | err_enable: | 539 | err_enable: |
426 | regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies), | 540 | regulator_bulk_disable(wm8994->num_supplies, |
427 | wm8994->supplies); | 541 | wm8994->supplies); |
428 | err_get: | 542 | err_get: |
429 | regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies); | 543 | regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); |
430 | err_supplies: | 544 | err_supplies: |
431 | kfree(wm8994->supplies); | 545 | kfree(wm8994->supplies); |
432 | err: | 546 | err: |
@@ -437,11 +551,12 @@ err: | |||
437 | 551 | ||
438 | static void wm8994_device_exit(struct wm8994 *wm8994) | 552 | static void wm8994_device_exit(struct wm8994 *wm8994) |
439 | { | 553 | { |
554 | pm_runtime_disable(wm8994->dev); | ||
440 | mfd_remove_devices(wm8994->dev); | 555 | mfd_remove_devices(wm8994->dev); |
441 | wm8994_irq_exit(wm8994); | 556 | wm8994_irq_exit(wm8994); |
442 | regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies), | 557 | regulator_bulk_disable(wm8994->num_supplies, |
443 | wm8994->supplies); | 558 | wm8994->supplies); |
444 | regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies); | 559 | regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); |
445 | kfree(wm8994->supplies); | 560 | kfree(wm8994->supplies); |
446 | kfree(wm8994); | 561 | kfree(wm8994); |
447 | } | 562 | } |
@@ -467,25 +582,29 @@ static int wm8994_i2c_read_device(struct wm8994 *wm8994, unsigned short reg, | |||
467 | return 0; | 582 | return 0; |
468 | } | 583 | } |
469 | 584 | ||
470 | /* Currently we allocate the write buffer on the stack; this is OK for | ||
471 | * small writes - if we need to do large writes this will need to be | ||
472 | * revised. | ||
473 | */ | ||
474 | static int wm8994_i2c_write_device(struct wm8994 *wm8994, unsigned short reg, | 585 | static int wm8994_i2c_write_device(struct wm8994 *wm8994, unsigned short reg, |
475 | int bytes, void *src) | 586 | int bytes, const void *src) |
476 | { | 587 | { |
477 | struct i2c_client *i2c = wm8994->control_data; | 588 | struct i2c_client *i2c = wm8994->control_data; |
478 | unsigned char msg[bytes + 2]; | 589 | struct i2c_msg xfer[2]; |
479 | int ret; | 590 | int ret; |
480 | 591 | ||
481 | reg = cpu_to_be16(reg); | 592 | reg = cpu_to_be16(reg); |
482 | memcpy(&msg[0], ®, 2); | ||
483 | memcpy(&msg[2], src, bytes); | ||
484 | 593 | ||
485 | ret = i2c_master_send(i2c, msg, bytes + 2); | 594 | xfer[0].addr = i2c->addr; |
595 | xfer[0].flags = 0; | ||
596 | xfer[0].len = 2; | ||
597 | xfer[0].buf = (char *)® | ||
598 | |||
599 | xfer[1].addr = i2c->addr; | ||
600 | xfer[1].flags = I2C_M_NOSTART; | ||
601 | xfer[1].len = bytes; | ||
602 | xfer[1].buf = (char *)src; | ||
603 | |||
604 | ret = i2c_transfer(i2c->adapter, xfer, 2); | ||
486 | if (ret < 0) | 605 | if (ret < 0) |
487 | return ret; | 606 | return ret; |
488 | if (ret < bytes + 2) | 607 | if (ret != 2) |
489 | return -EIO; | 608 | return -EIO; |
490 | 609 | ||
491 | return 0; | 610 | return 0; |
@@ -506,8 +625,9 @@ static int wm8994_i2c_probe(struct i2c_client *i2c, | |||
506 | wm8994->read_dev = wm8994_i2c_read_device; | 625 | wm8994->read_dev = wm8994_i2c_read_device; |
507 | wm8994->write_dev = wm8994_i2c_write_device; | 626 | wm8994->write_dev = wm8994_i2c_write_device; |
508 | wm8994->irq = i2c->irq; | 627 | wm8994->irq = i2c->irq; |
628 | wm8994->type = id->driver_data; | ||
509 | 629 | ||
510 | return wm8994_device_init(wm8994, id->driver_data, i2c->irq); | 630 | return wm8994_device_init(wm8994, i2c->irq); |
511 | } | 631 | } |
512 | 632 | ||
513 | static int wm8994_i2c_remove(struct i2c_client *i2c) | 633 | static int wm8994_i2c_remove(struct i2c_client *i2c) |
@@ -519,36 +639,24 @@ static int wm8994_i2c_remove(struct i2c_client *i2c) | |||
519 | return 0; | 639 | return 0; |
520 | } | 640 | } |
521 | 641 | ||
522 | #ifdef CONFIG_PM | ||
523 | static int wm8994_i2c_suspend(struct i2c_client *i2c, pm_message_t state) | ||
524 | { | ||
525 | return wm8994_device_suspend(&i2c->dev); | ||
526 | } | ||
527 | |||
528 | static int wm8994_i2c_resume(struct i2c_client *i2c) | ||
529 | { | ||
530 | return wm8994_device_resume(&i2c->dev); | ||
531 | } | ||
532 | #else | ||
533 | #define wm8994_i2c_suspend NULL | ||
534 | #define wm8994_i2c_resume NULL | ||
535 | #endif | ||
536 | |||
537 | static const struct i2c_device_id wm8994_i2c_id[] = { | 642 | static const struct i2c_device_id wm8994_i2c_id[] = { |
538 | { "wm8994", 0 }, | 643 | { "wm8994", WM8994 }, |
644 | { "wm8958", WM8958 }, | ||
539 | { } | 645 | { } |
540 | }; | 646 | }; |
541 | MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); | 647 | MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); |
542 | 648 | ||
649 | static UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, | ||
650 | NULL); | ||
651 | |||
543 | static struct i2c_driver wm8994_i2c_driver = { | 652 | static struct i2c_driver wm8994_i2c_driver = { |
544 | .driver = { | 653 | .driver = { |
545 | .name = "wm8994", | 654 | .name = "wm8994", |
546 | .owner = THIS_MODULE, | 655 | .owner = THIS_MODULE, |
656 | .pm = &wm8994_pm_ops, | ||
547 | }, | 657 | }, |
548 | .probe = wm8994_i2c_probe, | 658 | .probe = wm8994_i2c_probe, |
549 | .remove = wm8994_i2c_remove, | 659 | .remove = wm8994_i2c_remove, |
550 | .suspend = wm8994_i2c_suspend, | ||
551 | .resume = wm8994_i2c_resume, | ||
552 | .id_table = wm8994_i2c_id, | 660 | .id_table = wm8994_i2c_id, |
553 | }; | 661 | }; |
554 | 662 | ||
diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index 8400eb1ee5db..71c6e8f9aedb 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c | |||
@@ -156,16 +156,16 @@ static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994, | |||
156 | return &wm8994_irqs[irq - wm8994->irq_base]; | 156 | return &wm8994_irqs[irq - wm8994->irq_base]; |
157 | } | 157 | } |
158 | 158 | ||
159 | static void wm8994_irq_lock(unsigned int irq) | 159 | static void wm8994_irq_lock(struct irq_data *data) |
160 | { | 160 | { |
161 | struct wm8994 *wm8994 = get_irq_chip_data(irq); | 161 | struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); |
162 | 162 | ||
163 | mutex_lock(&wm8994->irq_lock); | 163 | mutex_lock(&wm8994->irq_lock); |
164 | } | 164 | } |
165 | 165 | ||
166 | static void wm8994_irq_sync_unlock(unsigned int irq) | 166 | static void wm8994_irq_sync_unlock(struct irq_data *data) |
167 | { | 167 | { |
168 | struct wm8994 *wm8994 = get_irq_chip_data(irq); | 168 | struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); |
169 | int i; | 169 | int i; |
170 | 170 | ||
171 | for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) { | 171 | for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) { |
@@ -182,28 +182,30 @@ static void wm8994_irq_sync_unlock(unsigned int irq) | |||
182 | mutex_unlock(&wm8994->irq_lock); | 182 | mutex_unlock(&wm8994->irq_lock); |
183 | } | 183 | } |
184 | 184 | ||
185 | static void wm8994_irq_unmask(unsigned int irq) | 185 | static void wm8994_irq_enable(struct irq_data *data) |
186 | { | 186 | { |
187 | struct wm8994 *wm8994 = get_irq_chip_data(irq); | 187 | struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); |
188 | struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq); | 188 | struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, |
189 | data->irq); | ||
189 | 190 | ||
190 | wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; | 191 | wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; |
191 | } | 192 | } |
192 | 193 | ||
193 | static void wm8994_irq_mask(unsigned int irq) | 194 | static void wm8994_irq_disable(struct irq_data *data) |
194 | { | 195 | { |
195 | struct wm8994 *wm8994 = get_irq_chip_data(irq); | 196 | struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); |
196 | struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq); | 197 | struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, |
198 | data->irq); | ||
197 | 199 | ||
198 | wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; | 200 | wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; |
199 | } | 201 | } |
200 | 202 | ||
201 | static struct irq_chip wm8994_irq_chip = { | 203 | static struct irq_chip wm8994_irq_chip = { |
202 | .name = "wm8994", | 204 | .name = "wm8994", |
203 | .bus_lock = wm8994_irq_lock, | 205 | .irq_bus_lock = wm8994_irq_lock, |
204 | .bus_sync_unlock = wm8994_irq_sync_unlock, | 206 | .irq_bus_sync_unlock = wm8994_irq_sync_unlock, |
205 | .mask = wm8994_irq_mask, | 207 | .irq_disable = wm8994_irq_disable, |
206 | .unmask = wm8994_irq_unmask, | 208 | .irq_enable = wm8994_irq_enable, |
207 | }; | 209 | }; |
208 | 210 | ||
209 | /* The processing of the primary interrupt occurs in a thread so that | 211 | /* The processing of the primary interrupt occurs in a thread so that |
@@ -223,9 +225,11 @@ static irqreturn_t wm8994_irq_thread(int irq, void *data) | |||
223 | return IRQ_NONE; | 225 | return IRQ_NONE; |
224 | } | 226 | } |
225 | 227 | ||
226 | /* Apply masking */ | 228 | /* Bit swap and apply masking */ |
227 | for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) | 229 | for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) { |
230 | status[i] = be16_to_cpu(status[i]); | ||
228 | status[i] &= ~wm8994->irq_masks_cur[i]; | 231 | status[i] &= ~wm8994->irq_masks_cur[i]; |
232 | } | ||
229 | 233 | ||
230 | /* Report */ | 234 | /* Report */ |
231 | for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) { | 235 | for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) { |
@@ -274,17 +278,17 @@ int wm8994_irq_init(struct wm8994 *wm8994) | |||
274 | for (cur_irq = wm8994->irq_base; | 278 | for (cur_irq = wm8994->irq_base; |
275 | cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base; | 279 | cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base; |
276 | cur_irq++) { | 280 | cur_irq++) { |
277 | set_irq_chip_data(cur_irq, wm8994); | 281 | irq_set_chip_data(cur_irq, wm8994); |
278 | set_irq_chip_and_handler(cur_irq, &wm8994_irq_chip, | 282 | irq_set_chip_and_handler(cur_irq, &wm8994_irq_chip, |
279 | handle_edge_irq); | 283 | handle_edge_irq); |
280 | set_irq_nested_thread(cur_irq, 1); | 284 | irq_set_nested_thread(cur_irq, 1); |
281 | 285 | ||
282 | /* ARM needs us to explicitly flag the IRQ as valid | 286 | /* ARM needs us to explicitly flag the IRQ as valid |
283 | * and will set them noprobe when we do so. */ | 287 | * and will set them noprobe when we do so. */ |
284 | #ifdef CONFIG_ARM | 288 | #ifdef CONFIG_ARM |
285 | set_irq_flags(cur_irq, IRQF_VALID); | 289 | set_irq_flags(cur_irq, IRQF_VALID); |
286 | #else | 290 | #else |
287 | set_irq_noprobe(cur_irq); | 291 | irq_set_noprobe(cur_irq); |
288 | #endif | 292 | #endif |
289 | } | 293 | } |
290 | 294 | ||