Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Base driver for Analog Devices ADP5520/ADP5501 MFD PMICs
0004  * LCD Backlight: drivers/video/backlight/adp5520_bl
0005  * LEDs     : drivers/led/leds-adp5520
0006  * GPIO     : drivers/gpio/adp5520-gpio (ADP5520 only)
0007  * Keys     : drivers/input/keyboard/adp5520-keys (ADP5520 only)
0008  *
0009  * Copyright 2009 Analog Devices Inc.
0010  *
0011  * Author: Michael Hennerich <michael.hennerich@analog.com>
0012  *
0013  * Derived from da903x:
0014  * Copyright (C) 2008 Compulab, Ltd.
0015  *  Mike Rapoport <mike@compulab.co.il>
0016  *
0017  * Copyright (C) 2006-2008 Marvell International Ltd.
0018  *  Eric Miao <eric.miao@marvell.com>
0019  */
0020 
0021 #include <linux/kernel.h>
0022 #include <linux/init.h>
0023 #include <linux/platform_device.h>
0024 #include <linux/slab.h>
0025 #include <linux/interrupt.h>
0026 #include <linux/irq.h>
0027 #include <linux/err.h>
0028 #include <linux/i2c.h>
0029 
0030 #include <linux/mfd/adp5520.h>
0031 
0032 struct adp5520_chip {
0033     struct i2c_client *client;
0034     struct device *dev;
0035     struct mutex lock;
0036     struct blocking_notifier_head notifier_list;
0037     int irq;
0038     unsigned long id;
0039     uint8_t mode;
0040 };
0041 
0042 static int __adp5520_read(struct i2c_client *client,
0043                 int reg, uint8_t *val)
0044 {
0045     int ret;
0046 
0047     ret = i2c_smbus_read_byte_data(client, reg);
0048     if (ret < 0) {
0049         dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
0050         return ret;
0051     }
0052 
0053     *val = (uint8_t)ret;
0054     return 0;
0055 }
0056 
0057 static int __adp5520_write(struct i2c_client *client,
0058                  int reg, uint8_t val)
0059 {
0060     int ret;
0061 
0062     ret = i2c_smbus_write_byte_data(client, reg, val);
0063     if (ret < 0) {
0064         dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
0065                 val, reg);
0066         return ret;
0067     }
0068     return 0;
0069 }
0070 
0071 static int __adp5520_ack_bits(struct i2c_client *client, int reg,
0072                   uint8_t bit_mask)
0073 {
0074     struct adp5520_chip *chip = i2c_get_clientdata(client);
0075     uint8_t reg_val;
0076     int ret;
0077 
0078     mutex_lock(&chip->lock);
0079 
0080     ret = __adp5520_read(client, reg, &reg_val);
0081 
0082     if (!ret) {
0083         reg_val |= bit_mask;
0084         ret = __adp5520_write(client, reg, reg_val);
0085     }
0086 
0087     mutex_unlock(&chip->lock);
0088     return ret;
0089 }
0090 
0091 int adp5520_write(struct device *dev, int reg, uint8_t val)
0092 {
0093     return __adp5520_write(to_i2c_client(dev), reg, val);
0094 }
0095 EXPORT_SYMBOL_GPL(adp5520_write);
0096 
0097 int adp5520_read(struct device *dev, int reg, uint8_t *val)
0098 {
0099     return __adp5520_read(to_i2c_client(dev), reg, val);
0100 }
0101 EXPORT_SYMBOL_GPL(adp5520_read);
0102 
0103 int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask)
0104 {
0105     struct adp5520_chip *chip = dev_get_drvdata(dev);
0106     uint8_t reg_val;
0107     int ret;
0108 
0109     mutex_lock(&chip->lock);
0110 
0111     ret = __adp5520_read(chip->client, reg, &reg_val);
0112 
0113     if (!ret && ((reg_val & bit_mask) != bit_mask)) {
0114         reg_val |= bit_mask;
0115         ret = __adp5520_write(chip->client, reg, reg_val);
0116     }
0117 
0118     mutex_unlock(&chip->lock);
0119     return ret;
0120 }
0121 EXPORT_SYMBOL_GPL(adp5520_set_bits);
0122 
0123 int adp5520_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
0124 {
0125     struct adp5520_chip *chip = dev_get_drvdata(dev);
0126     uint8_t reg_val;
0127     int ret;
0128 
0129     mutex_lock(&chip->lock);
0130 
0131     ret = __adp5520_read(chip->client, reg, &reg_val);
0132 
0133     if (!ret && (reg_val & bit_mask)) {
0134         reg_val &= ~bit_mask;
0135         ret = __adp5520_write(chip->client, reg, reg_val);
0136     }
0137 
0138     mutex_unlock(&chip->lock);
0139     return ret;
0140 }
0141 EXPORT_SYMBOL_GPL(adp5520_clr_bits);
0142 
0143 int adp5520_register_notifier(struct device *dev, struct notifier_block *nb,
0144                 unsigned int events)
0145 {
0146     struct adp5520_chip *chip = dev_get_drvdata(dev);
0147 
0148     if (chip->irq) {
0149         adp5520_set_bits(chip->dev, ADP5520_INTERRUPT_ENABLE,
0150             events & (ADP5520_KP_IEN | ADP5520_KR_IEN |
0151             ADP5520_OVP_IEN | ADP5520_CMPR_IEN));
0152 
0153         return blocking_notifier_chain_register(&chip->notifier_list,
0154              nb);
0155     }
0156 
0157     return -ENODEV;
0158 }
0159 EXPORT_SYMBOL_GPL(adp5520_register_notifier);
0160 
0161 int adp5520_unregister_notifier(struct device *dev, struct notifier_block *nb,
0162                 unsigned int events)
0163 {
0164     struct adp5520_chip *chip = dev_get_drvdata(dev);
0165 
0166     adp5520_clr_bits(chip->dev, ADP5520_INTERRUPT_ENABLE,
0167         events & (ADP5520_KP_IEN | ADP5520_KR_IEN |
0168         ADP5520_OVP_IEN | ADP5520_CMPR_IEN));
0169 
0170     return blocking_notifier_chain_unregister(&chip->notifier_list, nb);
0171 }
0172 EXPORT_SYMBOL_GPL(adp5520_unregister_notifier);
0173 
0174 static irqreturn_t adp5520_irq_thread(int irq, void *data)
0175 {
0176     struct adp5520_chip *chip = data;
0177     unsigned int events;
0178     uint8_t reg_val;
0179     int ret;
0180 
0181     ret = __adp5520_read(chip->client, ADP5520_MODE_STATUS, &reg_val);
0182     if (ret)
0183         goto out;
0184 
0185     events =  reg_val & (ADP5520_OVP_INT | ADP5520_CMPR_INT |
0186         ADP5520_GPI_INT | ADP5520_KR_INT | ADP5520_KP_INT);
0187 
0188     blocking_notifier_call_chain(&chip->notifier_list, events, NULL);
0189     /* ACK, Sticky bits are W1C */
0190     __adp5520_ack_bits(chip->client, ADP5520_MODE_STATUS, events);
0191 
0192 out:
0193     return IRQ_HANDLED;
0194 }
0195 
0196 static int __remove_subdev(struct device *dev, void *unused)
0197 {
0198     platform_device_unregister(to_platform_device(dev));
0199     return 0;
0200 }
0201 
0202 static int adp5520_remove_subdevs(struct adp5520_chip *chip)
0203 {
0204     return device_for_each_child(chip->dev, NULL, __remove_subdev);
0205 }
0206 
0207 static int adp5520_probe(struct i2c_client *client,
0208                     const struct i2c_device_id *id)
0209 {
0210     struct adp5520_platform_data *pdata = dev_get_platdata(&client->dev);
0211     struct platform_device *pdev;
0212     struct adp5520_chip *chip;
0213     int ret;
0214 
0215     if (!i2c_check_functionality(client->adapter,
0216                     I2C_FUNC_SMBUS_BYTE_DATA)) {
0217         dev_err(&client->dev, "SMBUS Word Data not Supported\n");
0218         return -EIO;
0219     }
0220 
0221     if (pdata == NULL) {
0222         dev_err(&client->dev, "missing platform data\n");
0223         return -ENODEV;
0224     }
0225 
0226     chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
0227     if (!chip)
0228         return -ENOMEM;
0229 
0230     i2c_set_clientdata(client, chip);
0231     chip->client = client;
0232 
0233     chip->dev = &client->dev;
0234     chip->irq = client->irq;
0235     chip->id = id->driver_data;
0236     mutex_init(&chip->lock);
0237 
0238     if (chip->irq) {
0239         BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list);
0240 
0241         ret = request_threaded_irq(chip->irq, NULL, adp5520_irq_thread,
0242                 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
0243                 "adp5520", chip);
0244         if (ret) {
0245             dev_err(&client->dev, "failed to request irq %d\n",
0246                     chip->irq);
0247             return ret;
0248         }
0249     }
0250 
0251     ret = adp5520_write(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
0252     if (ret) {
0253         dev_err(&client->dev, "failed to write\n");
0254         goto out_free_irq;
0255     }
0256 
0257     if (pdata->keys) {
0258         pdev = platform_device_register_data(chip->dev, "adp5520-keys",
0259                 chip->id, pdata->keys, sizeof(*pdata->keys));
0260         if (IS_ERR(pdev)) {
0261             ret = PTR_ERR(pdev);
0262             goto out_remove_subdevs;
0263         }
0264     }
0265 
0266     if (pdata->gpio) {
0267         pdev = platform_device_register_data(chip->dev, "adp5520-gpio",
0268                 chip->id, pdata->gpio, sizeof(*pdata->gpio));
0269         if (IS_ERR(pdev)) {
0270             ret = PTR_ERR(pdev);
0271             goto out_remove_subdevs;
0272         }
0273     }
0274 
0275     if (pdata->leds) {
0276         pdev = platform_device_register_data(chip->dev, "adp5520-led",
0277                 chip->id, pdata->leds, sizeof(*pdata->leds));
0278         if (IS_ERR(pdev)) {
0279             ret = PTR_ERR(pdev);
0280             goto out_remove_subdevs;
0281         }
0282     }
0283 
0284     if (pdata->backlight) {
0285         pdev = platform_device_register_data(chip->dev,
0286                         "adp5520-backlight",
0287                         chip->id,
0288                         pdata->backlight,
0289                         sizeof(*pdata->backlight));
0290         if (IS_ERR(pdev)) {
0291             ret = PTR_ERR(pdev);
0292             goto out_remove_subdevs;
0293         }
0294     }
0295 
0296     return 0;
0297 
0298 out_remove_subdevs:
0299     adp5520_remove_subdevs(chip);
0300 
0301 out_free_irq:
0302     if (chip->irq)
0303         free_irq(chip->irq, chip);
0304 
0305     return ret;
0306 }
0307 
0308 #ifdef CONFIG_PM_SLEEP
0309 static int adp5520_suspend(struct device *dev)
0310 {
0311     struct i2c_client *client = to_i2c_client(dev);
0312     struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
0313 
0314     adp5520_read(chip->dev, ADP5520_MODE_STATUS, &chip->mode);
0315     /* All other bits are W1C */
0316     chip->mode &= ADP5520_BL_EN | ADP5520_DIM_EN | ADP5520_nSTNBY;
0317     adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0);
0318     return 0;
0319 }
0320 
0321 static int adp5520_resume(struct device *dev)
0322 {
0323     struct i2c_client *client = to_i2c_client(dev);
0324     struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
0325 
0326     adp5520_write(chip->dev, ADP5520_MODE_STATUS, chip->mode);
0327     return 0;
0328 }
0329 #endif
0330 
0331 static SIMPLE_DEV_PM_OPS(adp5520_pm, adp5520_suspend, adp5520_resume);
0332 
0333 static const struct i2c_device_id adp5520_id[] = {
0334     { "pmic-adp5520", ID_ADP5520 },
0335     { "pmic-adp5501", ID_ADP5501 },
0336     { }
0337 };
0338 
0339 static struct i2c_driver adp5520_driver = {
0340     .driver = {
0341         .name           = "adp5520",
0342         .pm         = &adp5520_pm,
0343         .suppress_bind_attrs    = true,
0344     },
0345     .probe      = adp5520_probe,
0346     .id_table   = adp5520_id,
0347 };
0348 builtin_i2c_driver(adp5520_driver);