linux/drivers/mfd/pm8921-core.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 and
   6 * only version 2 as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13
  14#define pr_fmt(fmt) "%s: " fmt, __func__
  15
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18#include <linux/platform_device.h>
  19#include <linux/slab.h>
  20#include <linux/err.h>
  21#include <linux/ssbi.h>
  22#include <linux/mfd/core.h>
  23#include <linux/mfd/pm8xxx/pm8921.h>
  24#include <linux/mfd/pm8xxx/core.h>
  25
  26#define REG_HWREV               0x002  /* PMIC4 revision */
  27#define REG_HWREV_2             0x0E8  /* PMIC4 revision 2 */
  28
  29struct pm8921 {
  30        struct device                   *dev;
  31        struct pm_irq_chip              *irq_chip;
  32};
  33
  34static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
  35{
  36        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
  37        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
  38
  39        return ssbi_read(pmic->dev->parent, addr, val, 1);
  40}
  41
  42static int pm8921_writeb(const struct device *dev, u16 addr, u8 val)
  43{
  44        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
  45        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
  46
  47        return ssbi_write(pmic->dev->parent, addr, &val, 1);
  48}
  49
  50static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf,
  51                                                                        int cnt)
  52{
  53        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
  54        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
  55
  56        return ssbi_read(pmic->dev->parent, addr, buf, cnt);
  57}
  58
  59static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
  60                                                                        int cnt)
  61{
  62        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
  63        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
  64
  65        return ssbi_write(pmic->dev->parent, addr, buf, cnt);
  66}
  67
  68static int pm8921_read_irq_stat(const struct device *dev, int irq)
  69{
  70        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
  71        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
  72
  73        return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
  74}
  75
  76static struct pm8xxx_drvdata pm8921_drvdata = {
  77        .pmic_readb             = pm8921_readb,
  78        .pmic_writeb            = pm8921_writeb,
  79        .pmic_read_buf          = pm8921_read_buf,
  80        .pmic_write_buf         = pm8921_write_buf,
  81        .pmic_read_irq_stat     = pm8921_read_irq_stat,
  82};
  83
  84static int pm8921_add_subdevices(const struct pm8921_platform_data
  85                                           *pdata,
  86                                           struct pm8921 *pmic,
  87                                           u32 rev)
  88{
  89        int ret = 0, irq_base = 0;
  90        struct pm_irq_chip *irq_chip;
  91
  92        if (pdata->irq_pdata) {
  93                pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
  94                pdata->irq_pdata->irq_cdata.rev = rev;
  95                irq_base = pdata->irq_pdata->irq_base;
  96                irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
  97
  98                if (IS_ERR(irq_chip)) {
  99                        pr_err("Failed to init interrupts ret=%ld\n",
 100                                        PTR_ERR(irq_chip));
 101                        return PTR_ERR(irq_chip);
 102                }
 103                pmic->irq_chip = irq_chip;
 104        }
 105        return ret;
 106}
 107
 108static int pm8921_probe(struct platform_device *pdev)
 109{
 110        const struct pm8921_platform_data *pdata = dev_get_platdata(&pdev->dev);
 111        struct pm8921 *pmic;
 112        int rc;
 113        u8 val;
 114        u32 rev;
 115
 116        if (!pdata) {
 117                pr_err("missing platform data\n");
 118                return -EINVAL;
 119        }
 120
 121        pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8921), GFP_KERNEL);
 122        if (!pmic) {
 123                pr_err("Cannot alloc pm8921 struct\n");
 124                return -ENOMEM;
 125        }
 126
 127        /* Read PMIC chip revision */
 128        rc = ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
 129        if (rc) {
 130                pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
 131                return rc;
 132        }
 133        pr_info("PMIC revision 1: %02X\n", val);
 134        rev = val;
 135
 136        /* Read PMIC chip revision 2 */
 137        rc = ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
 138        if (rc) {
 139                pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
 140                        REG_HWREV_2, rc);
 141                return rc;
 142        }
 143        pr_info("PMIC revision 2: %02X\n", val);
 144        rev |= val << BITS_PER_BYTE;
 145
 146        pmic->dev = &pdev->dev;
 147        pm8921_drvdata.pm_chip_data = pmic;
 148        platform_set_drvdata(pdev, &pm8921_drvdata);
 149
 150        rc = pm8921_add_subdevices(pdata, pmic, rev);
 151        if (rc) {
 152                pr_err("Cannot add subdevices rc=%d\n", rc);
 153                goto err;
 154        }
 155
 156        /* gpio might not work if no irq device is found */
 157        WARN_ON(pmic->irq_chip == NULL);
 158
 159        return 0;
 160
 161err:
 162        mfd_remove_devices(pmic->dev);
 163        return rc;
 164}
 165
 166static int pm8921_remove(struct platform_device *pdev)
 167{
 168        struct pm8xxx_drvdata *drvdata;
 169        struct pm8921 *pmic = NULL;
 170
 171        drvdata = platform_get_drvdata(pdev);
 172        if (drvdata)
 173                pmic = drvdata->pm_chip_data;
 174        if (pmic)
 175                mfd_remove_devices(pmic->dev);
 176        if (pmic->irq_chip) {
 177                pm8xxx_irq_exit(pmic->irq_chip);
 178                pmic->irq_chip = NULL;
 179        }
 180
 181        return 0;
 182}
 183
 184static struct platform_driver pm8921_driver = {
 185        .probe          = pm8921_probe,
 186        .remove         = pm8921_remove,
 187        .driver         = {
 188                .name   = "pm8921-core",
 189                .owner  = THIS_MODULE,
 190        },
 191};
 192
 193static int __init pm8921_init(void)
 194{
 195        return platform_driver_register(&pm8921_driver);
 196}
 197subsys_initcall(pm8921_init);
 198
 199static void __exit pm8921_exit(void)
 200{
 201        platform_driver_unregister(&pm8921_driver);
 202}
 203module_exit(pm8921_exit);
 204
 205MODULE_LICENSE("GPL v2");
 206MODULE_DESCRIPTION("PMIC 8921 core driver");
 207MODULE_VERSION("1.0");
 208MODULE_ALIAS("platform:pm8921-core");
 209
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.