diff options
-rw-r--r-- | drivers/platform/x86/asus-wmi.c | 35 | ||||
-rw-r--r-- | drivers/platform/x86/intel/pmc/core.c | 216 | ||||
-rw-r--r-- | include/linux/platform_data/x86/asus-wmi.h | 4 |
3 files changed, 149 insertions, 106 deletions
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 3f9b6285c9a6..26c45fd093a0 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -238,6 +238,7 @@ struct asus_wmi { struct led_classdev lightbar_led; int lightbar_led_wk; struct led_classdev micmute_led; + struct led_classdev camera_led; struct workqueue_struct *led_workqueue; struct work_struct tpd_led_work; struct work_struct wlan_led_work; @@ -1642,6 +1643,27 @@ static int micmute_led_set(struct led_classdev *led_cdev, return err < 0 ? err : 0; } +static enum led_brightness camera_led_get(struct led_classdev *led_cdev) +{ + struct asus_wmi *asus; + u32 result; + + asus = container_of(led_cdev, struct asus_wmi, camera_led); + asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CAMERA_LED, &result); + + return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK; +} + +static int camera_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + int state = brightness != LED_OFF; + int err; + + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CAMERA_LED, state, NULL); + return err < 0 ? err : 0; +} + static void asus_wmi_led_exit(struct asus_wmi *asus) { led_classdev_unregister(&asus->kbd_led); @@ -1649,6 +1671,7 @@ static void asus_wmi_led_exit(struct asus_wmi *asus) led_classdev_unregister(&asus->wlan_led); led_classdev_unregister(&asus->lightbar_led); led_classdev_unregister(&asus->micmute_led); + led_classdev_unregister(&asus->camera_led); if (asus->led_workqueue) destroy_workqueue(asus->led_workqueue); @@ -1740,6 +1763,18 @@ static int asus_wmi_led_init(struct asus_wmi *asus) goto error; } + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CAMERA_LED)) { + asus->camera_led.name = "asus::camera"; + asus->camera_led.max_brightness = 1; + asus->camera_led.brightness_get = camera_led_get; + asus->camera_led.brightness_set_blocking = camera_led_set; + + rv = led_classdev_register(&asus->platform_device->dev, + &asus->camera_led); + if (rv) + goto error; + } + error: if (rv) asus_wmi_led_exit(asus); diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c index 65eb09c7af6a..01ae71c6df59 100644 --- a/drivers/platform/x86/intel/pmc/core.c +++ b/drivers/platform/x86/intel/pmc/core.c @@ -87,35 +87,26 @@ static int set_etr3(struct pmc_dev *pmcdev) struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; const struct pmc_reg_map *map = pmc->map; u32 reg; - int err; if (!map->etr3_offset) return -EOPNOTSUPP; - mutex_lock(&pmcdev->lock); + guard(mutex)(&pmcdev->lock); /* check if CF9 is locked */ reg = pmc_core_reg_read(pmc, map->etr3_offset); - if (reg & ETR3_CF9LOCK) { - err = -EACCES; - goto out_unlock; - } + if (reg & ETR3_CF9LOCK) + return -EACCES; /* write CF9 global reset bit */ reg |= ETR3_CF9GR; pmc_core_reg_write(pmc, map->etr3_offset, reg); reg = pmc_core_reg_read(pmc, map->etr3_offset); - if (!(reg & ETR3_CF9GR)) { - err = -EIO; - goto out_unlock; - } - - err = 0; + if (!(reg & ETR3_CF9GR)) + return -EIO; -out_unlock: - mutex_unlock(&pmcdev->lock); - return err; + return 0; } static umode_t etr3_is_visible(struct kobject *kobj, struct attribute *attr, @@ -127,9 +118,8 @@ static umode_t etr3_is_visible(struct kobject *kobj, const struct pmc_reg_map *map = pmc->map; u32 reg; - mutex_lock(&pmcdev->lock); - reg = pmc_core_reg_read(pmc, map->etr3_offset); - mutex_unlock(&pmcdev->lock); + scoped_guard(mutex, &pmcdev->lock) + reg = pmc_core_reg_read(pmc, map->etr3_offset); return reg & ETR3_CF9LOCK ? attr->mode & (SYSFS_PREALLOC | 0444) : attr->mode; } @@ -145,12 +135,10 @@ static ssize_t etr3_show(struct device *dev, if (!map->etr3_offset) return -EOPNOTSUPP; - mutex_lock(&pmcdev->lock); - - reg = pmc_core_reg_read(pmc, map->etr3_offset); - reg &= ETR3_CF9GR | ETR3_CF9LOCK; - - mutex_unlock(&pmcdev->lock); + scoped_guard(mutex, &pmcdev->lock) { + reg = pmc_core_reg_read(pmc, map->etr3_offset); + reg &= ETR3_CF9GR | ETR3_CF9LOCK; + } return sysfs_emit(buf, "0x%08x", reg); } @@ -257,9 +245,9 @@ static void pmc_core_slps0_display(struct pmc *pmc, struct device *dev, } } -static int pmc_core_lpm_get_arr_size(const struct pmc_bit_map **maps) +static unsigned int pmc_core_lpm_get_arr_size(const struct pmc_bit_map **maps) { - int idx; + unsigned int idx; for (idx = 0; maps[idx]; idx++) ;/* Nothing */ @@ -272,8 +260,8 @@ static void pmc_core_lpm_display(struct pmc *pmc, struct device *dev, const char *str, const struct pmc_bit_map **maps) { - int index, idx, len = 32, bit_mask, arr_size; - u32 *lpm_regs; + unsigned int index, idx, len = 32, arr_size; + u32 bit_mask, *lpm_regs; arr_size = pmc_core_lpm_get_arr_size(maps); lpm_regs = kmalloc_array(arr_size, sizeof(*lpm_regs), GFP_KERNEL); @@ -326,13 +314,13 @@ static void pmc_core_display_map(struct seq_file *s, int index, int idx, int ip, static int pmc_core_ppfear_show(struct seq_file *s, void *unused) { struct pmc_dev *pmcdev = s->private; - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { struct pmc *pmc = pmcdev->pmcs[i]; const struct pmc_bit_map **maps; u8 pf_regs[PPFEAR_MAX_NUM_ENTRIES]; - int index, iter, idx, ip = 0; + unsigned int index, iter, idx, ip = 0; if (!pmc) continue; @@ -391,7 +379,8 @@ static int pmc_core_mphy_pg_show(struct seq_file *s, void *unused) const struct pmc_bit_map *map = pmc->map->mphy_sts; u32 mphy_core_reg_low, mphy_core_reg_high; u32 val_low, val_high; - int index, err = 0; + unsigned int index; + int err = 0; if (pmcdev->pmc_xram_read_bit) { seq_puts(s, "Access denied: please disable PMC_READ_DISABLE setting in BIOS."); @@ -401,20 +390,18 @@ static int pmc_core_mphy_pg_show(struct seq_file *s, void *unused) mphy_core_reg_low = (SPT_PMC_MPHY_CORE_STS_0 << 16); mphy_core_reg_high = (SPT_PMC_MPHY_CORE_STS_1 << 16); - mutex_lock(&pmcdev->lock); + guard(mutex)(&pmcdev->lock); - if (pmc_core_send_msg(pmc, &mphy_core_reg_low) != 0) { - err = -EBUSY; - goto out_unlock; - } + err = pmc_core_send_msg(pmc, &mphy_core_reg_low); + if (err) + return err; msleep(10); val_low = pmc_core_reg_read(pmc, SPT_PMC_MFPMC_OFFSET); - if (pmc_core_send_msg(pmc, &mphy_core_reg_high) != 0) { - err = -EBUSY; - goto out_unlock; - } + err = pmc_core_send_msg(pmc, &mphy_core_reg_high); + if (err) + return err; msleep(10); val_high = pmc_core_reg_read(pmc, SPT_PMC_MFPMC_OFFSET); @@ -433,9 +420,7 @@ static int pmc_core_mphy_pg_show(struct seq_file *s, void *unused) "Power gated"); } -out_unlock: - mutex_unlock(&pmcdev->lock); - return err; + return 0; } DEFINE_SHOW_ATTRIBUTE(pmc_core_mphy_pg); @@ -445,7 +430,8 @@ static int pmc_core_pll_show(struct seq_file *s, void *unused) struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; const struct pmc_bit_map *map = pmc->map->pll_sts; u32 mphy_common_reg, val; - int index, err = 0; + unsigned int index; + int err = 0; if (pmcdev->pmc_xram_read_bit) { seq_puts(s, "Access denied: please disable PMC_READ_DISABLE setting in BIOS."); @@ -453,12 +439,11 @@ static int pmc_core_pll_show(struct seq_file *s, void *unused) } mphy_common_reg = (SPT_PMC_MPHY_COM_STS_0 << 16); - mutex_lock(&pmcdev->lock); + guard(mutex)(&pmcdev->lock); - if (pmc_core_send_msg(pmc, &mphy_common_reg) != 0) { - err = -EBUSY; - goto out_unlock; - } + err = pmc_core_send_msg(pmc, &mphy_common_reg); + if (err) + return err; /* Observed PMC HW response latency for MTPMC-MFPMC is ~10 ms */ msleep(10); @@ -470,9 +455,7 @@ static int pmc_core_pll_show(struct seq_file *s, void *unused) map[index].bit_mask & val ? "Active" : "Idle"); } -out_unlock: - mutex_unlock(&pmcdev->lock); - return err; + return 0; } DEFINE_SHOW_ATTRIBUTE(pmc_core_pll); @@ -481,7 +464,8 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore) struct pmc *pmc; const struct pmc_reg_map *map; u32 reg; - int pmc_index, ltr_index; + unsigned int pmc_index; + int ltr_index; ltr_index = value; /* For platforms with multiple pmcs, ltr index value given by user @@ -511,7 +495,7 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore) pr_debug("ltr_ignore for pmc%d: ltr_index:%d\n", pmc_index, ltr_index); - mutex_lock(&pmcdev->lock); + guard(mutex)(&pmcdev->lock); reg = pmc_core_reg_read(pmc, map->ltr_ignore_offset); if (ignore) @@ -520,48 +504,56 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore) reg &= ~BIT(ltr_index); pmc_core_reg_write(pmc, map->ltr_ignore_offset, reg); - mutex_unlock(&pmcdev->lock); - return 0; } -static ssize_t pmc_core_ltr_ignore_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) +static ssize_t pmc_core_ltr_write(struct pmc_dev *pmcdev, + const char __user *userbuf, + size_t count, int ignore) { - struct seq_file *s = file->private_data; - struct pmc_dev *pmcdev = s->private; - u32 buf_size, value; + u32 value; int err; - buf_size = min_t(u32, count, 64); - - err = kstrtou32_from_user(userbuf, buf_size, 10, &value); + err = kstrtou32_from_user(userbuf, count, 10, &value); if (err) return err; - err = pmc_core_send_ltr_ignore(pmcdev, value, 1); + err = pmc_core_send_ltr_ignore(pmcdev, value, ignore); + + return err ?: count; +} + +static ssize_t pmc_core_ltr_ignore_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct pmc_dev *pmcdev = s->private; - return err == 0 ? count : err; + return pmc_core_ltr_write(pmcdev, userbuf, count, 1); } static int pmc_core_ltr_ignore_show(struct seq_file *s, void *unused) { return 0; } +DEFINE_SHOW_STORE_ATTRIBUTE(pmc_core_ltr_ignore); -static int pmc_core_ltr_ignore_open(struct inode *inode, struct file *file) +static ssize_t pmc_core_ltr_restore_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) { - return single_open(file, pmc_core_ltr_ignore_show, inode->i_private); + struct seq_file *s = file->private_data; + struct pmc_dev *pmcdev = s->private; + + return pmc_core_ltr_write(pmcdev, userbuf, count, 0); } -static const struct file_operations pmc_core_ltr_ignore_ops = { - .open = pmc_core_ltr_ignore_open, - .read = seq_read, - .write = pmc_core_ltr_ignore_write, - .llseek = seq_lseek, - .release = single_release, -}; +static int pmc_core_ltr_restore_show(struct seq_file *s, void *unused) +{ + return 0; +} +DEFINE_SHOW_STORE_ATTRIBUTE(pmc_core_ltr_restore); static void pmc_core_slps0_dbg_latch(struct pmc_dev *pmcdev, bool reset) { @@ -569,10 +561,10 @@ static void pmc_core_slps0_dbg_latch(struct pmc_dev *pmcdev, bool reset) const struct pmc_reg_map *map = pmc->map; u32 fd; - mutex_lock(&pmcdev->lock); + guard(mutex)(&pmcdev->lock); if (!reset && !slps0_dbg_latch) - goto out_unlock; + return; fd = pmc_core_reg_read(pmc, map->slps0_dbg_offset); if (reset) @@ -582,9 +574,6 @@ static void pmc_core_slps0_dbg_latch(struct pmc_dev *pmcdev, bool reset) pmc_core_reg_write(pmc, map->slps0_dbg_offset, fd); slps0_dbg_latch = false; - -out_unlock: - mutex_unlock(&pmcdev->lock); } static int pmc_core_slps0_dbg_show(struct seq_file *s, void *unused) @@ -639,17 +628,29 @@ static int pmc_core_ltr_show(struct seq_file *s, void *unused) u64 decoded_snoop_ltr, decoded_non_snoop_ltr; u32 ltr_raw_data, scale, val; u16 snoop_ltr, nonsnoop_ltr; - int i, index, ltr_index = 0; + unsigned int i, index, ltr_index = 0; for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { - struct pmc *pmc = pmcdev->pmcs[i]; + struct pmc *pmc; const struct pmc_bit_map *map; + u32 ltr_ign_reg; + pmc = pmcdev->pmcs[i]; if (!pmc) continue; + scoped_guard(mutex, &pmcdev->lock) + ltr_ign_reg = pmc_core_reg_read(pmc, pmc->map->ltr_ignore_offset); + map = pmc->map->ltr_show_sts; for (index = 0; map[index].name; index++) { + bool ltr_ign_data; + + if (index > pmc->map->ltr_ignore_max) + ltr_ign_data = false; + else + ltr_ign_data = ltr_ign_reg & BIT(index); + decoded_snoop_ltr = decoded_non_snoop_ltr = 0; ltr_raw_data = pmc_core_reg_read(pmc, map[index].bit_mask); @@ -667,10 +668,10 @@ static int pmc_core_ltr_show(struct seq_file *s, void *unused) decoded_snoop_ltr = val * convert_ltr_scale(scale); } - seq_printf(s, "%d\tPMC%d:%-32s\tLTR: RAW: 0x%-16x\tNon-Snoop(ns): %-16llu\tSnoop(ns): %-16llu\n", + seq_printf(s, "%d\tPMC%d:%-32s\tLTR: RAW: 0x%-16x\tNon-Snoop(ns): %-16llu\tSnoop(ns): %-16llu\tLTR_IGNORE: %d\n", ltr_index, i, map[index].name, ltr_raw_data, decoded_non_snoop_ltr, - decoded_snoop_ltr); + decoded_snoop_ltr, ltr_ign_data); ltr_index++; } } @@ -727,7 +728,8 @@ static int pmc_core_substate_res_show(struct seq_file *s, void *unused) struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; const int lpm_adj_x2 = pmc->map->lpm_res_counter_step_x2; u32 offset = pmc->map->lpm_residency_offset; - int i, mode; + unsigned int i; + int mode; seq_printf(s, "%-10s %-15s\n", "Substate", "Residency"); @@ -743,7 +745,7 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_res); static int pmc_core_substate_sts_regs_show(struct seq_file *s, void *unused) { struct pmc_dev *pmcdev = s->private; - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { struct pmc *pmc = pmcdev->pmcs[i]; @@ -764,7 +766,7 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_sts_regs); static int pmc_core_substate_l_sts_regs_show(struct seq_file *s, void *unused) { struct pmc_dev *pmcdev = s->private; - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { struct pmc *pmc = pmcdev->pmcs[i]; @@ -785,7 +787,8 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_l_sts_regs); static void pmc_core_substate_req_header_show(struct seq_file *s, int pmc_index) { struct pmc_dev *pmcdev = s->private; - int i, mode; + unsigned int i; + int mode; seq_printf(s, "%30s |", "Element"); pmc_for_each_mode(i, mode, pmcdev) @@ -799,7 +802,8 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused) struct pmc_dev *pmcdev = s->private; u32 sts_offset; u32 *lpm_req_regs; - int num_maps, mp, pmc_index; + unsigned int mp, pmc_index; + int num_maps; for (pmc_index = 0; pmc_index < ARRAY_SIZE(pmcdev->pmcs); ++pmc_index) { struct pmc *pmc = pmcdev->pmcs[pmc_index]; @@ -921,9 +925,10 @@ static int pmc_core_lpm_latch_mode_show(struct seq_file *s, void *unused) { struct pmc_dev *pmcdev = s->private; struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; + unsigned int idx; bool c10; u32 reg; - int idx, mode; + int mode; reg = pmc_core_reg_read(pmc, pmc->map->lpm_sts_latch_en_offset); if (reg & LPM_STS_LATCH_MODE) { @@ -955,7 +960,8 @@ static ssize_t pmc_core_lpm_latch_mode_write(struct file *file, struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; bool clear = false, c10 = false; unsigned char buf[8]; - int idx, m, mode; + unsigned int idx; + int m, mode; u32 reg; if (count > sizeof(buf) - 1) @@ -987,26 +993,22 @@ static ssize_t pmc_core_lpm_latch_mode_write(struct file *file, } if (clear) { - mutex_lock(&pmcdev->lock); + guard(mutex)(&pmcdev->lock); reg = pmc_core_reg_read(pmc, pmc->map->etr3_offset); reg |= ETR3_CLEAR_LPM_EVENTS; pmc_core_reg_write(pmc, pmc->map->etr3_offset, reg); - mutex_unlock(&pmcdev->lock); - return count; } if (c10) { - mutex_lock(&pmcdev->lock); + guard(mutex)(&pmcdev->lock); reg = pmc_core_reg_read(pmc, pmc->map->lpm_sts_latch_en_offset); reg &= ~LPM_STS_LATCH_MODE; pmc_core_reg_write(pmc, pmc->map->lpm_sts_latch_en_offset, reg); - mutex_unlock(&pmcdev->lock); - return count; } @@ -1015,9 +1017,8 @@ static ssize_t pmc_core_lpm_latch_mode_write(struct file *file, * and clear everything else. */ reg = LPM_STS_LATCH_MODE | BIT(mode); - mutex_lock(&pmcdev->lock); + guard(mutex)(&pmcdev->lock); pmc_core_reg_write(pmc, pmc->map->lpm_sts_latch_en_offset, reg); - mutex_unlock(&pmcdev->lock); return count; } @@ -1028,7 +1029,7 @@ static int pmc_core_pkgc_show(struct seq_file *s, void *unused) struct pmc *pmc = s->private; const struct pmc_bit_map *map = pmc->map->msr_sts; u64 pcstate_count; - int index; + unsigned int index; for (index = 0; map[index].name ; index++) { if (rdmsrl_safe(map[index].bit_mask, &pcstate_count)) @@ -1046,7 +1047,7 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_pkgc); static bool pmc_core_pri_verify(u32 lpm_pri, u8 *mode_order) { - int i, j; + unsigned int i, j; if (!lpm_pri) return false; @@ -1081,7 +1082,8 @@ void pmc_core_get_low_power_modes(struct pmc_dev *pmcdev) u8 mode_order[LPM_MAX_NUM_MODES]; u32 lpm_pri; u32 lpm_en; - int mode, i, p; + unsigned int i; + int mode, p; /* Use LPM Maps to indicate support for substates */ if (!pmc->map->lpm_num_maps) @@ -1228,7 +1230,9 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev) pmcdev, &pmc_core_ppfear_fops); debugfs_create_file("ltr_ignore", 0644, dir, pmcdev, - &pmc_core_ltr_ignore_ops); + &pmc_core_ltr_ignore_fops); + + debugfs_create_file("ltr_restore", 0200, dir, pmcdev, &pmc_core_ltr_restore_fops); debugfs_create_file("ltr_show", 0444, dir, pmcdev, &pmc_core_ltr_fops); @@ -1373,7 +1377,7 @@ static void pmc_core_do_dmi_quirks(struct pmc *pmc) static void pmc_core_clean_structure(struct platform_device *pdev) { struct pmc_dev *pmcdev = platform_get_drvdata(pdev); - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { struct pmc *pmc = pmcdev->pmcs[i]; @@ -1536,7 +1540,7 @@ int pmc_core_resume_common(struct pmc_dev *pmcdev) struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN]; const struct pmc_bit_map **maps = pmc->map->lpm_sts; int offset = pmc->map->lpm_status_offset; - int i; + unsigned int i; /* Check if the syspend used S0ix */ if (pm_suspend_via_firmware()) diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 3eb5cd6773ad..0aeeae1c1943 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -51,6 +51,10 @@ #define ASUS_WMI_DEVID_LED6 0x00020016 #define ASUS_WMI_DEVID_MICMUTE_LED 0x00040017 +/* Disable Camera LED */ +#define ASUS_WMI_DEVID_CAMERA_LED_NEG 0x00060078 /* 0 = on (unused) */ +#define ASUS_WMI_DEVID_CAMERA_LED 0x00060079 /* 1 = on */ + /* Backlight and Brightness */ #define ASUS_WMI_DEVID_ALS_ENABLE 0x00050001 /* Ambient Light Sensor */ #define ASUS_WMI_DEVID_BACKLIGHT 0x00050011 |