Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.13-rc4 209 lines 5.3 kB view raw
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 182 return 0; 183} 184 185static struct platform_driver pm8921_driver = { 186 .probe = pm8921_probe, 187 .remove = pm8921_remove, 188 .driver = { 189 .name = "pm8921-core", 190 .owner = THIS_MODULE, 191 }, 192}; 193 194static int __init pm8921_init(void) 195{ 196 return platform_driver_register(&pm8921_driver); 197} 198subsys_initcall(pm8921_init); 199 200static void __exit pm8921_exit(void) 201{ 202 platform_driver_unregister(&pm8921_driver); 203} 204module_exit(pm8921_exit); 205 206MODULE_LICENSE("GPL v2"); 207MODULE_DESCRIPTION("PMIC 8921 core driver"); 208MODULE_VERSION("1.0"); 209MODULE_ALIAS("platform:pm8921-core");