brintos

brintos / linux-shallow public Read only

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