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/platform_device.h>
  18#include <linux/slab.h>
  19#include <linux/err.h>
  20#include <linux/msm_ssbi.h>
  21#include <linux/mfd/core.h>
  22#include <linux/mfd/pm8xxx/pm8921.h>
  23#include <linux/mfd/pm8xxx/core.h>
  24
  25#define REG_HWREV               0x002  /* PMIC4 revision */
  26#define REG_HWREV_2             0x0E8  /* PMIC4 revision 2 */
  27
  28struct pm8921 {
  29        struct device                   *dev;
  30        struct pm_irq_chip              *irq_chip;
  31};
  32
  33static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
  34{
  35        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
  36        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
  37
  38        return msm_ssbi_read(pmic->dev->parent, addr, val, 1);
  39}
  40
  41static int pm8921_writeb(const struct device *dev, u16 addr, u8 val)
  42{
  43        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
  44        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
  45
  46        return msm_ssbi_write(pmic->dev->parent, addr, &val, 1);
  47}
  48
  49static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf,
  50                                                                        int cnt)
  51{
  52        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
  53        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
  54
  55        return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt);
  56}
  57
  58static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
  59                                                                        int cnt)
  60{
  61        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
  62        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
  63
  64        return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
  65}
  66
  67static int pm8921_read_irq_stat(const struct device *dev, int irq)
  68{
  69        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
  70        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
  71
  72        return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
  73}
  74
  75static struct pm8xxx_drvdata pm8921_drvdata = {
  76        .pmic_readb             = pm8921_readb,
  77        .pmic_writeb            = pm8921_writeb,
  78        .pmic_read_buf          = pm8921_read_buf,
  79        .pmic_write_buf         = pm8921_write_buf,
  80        .pmic_read_irq_stat     = pm8921_read_irq_stat,
  81};
  82
  83static int pm8921_add_subdevices(const struct pm8921_platform_data
  84                                           *pdata,
  85                                           struct pm8921 *pmic,
  86                                           u32 rev)
  87{
  88        int ret = 0, irq_base = 0;
  89        struct pm_irq_chip *irq_chip;
  90
  91        if (pdata->irq_pdata) {
  92                pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
  93                pdata->irq_pdata->irq_cdata.rev = rev;
  94                irq_base = pdata->irq_pdata->irq_base;
  95                irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
  96
  97                if (IS_ERR(irq_chip)) {
  98                        pr_err("Failed to init interrupts ret=%ld\n",
  99                                        PTR_ERR(irq_chip));
 100                        return PTR_ERR(irq_chip);
 101                }
 102                pmic->irq_chip = irq_chip;
 103        }
 104        return ret;
 105}
 106
 107static int pm8921_probe(struct platform_device *pdev)
 108{
 109        const struct pm8921_platform_data *pdata = pdev->dev.platform_data;
 110        struct pm8921 *pmic;
 111        int rc;
 112        u8 val;
 113        u32 rev;
 114
 115        if (!pdata) {
 116                pr_err("missing platform data\n");
 117                return -EINVAL;
 118        }
 119
 120        pmic = kzalloc(sizeof(struct pm8921), GFP_KERNEL);
 121        if (!pmic) {
 122                pr_err("Cannot alloc pm8921 struct\n");
 123                return -ENOMEM;
 124        }
 125
 126        /* Read PMIC chip revision */
 127        rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
 128        if (rc) {
 129                pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
 130                goto err_read_rev;
 131        }
 132        pr_info("PMIC revision 1: %02X\n", val);
 133        rev = val;
 134
 135        /* Read PMIC chip revision 2 */
 136        rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
 137        if (rc) {
 138                pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
 139                        REG_HWREV_2, rc);
 140                goto err_read_rev;
 141        }
 142        pr_info("PMIC revision 2: %02X\n", val);
 143        rev |= val << BITS_PER_BYTE;
 144
 145        pmic->dev = &pdev->dev;
 146        pm8921_drvdata.pm_chip_data = pmic;
 147        platform_set_drvdata(pdev, &pm8921_drvdata);
 148
 149        rc = pm8921_add_subdevices(pdata, pmic, rev);
 150        if (rc) {
 151                pr_err("Cannot add subdevices rc=%d\n", rc);
 152                goto err;
 153        }
 154
 155        /* gpio might not work if no irq device is found */
 156        WARN_ON(pmic->irq_chip == NULL);
 157
 158        return 0;
 159
 160err:
 161        mfd_remove_devices(pmic->dev);
 162        platform_set_drvdata(pdev, NULL);
 163err_read_rev:
 164        kfree(pmic);
 165        return rc;
 166}
 167
 168static int pm8921_remove(struct platform_device *pdev)
 169{
 170        struct pm8xxx_drvdata *drvdata;
 171        struct pm8921 *pmic = NULL;
 172
 173        drvdata = platform_get_drvdata(pdev);
 174        if (drvdata)
 175                pmic = drvdata->pm_chip_data;
 176        if (pmic)
 177                mfd_remove_devices(pmic->dev);
 178        if (pmic->irq_chip) {
 179                pm8xxx_irq_exit(pmic->irq_chip);
 180                pmic->irq_chip = NULL;
 181        }
 182        platform_set_drvdata(pdev, NULL);
 183        kfree(pmic);
 184
 185        return 0;
 186}
 187
 188static struct platform_driver pm8921_driver = {
 189        .probe          = pm8921_probe,
 190        .remove         = pm8921_remove,
 191        .driver         = {
 192                .name   = "pm8921-core",
 193                .owner  = THIS_MODULE,
 194        },
 195};
 196
 197static int __init pm8921_init(void)
 198{
 199        return platform_driver_register(&pm8921_driver);
 200}
 201subsys_initcall(pm8921_init);
 202
 203static void __exit pm8921_exit(void)
 204{
 205        platform_driver_unregister(&pm8921_driver);
 206}
 207module_exit(pm8921_exit);
 208
 209MODULE_LICENSE("GPL v2");
 210MODULE_DESCRIPTION("PMIC 8921 core driver");
 211MODULE_VERSION("1.0");
 212MODULE_ALIAS("platform:pm8921-core");
 213
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.