1 /* 2 * AS3711 PMIC MFC driver 3 * 4 * Copyright (C) 2012 Renesas Electronics Corporation 5 * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the version 2 of the GNU General Public License as 9 * published by the Free Software Foundation 10 */ 11 12 #include <linux/device.h> 13 #include <linux/err.h> 14 #include <linux/i2c.h> 15 #include <linux/init.h> 16 #include <linux/kernel.h> 17 #include <linux/mfd/as3711.h> 18 #include <linux/mfd/core.h> 19 #include <linux/of.h> 20 #include <linux/regmap.h> 21 #include <linux/slab.h> 22 23 enum { 24 AS3711_REGULATOR, 25 AS3711_BACKLIGHT, 26 }; 27 28 /* 29 * Ok to have it static: it is only used during probing and multiple I2C devices 30 * cannot be probed simultaneously. Just make sure to avoid stale data. 31 */ 32 static struct mfd_cell as3711_subdevs[] = { 33 [AS3711_REGULATOR] = {.name = "as3711-regulator",}, 34 [AS3711_BACKLIGHT] = {.name = "as3711-backlight",}, 35 }; 36 37 static bool as3711_volatile_reg(struct device *dev, unsigned int reg) 38 { 39 switch (reg) { 40 case AS3711_GPIO_SIGNAL_IN: 41 case AS3711_INTERRUPT_STATUS_1: 42 case AS3711_INTERRUPT_STATUS_2: 43 case AS3711_INTERRUPT_STATUS_3: 44 case AS3711_CHARGER_STATUS_1: 45 case AS3711_CHARGER_STATUS_2: 46 case AS3711_REG_STATUS: 47 return true; 48 } 49 return false; 50 } 51 52 static bool as3711_precious_reg(struct device *dev, unsigned int reg) 53 { 54 switch (reg) { 55 case AS3711_INTERRUPT_STATUS_1: 56 case AS3711_INTERRUPT_STATUS_2: 57 case AS3711_INTERRUPT_STATUS_3: 58 return true; 59 } 60 return false; 61 } 62 63 static bool as3711_readable_reg(struct device *dev, unsigned int reg) 64 { 65 switch (reg) { 66 case AS3711_SD_1_VOLTAGE: 67 case AS3711_SD_2_VOLTAGE: 68 case AS3711_SD_3_VOLTAGE: 69 case AS3711_SD_4_VOLTAGE: 70 case AS3711_LDO_1_VOLTAGE: 71 case AS3711_LDO_2_VOLTAGE: 72 case AS3711_LDO_3_VOLTAGE: 73 case AS3711_LDO_4_VOLTAGE: 74 case AS3711_LDO_5_VOLTAGE: 75 case AS3711_LDO_6_VOLTAGE: 76 case AS3711_LDO_7_VOLTAGE: 77 case AS3711_LDO_8_VOLTAGE: 78 case AS3711_SD_CONTROL: 79 case AS3711_GPIO_SIGNAL_OUT: 80 case AS3711_GPIO_SIGNAL_IN: 81 case AS3711_SD_CONTROL_1: 82 case AS3711_SD_CONTROL_2: 83 case AS3711_CURR_CONTROL: 84 case AS3711_CURR1_VALUE: 85 case AS3711_CURR2_VALUE: 86 case AS3711_CURR3_VALUE: 87 case AS3711_STEPUP_CONTROL_1: 88 case AS3711_STEPUP_CONTROL_2: 89 case AS3711_STEPUP_CONTROL_4: 90 case AS3711_STEPUP_CONTROL_5: 91 case AS3711_REG_STATUS: 92 case AS3711_INTERRUPT_STATUS_1: 93 case AS3711_INTERRUPT_STATUS_2: 94 case AS3711_INTERRUPT_STATUS_3: 95 case AS3711_CHARGER_STATUS_1: 96 case AS3711_CHARGER_STATUS_2: 97 case AS3711_ASIC_ID_1: 98 case AS3711_ASIC_ID_2: 99 return true; 100 } 101 return false; 102 } 103 104 static const struct regmap_config as3711_regmap_config = { 105 .reg_bits = 8, 106 .val_bits = 8, 107 .volatile_reg = as3711_volatile_reg, 108 .readable_reg = as3711_readable_reg, 109 .precious_reg = as3711_precious_reg, 110 .max_register = AS3711_MAX_REG, 111 .num_reg_defaults_raw = AS3711_NUM_REGS, 112 .cache_type = REGCACHE_RBTREE, 113 }; 114 115 #ifdef CONFIG_OF 116 static const struct of_device_id as3711_of_match[] = { 117 {.compatible = "ams,as3711",}, 118 {} 119 }; 120 #endif 121 122 static int as3711_i2c_probe(struct i2c_client *client, 123 const struct i2c_device_id *id) 124 { 125 struct as3711 *as3711; 126 struct as3711_platform_data *pdata; 127 unsigned int id1, id2; 128 int ret; 129 130 if (!client->dev.of_node) { 131 pdata = dev_get_platdata(&client->dev); 132 if (!pdata) 133 dev_dbg(&client->dev, "Platform data not found\n"); 134 } else { 135 pdata = devm_kzalloc(&client->dev, 136 sizeof(*pdata), GFP_KERNEL); 137 if (!pdata) 138 return -ENOMEM; 139 } 140 141 as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL); 142 if (!as3711) 143 return -ENOMEM; 144 145 as3711->dev = &client->dev; 146 i2c_set_clientdata(client, as3711); 147 148 if (client->irq) 149 dev_notice(&client->dev, "IRQ not supported yet\n"); 150 151 as3711->regmap = devm_regmap_init_i2c(client, &as3711_regmap_config); 152 if (IS_ERR(as3711->regmap)) { 153 ret = PTR_ERR(as3711->regmap); 154 dev_err(&client->dev, 155 "regmap initialization failed: %d\n", ret); 156 return ret; 157 } 158 159 ret = regmap_read(as3711->regmap, AS3711_ASIC_ID_1, &id1); 160 if (!ret) 161 ret = regmap_read(as3711->regmap, AS3711_ASIC_ID_2, &id2); 162 if (ret < 0) { 163 dev_err(&client->dev, "regmap_read() failed: %d\n", ret); 164 return ret; 165 } 166 if (id1 != 0x8b) 167 return -ENODEV; 168 dev_info(as3711->dev, "AS3711 detected: %x:%x\n", id1, id2); 169 170 /* 171 * We can reuse as3711_subdevs[], 172 * it will be copied in mfd_add_devices() 173 */ 174 if (pdata) { 175 as3711_subdevs[AS3711_REGULATOR].platform_data = 176 &pdata->regulator; 177 as3711_subdevs[AS3711_REGULATOR].pdata_size = 178 sizeof(pdata->regulator); 179 as3711_subdevs[AS3711_BACKLIGHT].platform_data = 180 &pdata->backlight; 181 as3711_subdevs[AS3711_BACKLIGHT].pdata_size = 182 sizeof(pdata->backlight); 183 } else { 184 as3711_subdevs[AS3711_REGULATOR].platform_data = NULL; 185 as3711_subdevs[AS3711_REGULATOR].pdata_size = 0; 186 as3711_subdevs[AS3711_BACKLIGHT].platform_data = NULL; 187 as3711_subdevs[AS3711_BACKLIGHT].pdata_size = 0; 188 } 189 190 ret = devm_mfd_add_devices(as3711->dev, -1, as3711_subdevs, 191 ARRAY_SIZE(as3711_subdevs), NULL, 0, NULL); 192 if (ret < 0) 193 dev_err(&client->dev, "add mfd devices failed: %d\n", ret); 194 195 return ret; 196 } 197 198 static const struct i2c_device_id as3711_i2c_id[] = { 199 {.name = "as3711", .driver_data = 0}, 200 {} 201 }; 202 203 static struct i2c_driver as3711_i2c_driver = { 204 .driver = { 205 .name = "as3711", 206 .of_match_table = of_match_ptr(as3711_of_match), 207 }, 208 .probe = as3711_i2c_probe, 209 .id_table = as3711_i2c_id, 210 }; 211 212 static int __init as3711_i2c_init(void) 213 { 214 return i2c_add_driver(&as3711_i2c_driver); 215 } 216 /* Initialise early */ 217 subsys_initcall(as3711_i2c_init); 218