linux/drivers/mfd/pcf50633-core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* NXP PCF50633 Power Management Unit (PMU) driver
   3 *
   4 * (C) 2006-2008 by Openmoko, Inc.
   5 * Author: Harald Welte <laforge@openmoko.org>
   6 *         Balaji Rao <balajirrao@openmoko.org>
   7 * All rights reserved.
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/device.h>
  12#include <linux/sysfs.h>
  13#include <linux/module.h>
  14#include <linux/types.h>
  15#include <linux/interrupt.h>
  16#include <linux/workqueue.h>
  17#include <linux/platform_device.h>
  18#include <linux/i2c.h>
  19#include <linux/pm.h>
  20#include <linux/slab.h>
  21#include <linux/regmap.h>
  22#include <linux/err.h>
  23
  24#include <linux/mfd/pcf50633/core.h>
  25
  26/* Read a block of up to 32 regs  */
  27int pcf50633_read_block(struct pcf50633 *pcf, u8 reg,
  28                                        int nr_regs, u8 *data)
  29{
  30        int ret;
  31
  32        ret = regmap_raw_read(pcf->regmap, reg, data, nr_regs);
  33        if (ret != 0)
  34                return ret;
  35
  36        return nr_regs;
  37}
  38EXPORT_SYMBOL_GPL(pcf50633_read_block);
  39
  40/* Write a block of up to 32 regs  */
  41int pcf50633_write_block(struct pcf50633 *pcf , u8 reg,
  42                                        int nr_regs, u8 *data)
  43{
  44        return regmap_raw_write(pcf->regmap, reg, data, nr_regs);
  45}
  46EXPORT_SYMBOL_GPL(pcf50633_write_block);
  47
  48u8 pcf50633_reg_read(struct pcf50633 *pcf, u8 reg)
  49{
  50        unsigned int val;
  51        int ret;
  52
  53        ret = regmap_read(pcf->regmap, reg, &val);
  54        if (ret < 0)
  55                return -1;
  56
  57        return val;
  58}
  59EXPORT_SYMBOL_GPL(pcf50633_reg_read);
  60
  61int pcf50633_reg_write(struct pcf50633 *pcf, u8 reg, u8 val)
  62{
  63        return regmap_write(pcf->regmap, reg, val);
  64}
  65EXPORT_SYMBOL_GPL(pcf50633_reg_write);
  66
  67int pcf50633_reg_set_bit_mask(struct pcf50633 *pcf, u8 reg, u8 mask, u8 val)
  68{
  69        return regmap_update_bits(pcf->regmap, reg, mask, val);
  70}
  71EXPORT_SYMBOL_GPL(pcf50633_reg_set_bit_mask);
  72
  73int pcf50633_reg_clear_bits(struct pcf50633 *pcf, u8 reg, u8 val)
  74{
  75        return regmap_update_bits(pcf->regmap, reg, val, 0);
  76}
  77EXPORT_SYMBOL_GPL(pcf50633_reg_clear_bits);
  78
  79/* sysfs attributes */
  80static ssize_t dump_regs_show(struct device *dev,
  81                              struct device_attribute *attr, char *buf)
  82{
  83        struct pcf50633 *pcf = dev_get_drvdata(dev);
  84        u8 dump[16];
  85        int n, n1, idx = 0;
  86        char *buf1 = buf;
  87        static u8 address_no_read[] = { /* must be ascending */
  88                PCF50633_REG_INT1,
  89                PCF50633_REG_INT2,
  90                PCF50633_REG_INT3,
  91                PCF50633_REG_INT4,
  92                PCF50633_REG_INT5,
  93                0 /* terminator */
  94        };
  95
  96        for (n = 0; n < 256; n += sizeof(dump)) {
  97                for (n1 = 0; n1 < sizeof(dump); n1++)
  98                        if (n == address_no_read[idx]) {
  99                                idx++;
 100                                dump[n1] = 0x00;
 101                        } else
 102                                dump[n1] = pcf50633_reg_read(pcf, n + n1);
 103
 104                buf1 += sprintf(buf1, "%*ph\n", (int)sizeof(dump), dump);
 105        }
 106
 107        return buf1 - buf;
 108}
 109static DEVICE_ATTR_ADMIN_RO(dump_regs);
 110
 111static ssize_t resume_reason_show(struct device *dev,
 112                                  struct device_attribute *attr, char *buf)
 113{
 114        struct pcf50633 *pcf = dev_get_drvdata(dev);
 115        int n;
 116
 117        n = sprintf(buf, "%02x%02x%02x%02x%02x\n",
 118                                pcf->resume_reason[0],
 119                                pcf->resume_reason[1],
 120                                pcf->resume_reason[2],
 121                                pcf->resume_reason[3],
 122                                pcf->resume_reason[4]);
 123
 124        return n;
 125}
 126static DEVICE_ATTR_ADMIN_RO(resume_reason);
 127
 128static struct attribute *pcf_sysfs_entries[] = {
 129        &dev_attr_dump_regs.attr,
 130        &dev_attr_resume_reason.attr,
 131        NULL,
 132};
 133
 134static struct attribute_group pcf_attr_group = {
 135        .name   = NULL,                 /* put in device directory */
 136        .attrs  = pcf_sysfs_entries,
 137};
 138
 139static void
 140pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
 141                                                struct platform_device **pdev)
 142{
 143        int ret;
 144
 145        *pdev = platform_device_alloc(name, -1);
 146        if (!*pdev) {
 147                dev_err(pcf->dev, "Failed to allocate %s\n", name);
 148                return;
 149        }
 150
 151        (*pdev)->dev.parent = pcf->dev;
 152
 153        ret = platform_device_add(*pdev);
 154        if (ret) {
 155                dev_err(pcf->dev, "Failed to register %s: %d\n", name, ret);
 156                platform_device_put(*pdev);
 157                *pdev = NULL;
 158        }
 159}
 160
 161#ifdef CONFIG_PM_SLEEP
 162static int pcf50633_suspend(struct device *dev)
 163{
 164        struct i2c_client *client = to_i2c_client(dev);
 165        struct pcf50633 *pcf = i2c_get_clientdata(client);
 166
 167        return pcf50633_irq_suspend(pcf);
 168}
 169
 170static int pcf50633_resume(struct device *dev)
 171{
 172        struct i2c_client *client = to_i2c_client(dev);
 173        struct pcf50633 *pcf = i2c_get_clientdata(client);
 174
 175        return pcf50633_irq_resume(pcf);
 176}
 177#endif
 178
 179static SIMPLE_DEV_PM_OPS(pcf50633_pm, pcf50633_suspend, pcf50633_resume);
 180
 181static const struct regmap_config pcf50633_regmap_config = {
 182        .reg_bits = 8,
 183        .val_bits = 8,
 184};
 185
 186static int pcf50633_probe(struct i2c_client *client,
 187                                const struct i2c_device_id *ids)
 188{
 189        struct pcf50633 *pcf;
 190        struct platform_device *pdev;
 191        struct pcf50633_platform_data *pdata = dev_get_platdata(&client->dev);
 192        int i, j, ret;
 193        int version, variant;
 194
 195        if (!client->irq) {
 196                dev_err(&client->dev, "Missing IRQ\n");
 197                return -ENOENT;
 198        }
 199
 200        pcf = devm_kzalloc(&client->dev, sizeof(*pcf), GFP_KERNEL);
 201        if (!pcf)
 202                return -ENOMEM;
 203
 204        i2c_set_clientdata(client, pcf);
 205        pcf->dev = &client->dev;
 206        pcf->pdata = pdata;
 207
 208        mutex_init(&pcf->lock);
 209
 210        pcf->regmap = devm_regmap_init_i2c(client, &pcf50633_regmap_config);
 211        if (IS_ERR(pcf->regmap)) {
 212                ret = PTR_ERR(pcf->regmap);
 213                dev_err(pcf->dev, "Failed to allocate register map: %d\n", ret);
 214                return ret;
 215        }
 216
 217        version = pcf50633_reg_read(pcf, 0);
 218        variant = pcf50633_reg_read(pcf, 1);
 219        if (version < 0 || variant < 0) {
 220                dev_err(pcf->dev, "Unable to probe pcf50633\n");
 221                ret = -ENODEV;
 222                return ret;
 223        }
 224
 225        dev_info(pcf->dev, "Probed device version %d variant %d\n",
 226                                                        version, variant);
 227
 228        pcf50633_irq_init(pcf, client->irq);
 229
 230        /* Create sub devices */
 231        pcf50633_client_dev_register(pcf, "pcf50633-input", &pcf->input_pdev);
 232        pcf50633_client_dev_register(pcf, "pcf50633-rtc", &pcf->rtc_pdev);
 233        pcf50633_client_dev_register(pcf, "pcf50633-mbc", &pcf->mbc_pdev);
 234        pcf50633_client_dev_register(pcf, "pcf50633-adc", &pcf->adc_pdev);
 235        pcf50633_client_dev_register(pcf, "pcf50633-backlight", &pcf->bl_pdev);
 236
 237
 238        for (i = 0; i < PCF50633_NUM_REGULATORS; i++) {
 239                pdev = platform_device_alloc("pcf50633-regulator", i);
 240                if (!pdev) {
 241                        ret = -ENOMEM;
 242                        goto err2;
 243                }
 244
 245                pdev->dev.parent = pcf->dev;
 246                ret = platform_device_add_data(pdev, &pdata->reg_init_data[i],
 247                                               sizeof(pdata->reg_init_data[i]));
 248                if (ret)
 249                        goto err;
 250
 251                ret = platform_device_add(pdev);
 252                if (ret)
 253                        goto err;
 254
 255                pcf->regulator_pdev[i] = pdev;
 256        }
 257
 258        ret = sysfs_create_group(&client->dev.kobj, &pcf_attr_group);
 259        if (ret)
 260                dev_warn(pcf->dev, "error creating sysfs entries\n");
 261
 262        if (pdata->probe_done)
 263                pdata->probe_done(pcf);
 264
 265        return 0;
 266
 267err:
 268        platform_device_put(pdev);
 269err2:
 270        for (j = 0; j < i; j++)
 271                platform_device_put(pcf->regulator_pdev[j]);
 272
 273        return ret;
 274}
 275
 276static int pcf50633_remove(struct i2c_client *client)
 277{
 278        struct pcf50633 *pcf = i2c_get_clientdata(client);
 279        int i;
 280
 281        sysfs_remove_group(&client->dev.kobj, &pcf_attr_group);
 282        pcf50633_irq_free(pcf);
 283
 284        platform_device_unregister(pcf->input_pdev);
 285        platform_device_unregister(pcf->rtc_pdev);
 286        platform_device_unregister(pcf->mbc_pdev);
 287        platform_device_unregister(pcf->adc_pdev);
 288        platform_device_unregister(pcf->bl_pdev);
 289
 290        for (i = 0; i < PCF50633_NUM_REGULATORS; i++)
 291                platform_device_unregister(pcf->regulator_pdev[i]);
 292
 293        return 0;
 294}
 295
 296static const struct i2c_device_id pcf50633_id_table[] = {
 297        {"pcf50633", 0x73},
 298        {/* end of list */}
 299};
 300MODULE_DEVICE_TABLE(i2c, pcf50633_id_table);
 301
 302static struct i2c_driver pcf50633_driver = {
 303        .driver = {
 304                .name   = "pcf50633",
 305                .pm     = &pcf50633_pm,
 306        },
 307        .id_table = pcf50633_id_table,
 308        .probe = pcf50633_probe,
 309        .remove = pcf50633_remove,
 310};
 311
 312static int __init pcf50633_init(void)
 313{
 314        return i2c_add_driver(&pcf50633_driver);
 315}
 316
 317static void __exit pcf50633_exit(void)
 318{
 319        i2c_del_driver(&pcf50633_driver);
 320}
 321
 322MODULE_DESCRIPTION("I2C chip driver for NXP PCF50633 PMU");
 323MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
 324MODULE_LICENSE("GPL");
 325
 326subsys_initcall(pcf50633_init);
 327module_exit(pcf50633_exit);
 328