brintos

brintos / linux-shallow public Read only

0
0
Text · 7.1 KiB · 1e107fd Raw
262 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Author: Dan Scally <djrscally@gmail.com> */3 4#include <linux/acpi.h>5#include <linux/i2c.h>6#include <linux/kernel.h>7#include <linux/mfd/core.h>8#include <linux/mfd/tps68470.h>9#include <linux/platform_device.h>10#include <linux/platform_data/tps68470.h>11#include <linux/regmap.h>12#include <linux/string.h>13 14#include "common.h"15#include "tps68470.h"16 17#define DESIGNED_FOR_CHROMEOS		118#define DESIGNED_FOR_WINDOWS		219 20#define TPS68470_WIN_MFD_CELL_COUNT	321 22static const struct mfd_cell tps68470_cros[] = {23	{ .name = "tps68470-gpio" },24	{ .name = "tps68470_pmic_opregion" },25};26 27static const struct regmap_config tps68470_regmap_config = {28	.reg_bits = 8,29	.val_bits = 8,30	.max_register = TPS68470_REG_MAX,31};32 33static int tps68470_chip_init(struct device *dev, struct regmap *regmap)34{35	unsigned int version;36	int ret;37 38	/* Force software reset */39	ret = regmap_write(regmap, TPS68470_REG_RESET, TPS68470_REG_RESET_MASK);40	if (ret)41		return ret;42 43	ret = regmap_read(regmap, TPS68470_REG_REVID, &version);44	if (ret) {45		dev_err(dev, "Failed to read revision register: %d\n", ret);46		return ret;47	}48 49	dev_info(dev, "TPS68470 REVID: 0x%02x\n", version);50 51	return 0;52}53 54/** skl_int3472_tps68470_calc_type: Check what platform a device is designed for55 * @adev: A pointer to a &struct acpi_device56 *57 * Check CLDB buffer against the PMIC's adev. If present, then we check58 * the value of control_logic_type field and follow one of the59 * following scenarios:60 *61 *	1. No CLDB - likely ACPI tables designed for ChromeOS. We62 *	create platform devices for the GPIOs and OpRegion drivers.63 *64 *	2. CLDB, with control_logic_type = 2 - probably ACPI tables65 *	made for Windows 2-in-1 platforms. Register pdevs for GPIO,66 *	Clock and Regulator drivers to bind to.67 *68 *	3. Any other value in control_logic_type, we should never have69 *	gotten to this point; fail probe and return.70 *71 * Return:72 * * 1		Device intended for ChromeOS73 * * 2		Device intended for Windows74 * * -EINVAL	Where @adev has an object named CLDB but it does not conform to75 *		our expectations76 */77static int skl_int3472_tps68470_calc_type(struct acpi_device *adev)78{79	struct int3472_cldb cldb = { 0 };80	int ret;81 82	/*83	 * A CLDB buffer that exists, but which does not match our expectations84	 * should trigger an error so we don't blindly continue.85	 */86	ret = skl_int3472_fill_cldb(adev, &cldb);87	if (ret && ret != -ENODEV)88		return ret;89 90	if (ret)91		return DESIGNED_FOR_CHROMEOS;92 93	if (cldb.control_logic_type != 2)94		return -EINVAL;95 96	return DESIGNED_FOR_WINDOWS;97}98 99/*100 * Return the size of the flexible array member, because we'll need that later101 * on to pass .pdata_size to cells.102 */103static int104skl_int3472_fill_clk_pdata(struct device *dev, struct tps68470_clk_platform_data **clk_pdata)105{106	struct acpi_device *adev = ACPI_COMPANION(dev);107	struct acpi_device *consumer;108	unsigned int n_consumers = 0;109	const char *sensor_name;110	unsigned int i = 0;111 112	for_each_acpi_consumer_dev(adev, consumer)113		n_consumers++;114 115	if (!n_consumers) {116		dev_err(dev, "INT3472 seems to have no dependents\n");117		return -ENODEV;118	}119 120	*clk_pdata = devm_kzalloc(dev, struct_size(*clk_pdata, consumers, n_consumers),121				  GFP_KERNEL);122	if (!*clk_pdata)123		return -ENOMEM;124 125	(*clk_pdata)->n_consumers = n_consumers;126	i = 0;127 128	for_each_acpi_consumer_dev(adev, consumer) {129		sensor_name = devm_kasprintf(dev, GFP_KERNEL, I2C_DEV_NAME_FORMAT,130					     acpi_dev_name(consumer));131		if (!sensor_name) {132			acpi_dev_put(consumer);133			return -ENOMEM;134		}135 136		(*clk_pdata)->consumers[i].consumer_dev_name = sensor_name;137		i++;138	}139 140	return n_consumers;141}142 143static int skl_int3472_tps68470_probe(struct i2c_client *client)144{145	struct acpi_device *adev = ACPI_COMPANION(&client->dev);146	const struct int3472_tps68470_board_data *board_data;147	struct tps68470_clk_platform_data *clk_pdata;148	struct mfd_cell *cells;149	struct regmap *regmap;150	int n_consumers;151	int device_type;152	int ret;153	int i;154 155	n_consumers = skl_int3472_fill_clk_pdata(&client->dev, &clk_pdata);156	if (n_consumers < 0)157		return n_consumers;158 159	regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);160	if (IS_ERR(regmap)) {161		dev_err(&client->dev, "Failed to create regmap: %ld\n", PTR_ERR(regmap));162		return PTR_ERR(regmap);163	}164 165	i2c_set_clientdata(client, regmap);166 167	ret = tps68470_chip_init(&client->dev, regmap);168	if (ret < 0) {169		dev_err(&client->dev, "TPS68470 init error %d\n", ret);170		return ret;171	}172 173	device_type = skl_int3472_tps68470_calc_type(adev);174	switch (device_type) {175	case DESIGNED_FOR_WINDOWS:176		board_data = int3472_tps68470_get_board_data(dev_name(&client->dev));177		if (!board_data)178			return dev_err_probe(&client->dev, -ENODEV, "No board-data found for this model\n");179 180		cells = kcalloc(TPS68470_WIN_MFD_CELL_COUNT, sizeof(*cells), GFP_KERNEL);181		if (!cells)182			return -ENOMEM;183 184		/*185		 * The order of the cells matters here! The clk must be first186		 * because the regulator depends on it. The gpios must be last,187		 * acpi_gpiochip_add() calls acpi_dev_clear_dependencies() and188		 * the clk + regulators must be ready when this happens.189		 */190		cells[0].name = "tps68470-clk";191		cells[0].platform_data = clk_pdata;192		cells[0].pdata_size = struct_size(clk_pdata, consumers, n_consumers);193		cells[1].name = "tps68470-regulator";194		cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata;195		cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data);196		cells[2].name = "tps68470-gpio";197 198		for (i = 0; i < board_data->n_gpiod_lookups; i++)199			gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]);200 201		ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,202					   cells, TPS68470_WIN_MFD_CELL_COUNT,203					   NULL, 0, NULL);204		kfree(cells);205 206		if (ret) {207			for (i = 0; i < board_data->n_gpiod_lookups; i++)208				gpiod_remove_lookup_table(board_data->tps68470_gpio_lookup_tables[i]);209		}210 211		break;212	case DESIGNED_FOR_CHROMEOS:213		ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,214					   tps68470_cros, ARRAY_SIZE(tps68470_cros),215					   NULL, 0, NULL);216		break;217	default:218		dev_err(&client->dev, "Failed to add MFD devices\n");219		return device_type;220	}221 222	/*223	 * No acpi_dev_clear_dependencies() here, since the acpi_gpiochip_add()224	 * for the GPIO cell already does this.225	 */226 227	return ret;228}229 230static void skl_int3472_tps68470_remove(struct i2c_client *client)231{232	const struct int3472_tps68470_board_data *board_data;233	int i;234 235	board_data = int3472_tps68470_get_board_data(dev_name(&client->dev));236	if (board_data) {237		for (i = 0; i < board_data->n_gpiod_lookups; i++)238			gpiod_remove_lookup_table(board_data->tps68470_gpio_lookup_tables[i]);239	}240}241 242static const struct acpi_device_id int3472_device_id[] = {243	{ "INT3472", 0 },244	{ }245};246MODULE_DEVICE_TABLE(acpi, int3472_device_id);247 248static struct i2c_driver int3472_tps68470 = {249	.driver = {250		.name = "int3472-tps68470",251		.acpi_match_table = int3472_device_id,252	},253	.probe = skl_int3472_tps68470_probe,254	.remove = skl_int3472_tps68470_remove,255};256module_i2c_driver(int3472_tps68470);257 258MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI TPS68470 Device Driver");259MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>");260MODULE_LICENSE("GPL v2");261MODULE_SOFTDEP("pre: clk-tps68470 tps68470-regulator");262