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