/* * Unregister a notification. * * Note: the function may sleep and must be called in a task context. * * n: the notifcation object that was registered previously. * * Return value: * 0: success * -ENODEV: RPM driver not initialized */ int msm_rpm_unregister_notification(struct msm_rpm_notification *n) { unsigned long flags; unsigned int ctx; struct msm_rpm_notif_config cfg; int rc = 0; int i; mutex_lock(&msm_rpm_mutex); ctx = MSM_RPM_CTX_SET_0; cfg = msm_rpm_notif_cfgs[ctx]; for (i = 0; i < msm_rpm_sel_mask_size; i++) registered_iv(&cfg)[i].value = 0; spin_lock_irqsave(&msm_rpm_irq_lock, flags); list_del(&n->list); list_for_each_entry(n, &msm_rpm_notifications, list) for (i = 0; i < msm_rpm_sel_mask_size; i++) registered_iv(&cfg)[i].value |= n->sel_masks[i]; spin_unlock_irqrestore(&msm_rpm_irq_lock, flags); msm_rpm_update_notification(ctx, &msm_rpm_notif_cfgs[ctx], &cfg); mutex_unlock(&msm_rpm_mutex); return rc; }
/* * Unregister a notification. * * Note: the function may sleep and must be called in a task context. * * n: the notifcation object that was registered previously. * * Return value: * 0: success * -ENODEV: RPM driver not initialized */ int msm_rpm_unregister_notification(struct msm_rpm_notification *n) { unsigned long flags; unsigned int ctx; struct msm_rpm_notif_config cfg; int rc = 0; int i; if (!msm_rpm_platform) { if (cpu_is_apq8064()) return 0; else return -ENODEV; } mutex_lock(&msm_rpm_mutex); ctx = MSM_RPM_CTX_SET_0; cfg = msm_rpm_notif_cfgs[ctx]; for (i = 0; i < MSM_RPM_SEL_MASK_SIZE; i++) registered_iv(&cfg)[i].value = 0; spin_lock_irqsave(&msm_rpm_irq_lock, flags); list_del(&n->list); list_for_each_entry(n, &msm_rpm_notifications, list) for (i = 0; i < MSM_RPM_SEL_MASK_SIZE; i++) registered_iv(&cfg)[i].value |= n->sel_masks[i]; spin_unlock_irqrestore(&msm_rpm_irq_lock, flags); msm_rpm_update_notification(ctx, &msm_rpm_notif_cfgs[ctx], &cfg); mutex_unlock(&msm_rpm_mutex); return rc; }
/* * Note: assumes caller has acquired <msm_rpm_mutex>. */ static void msm_rpm_initialize_notification(void) { struct msm_rpm_notif_config cfg; unsigned int ctx; int i; for (ctx = MSM_RPM_CTX_SET_0; ctx <= MSM_RPM_CTX_SET_SLEEP; ctx++) { cfg = msm_rpm_notif_cfgs[ctx]; for (i = 0; i < msm_rpm_sel_mask_size; i++) { configured_iv(&cfg)[i].id = MSM_RPM_ID_NOTIFICATION_CONFIGURED_0 + i; configured_iv(&cfg)[i].value = ~0UL; registered_iv(&cfg)[i].id = MSM_RPM_ID_NOTIFICATION_REGISTERED_0 + i; registered_iv(&cfg)[i].value = 0; } msm_rpm_update_notification(ctx, &msm_rpm_notif_cfgs[ctx], &cfg); } }
/* * Register for RPM notification. When the specified resources * change their status on RPM, RPM sends out notifications and the * driver will "up" the semaphore in struct msm_rpm_notification. * * Note: the function may sleep and must be called in a task context. * * Memory for <n> must not be freed until the notification is * unregistered. Memory for <req> can be freed after this * function returns. * * n: the notifcation object. Caller should initialize only the * semaphore field. When a notification arrives later, the * semaphore will be "up"ed. * req: array of id-value pairs. Each <id> specifies a status register, * i.e, one of MSM_RPM_STATUS_ID_xxxx. <value>'s are ignored. * count: number of id-value pairs in the array * * Return value: * 0: success * -EINVAL: invalid id in <req> array * -ENODEV: RPM driver not initialized */ int msm_rpm_register_notification(struct msm_rpm_notification *n, struct msm_rpm_iv_pair *req, int count) { unsigned long flags; unsigned int ctx; struct msm_rpm_notif_config cfg; int rc; int i; if (!msm_rpm_platform) { if (cpu_is_apq8064()) return 0; else return -ENODEV; } INIT_LIST_HEAD(&n->list); rc = msm_rpm_fill_sel_masks(n->sel_masks, req, count); if (rc) goto register_notification_exit; mutex_lock(&msm_rpm_mutex); if (!msm_rpm_init_notif_done) { msm_rpm_initialize_notification(); msm_rpm_init_notif_done = true; } spin_lock_irqsave(&msm_rpm_irq_lock, flags); list_add(&n->list, &msm_rpm_notifications); spin_unlock_irqrestore(&msm_rpm_irq_lock, flags); ctx = MSM_RPM_CTX_SET_0; cfg = msm_rpm_notif_cfgs[ctx]; for (i = 0; i < MSM_RPM_SEL_MASK_SIZE; i++) registered_iv(&cfg)[i].value |= n->sel_masks[i]; msm_rpm_update_notification(ctx, &msm_rpm_notif_cfgs[ctx], &cfg); mutex_unlock(&msm_rpm_mutex); register_notification_exit: return rc; }