root/drivers/mfd/88pm805.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. device_irq_init_805
  2. device_irq_exit_805
  3. device_805_init
  4. pm805_probe
  5. pm805_remove
  6. pm805_i2c_init
  7. pm805_i2c_exit

   1 /*
   2  * Base driver for Marvell 88PM805
   3  *
   4  * Copyright (C) 2012 Marvell International Ltd.
   5  * Haojian Zhuang <haojian.zhuang@marvell.com>
   6  * Joseph(Yossi) Hanin <yhanin@marvell.com>
   7  * Qiao Zhou <zhouqiao@marvell.com>
   8  *
   9  * This file is subject to the terms and conditions of the GNU General
  10  * Public License. See the file "COPYING" in the main directory of this
  11  * archive for more details.
  12  *
  13  * This program is distributed in the hope that it will be useful,
  14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16  * GNU General Public License for more details.
  17  *
  18  * You should have received a copy of the GNU General Public License
  19  * along with this program; if not, write to the Free Software
  20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21  */
  22 
  23 #include <linux/kernel.h>
  24 #include <linux/module.h>
  25 #include <linux/i2c.h>
  26 #include <linux/irq.h>
  27 #include <linux/mfd/core.h>
  28 #include <linux/mfd/88pm80x.h>
  29 #include <linux/slab.h>
  30 #include <linux/delay.h>
  31 
  32 static const struct i2c_device_id pm80x_id_table[] = {
  33         {"88PM805", 0},
  34         {} /* NULL terminated */
  35 };
  36 MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
  37 
  38 /* Interrupt Number in 88PM805 */
  39 enum {
  40         PM805_IRQ_LDO_OFF,      /*0 */
  41         PM805_IRQ_SRC_DPLL_LOCK,        /*1 */
  42         PM805_IRQ_CLIP_FAULT,
  43         PM805_IRQ_MIC_CONFLICT,
  44         PM805_IRQ_HP2_SHRT,
  45         PM805_IRQ_HP1_SHRT,     /*5 */
  46         PM805_IRQ_FINE_PLL_FAULT,
  47         PM805_IRQ_RAW_PLL_FAULT,
  48         PM805_IRQ_VOLP_BTN_DET,
  49         PM805_IRQ_VOLM_BTN_DET,
  50         PM805_IRQ_SHRT_BTN_DET, /*10 */
  51         PM805_IRQ_MIC_DET,      /*11 */
  52 
  53         PM805_MAX_IRQ,
  54 };
  55 
  56 static struct resource codec_resources[] = {
  57         {
  58          /* Headset microphone insertion or removal */
  59          .name = "micin",
  60          .start = PM805_IRQ_MIC_DET,
  61          .end = PM805_IRQ_MIC_DET,
  62          .flags = IORESOURCE_IRQ,
  63          },
  64         {
  65          /* Audio short HP1 */
  66          .name = "audio-short1",
  67          .start = PM805_IRQ_HP1_SHRT,
  68          .end = PM805_IRQ_HP1_SHRT,
  69          .flags = IORESOURCE_IRQ,
  70          },
  71         {
  72          /* Audio short HP2 */
  73          .name = "audio-short2",
  74          .start = PM805_IRQ_HP2_SHRT,
  75          .end = PM805_IRQ_HP2_SHRT,
  76          .flags = IORESOURCE_IRQ,
  77          },
  78 };
  79 
  80 static const struct mfd_cell codec_devs[] = {
  81         {
  82          .name = "88pm80x-codec",
  83          .num_resources = ARRAY_SIZE(codec_resources),
  84          .resources = &codec_resources[0],
  85          .id = -1,
  86          },
  87 };
  88 
  89 static struct regmap_irq pm805_irqs[] = {
  90         /* INT0 */
  91         [PM805_IRQ_LDO_OFF] = {
  92                 .mask = PM805_INT1_HP1_SHRT,
  93         },
  94         [PM805_IRQ_SRC_DPLL_LOCK] = {
  95                 .mask = PM805_INT1_HP2_SHRT,
  96         },
  97         [PM805_IRQ_CLIP_FAULT] = {
  98                 .mask = PM805_INT1_MIC_CONFLICT,
  99         },
 100         [PM805_IRQ_MIC_CONFLICT] = {
 101                 .mask = PM805_INT1_CLIP_FAULT,
 102         },
 103         [PM805_IRQ_HP2_SHRT] = {
 104                 .mask = PM805_INT1_LDO_OFF,
 105         },
 106         [PM805_IRQ_HP1_SHRT] = {
 107                 .mask = PM805_INT1_SRC_DPLL_LOCK,
 108         },
 109         /* INT1 */
 110         [PM805_IRQ_FINE_PLL_FAULT] = {
 111                 .reg_offset = 1,
 112                 .mask = PM805_INT2_MIC_DET,
 113         },
 114         [PM805_IRQ_RAW_PLL_FAULT] = {
 115                 .reg_offset = 1,
 116                 .mask = PM805_INT2_SHRT_BTN_DET,
 117         },
 118         [PM805_IRQ_VOLP_BTN_DET] = {
 119                 .reg_offset = 1,
 120                 .mask = PM805_INT2_VOLM_BTN_DET,
 121         },
 122         [PM805_IRQ_VOLM_BTN_DET] = {
 123                 .reg_offset = 1,
 124                 .mask = PM805_INT2_VOLP_BTN_DET,
 125         },
 126         [PM805_IRQ_SHRT_BTN_DET] = {
 127                 .reg_offset = 1,
 128                 .mask = PM805_INT2_RAW_PLL_FAULT,
 129         },
 130         [PM805_IRQ_MIC_DET] = {
 131                 .reg_offset = 1,
 132                 .mask = PM805_INT2_FINE_PLL_FAULT,
 133         },
 134 };
 135 
 136 static int device_irq_init_805(struct pm80x_chip *chip)
 137 {
 138         struct regmap *map = chip->regmap;
 139         unsigned long flags = IRQF_ONESHOT;
 140         int data, mask, ret = -EINVAL;
 141 
 142         if (!map || !chip->irq) {
 143                 dev_err(chip->dev, "incorrect parameters\n");
 144                 return -EINVAL;
 145         }
 146 
 147         /*
 148          * irq_mode defines the way of clearing interrupt. it's read-clear by
 149          * default.
 150          */
 151         mask =
 152             PM805_STATUS0_INT_CLEAR | PM805_STATUS0_INV_INT |
 153             PM800_STATUS0_INT_MASK;
 154 
 155         data = PM805_STATUS0_INT_CLEAR;
 156         ret = regmap_update_bits(map, PM805_INT_STATUS0, mask, data);
 157         /*
 158          * PM805_INT_STATUS is under 32K clock domain, so need to
 159          * add proper delay before the next I2C register access.
 160          */
 161         usleep_range(1000, 3000);
 162 
 163         if (ret < 0)
 164                 goto out;
 165 
 166         ret =
 167             regmap_add_irq_chip(chip->regmap, chip->irq, flags, -1,
 168                                 chip->regmap_irq_chip, &chip->irq_data);
 169 
 170 out:
 171         return ret;
 172 }
 173 
 174 static void device_irq_exit_805(struct pm80x_chip *chip)
 175 {
 176         regmap_del_irq_chip(chip->irq, chip->irq_data);
 177 }
 178 
 179 static struct regmap_irq_chip pm805_irq_chip = {
 180         .name = "88pm805",
 181         .irqs = pm805_irqs,
 182         .num_irqs = ARRAY_SIZE(pm805_irqs),
 183 
 184         .num_regs = 2,
 185         .status_base = PM805_INT_STATUS1,
 186         .mask_base = PM805_INT_MASK1,
 187         .ack_base = PM805_INT_STATUS1,
 188 };
 189 
 190 static int device_805_init(struct pm80x_chip *chip)
 191 {
 192         int ret = 0;
 193         struct regmap *map = chip->regmap;
 194 
 195         if (!map) {
 196                 dev_err(chip->dev, "regmap is invalid\n");
 197                 return -EINVAL;
 198         }
 199 
 200         chip->regmap_irq_chip = &pm805_irq_chip;
 201 
 202         ret = device_irq_init_805(chip);
 203         if (ret < 0) {
 204                 dev_err(chip->dev, "Failed to init pm805 irq!\n");
 205                 goto out_irq_init;
 206         }
 207 
 208         ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
 209                               ARRAY_SIZE(codec_devs), &codec_resources[0], 0,
 210                               NULL);
 211         if (ret < 0) {
 212                 dev_err(chip->dev, "Failed to add codec subdev\n");
 213                 goto out_codec;
 214         } else
 215                 dev_info(chip->dev, "[%s]:Added mfd codec_devs\n", __func__);
 216 
 217         return 0;
 218 
 219 out_codec:
 220         device_irq_exit_805(chip);
 221 out_irq_init:
 222         return ret;
 223 }
 224 
 225 static int pm805_probe(struct i2c_client *client,
 226                                  const struct i2c_device_id *id)
 227 {
 228         int ret = 0;
 229         struct pm80x_chip *chip;
 230         struct pm80x_platform_data *pdata = dev_get_platdata(&client->dev);
 231 
 232         ret = pm80x_init(client);
 233         if (ret) {
 234                 dev_err(&client->dev, "pm805_init fail!\n");
 235                 goto out_init;
 236         }
 237 
 238         chip = i2c_get_clientdata(client);
 239 
 240         ret = device_805_init(chip);
 241         if (ret) {
 242                 dev_err(chip->dev, "Failed to initialize 88pm805 devices\n");
 243                 goto err_805_init;
 244         }
 245 
 246         if (pdata && pdata->plat_config)
 247                 pdata->plat_config(chip, pdata);
 248 
 249 err_805_init:
 250         pm80x_deinit();
 251 out_init:
 252         return ret;
 253 }
 254 
 255 static int pm805_remove(struct i2c_client *client)
 256 {
 257         struct pm80x_chip *chip = i2c_get_clientdata(client);
 258 
 259         mfd_remove_devices(chip->dev);
 260         device_irq_exit_805(chip);
 261 
 262         pm80x_deinit();
 263 
 264         return 0;
 265 }
 266 
 267 static struct i2c_driver pm805_driver = {
 268         .driver = {
 269                 .name = "88PM805",
 270                 .pm = &pm80x_pm_ops,
 271                 },
 272         .probe = pm805_probe,
 273         .remove = pm805_remove,
 274         .id_table = pm80x_id_table,
 275 };
 276 
 277 static int __init pm805_i2c_init(void)
 278 {
 279         return i2c_add_driver(&pm805_driver);
 280 }
 281 subsys_initcall(pm805_i2c_init);
 282 
 283 static void __exit pm805_i2c_exit(void)
 284 {
 285         i2c_del_driver(&pm805_driver);
 286 }
 287 module_exit(pm805_i2c_exit);
 288 
 289 MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM805");
 290 MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>");
 291 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */