0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/of_irq.h>
0013 #include <linux/interrupt.h>
0014 #include <asm/pmac_feature.h>
0015 #include "../aoa.h"
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 static int headphone_mute_gpio;
0026 static int master_mute_gpio;
0027 static int amp_mute_gpio;
0028 static int lineout_mute_gpio;
0029 static int hw_reset_gpio;
0030 static int lineout_detect_gpio;
0031 static int headphone_detect_gpio;
0032 static int linein_detect_gpio;
0033
0034
0035 static int headphone_mute_gpio_activestate;
0036 static int master_mute_gpio_activestate;
0037 static int amp_mute_gpio_activestate;
0038 static int lineout_mute_gpio_activestate;
0039 static int hw_reset_gpio_activestate;
0040 static int lineout_detect_gpio_activestate;
0041 static int headphone_detect_gpio_activestate;
0042 static int linein_detect_gpio_activestate;
0043
0044
0045
0046 static struct device_node *lineout_detect_node;
0047 static struct device_node *linein_detect_node;
0048 static struct device_node *headphone_detect_node;
0049
0050 static int lineout_detect_irq;
0051 static int linein_detect_irq;
0052 static int headphone_detect_irq;
0053
0054 static struct device_node *get_gpio(char *name,
0055 char *altname,
0056 int *gpioptr,
0057 int *gpioactiveptr)
0058 {
0059 struct device_node *np, *gpio;
0060 const u32 *reg;
0061 const char *audio_gpio;
0062
0063 *gpioptr = -1;
0064
0065
0066 np = of_find_node_by_name(NULL, name);
0067 if (!np) {
0068
0069
0070
0071
0072 gpio = of_find_node_by_name(NULL, "gpio");
0073 if (!gpio)
0074 return NULL;
0075 while ((np = of_get_next_child(gpio, np))) {
0076 audio_gpio = of_get_property(np, "audio-gpio", NULL);
0077 if (!audio_gpio)
0078 continue;
0079 if (strcmp(audio_gpio, name) == 0)
0080 break;
0081 if (altname && (strcmp(audio_gpio, altname) == 0))
0082 break;
0083 }
0084 of_node_put(gpio);
0085
0086 if (!np)
0087 return NULL;
0088 }
0089
0090 reg = of_get_property(np, "reg", NULL);
0091 if (!reg) {
0092 of_node_put(np);
0093 return NULL;
0094 }
0095
0096 *gpioptr = *reg;
0097
0098
0099
0100
0101 if (*gpioptr < 0x50)
0102 *gpioptr += 0x50;
0103
0104 reg = of_get_property(np, "audio-gpio-active-state", NULL);
0105 if (!reg)
0106
0107
0108
0109
0110
0111 *gpioactiveptr = 0;
0112 else
0113 *gpioactiveptr = *reg;
0114
0115 return np;
0116 }
0117
0118 static void get_irq(struct device_node * np, int *irqptr)
0119 {
0120 if (np)
0121 *irqptr = irq_of_parse_and_map(np, 0);
0122 else
0123 *irqptr = 0;
0124 }
0125
0126
0127 #define SWITCH_GPIO(name, v, on) \
0128 (((v)&~1) | ((on)? \
0129 (name##_gpio_activestate==0?4:5): \
0130 (name##_gpio_activestate==0?5:4)))
0131
0132 #define FTR_GPIO(name, bit) \
0133 static void ftr_gpio_set_##name(struct gpio_runtime *rt, int on)\
0134 { \
0135 int v; \
0136 \
0137 if (unlikely(!rt)) return; \
0138 \
0139 if (name##_mute_gpio < 0) \
0140 return; \
0141 \
0142 v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, \
0143 name##_mute_gpio, \
0144 0); \
0145 \
0146 \
0147 v = SWITCH_GPIO(name##_mute, v, !on); \
0148 \
0149 pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, \
0150 name##_mute_gpio, v); \
0151 \
0152 rt->implementation_private &= ~(1<<bit); \
0153 rt->implementation_private |= (!!on << bit); \
0154 } \
0155 static int ftr_gpio_get_##name(struct gpio_runtime *rt) \
0156 { \
0157 if (unlikely(!rt)) return 0; \
0158 return (rt->implementation_private>>bit)&1; \
0159 }
0160
0161 FTR_GPIO(headphone, 0);
0162 FTR_GPIO(amp, 1);
0163 FTR_GPIO(lineout, 2);
0164 FTR_GPIO(master, 3);
0165
0166 static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
0167 {
0168 int v;
0169
0170 if (unlikely(!rt)) return;
0171 if (hw_reset_gpio < 0)
0172 return;
0173
0174 v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL,
0175 hw_reset_gpio, 0);
0176 v = SWITCH_GPIO(hw_reset, v, on);
0177 pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,
0178 hw_reset_gpio, v);
0179 }
0180
0181 static struct gpio_methods methods;
0182
0183 static void ftr_gpio_all_amps_off(struct gpio_runtime *rt)
0184 {
0185 int saved;
0186
0187 if (unlikely(!rt)) return;
0188 saved = rt->implementation_private;
0189 ftr_gpio_set_headphone(rt, 0);
0190 ftr_gpio_set_amp(rt, 0);
0191 ftr_gpio_set_lineout(rt, 0);
0192 if (methods.set_master)
0193 ftr_gpio_set_master(rt, 0);
0194 rt->implementation_private = saved;
0195 }
0196
0197 static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt)
0198 {
0199 int s;
0200
0201 if (unlikely(!rt)) return;
0202 s = rt->implementation_private;
0203 ftr_gpio_set_headphone(rt, (s>>0)&1);
0204 ftr_gpio_set_amp(rt, (s>>1)&1);
0205 ftr_gpio_set_lineout(rt, (s>>2)&1);
0206 if (methods.set_master)
0207 ftr_gpio_set_master(rt, (s>>3)&1);
0208 }
0209
0210 static void ftr_handle_notify(struct work_struct *work)
0211 {
0212 struct gpio_notification *notif =
0213 container_of(work, struct gpio_notification, work.work);
0214
0215 mutex_lock(¬if->mutex);
0216 if (notif->notify)
0217 notif->notify(notif->data);
0218 mutex_unlock(¬if->mutex);
0219 }
0220
0221 static void gpio_enable_dual_edge(int gpio)
0222 {
0223 int v;
0224
0225 if (gpio == -1)
0226 return;
0227 v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio, 0);
0228 v |= 0x80;
0229 pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio, v);
0230 }
0231
0232 static void ftr_gpio_init(struct gpio_runtime *rt)
0233 {
0234 get_gpio("headphone-mute", NULL,
0235 &headphone_mute_gpio,
0236 &headphone_mute_gpio_activestate);
0237 get_gpio("amp-mute", NULL,
0238 &_mute_gpio,
0239 &_mute_gpio_activestate);
0240 get_gpio("lineout-mute", NULL,
0241 &lineout_mute_gpio,
0242 &lineout_mute_gpio_activestate);
0243 get_gpio("hw-reset", "audio-hw-reset",
0244 &hw_reset_gpio,
0245 &hw_reset_gpio_activestate);
0246 if (get_gpio("master-mute", NULL,
0247 &master_mute_gpio,
0248 &master_mute_gpio_activestate)) {
0249 methods.set_master = ftr_gpio_set_master;
0250 methods.get_master = ftr_gpio_get_master;
0251 }
0252
0253 headphone_detect_node = get_gpio("headphone-detect", NULL,
0254 &headphone_detect_gpio,
0255 &headphone_detect_gpio_activestate);
0256
0257
0258 lineout_detect_node = get_gpio("lineout-detect", "line-output-detect",
0259 &lineout_detect_gpio,
0260 &lineout_detect_gpio_activestate);
0261 linein_detect_node = get_gpio("linein-detect", "line-input-detect",
0262 &linein_detect_gpio,
0263 &linein_detect_gpio_activestate);
0264
0265 gpio_enable_dual_edge(headphone_detect_gpio);
0266 gpio_enable_dual_edge(lineout_detect_gpio);
0267 gpio_enable_dual_edge(linein_detect_gpio);
0268
0269 get_irq(headphone_detect_node, &headphone_detect_irq);
0270 get_irq(lineout_detect_node, &lineout_detect_irq);
0271 get_irq(linein_detect_node, &linein_detect_irq);
0272
0273 ftr_gpio_all_amps_off(rt);
0274 rt->implementation_private = 0;
0275 INIT_DELAYED_WORK(&rt->headphone_notify.work, ftr_handle_notify);
0276 INIT_DELAYED_WORK(&rt->line_in_notify.work, ftr_handle_notify);
0277 INIT_DELAYED_WORK(&rt->line_out_notify.work, ftr_handle_notify);
0278 mutex_init(&rt->headphone_notify.mutex);
0279 mutex_init(&rt->line_in_notify.mutex);
0280 mutex_init(&rt->line_out_notify.mutex);
0281 }
0282
0283 static void ftr_gpio_exit(struct gpio_runtime *rt)
0284 {
0285 ftr_gpio_all_amps_off(rt);
0286 rt->implementation_private = 0;
0287 if (rt->headphone_notify.notify)
0288 free_irq(headphone_detect_irq, &rt->headphone_notify);
0289 if (rt->line_in_notify.gpio_private)
0290 free_irq(linein_detect_irq, &rt->line_in_notify);
0291 if (rt->line_out_notify.gpio_private)
0292 free_irq(lineout_detect_irq, &rt->line_out_notify);
0293 cancel_delayed_work_sync(&rt->headphone_notify.work);
0294 cancel_delayed_work_sync(&rt->line_in_notify.work);
0295 cancel_delayed_work_sync(&rt->line_out_notify.work);
0296 mutex_destroy(&rt->headphone_notify.mutex);
0297 mutex_destroy(&rt->line_in_notify.mutex);
0298 mutex_destroy(&rt->line_out_notify.mutex);
0299 }
0300
0301 static irqreturn_t ftr_handle_notify_irq(int xx, void *data)
0302 {
0303 struct gpio_notification *notif = data;
0304
0305 schedule_delayed_work(¬if->work, 0);
0306
0307 return IRQ_HANDLED;
0308 }
0309
0310 static int ftr_set_notify(struct gpio_runtime *rt,
0311 enum notify_type type,
0312 notify_func_t notify,
0313 void *data)
0314 {
0315 struct gpio_notification *notif;
0316 notify_func_t old;
0317 int irq;
0318 char *name;
0319 int err = -EBUSY;
0320
0321 switch (type) {
0322 case AOA_NOTIFY_HEADPHONE:
0323 notif = &rt->headphone_notify;
0324 name = "headphone-detect";
0325 irq = headphone_detect_irq;
0326 break;
0327 case AOA_NOTIFY_LINE_IN:
0328 notif = &rt->line_in_notify;
0329 name = "linein-detect";
0330 irq = linein_detect_irq;
0331 break;
0332 case AOA_NOTIFY_LINE_OUT:
0333 notif = &rt->line_out_notify;
0334 name = "lineout-detect";
0335 irq = lineout_detect_irq;
0336 break;
0337 default:
0338 return -EINVAL;
0339 }
0340
0341 if (!irq)
0342 return -ENODEV;
0343
0344 mutex_lock(¬if->mutex);
0345
0346 old = notif->notify;
0347
0348 if (!old && !notify) {
0349 err = 0;
0350 goto out_unlock;
0351 }
0352
0353 if (old && notify) {
0354 if (old == notify && notif->data == data)
0355 err = 0;
0356 goto out_unlock;
0357 }
0358
0359 if (old && !notify)
0360 free_irq(irq, notif);
0361
0362 if (!old && notify) {
0363 err = request_irq(irq, ftr_handle_notify_irq, 0, name, notif);
0364 if (err)
0365 goto out_unlock;
0366 }
0367
0368 notif->notify = notify;
0369 notif->data = data;
0370
0371 err = 0;
0372 out_unlock:
0373 mutex_unlock(¬if->mutex);
0374 return err;
0375 }
0376
0377 static int ftr_get_detect(struct gpio_runtime *rt,
0378 enum notify_type type)
0379 {
0380 int gpio, ret, active;
0381
0382 switch (type) {
0383 case AOA_NOTIFY_HEADPHONE:
0384 gpio = headphone_detect_gpio;
0385 active = headphone_detect_gpio_activestate;
0386 break;
0387 case AOA_NOTIFY_LINE_IN:
0388 gpio = linein_detect_gpio;
0389 active = linein_detect_gpio_activestate;
0390 break;
0391 case AOA_NOTIFY_LINE_OUT:
0392 gpio = lineout_detect_gpio;
0393 active = lineout_detect_gpio_activestate;
0394 break;
0395 default:
0396 return -EINVAL;
0397 }
0398
0399 if (gpio == -1)
0400 return -ENODEV;
0401
0402 ret = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio, 0);
0403 if (ret < 0)
0404 return ret;
0405 return ((ret >> 1) & 1) == active;
0406 }
0407
0408 static struct gpio_methods methods = {
0409 .init = ftr_gpio_init,
0410 .exit = ftr_gpio_exit,
0411 .all_amps_off = ftr_gpio_all_amps_off,
0412 .all_amps_restore = ftr_gpio_all_amps_restore,
0413 .set_headphone = ftr_gpio_set_headphone,
0414 .set_speakers = ftr_gpio_set_amp,
0415 .set_lineout = ftr_gpio_set_lineout,
0416 .set_hw_reset = ftr_gpio_set_hw_reset,
0417 .get_headphone = ftr_gpio_get_headphone,
0418 .get_speakers = ftr_gpio_get_amp,
0419 .get_lineout = ftr_gpio_get_lineout,
0420 .set_notify = ftr_set_notify,
0421 .get_detect = ftr_get_detect,
0422 };
0423
0424 struct gpio_methods *ftr_gpio_methods = &methods;
0425 EXPORT_SYMBOL_GPL(ftr_gpio_methods);