Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * MAX8925 ONKEY driver
0003  *
0004  * Copyright (C) 2009 Marvell International Ltd.
0005  *      Haojian Zhuang <haojian.zhuang@marvell.com>
0006  *
0007  * This file is subject to the terms and conditions of the GNU General
0008  * Public License. See the file "COPYING" in the main directory of this
0009  * archive for more details.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program; if not, write to the Free Software
0018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0019  */
0020 
0021 #include <linux/kernel.h>
0022 #include <linux/module.h>
0023 #include <linux/platform_device.h>
0024 #include <linux/i2c.h>
0025 #include <linux/input.h>
0026 #include <linux/interrupt.h>
0027 #include <linux/mfd/max8925.h>
0028 #include <linux/slab.h>
0029 #include <linux/device.h>
0030 
0031 #define SW_INPUT        (1 << 7)    /* 0/1 -- up/down */
0032 #define HARDRESET_EN        (1 << 7)
0033 #define PWREN_EN        (1 << 7)
0034 
0035 struct max8925_onkey_info {
0036     struct input_dev    *idev;
0037     struct i2c_client   *i2c;
0038     struct device       *dev;
0039     unsigned int        irq[2];
0040 };
0041 
0042 /*
0043  * MAX8925 gives us an interrupt when ONKEY is pressed or released.
0044  * max8925_set_bits() operates I2C bus and may sleep. So implement
0045  * it in thread IRQ handler.
0046  */
0047 static irqreturn_t max8925_onkey_handler(int irq, void *data)
0048 {
0049     struct max8925_onkey_info *info = data;
0050     int state;
0051 
0052     state = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS);
0053 
0054     input_report_key(info->idev, KEY_POWER, state & SW_INPUT);
0055     input_sync(info->idev);
0056 
0057     dev_dbg(info->dev, "onkey state:%d\n", state);
0058 
0059     /* Enable hardreset to halt if system isn't shutdown on time */
0060     max8925_set_bits(info->i2c, MAX8925_SYSENSEL,
0061              HARDRESET_EN, HARDRESET_EN);
0062 
0063     return IRQ_HANDLED;
0064 }
0065 
0066 static int max8925_onkey_probe(struct platform_device *pdev)
0067 {
0068     struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
0069     struct max8925_onkey_info *info;
0070     struct input_dev *input;
0071     int irq[2], error;
0072 
0073     irq[0] = platform_get_irq(pdev, 0);
0074     if (irq[0] < 0)
0075         return -EINVAL;
0076 
0077     irq[1] = platform_get_irq(pdev, 1);
0078     if (irq[1] < 0)
0079         return -EINVAL;
0080 
0081     info = devm_kzalloc(&pdev->dev, sizeof(struct max8925_onkey_info),
0082                 GFP_KERNEL);
0083     if (!info)
0084         return -ENOMEM;
0085 
0086     input = devm_input_allocate_device(&pdev->dev);
0087     if (!input)
0088         return -ENOMEM;
0089 
0090     info->idev = input;
0091     info->i2c = chip->i2c;
0092     info->dev = &pdev->dev;
0093     info->irq[0] = irq[0];
0094     info->irq[1] = irq[1];
0095 
0096     input->name = "max8925_on";
0097     input->phys = "max8925_on/input0";
0098     input->id.bustype = BUS_I2C;
0099     input->dev.parent = &pdev->dev;
0100     input_set_capability(input, EV_KEY, KEY_POWER);
0101 
0102     error = devm_request_threaded_irq(&pdev->dev, irq[0], NULL,
0103                       max8925_onkey_handler, IRQF_ONESHOT,
0104                       "onkey-down", info);
0105     if (error < 0) {
0106         dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
0107             irq[0], error);
0108         return error;
0109     }
0110 
0111     error = devm_request_threaded_irq(&pdev->dev, irq[1], NULL,
0112                       max8925_onkey_handler, IRQF_ONESHOT,
0113                       "onkey-up", info);
0114     if (error < 0) {
0115         dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
0116             irq[1], error);
0117         return error;
0118     }
0119 
0120     error = input_register_device(info->idev);
0121     if (error) {
0122         dev_err(chip->dev, "Can't register input device: %d\n", error);
0123         return error;
0124     }
0125 
0126     platform_set_drvdata(pdev, info);
0127     device_init_wakeup(&pdev->dev, 1);
0128 
0129     return 0;
0130 }
0131 
0132 static int __maybe_unused max8925_onkey_suspend(struct device *dev)
0133 {
0134     struct platform_device *pdev = to_platform_device(dev);
0135     struct max8925_onkey_info *info = platform_get_drvdata(pdev);
0136     struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
0137 
0138     if (device_may_wakeup(dev)) {
0139         chip->wakeup_flag |= 1 << info->irq[0];
0140         chip->wakeup_flag |= 1 << info->irq[1];
0141     }
0142 
0143     return 0;
0144 }
0145 
0146 static int __maybe_unused max8925_onkey_resume(struct device *dev)
0147 {
0148     struct platform_device *pdev = to_platform_device(dev);
0149     struct max8925_onkey_info *info = platform_get_drvdata(pdev);
0150     struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
0151 
0152     if (device_may_wakeup(dev)) {
0153         chip->wakeup_flag &= ~(1 << info->irq[0]);
0154         chip->wakeup_flag &= ~(1 << info->irq[1]);
0155     }
0156 
0157     return 0;
0158 }
0159 
0160 static SIMPLE_DEV_PM_OPS(max8925_onkey_pm_ops, max8925_onkey_suspend, max8925_onkey_resume);
0161 
0162 static struct platform_driver max8925_onkey_driver = {
0163     .driver     = {
0164         .name   = "max8925-onkey",
0165         .pm = &max8925_onkey_pm_ops,
0166     },
0167     .probe      = max8925_onkey_probe,
0168 };
0169 module_platform_driver(max8925_onkey_driver);
0170 
0171 MODULE_DESCRIPTION("Maxim MAX8925 ONKEY driver");
0172 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
0173 MODULE_LICENSE("GPL");