Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Author: Dan Scally <djrscally@gmail.com> */
  3
  4#include <linux/i2c.h>
  5#include <linux/mfd/core.h>
  6#include <linux/mfd/tps68470.h>
  7#include <linux/platform_device.h>
  8#include <linux/regmap.h>
  9
 10#include "intel_skl_int3472_common.h"
 11
 12#define DESIGNED_FOR_CHROMEOS		1
 13#define DESIGNED_FOR_WINDOWS		2
 14
 15static const struct mfd_cell tps68470_cros[] = {
 16	{ .name = "tps68470-gpio" },
 17	{ .name = "tps68470_pmic_opregion" },
 18};
 19
 20static const struct mfd_cell tps68470_win[] = {
 21	{ .name = "tps68470-gpio" },
 22	{ .name = "tps68470-clk" },
 23	{ .name = "tps68470-regulator" },
 24};
 25
 26static const struct regmap_config tps68470_regmap_config = {
 27	.reg_bits = 8,
 28	.val_bits = 8,
 29	.max_register = TPS68470_REG_MAX,
 30};
 31
 32static int tps68470_chip_init(struct device *dev, struct regmap *regmap)
 33{
 34	unsigned int version;
 35	int ret;
 36
 37	/* Force software reset */
 38	ret = regmap_write(regmap, TPS68470_REG_RESET, TPS68470_REG_RESET_MASK);
 39	if (ret)
 40		return ret;
 41
 42	ret = regmap_read(regmap, TPS68470_REG_REVID, &version);
 43	if (ret) {
 44		dev_err(dev, "Failed to read revision register: %d\n", ret);
 45		return ret;
 46	}
 47
 48	dev_info(dev, "TPS68470 REVID: 0x%02x\n", version);
 49
 50	return 0;
 51}
 52
 53/** skl_int3472_tps68470_calc_type: Check what platform a device is designed for
 54 * @adev: A pointer to a &struct acpi_device
 55 *
 56 * Check CLDB buffer against the PMIC's adev. If present, then we check
 57 * the value of control_logic_type field and follow one of the
 58 * following scenarios:
 59 *
 60 *	1. No CLDB - likely ACPI tables designed for ChromeOS. We
 61 *	create platform devices for the GPIOs and OpRegion drivers.
 62 *
 63 *	2. CLDB, with control_logic_type = 2 - probably ACPI tables
 64 *	made for Windows 2-in-1 platforms. Register pdevs for GPIO,
 65 *	Clock and Regulator drivers to bind to.
 66 *
 67 *	3. Any other value in control_logic_type, we should never have
 68 *	gotten to this point; fail probe and return.
 69 *
 70 * Return:
 71 * * 1		Device intended for ChromeOS
 72 * * 2		Device intended for Windows
 73 * * -EINVAL	Where @adev has an object named CLDB but it does not conform to
 74 *		our expectations
 75 */
 76static int skl_int3472_tps68470_calc_type(struct acpi_device *adev)
 77{
 78	struct int3472_cldb cldb = { 0 };
 79	int ret;
 80
 81	/*
 82	 * A CLDB buffer that exists, but which does not match our expectations
 83	 * should trigger an error so we don't blindly continue.
 84	 */
 85	ret = skl_int3472_fill_cldb(adev, &cldb);
 86	if (ret && ret != -ENODEV)
 87		return ret;
 88
 89	if (ret)
 90		return DESIGNED_FOR_CHROMEOS;
 91
 92	if (cldb.control_logic_type != 2)
 93		return -EINVAL;
 94
 95	return DESIGNED_FOR_WINDOWS;
 96}
 97
 98int skl_int3472_tps68470_probe(struct i2c_client *client)
 99{
100	struct acpi_device *adev = ACPI_COMPANION(&client->dev);
101	struct regmap *regmap;
102	int device_type;
103	int ret;
104
105	regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
106	if (IS_ERR(regmap)) {
107		dev_err(&client->dev, "Failed to create regmap: %ld\n", PTR_ERR(regmap));
108		return PTR_ERR(regmap);
109	}
110
111	i2c_set_clientdata(client, regmap);
112
113	ret = tps68470_chip_init(&client->dev, regmap);
114	if (ret < 0) {
115		dev_err(&client->dev, "TPS68470 init error %d\n", ret);
116		return ret;
117	}
118
119	device_type = skl_int3472_tps68470_calc_type(adev);
120	switch (device_type) {
121	case DESIGNED_FOR_WINDOWS:
122		ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
123					   tps68470_win, ARRAY_SIZE(tps68470_win),
124					   NULL, 0, NULL);
125		break;
126	case DESIGNED_FOR_CHROMEOS:
127		ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
128					   tps68470_cros, ARRAY_SIZE(tps68470_cros),
129					   NULL, 0, NULL);
130		break;
131	default:
132		dev_err(&client->dev, "Failed to add MFD devices\n");
133		return device_type;
134	}
135
136	return ret;
137}