Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 //
0003 // wm831x-isink.c  --  Current sink driver for the WM831x series
0004 //
0005 // Copyright 2009 Wolfson Microelectronics PLC.
0006 //
0007 // Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
0008 
0009 #include <linux/module.h>
0010 #include <linux/moduleparam.h>
0011 #include <linux/init.h>
0012 #include <linux/bitops.h>
0013 #include <linux/err.h>
0014 #include <linux/i2c.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/regulator/driver.h>
0017 #include <linux/slab.h>
0018 
0019 #include <linux/mfd/wm831x/core.h>
0020 #include <linux/mfd/wm831x/regulator.h>
0021 #include <linux/mfd/wm831x/pdata.h>
0022 
0023 #define WM831X_ISINK_MAX_NAME 7
0024 
0025 struct wm831x_isink {
0026     char name[WM831X_ISINK_MAX_NAME];
0027     struct regulator_desc desc;
0028     int reg;
0029     struct wm831x *wm831x;
0030     struct regulator_dev *regulator;
0031 };
0032 
0033 static int wm831x_isink_enable(struct regulator_dev *rdev)
0034 {
0035     struct wm831x_isink *isink = rdev_get_drvdata(rdev);
0036     struct wm831x *wm831x = isink->wm831x;
0037     int ret;
0038 
0039     /* We have a two stage enable: first start the ISINK... */
0040     ret = wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_ENA,
0041                   WM831X_CS1_ENA);
0042     if (ret != 0)
0043         return ret;
0044 
0045     /* ...then enable drive */
0046     ret = wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_DRIVE,
0047                   WM831X_CS1_DRIVE);
0048     if (ret != 0)
0049         wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_ENA, 0);
0050 
0051     return ret;
0052 
0053 }
0054 
0055 static int wm831x_isink_disable(struct regulator_dev *rdev)
0056 {
0057     struct wm831x_isink *isink = rdev_get_drvdata(rdev);
0058     struct wm831x *wm831x = isink->wm831x;
0059     int ret;
0060 
0061     ret = wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_DRIVE, 0);
0062     if (ret < 0)
0063         return ret;
0064 
0065     ret = wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_ENA, 0);
0066     if (ret < 0)
0067         return ret;
0068 
0069     return ret;
0070 
0071 }
0072 
0073 static int wm831x_isink_is_enabled(struct regulator_dev *rdev)
0074 {
0075     struct wm831x_isink *isink = rdev_get_drvdata(rdev);
0076     struct wm831x *wm831x = isink->wm831x;
0077     int ret;
0078 
0079     ret = wm831x_reg_read(wm831x, isink->reg);
0080     if (ret < 0)
0081         return ret;
0082 
0083     if ((ret & (WM831X_CS1_ENA | WM831X_CS1_DRIVE)) ==
0084         (WM831X_CS1_ENA | WM831X_CS1_DRIVE))
0085         return 1;
0086     else
0087         return 0;
0088 }
0089 
0090 static const struct regulator_ops wm831x_isink_ops = {
0091     .is_enabled = wm831x_isink_is_enabled,
0092     .enable = wm831x_isink_enable,
0093     .disable = wm831x_isink_disable,
0094     .set_current_limit = regulator_set_current_limit_regmap,
0095     .get_current_limit = regulator_get_current_limit_regmap,
0096 };
0097 
0098 static irqreturn_t wm831x_isink_irq(int irq, void *data)
0099 {
0100     struct wm831x_isink *isink = data;
0101 
0102     regulator_notifier_call_chain(isink->regulator,
0103                       REGULATOR_EVENT_OVER_CURRENT,
0104                       NULL);
0105 
0106     return IRQ_HANDLED;
0107 }
0108 
0109 
0110 static int wm831x_isink_probe(struct platform_device *pdev)
0111 {
0112     struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
0113     struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
0114     struct wm831x_isink *isink;
0115     int id = pdev->id % ARRAY_SIZE(pdata->isink);
0116     struct regulator_config config = { };
0117     struct resource *res;
0118     int ret, irq;
0119 
0120     dev_dbg(&pdev->dev, "Probing ISINK%d\n", id + 1);
0121 
0122     if (pdata == NULL || pdata->isink[id] == NULL)
0123         return -ENODEV;
0124 
0125     isink = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_isink),
0126                  GFP_KERNEL);
0127     if (!isink)
0128         return -ENOMEM;
0129 
0130     isink->wm831x = wm831x;
0131 
0132     res = platform_get_resource(pdev, IORESOURCE_REG, 0);
0133     if (res == NULL) {
0134         dev_err(&pdev->dev, "No REG resource\n");
0135         ret = -EINVAL;
0136         goto err;
0137     }
0138     isink->reg = res->start;
0139 
0140     /* For current parts this is correct; probably need to revisit
0141      * in future.
0142      */
0143     snprintf(isink->name, sizeof(isink->name), "ISINK%d", id + 1);
0144     isink->desc.name = isink->name;
0145     isink->desc.id = id;
0146     isink->desc.ops = &wm831x_isink_ops;
0147     isink->desc.type = REGULATOR_CURRENT;
0148     isink->desc.owner = THIS_MODULE;
0149     isink->desc.curr_table = wm831x_isinkv_values,
0150     isink->desc.n_current_limits = ARRAY_SIZE(wm831x_isinkv_values),
0151     isink->desc.csel_reg = isink->reg,
0152     isink->desc.csel_mask = WM831X_CS1_ISEL_MASK,
0153 
0154     config.dev = pdev->dev.parent;
0155     config.init_data = pdata->isink[id];
0156     config.driver_data = isink;
0157     config.regmap = wm831x->regmap;
0158 
0159     isink->regulator = devm_regulator_register(&pdev->dev, &isink->desc,
0160                            &config);
0161     if (IS_ERR(isink->regulator)) {
0162         ret = PTR_ERR(isink->regulator);
0163         dev_err(wm831x->dev, "Failed to register ISINK%d: %d\n",
0164             id + 1, ret);
0165         goto err;
0166     }
0167 
0168     irq = wm831x_irq(wm831x, platform_get_irq(pdev, 0));
0169     ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
0170                     wm831x_isink_irq,
0171                     IRQF_TRIGGER_RISING | IRQF_ONESHOT,
0172                     isink->name,
0173                     isink);
0174     if (ret != 0) {
0175         dev_err(&pdev->dev, "Failed to request ISINK IRQ %d: %d\n",
0176             irq, ret);
0177         goto err;
0178     }
0179 
0180     platform_set_drvdata(pdev, isink);
0181 
0182     return 0;
0183 
0184 err:
0185     return ret;
0186 }
0187 
0188 static struct platform_driver wm831x_isink_driver = {
0189     .probe = wm831x_isink_probe,
0190     .driver     = {
0191         .name   = "wm831x-isink",
0192     },
0193 };
0194 
0195 static int __init wm831x_isink_init(void)
0196 {
0197     int ret;
0198     ret = platform_driver_register(&wm831x_isink_driver);
0199     if (ret != 0)
0200         pr_err("Failed to register WM831x ISINK driver: %d\n", ret);
0201 
0202     return ret;
0203 }
0204 subsys_initcall(wm831x_isink_init);
0205 
0206 static void __exit wm831x_isink_exit(void)
0207 {
0208     platform_driver_unregister(&wm831x_isink_driver);
0209 }
0210 module_exit(wm831x_isink_exit);
0211 
0212 /* Module information */
0213 MODULE_AUTHOR("Mark Brown");
0214 MODULE_DESCRIPTION("WM831x current sink driver");
0215 MODULE_LICENSE("GPL");
0216 MODULE_ALIAS("platform:wm831x-isink");