Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * axp20x power button driver.
0003  *
0004  * Copyright (C) 2013 Carlo Caione <carlo@caione.org>
0005  *
0006  * This file is subject to the terms and conditions of the GNU General
0007  * Public License. See the file "COPYING" in the main directory of this
0008  * archive for more details.
0009  *
0010  * This program is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0013  * GNU General Public License for more details.
0014  */
0015 
0016 #include <linux/acpi.h>
0017 #include <linux/errno.h>
0018 #include <linux/irq.h>
0019 #include <linux/init.h>
0020 #include <linux/input.h>
0021 #include <linux/interrupt.h>
0022 #include <linux/kernel.h>
0023 #include <linux/mfd/axp20x.h>
0024 #include <linux/module.h>
0025 #include <linux/platform_data/x86/soc.h>
0026 #include <linux/platform_device.h>
0027 #include <linux/regmap.h>
0028 #include <linux/slab.h>
0029 
0030 #define AXP20X_PEK_STARTUP_MASK     (0xc0)
0031 #define AXP20X_PEK_SHUTDOWN_MASK    (0x03)
0032 
0033 struct axp20x_info {
0034     const struct axp20x_time *startup_time;
0035     unsigned int startup_mask;
0036     const struct axp20x_time *shutdown_time;
0037     unsigned int shutdown_mask;
0038 };
0039 
0040 struct axp20x_pek {
0041     struct axp20x_dev *axp20x;
0042     struct input_dev *input;
0043     struct axp20x_info *info;
0044     int irq_dbr;
0045     int irq_dbf;
0046 };
0047 
0048 struct axp20x_time {
0049     unsigned int time;
0050     unsigned int idx;
0051 };
0052 
0053 static const struct axp20x_time startup_time[] = {
0054     { .time = 128,  .idx = 0 },
0055     { .time = 1000, .idx = 2 },
0056     { .time = 3000, .idx = 1 },
0057     { .time = 2000, .idx = 3 },
0058 };
0059 
0060 static const struct axp20x_time axp221_startup_time[] = {
0061     { .time = 128,  .idx = 0 },
0062     { .time = 1000, .idx = 1 },
0063     { .time = 2000, .idx = 2 },
0064     { .time = 3000, .idx = 3 },
0065 };
0066 
0067 static const struct axp20x_time shutdown_time[] = {
0068     { .time = 4000,  .idx = 0 },
0069     { .time = 6000,  .idx = 1 },
0070     { .time = 8000,  .idx = 2 },
0071     { .time = 10000, .idx = 3 },
0072 };
0073 
0074 static const struct axp20x_info axp20x_info = {
0075     .startup_time = startup_time,
0076     .startup_mask = AXP20X_PEK_STARTUP_MASK,
0077     .shutdown_time = shutdown_time,
0078     .shutdown_mask = AXP20X_PEK_SHUTDOWN_MASK,
0079 };
0080 
0081 static const struct axp20x_info axp221_info = {
0082     .startup_time = axp221_startup_time,
0083     .startup_mask = AXP20X_PEK_STARTUP_MASK,
0084     .shutdown_time = shutdown_time,
0085     .shutdown_mask = AXP20X_PEK_SHUTDOWN_MASK,
0086 };
0087 
0088 static ssize_t axp20x_show_attr(struct device *dev,
0089                 const struct axp20x_time *time,
0090                 unsigned int mask, char *buf)
0091 {
0092     struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
0093     unsigned int val;
0094     int ret, i;
0095 
0096     ret = regmap_read(axp20x_pek->axp20x->regmap, AXP20X_PEK_KEY, &val);
0097     if (ret != 0)
0098         return ret;
0099 
0100     val &= mask;
0101     val >>= ffs(mask) - 1;
0102 
0103     for (i = 0; i < 4; i++)
0104         if (val == time[i].idx)
0105             val = time[i].time;
0106 
0107     return sprintf(buf, "%u\n", val);
0108 }
0109 
0110 static ssize_t axp20x_show_attr_startup(struct device *dev,
0111                     struct device_attribute *attr,
0112                     char *buf)
0113 {
0114     struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
0115 
0116     return axp20x_show_attr(dev, axp20x_pek->info->startup_time,
0117                 axp20x_pek->info->startup_mask, buf);
0118 }
0119 
0120 static ssize_t axp20x_show_attr_shutdown(struct device *dev,
0121                      struct device_attribute *attr,
0122                      char *buf)
0123 {
0124     struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
0125 
0126     return axp20x_show_attr(dev, axp20x_pek->info->shutdown_time,
0127                 axp20x_pek->info->shutdown_mask, buf);
0128 }
0129 
0130 static ssize_t axp20x_store_attr(struct device *dev,
0131                  const struct axp20x_time *time,
0132                  unsigned int mask, const char *buf,
0133                  size_t count)
0134 {
0135     struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
0136     char val_str[20];
0137     size_t len;
0138     int ret, i;
0139     unsigned int val, idx = 0;
0140     unsigned int best_err = UINT_MAX;
0141 
0142     val_str[sizeof(val_str) - 1] = '\0';
0143     strncpy(val_str, buf, sizeof(val_str) - 1);
0144     len = strlen(val_str);
0145 
0146     if (len && val_str[len - 1] == '\n')
0147         val_str[len - 1] = '\0';
0148 
0149     ret = kstrtouint(val_str, 10, &val);
0150     if (ret)
0151         return ret;
0152 
0153     for (i = 3; i >= 0; i--) {
0154         unsigned int err;
0155 
0156         err = abs(time[i].time - val);
0157         if (err < best_err) {
0158             best_err = err;
0159             idx = time[i].idx;
0160         }
0161 
0162         if (!err)
0163             break;
0164     }
0165 
0166     idx <<= ffs(mask) - 1;
0167     ret = regmap_update_bits(axp20x_pek->axp20x->regmap, AXP20X_PEK_KEY,
0168                  mask, idx);
0169     if (ret != 0)
0170         return -EINVAL;
0171 
0172     return count;
0173 }
0174 
0175 static ssize_t axp20x_store_attr_startup(struct device *dev,
0176                      struct device_attribute *attr,
0177                      const char *buf, size_t count)
0178 {
0179     struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
0180 
0181     return axp20x_store_attr(dev, axp20x_pek->info->startup_time,
0182                  axp20x_pek->info->startup_mask, buf, count);
0183 }
0184 
0185 static ssize_t axp20x_store_attr_shutdown(struct device *dev,
0186                       struct device_attribute *attr,
0187                       const char *buf, size_t count)
0188 {
0189     struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
0190 
0191     return axp20x_store_attr(dev, axp20x_pek->info->shutdown_time,
0192                  axp20x_pek->info->shutdown_mask, buf, count);
0193 }
0194 
0195 static DEVICE_ATTR(startup, 0644, axp20x_show_attr_startup,
0196            axp20x_store_attr_startup);
0197 static DEVICE_ATTR(shutdown, 0644, axp20x_show_attr_shutdown,
0198            axp20x_store_attr_shutdown);
0199 
0200 static struct attribute *axp20x_attrs[] = {
0201     &dev_attr_startup.attr,
0202     &dev_attr_shutdown.attr,
0203     NULL,
0204 };
0205 ATTRIBUTE_GROUPS(axp20x);
0206 
0207 static irqreturn_t axp20x_pek_irq(int irq, void *pwr)
0208 {
0209     struct input_dev *idev = pwr;
0210     struct axp20x_pek *axp20x_pek = input_get_drvdata(idev);
0211 
0212     /*
0213      * The power-button is connected to ground so a falling edge (dbf)
0214      * means it is pressed.
0215      */
0216     if (irq == axp20x_pek->irq_dbf)
0217         input_report_key(idev, KEY_POWER, true);
0218     else if (irq == axp20x_pek->irq_dbr)
0219         input_report_key(idev, KEY_POWER, false);
0220 
0221     input_sync(idev);
0222 
0223     return IRQ_HANDLED;
0224 }
0225 
0226 static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,
0227                      struct platform_device *pdev)
0228 {
0229     struct axp20x_dev *axp20x = axp20x_pek->axp20x;
0230     struct input_dev *idev;
0231     int error;
0232 
0233     axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR");
0234     if (axp20x_pek->irq_dbr < 0)
0235         return axp20x_pek->irq_dbr;
0236     axp20x_pek->irq_dbr = regmap_irq_get_virq(axp20x->regmap_irqc,
0237                           axp20x_pek->irq_dbr);
0238 
0239     axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF");
0240     if (axp20x_pek->irq_dbf < 0)
0241         return axp20x_pek->irq_dbf;
0242     axp20x_pek->irq_dbf = regmap_irq_get_virq(axp20x->regmap_irqc,
0243                           axp20x_pek->irq_dbf);
0244 
0245     axp20x_pek->input = devm_input_allocate_device(&pdev->dev);
0246     if (!axp20x_pek->input)
0247         return -ENOMEM;
0248 
0249     idev = axp20x_pek->input;
0250 
0251     idev->name = "axp20x-pek";
0252     idev->phys = "m1kbd/input2";
0253     idev->dev.parent = &pdev->dev;
0254 
0255     input_set_capability(idev, EV_KEY, KEY_POWER);
0256 
0257     input_set_drvdata(idev, axp20x_pek);
0258 
0259     error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr,
0260                          axp20x_pek_irq, 0,
0261                          "axp20x-pek-dbr", idev);
0262     if (error < 0) {
0263         dev_err(&pdev->dev, "Failed to request dbr IRQ#%d: %d\n",
0264             axp20x_pek->irq_dbr, error);
0265         return error;
0266     }
0267 
0268     error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbf,
0269                       axp20x_pek_irq, 0,
0270                       "axp20x-pek-dbf", idev);
0271     if (error < 0) {
0272         dev_err(&pdev->dev, "Failed to request dbf IRQ#%d: %d\n",
0273             axp20x_pek->irq_dbf, error);
0274         return error;
0275     }
0276 
0277     error = input_register_device(idev);
0278     if (error) {
0279         dev_err(&pdev->dev, "Can't register input device: %d\n",
0280             error);
0281         return error;
0282     }
0283 
0284     device_init_wakeup(&pdev->dev, true);
0285 
0286     return 0;
0287 }
0288 
0289 static bool axp20x_pek_should_register_input(struct axp20x_pek *axp20x_pek)
0290 {
0291     if (IS_ENABLED(CONFIG_INPUT_SOC_BUTTON_ARRAY) &&
0292         axp20x_pek->axp20x->variant == AXP288_ID) {
0293         /*
0294          * On Cherry Trail platforms (hrv == 3), do not register the
0295          * input device if there is an "INTCFD9" or "ACPI0011" gpio
0296          * button ACPI device, as that handles the power button too,
0297          * and otherwise we end up reporting all presses twice.
0298          */
0299         if (soc_intel_is_cht() &&
0300                 (acpi_dev_present("INTCFD9", NULL, -1) ||
0301                  acpi_dev_present("ACPI0011", NULL, -1)))
0302             return false;
0303     }
0304 
0305     return true;
0306 }
0307 
0308 static int axp20x_pek_probe(struct platform_device *pdev)
0309 {
0310     struct axp20x_pek *axp20x_pek;
0311     const struct platform_device_id *match = platform_get_device_id(pdev);
0312     int error;
0313 
0314     if (!match) {
0315         dev_err(&pdev->dev, "Failed to get platform_device_id\n");
0316         return -EINVAL;
0317     }
0318 
0319     axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek),
0320                   GFP_KERNEL);
0321     if (!axp20x_pek)
0322         return -ENOMEM;
0323 
0324     axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent);
0325 
0326     if (axp20x_pek_should_register_input(axp20x_pek)) {
0327         error = axp20x_pek_probe_input_device(axp20x_pek, pdev);
0328         if (error)
0329             return error;
0330     }
0331 
0332     axp20x_pek->info = (struct axp20x_info *)match->driver_data;
0333 
0334     platform_set_drvdata(pdev, axp20x_pek);
0335 
0336     return 0;
0337 }
0338 
0339 static int __maybe_unused axp20x_pek_suspend(struct device *dev)
0340 {
0341     struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
0342 
0343     /*
0344      * As nested threaded IRQs are not automatically disabled during
0345      * suspend, we must explicitly disable non-wakeup IRQs.
0346      */
0347     if (device_may_wakeup(dev)) {
0348         enable_irq_wake(axp20x_pek->irq_dbf);
0349         enable_irq_wake(axp20x_pek->irq_dbr);
0350     } else {
0351         disable_irq(axp20x_pek->irq_dbf);
0352         disable_irq(axp20x_pek->irq_dbr);
0353     }
0354 
0355     return 0;
0356 }
0357 
0358 static int __maybe_unused axp20x_pek_resume(struct device *dev)
0359 {
0360     struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
0361 
0362     if (device_may_wakeup(dev)) {
0363         disable_irq_wake(axp20x_pek->irq_dbf);
0364         disable_irq_wake(axp20x_pek->irq_dbr);
0365     } else {
0366         enable_irq(axp20x_pek->irq_dbf);
0367         enable_irq(axp20x_pek->irq_dbr);
0368     }
0369 
0370     return 0;
0371 }
0372 
0373 static int __maybe_unused axp20x_pek_resume_noirq(struct device *dev)
0374 {
0375     struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
0376 
0377     if (axp20x_pek->axp20x->variant != AXP288_ID)
0378         return 0;
0379 
0380     /*
0381      * Clear interrupts from button presses during suspend, to avoid
0382      * a wakeup power-button press getting reported to userspace.
0383      */
0384     regmap_write(axp20x_pek->axp20x->regmap,
0385              AXP20X_IRQ1_STATE + AXP288_IRQ_POKN / 8,
0386              BIT(AXP288_IRQ_POKN % 8));
0387 
0388     return 0;
0389 }
0390 
0391 static const struct dev_pm_ops axp20x_pek_pm_ops = {
0392     SET_SYSTEM_SLEEP_PM_OPS(axp20x_pek_suspend, axp20x_pek_resume)
0393 #ifdef CONFIG_PM_SLEEP
0394     .resume_noirq = axp20x_pek_resume_noirq,
0395 #endif
0396 };
0397 
0398 static const struct platform_device_id axp_pek_id_match[] = {
0399     {
0400         .name = "axp20x-pek",
0401         .driver_data = (kernel_ulong_t)&axp20x_info,
0402     },
0403     {
0404         .name = "axp221-pek",
0405         .driver_data = (kernel_ulong_t)&axp221_info,
0406     },
0407     { /* sentinel */ }
0408 };
0409 MODULE_DEVICE_TABLE(platform, axp_pek_id_match);
0410 
0411 static struct platform_driver axp20x_pek_driver = {
0412     .probe      = axp20x_pek_probe,
0413     .id_table   = axp_pek_id_match,
0414     .driver     = {
0415         .name       = "axp20x-pek",
0416         .pm     = &axp20x_pek_pm_ops,
0417         .dev_groups = axp20x_groups,
0418     },
0419 };
0420 module_platform_driver(axp20x_pek_driver);
0421 
0422 MODULE_DESCRIPTION("axp20x Power Button");
0423 MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
0424 MODULE_LICENSE("GPL");