Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * AS3711 PMIC MFC driver
0004  *
0005  * Copyright (C) 2012 Renesas Electronics Corporation
0006  * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de>
0007  */
0008 
0009 #include <linux/device.h>
0010 #include <linux/err.h>
0011 #include <linux/i2c.h>
0012 #include <linux/init.h>
0013 #include <linux/kernel.h>
0014 #include <linux/mfd/as3711.h>
0015 #include <linux/mfd/core.h>
0016 #include <linux/of.h>
0017 #include <linux/regmap.h>
0018 #include <linux/slab.h>
0019 
0020 enum {
0021     AS3711_REGULATOR,
0022     AS3711_BACKLIGHT,
0023 };
0024 
0025 /*
0026  * Ok to have it static: it is only used during probing and multiple I2C devices
0027  * cannot be probed simultaneously. Just make sure to avoid stale data.
0028  */
0029 static struct mfd_cell as3711_subdevs[] = {
0030     [AS3711_REGULATOR] = {.name = "as3711-regulator",},
0031     [AS3711_BACKLIGHT] = {.name = "as3711-backlight",},
0032 };
0033 
0034 static bool as3711_volatile_reg(struct device *dev, unsigned int reg)
0035 {
0036     switch (reg) {
0037     case AS3711_GPIO_SIGNAL_IN:
0038     case AS3711_INTERRUPT_STATUS_1:
0039     case AS3711_INTERRUPT_STATUS_2:
0040     case AS3711_INTERRUPT_STATUS_3:
0041     case AS3711_CHARGER_STATUS_1:
0042     case AS3711_CHARGER_STATUS_2:
0043     case AS3711_REG_STATUS:
0044         return true;
0045     }
0046     return false;
0047 }
0048 
0049 static bool as3711_precious_reg(struct device *dev, unsigned int reg)
0050 {
0051     switch (reg) {
0052     case AS3711_INTERRUPT_STATUS_1:
0053     case AS3711_INTERRUPT_STATUS_2:
0054     case AS3711_INTERRUPT_STATUS_3:
0055         return true;
0056     }
0057     return false;
0058 }
0059 
0060 static bool as3711_readable_reg(struct device *dev, unsigned int reg)
0061 {
0062     switch (reg) {
0063     case AS3711_SD_1_VOLTAGE:
0064     case AS3711_SD_2_VOLTAGE:
0065     case AS3711_SD_3_VOLTAGE:
0066     case AS3711_SD_4_VOLTAGE:
0067     case AS3711_LDO_1_VOLTAGE:
0068     case AS3711_LDO_2_VOLTAGE:
0069     case AS3711_LDO_3_VOLTAGE:
0070     case AS3711_LDO_4_VOLTAGE:
0071     case AS3711_LDO_5_VOLTAGE:
0072     case AS3711_LDO_6_VOLTAGE:
0073     case AS3711_LDO_7_VOLTAGE:
0074     case AS3711_LDO_8_VOLTAGE:
0075     case AS3711_SD_CONTROL:
0076     case AS3711_GPIO_SIGNAL_OUT:
0077     case AS3711_GPIO_SIGNAL_IN:
0078     case AS3711_SD_CONTROL_1:
0079     case AS3711_SD_CONTROL_2:
0080     case AS3711_CURR_CONTROL:
0081     case AS3711_CURR1_VALUE:
0082     case AS3711_CURR2_VALUE:
0083     case AS3711_CURR3_VALUE:
0084     case AS3711_STEPUP_CONTROL_1:
0085     case AS3711_STEPUP_CONTROL_2:
0086     case AS3711_STEPUP_CONTROL_4:
0087     case AS3711_STEPUP_CONTROL_5:
0088     case AS3711_REG_STATUS:
0089     case AS3711_INTERRUPT_STATUS_1:
0090     case AS3711_INTERRUPT_STATUS_2:
0091     case AS3711_INTERRUPT_STATUS_3:
0092     case AS3711_CHARGER_STATUS_1:
0093     case AS3711_CHARGER_STATUS_2:
0094     case AS3711_ASIC_ID_1:
0095     case AS3711_ASIC_ID_2:
0096         return true;
0097     }
0098     return false;
0099 }
0100 
0101 static const struct regmap_config as3711_regmap_config = {
0102     .reg_bits = 8,
0103     .val_bits = 8,
0104     .volatile_reg = as3711_volatile_reg,
0105     .readable_reg = as3711_readable_reg,
0106     .precious_reg = as3711_precious_reg,
0107     .max_register = AS3711_MAX_REG,
0108     .num_reg_defaults_raw = AS3711_NUM_REGS,
0109     .cache_type = REGCACHE_RBTREE,
0110 };
0111 
0112 #ifdef CONFIG_OF
0113 static const struct of_device_id as3711_of_match[] = {
0114     {.compatible = "ams,as3711",},
0115     {}
0116 };
0117 #endif
0118 
0119 static int as3711_i2c_probe(struct i2c_client *client,
0120                 const struct i2c_device_id *id)
0121 {
0122     struct as3711 *as3711;
0123     struct as3711_platform_data *pdata;
0124     unsigned int id1, id2;
0125     int ret;
0126 
0127     if (!client->dev.of_node) {
0128         pdata = dev_get_platdata(&client->dev);
0129         if (!pdata)
0130             dev_dbg(&client->dev, "Platform data not found\n");
0131     } else {
0132         pdata = devm_kzalloc(&client->dev,
0133                      sizeof(*pdata), GFP_KERNEL);
0134         if (!pdata)
0135             return -ENOMEM;
0136     }
0137 
0138     as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL);
0139     if (!as3711)
0140         return -ENOMEM;
0141 
0142     as3711->dev = &client->dev;
0143     i2c_set_clientdata(client, as3711);
0144 
0145     if (client->irq)
0146         dev_notice(&client->dev, "IRQ not supported yet\n");
0147 
0148     as3711->regmap = devm_regmap_init_i2c(client, &as3711_regmap_config);
0149     if (IS_ERR(as3711->regmap)) {
0150         ret = PTR_ERR(as3711->regmap);
0151         dev_err(&client->dev,
0152             "regmap initialization failed: %d\n", ret);
0153         return ret;
0154     }
0155 
0156     ret = regmap_read(as3711->regmap, AS3711_ASIC_ID_1, &id1);
0157     if (!ret)
0158         ret = regmap_read(as3711->regmap, AS3711_ASIC_ID_2, &id2);
0159     if (ret < 0) {
0160         dev_err(&client->dev, "regmap_read() failed: %d\n", ret);
0161         return ret;
0162     }
0163     if (id1 != 0x8b)
0164         return -ENODEV;
0165     dev_info(as3711->dev, "AS3711 detected: %x:%x\n", id1, id2);
0166 
0167     /*
0168      * We can reuse as3711_subdevs[],
0169      * it will be copied in mfd_add_devices()
0170      */
0171     if (pdata) {
0172         as3711_subdevs[AS3711_REGULATOR].platform_data =
0173             &pdata->regulator;
0174         as3711_subdevs[AS3711_REGULATOR].pdata_size =
0175             sizeof(pdata->regulator);
0176         as3711_subdevs[AS3711_BACKLIGHT].platform_data =
0177             &pdata->backlight;
0178         as3711_subdevs[AS3711_BACKLIGHT].pdata_size =
0179             sizeof(pdata->backlight);
0180     } else {
0181         as3711_subdevs[AS3711_REGULATOR].platform_data = NULL;
0182         as3711_subdevs[AS3711_REGULATOR].pdata_size = 0;
0183         as3711_subdevs[AS3711_BACKLIGHT].platform_data = NULL;
0184         as3711_subdevs[AS3711_BACKLIGHT].pdata_size = 0;
0185     }
0186 
0187     ret = devm_mfd_add_devices(as3711->dev, -1, as3711_subdevs,
0188                    ARRAY_SIZE(as3711_subdevs), NULL, 0, NULL);
0189     if (ret < 0)
0190         dev_err(&client->dev, "add mfd devices failed: %d\n", ret);
0191 
0192     return ret;
0193 }
0194 
0195 static const struct i2c_device_id as3711_i2c_id[] = {
0196     {.name = "as3711", .driver_data = 0},
0197     {}
0198 };
0199 
0200 static struct i2c_driver as3711_i2c_driver = {
0201     .driver = {
0202            .name = "as3711",
0203            .of_match_table = of_match_ptr(as3711_of_match),
0204     },
0205     .probe = as3711_i2c_probe,
0206     .id_table = as3711_i2c_id,
0207 };
0208 
0209 static int __init as3711_i2c_init(void)
0210 {
0211     return i2c_add_driver(&as3711_i2c_driver);
0212 }
0213 /* Initialise early */
0214 subsys_initcall(as3711_i2c_init);