Signed tag for the immutable platform-drivers-x86-int3472 branch
This branch contains 5.16-rc1 + the pending ACPI/i2c, tps68570 platform_data and INT3472 driver patches. -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEEuvA7XScYQRpenhd+kuxHeUQDJ9wFAmG6YLQUHGhkZWdvZWRl QHJlZGhhdC5jb20ACgkQkuxHeUQDJ9zwGwf8Csb4wXyc3duBlnX/9jO9REDVKTN9 HhmU2KQm29g10dN2nlFXEOG16xAy8zt3BE7QwniL/R5sUsKTCAEugY8Aqq/4+lFA vTU+YR9YqZFmEDGMfDngHeh9ZvSWIJS7IEXthxCkgGVhrd2Wl50jKTjVyq1RIDKv a7B4fOhguFv95xRlnXK+yoVUU7zZPWAgxyCqV0E0JEi8aWE8Y483IRCzcDEyJeDa HkgZLVwD9l3WQ4uZllVg1q5jfSprHwBa8dFxgcd6mOOYaKowiJ+GjnvnXOto5X72 zsODBJH15VzfVXF5cAqIvzN6nAFR8Mxieei+21iFyUD/Ps1vfWlodFHH2w== =Q1N9 -----END PGP SIGNATURE----- Merge tag 'platform-drivers-x86-int3472-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86 into media_tree Signed tag for the immutable platform-drivers-x86-int3472 branch This branch contains 5.16-rc1 + the pending ACPI/i2c, tps68570 platform_data and INT3472 driver patches. * tag 'platform-drivers-x86-int3472-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: platform/x86: int3472: Deal with probe ordering issues platform/x86: int3472: Pass tps68470_regulator_platform_data to the tps68470-regulator MFD-cell platform/x86: int3472: Pass tps68470_clk_platform_data to the tps68470-regulator MFD-cell platform/x86: int3472: Add get_sensor_adev_and_name() helper platform/x86: int3472: Split into 2 drivers platform_data: Add linux/platform_data/tps68470.h file i2c: acpi: Add i2c_acpi_new_device_by_fwnode() function i2c: acpi: Use acpi_dev_ready_for_enumeration() helper ACPI: delay enumeration of devices with a _DEP pointing to an INT3472 device
This commit is contained in:
commit
3a956f0b12
|
@ -797,6 +797,12 @@ static const char * const acpi_ignore_dep_ids[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
/* List of HIDs for which we honor deps of matching ACPI devs, when checking _DEP lists. */
|
||||
static const char * const acpi_honor_dep_ids[] = {
|
||||
"INT3472", /* Camera sensor PMIC / clk and regulator info */
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct acpi_device *acpi_bus_get_parent(acpi_handle handle)
|
||||
{
|
||||
struct acpi_device *device = NULL;
|
||||
|
@ -1762,8 +1768,12 @@ static void acpi_scan_dep_init(struct acpi_device *adev)
|
|||
struct acpi_dep_data *dep;
|
||||
|
||||
list_for_each_entry(dep, &acpi_dep_list, node) {
|
||||
if (dep->consumer == adev->handle)
|
||||
if (dep->consumer == adev->handle) {
|
||||
if (dep->honor_dep)
|
||||
adev->flags.honor_deps = 1;
|
||||
|
||||
adev->dep_unmet++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1967,7 +1977,7 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
|
|||
for (count = 0, i = 0; i < dep_devices.count; i++) {
|
||||
struct acpi_device_info *info;
|
||||
struct acpi_dep_data *dep;
|
||||
bool skip;
|
||||
bool skip, honor_dep;
|
||||
|
||||
status = acpi_get_object_info(dep_devices.handles[i], &info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
@ -1976,6 +1986,7 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
|
|||
}
|
||||
|
||||
skip = acpi_info_matches_ids(info, acpi_ignore_dep_ids);
|
||||
honor_dep = acpi_info_matches_ids(info, acpi_honor_dep_ids);
|
||||
kfree(info);
|
||||
|
||||
if (skip)
|
||||
|
@ -1989,6 +2000,7 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
|
|||
|
||||
dep->supplier = dep_devices.handles[i];
|
||||
dep->consumer = handle;
|
||||
dep->honor_dep = honor_dep;
|
||||
|
||||
mutex_lock(&acpi_dep_list_lock);
|
||||
list_add_tail(&dep->node , &acpi_dep_list);
|
||||
|
@ -2155,8 +2167,8 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
|
|||
register_dock_dependent_device(device, ejd);
|
||||
|
||||
acpi_bus_get_status(device);
|
||||
/* Skip devices that are not present. */
|
||||
if (!acpi_device_is_present(device)) {
|
||||
/* Skip devices that are not ready for enumeration (e.g. not present) */
|
||||
if (!acpi_dev_ready_for_enumeration(device)) {
|
||||
device->flags.initialized = false;
|
||||
acpi_device_clear_enumerated(device);
|
||||
device->flags.power_manageable = 0;
|
||||
|
@ -2318,6 +2330,23 @@ void acpi_dev_clear_dependencies(struct acpi_device *supplier)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_dev_clear_dependencies);
|
||||
|
||||
/**
|
||||
* acpi_dev_ready_for_enumeration - Check if the ACPI device is ready for enumeration
|
||||
* @device: Pointer to the &struct acpi_device to check
|
||||
*
|
||||
* Check if the device is present and has no unmet dependencies.
|
||||
*
|
||||
* Return true if the device is ready for enumeratino. Otherwise, return false.
|
||||
*/
|
||||
bool acpi_dev_ready_for_enumeration(const struct acpi_device *device)
|
||||
{
|
||||
if (device->flags.honor_deps && device->dep_unmet)
|
||||
return false;
|
||||
|
||||
return acpi_device_is_present(device);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_dev_ready_for_enumeration);
|
||||
|
||||
/**
|
||||
* acpi_dev_get_first_consumer_dev - Return ACPI device dependent on @supplier
|
||||
* @supplier: Pointer to the dependee device
|
||||
|
|
|
@ -144,9 +144,12 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev,
|
|||
struct list_head resource_list;
|
||||
int ret;
|
||||
|
||||
if (acpi_bus_get_status(adev) || !adev->status.present)
|
||||
if (acpi_bus_get_status(adev))
|
||||
return -EINVAL;
|
||||
|
||||
if (!acpi_dev_ready_for_enumeration(adev))
|
||||
return -ENODEV;
|
||||
|
||||
if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0)
|
||||
return -ENODEV;
|
||||
|
||||
|
@ -473,8 +476,8 @@ struct notifier_block i2c_acpi_notifier = {
|
|||
};
|
||||
|
||||
/**
|
||||
* i2c_acpi_new_device - Create i2c-client for the Nth I2cSerialBus resource
|
||||
* @dev: Device owning the ACPI resources to get the client from
|
||||
* i2c_acpi_new_device_by_fwnode - Create i2c-client for the Nth I2cSerialBus resource
|
||||
* @fwnode: fwnode with the ACPI resources to get the client from
|
||||
* @index: Index of ACPI resource to get
|
||||
* @info: describes the I2C device; note this is modified (addr gets set)
|
||||
* Context: can sleep
|
||||
|
@ -490,15 +493,20 @@ struct notifier_block i2c_acpi_notifier = {
|
|||
* Returns a pointer to the new i2c-client, or error pointer in case of failure.
|
||||
* Specifically, -EPROBE_DEFER is returned if the adapter is not found.
|
||||
*/
|
||||
struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
|
||||
struct i2c_board_info *info)
|
||||
struct i2c_client *i2c_acpi_new_device_by_fwnode(struct fwnode_handle *fwnode,
|
||||
int index,
|
||||
struct i2c_board_info *info)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
struct i2c_acpi_lookup lookup;
|
||||
struct i2c_adapter *adapter;
|
||||
struct acpi_device *adev;
|
||||
LIST_HEAD(resource_list);
|
||||
int ret;
|
||||
|
||||
adev = to_acpi_device_node(fwnode);
|
||||
if (!adev)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
memset(&lookup, 0, sizeof(lookup));
|
||||
lookup.info = info;
|
||||
lookup.device_handle = acpi_device_handle(adev);
|
||||
|
@ -520,7 +528,7 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
|
|||
|
||||
return i2c_new_client_device(adapter, info);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
|
||||
EXPORT_SYMBOL_GPL(i2c_acpi_new_device_by_fwnode);
|
||||
|
||||
bool i2c_acpi_waive_d0_probe(struct device *dev)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472.o
|
||||
intel_skl_int3472-y := intel_skl_int3472_common.o \
|
||||
intel_skl_int3472_discrete.o \
|
||||
intel_skl_int3472_tps68470.o \
|
||||
intel_skl_int3472_clk_and_regulator.o
|
||||
obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472_discrete.o \
|
||||
intel_skl_int3472_tps68470.o
|
||||
intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o common.o
|
||||
intel_skl_int3472_tps68470-y := tps68470.o tps68470_board_data.o common.o
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <linux/regulator/driver.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "intel_skl_int3472_common.h"
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* The regulators have to have .ops to be valid, but the only ops we actually
|
|
@ -0,0 +1,82 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Author: Dan Scally <djrscally@gmail.com> */
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev, char *id)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
acpi_handle handle = adev->handle;
|
||||
union acpi_object *obj;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_evaluate_object(handle, id, NULL, &buffer);
|
||||
if (ACPI_FAILURE(status))
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
obj = buffer.pointer;
|
||||
if (!obj)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
acpi_handle_err(handle, "%s object is not an ACPI buffer\n", id);
|
||||
kfree(obj);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb)
|
||||
{
|
||||
union acpi_object *obj;
|
||||
int ret;
|
||||
|
||||
obj = skl_int3472_get_acpi_buffer(adev, "CLDB");
|
||||
if (IS_ERR(obj))
|
||||
return PTR_ERR(obj);
|
||||
|
||||
if (obj->buffer.length > sizeof(*cldb)) {
|
||||
acpi_handle_err(adev->handle, "The CLDB buffer is too large\n");
|
||||
ret = -EINVAL;
|
||||
goto out_free_obj;
|
||||
}
|
||||
|
||||
memcpy(cldb, obj->buffer.pointer, obj->buffer.length);
|
||||
ret = 0;
|
||||
|
||||
out_free_obj:
|
||||
kfree(obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* sensor_adev_ret may be NULL, name_ret must not be NULL */
|
||||
int skl_int3472_get_sensor_adev_and_name(struct device *dev,
|
||||
struct acpi_device **sensor_adev_ret,
|
||||
const char **name_ret)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
struct acpi_device *sensor;
|
||||
int ret = 0;
|
||||
|
||||
sensor = acpi_dev_get_first_consumer_dev(adev);
|
||||
if (!sensor) {
|
||||
dev_err(dev, "INT3472 seems to have no dependents.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
*name_ret = devm_kasprintf(dev, GFP_KERNEL, I2C_DEV_NAME_FORMAT,
|
||||
acpi_dev_name(sensor));
|
||||
if (!*name_ret)
|
||||
ret = -ENOMEM;
|
||||
|
||||
if (ret == 0 && sensor_adev_ret)
|
||||
*sensor_adev_ret = sensor;
|
||||
else
|
||||
acpi_dev_put(sensor);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -105,12 +105,12 @@ struct int3472_discrete_device {
|
|||
struct gpiod_lookup_table gpios;
|
||||
};
|
||||
|
||||
int skl_int3472_discrete_probe(struct platform_device *pdev);
|
||||
int skl_int3472_discrete_remove(struct platform_device *pdev);
|
||||
int skl_int3472_tps68470_probe(struct i2c_client *client);
|
||||
union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev,
|
||||
char *id);
|
||||
int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb);
|
||||
int skl_int3472_get_sensor_adev_and_name(struct device *dev,
|
||||
struct acpi_device **sensor_adev_ret,
|
||||
const char **name_ret);
|
||||
|
||||
int skl_int3472_register_clock(struct int3472_discrete_device *int3472);
|
||||
void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472);
|
|
@ -14,7 +14,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/uuid.h>
|
||||
|
||||
#include "intel_skl_int3472_common.h"
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* 79234640-9e10-4fea-a5c1-b5aa8b19756f
|
||||
|
@ -332,7 +332,9 @@ static int skl_int3472_parse_crs(struct int3472_discrete_device *int3472)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int skl_int3472_discrete_probe(struct platform_device *pdev)
|
||||
static int skl_int3472_discrete_remove(struct platform_device *pdev);
|
||||
|
||||
static int skl_int3472_discrete_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
|
||||
struct int3472_discrete_device *int3472;
|
||||
|
@ -361,19 +363,10 @@ int skl_int3472_discrete_probe(struct platform_device *pdev)
|
|||
int3472->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, int3472);
|
||||
|
||||
int3472->sensor = acpi_dev_get_first_consumer_dev(adev);
|
||||
if (!int3472->sensor) {
|
||||
dev_err(&pdev->dev, "INT3472 seems to have no dependents.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int3472->sensor_name = devm_kasprintf(int3472->dev, GFP_KERNEL,
|
||||
I2C_DEV_NAME_FORMAT,
|
||||
acpi_dev_name(int3472->sensor));
|
||||
if (!int3472->sensor_name) {
|
||||
ret = -ENOMEM;
|
||||
goto err_put_sensor;
|
||||
}
|
||||
ret = skl_int3472_get_sensor_adev_and_name(&pdev->dev, &int3472->sensor,
|
||||
&int3472->sensor_name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Initialising this list means we can call gpiod_remove_lookup_table()
|
||||
|
@ -387,15 +380,11 @@ int skl_int3472_discrete_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
acpi_dev_clear_dependencies(adev);
|
||||
return 0;
|
||||
|
||||
err_put_sensor:
|
||||
acpi_dev_put(int3472->sensor);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int skl_int3472_discrete_remove(struct platform_device *pdev)
|
||||
static int skl_int3472_discrete_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct int3472_discrete_device *int3472 = platform_get_drvdata(pdev);
|
||||
|
||||
|
@ -411,3 +400,23 @@ int skl_int3472_discrete_remove(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id int3472_device_id[] = {
|
||||
{ "INT3472", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, int3472_device_id);
|
||||
|
||||
static struct platform_driver int3472_discrete = {
|
||||
.driver = {
|
||||
.name = "int3472-discrete",
|
||||
.acpi_match_table = int3472_device_id,
|
||||
},
|
||||
.probe = skl_int3472_discrete_probe,
|
||||
.remove = skl_int3472_discrete_remove,
|
||||
};
|
||||
module_platform_driver(int3472_discrete);
|
||||
|
||||
MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI Discrete Device Driver");
|
||||
MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -1,106 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Author: Dan Scally <djrscally@gmail.com> */
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "intel_skl_int3472_common.h"
|
||||
|
||||
union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev, char *id)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
acpi_handle handle = adev->handle;
|
||||
union acpi_object *obj;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_evaluate_object(handle, id, NULL, &buffer);
|
||||
if (ACPI_FAILURE(status))
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
obj = buffer.pointer;
|
||||
if (!obj)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
acpi_handle_err(handle, "%s object is not an ACPI buffer\n", id);
|
||||
kfree(obj);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb)
|
||||
{
|
||||
union acpi_object *obj;
|
||||
int ret;
|
||||
|
||||
obj = skl_int3472_get_acpi_buffer(adev, "CLDB");
|
||||
if (IS_ERR(obj))
|
||||
return PTR_ERR(obj);
|
||||
|
||||
if (obj->buffer.length > sizeof(*cldb)) {
|
||||
acpi_handle_err(adev->handle, "The CLDB buffer is too large\n");
|
||||
ret = -EINVAL;
|
||||
goto out_free_obj;
|
||||
}
|
||||
|
||||
memcpy(cldb, obj->buffer.pointer, obj->buffer.length);
|
||||
ret = 0;
|
||||
|
||||
out_free_obj:
|
||||
kfree(obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id int3472_device_id[] = {
|
||||
{ "INT3472", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, int3472_device_id);
|
||||
|
||||
static struct platform_driver int3472_discrete = {
|
||||
.driver = {
|
||||
.name = "int3472-discrete",
|
||||
.acpi_match_table = int3472_device_id,
|
||||
},
|
||||
.probe = skl_int3472_discrete_probe,
|
||||
.remove = skl_int3472_discrete_remove,
|
||||
};
|
||||
|
||||
static struct i2c_driver int3472_tps68470 = {
|
||||
.driver = {
|
||||
.name = "int3472-tps68470",
|
||||
.acpi_match_table = int3472_device_id,
|
||||
},
|
||||
.probe_new = skl_int3472_tps68470_probe,
|
||||
};
|
||||
|
||||
static int skl_int3472_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&int3472_discrete);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i2c_register_driver(THIS_MODULE, &int3472_tps68470);
|
||||
if (ret)
|
||||
platform_driver_unregister(&int3472_discrete);
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(skl_int3472_init);
|
||||
|
||||
static void skl_int3472_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&int3472_discrete);
|
||||
i2c_del_driver(&int3472_tps68470);
|
||||
}
|
||||
module_exit(skl_int3472_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI Device Driver");
|
||||
MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -2,27 +2,27 @@
|
|||
/* Author: Dan Scally <djrscally@gmail.com> */
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/tps68470.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/tps68470.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "intel_skl_int3472_common.h"
|
||||
#include "common.h"
|
||||
#include "tps68470.h"
|
||||
|
||||
#define DESIGNED_FOR_CHROMEOS 1
|
||||
#define DESIGNED_FOR_WINDOWS 2
|
||||
|
||||
#define TPS68470_WIN_MFD_CELL_COUNT 3
|
||||
|
||||
static const struct mfd_cell tps68470_cros[] = {
|
||||
{ .name = "tps68470-gpio" },
|
||||
{ .name = "tps68470_pmic_opregion" },
|
||||
};
|
||||
|
||||
static const struct mfd_cell tps68470_win[] = {
|
||||
{ .name = "tps68470-gpio" },
|
||||
{ .name = "tps68470-clk" },
|
||||
{ .name = "tps68470-regulator" },
|
||||
};
|
||||
|
||||
static const struct regmap_config tps68470_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
@ -95,13 +95,21 @@ static int skl_int3472_tps68470_calc_type(struct acpi_device *adev)
|
|||
return DESIGNED_FOR_WINDOWS;
|
||||
}
|
||||
|
||||
int skl_int3472_tps68470_probe(struct i2c_client *client)
|
||||
static int skl_int3472_tps68470_probe(struct i2c_client *client)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(&client->dev);
|
||||
const struct int3472_tps68470_board_data *board_data;
|
||||
struct tps68470_clk_platform_data clk_pdata = {};
|
||||
struct mfd_cell *cells;
|
||||
struct regmap *regmap;
|
||||
int device_type;
|
||||
int ret;
|
||||
|
||||
ret = skl_int3472_get_sensor_adev_and_name(&client->dev, NULL,
|
||||
&clk_pdata.consumer_dev_name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&client->dev, "Failed to create regmap: %ld\n", PTR_ERR(regmap));
|
||||
|
@ -119,9 +127,38 @@ int skl_int3472_tps68470_probe(struct i2c_client *client)
|
|||
device_type = skl_int3472_tps68470_calc_type(adev);
|
||||
switch (device_type) {
|
||||
case DESIGNED_FOR_WINDOWS:
|
||||
board_data = int3472_tps68470_get_board_data(dev_name(&client->dev));
|
||||
if (!board_data)
|
||||
return dev_err_probe(&client->dev, -ENODEV, "No board-data found for this model\n");
|
||||
|
||||
cells = kcalloc(TPS68470_WIN_MFD_CELL_COUNT, sizeof(*cells), GFP_KERNEL);
|
||||
if (!cells)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* The order of the cells matters here! The clk must be first
|
||||
* because the regulator depends on it. The gpios must be last,
|
||||
* acpi_gpiochip_add() calls acpi_dev_clear_dependencies() and
|
||||
* the clk + regulators must be ready when this happens.
|
||||
*/
|
||||
cells[0].name = "tps68470-clk";
|
||||
cells[0].platform_data = &clk_pdata;
|
||||
cells[0].pdata_size = sizeof(clk_pdata);
|
||||
cells[1].name = "tps68470-regulator";
|
||||
cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata;
|
||||
cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data);
|
||||
cells[2].name = "tps68470-gpio";
|
||||
|
||||
gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_table);
|
||||
|
||||
ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
|
||||
tps68470_win, ARRAY_SIZE(tps68470_win),
|
||||
cells, TPS68470_WIN_MFD_CELL_COUNT,
|
||||
NULL, 0, NULL);
|
||||
kfree(cells);
|
||||
|
||||
if (ret)
|
||||
gpiod_remove_lookup_table(board_data->tps68470_gpio_lookup_table);
|
||||
|
||||
break;
|
||||
case DESIGNED_FOR_CHROMEOS:
|
||||
ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
|
||||
|
@ -133,5 +170,42 @@ int skl_int3472_tps68470_probe(struct i2c_client *client)
|
|||
return device_type;
|
||||
}
|
||||
|
||||
/*
|
||||
* No acpi_dev_clear_dependencies() here, since the acpi_gpiochip_add()
|
||||
* for the GPIO cell already does this.
|
||||
*/
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int skl_int3472_tps68470_remove(struct i2c_client *client)
|
||||
{
|
||||
const struct int3472_tps68470_board_data *board_data;
|
||||
|
||||
board_data = int3472_tps68470_get_board_data(dev_name(&client->dev));
|
||||
if (board_data)
|
||||
gpiod_remove_lookup_table(board_data->tps68470_gpio_lookup_table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id int3472_device_id[] = {
|
||||
{ "INT3472", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, int3472_device_id);
|
||||
|
||||
static struct i2c_driver int3472_tps68470 = {
|
||||
.driver = {
|
||||
.name = "int3472-tps68470",
|
||||
.acpi_match_table = int3472_device_id,
|
||||
},
|
||||
.probe_new = skl_int3472_tps68470_probe,
|
||||
.remove = skl_int3472_tps68470_remove,
|
||||
};
|
||||
module_i2c_driver(int3472_tps68470);
|
||||
|
||||
MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI TPS68470 Device Driver");
|
||||
MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_SOFTDEP("pre: clk-tps68470 tps68470-regulator");
|
|
@ -0,0 +1,25 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* TI TPS68470 PMIC platform data definition.
|
||||
*
|
||||
* Copyright (c) 2021 Red Hat Inc.
|
||||
*
|
||||
* Red Hat authors:
|
||||
* Hans de Goede <hdegoede@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef _INTEL_SKL_INT3472_TPS68470_H
|
||||
#define _INTEL_SKL_INT3472_TPS68470_H
|
||||
|
||||
struct gpiod_lookup_table;
|
||||
struct tps68470_regulator_platform_data;
|
||||
|
||||
struct int3472_tps68470_board_data {
|
||||
const char *dev_name;
|
||||
struct gpiod_lookup_table *tps68470_gpio_lookup_table;
|
||||
const struct tps68470_regulator_platform_data *tps68470_regulator_pdata;
|
||||
};
|
||||
|
||||
const struct int3472_tps68470_board_data *int3472_tps68470_get_board_data(const char *dev_name);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,145 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* TI TPS68470 PMIC platform data definition.
|
||||
*
|
||||
* Copyright (c) 2021 Dan Scally <djrscally@gmail.com>
|
||||
* Copyright (c) 2021 Red Hat Inc.
|
||||
*
|
||||
* Red Hat authors:
|
||||
* Hans de Goede <hdegoede@redhat.com>
|
||||
*/
|
||||
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/platform_data/tps68470.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include "tps68470.h"
|
||||
|
||||
static struct regulator_consumer_supply int347a_core_consumer_supplies[] = {
|
||||
REGULATOR_SUPPLY("dvdd", "i2c-INT347A:00"),
|
||||
};
|
||||
|
||||
static struct regulator_consumer_supply int347a_ana_consumer_supplies[] = {
|
||||
REGULATOR_SUPPLY("avdd", "i2c-INT347A:00"),
|
||||
};
|
||||
|
||||
static struct regulator_consumer_supply int347a_vcm_consumer_supplies[] = {
|
||||
REGULATOR_SUPPLY("vdd", "i2c-INT347A:00-VCM"),
|
||||
};
|
||||
|
||||
static struct regulator_consumer_supply int347a_vsio_consumer_supplies[] = {
|
||||
REGULATOR_SUPPLY("dovdd", "i2c-INT347A:00"),
|
||||
REGULATOR_SUPPLY("vsio", "i2c-INT347A:00-VCM"),
|
||||
};
|
||||
|
||||
static const struct regulator_init_data surface_go_tps68470_core_reg_init_data = {
|
||||
.constraints = {
|
||||
.min_uV = 1200000,
|
||||
.max_uV = 1200000,
|
||||
.apply_uV = true,
|
||||
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
|
||||
},
|
||||
.num_consumer_supplies = ARRAY_SIZE(int347a_core_consumer_supplies),
|
||||
.consumer_supplies = int347a_core_consumer_supplies,
|
||||
};
|
||||
|
||||
static const struct regulator_init_data surface_go_tps68470_ana_reg_init_data = {
|
||||
.constraints = {
|
||||
.min_uV = 2815200,
|
||||
.max_uV = 2815200,
|
||||
.apply_uV = true,
|
||||
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
|
||||
},
|
||||
.num_consumer_supplies = ARRAY_SIZE(int347a_ana_consumer_supplies),
|
||||
.consumer_supplies = int347a_ana_consumer_supplies,
|
||||
};
|
||||
|
||||
static const struct regulator_init_data surface_go_tps68470_vcm_reg_init_data = {
|
||||
.constraints = {
|
||||
.min_uV = 2815200,
|
||||
.max_uV = 2815200,
|
||||
.apply_uV = true,
|
||||
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
|
||||
},
|
||||
.num_consumer_supplies = ARRAY_SIZE(int347a_vcm_consumer_supplies),
|
||||
.consumer_supplies = int347a_vcm_consumer_supplies,
|
||||
};
|
||||
|
||||
/* Ensure the always-on VIO regulator has the same voltage as VSIO */
|
||||
static const struct regulator_init_data surface_go_tps68470_vio_reg_init_data = {
|
||||
.constraints = {
|
||||
.min_uV = 1800600,
|
||||
.max_uV = 1800600,
|
||||
.apply_uV = true,
|
||||
.always_on = true,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regulator_init_data surface_go_tps68470_vsio_reg_init_data = {
|
||||
.constraints = {
|
||||
.min_uV = 1800600,
|
||||
.max_uV = 1800600,
|
||||
.apply_uV = true,
|
||||
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
|
||||
},
|
||||
.num_consumer_supplies = ARRAY_SIZE(int347a_vsio_consumer_supplies),
|
||||
.consumer_supplies = int347a_vsio_consumer_supplies,
|
||||
};
|
||||
|
||||
static const struct tps68470_regulator_platform_data surface_go_tps68470_pdata = {
|
||||
.reg_init_data = {
|
||||
[TPS68470_CORE] = &surface_go_tps68470_core_reg_init_data,
|
||||
[TPS68470_ANA] = &surface_go_tps68470_ana_reg_init_data,
|
||||
[TPS68470_VCM] = &surface_go_tps68470_vcm_reg_init_data,
|
||||
[TPS68470_VIO] = &surface_go_tps68470_vio_reg_init_data,
|
||||
[TPS68470_VSIO] = &surface_go_tps68470_vsio_reg_init_data,
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table surface_go_tps68470_gpios = {
|
||||
.dev_id = "i2c-INT347A:00",
|
||||
.table = {
|
||||
GPIO_LOOKUP("tps68470-gpio", 9, "reset", GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP("tps68470-gpio", 7, "powerdown", GPIO_ACTIVE_LOW)
|
||||
}
|
||||
};
|
||||
|
||||
static const struct int3472_tps68470_board_data surface_go_tps68470_board_data = {
|
||||
.dev_name = "i2c-INT3472:05",
|
||||
.tps68470_gpio_lookup_table = &surface_go_tps68470_gpios,
|
||||
.tps68470_regulator_pdata = &surface_go_tps68470_pdata,
|
||||
};
|
||||
|
||||
static const struct dmi_system_id int3472_tps68470_board_data_table[] = {
|
||||
{
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Go"),
|
||||
},
|
||||
.driver_data = (void *)&surface_go_tps68470_board_data,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Go 2"),
|
||||
},
|
||||
.driver_data = (void *)&surface_go_tps68470_board_data,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
const struct int3472_tps68470_board_data *int3472_tps68470_get_board_data(const char *dev_name)
|
||||
{
|
||||
const struct int3472_tps68470_board_data *board_data;
|
||||
const struct dmi_system_id *match;
|
||||
|
||||
for (match = dmi_first_match(int3472_tps68470_board_data_table);
|
||||
match;
|
||||
match = dmi_first_match(match + 1)) {
|
||||
board_data = match->driver_data;
|
||||
if (strcmp(board_data->dev_name, dev_name) == 0)
|
||||
return board_data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -202,7 +202,8 @@ struct acpi_device_flags {
|
|||
u32 coherent_dma:1;
|
||||
u32 cca_seen:1;
|
||||
u32 enumeration_by_parent:1;
|
||||
u32 reserved:19;
|
||||
u32 honor_deps:1;
|
||||
u32 reserved:18;
|
||||
};
|
||||
|
||||
/* File System */
|
||||
|
@ -285,6 +286,7 @@ struct acpi_dep_data {
|
|||
struct list_head node;
|
||||
acpi_handle supplier;
|
||||
acpi_handle consumer;
|
||||
bool honor_dep;
|
||||
};
|
||||
|
||||
/* Performance Management */
|
||||
|
@ -693,6 +695,7 @@ static inline bool acpi_device_can_poweroff(struct acpi_device *adev)
|
|||
bool acpi_dev_hid_uid_match(struct acpi_device *adev, const char *hid2, const char *uid2);
|
||||
|
||||
void acpi_dev_clear_dependencies(struct acpi_device *supplier);
|
||||
bool acpi_dev_ready_for_enumeration(const struct acpi_device *device);
|
||||
struct acpi_device *acpi_dev_get_first_consumer_dev(struct acpi_device *supplier);
|
||||
struct acpi_device *
|
||||
acpi_dev_get_next_match_dev(struct acpi_device *adev, const char *hid, const char *uid, s64 hrv);
|
||||
|
|
|
@ -1025,8 +1025,9 @@ bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
|
|||
struct acpi_resource_i2c_serialbus **i2c);
|
||||
int i2c_acpi_client_count(struct acpi_device *adev);
|
||||
u32 i2c_acpi_find_bus_speed(struct device *dev);
|
||||
struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
|
||||
struct i2c_board_info *info);
|
||||
struct i2c_client *i2c_acpi_new_device_by_fwnode(struct fwnode_handle *fwnode,
|
||||
int index,
|
||||
struct i2c_board_info *info);
|
||||
struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle);
|
||||
bool i2c_acpi_waive_d0_probe(struct device *dev);
|
||||
#else
|
||||
|
@ -1043,8 +1044,9 @@ static inline u32 i2c_acpi_find_bus_speed(struct device *dev)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
static inline struct i2c_client *i2c_acpi_new_device(struct device *dev,
|
||||
int index, struct i2c_board_info *info)
|
||||
static inline struct i2c_client *i2c_acpi_new_device_by_fwnode(
|
||||
struct fwnode_handle *fwnode, int index,
|
||||
struct i2c_board_info *info)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
@ -1058,4 +1060,11 @@ static inline bool i2c_acpi_waive_d0_probe(struct device *dev)
|
|||
}
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
static inline struct i2c_client *i2c_acpi_new_device(struct device *dev,
|
||||
int index,
|
||||
struct i2c_board_info *info)
|
||||
{
|
||||
return i2c_acpi_new_device_by_fwnode(dev_fwnode(dev), index, info);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_I2C_H */
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* TI TPS68470 PMIC platform data definition.
|
||||
*
|
||||
* Copyright (c) 2021 Red Hat Inc.
|
||||
*
|
||||
* Red Hat authors:
|
||||
* Hans de Goede <hdegoede@redhat.com>
|
||||
*/
|
||||
#ifndef __PDATA_TPS68470_H
|
||||
#define __PDATA_TPS68470_H
|
||||
|
||||
enum tps68470_regulators {
|
||||
TPS68470_CORE,
|
||||
TPS68470_ANA,
|
||||
TPS68470_VCM,
|
||||
TPS68470_VIO,
|
||||
TPS68470_VSIO,
|
||||
TPS68470_AUX1,
|
||||
TPS68470_AUX2,
|
||||
TPS68470_NUM_REGULATORS
|
||||
};
|
||||
|
||||
struct regulator_init_data;
|
||||
|
||||
struct tps68470_regulator_platform_data {
|
||||
const struct regulator_init_data *reg_init_data[TPS68470_NUM_REGULATORS];
|
||||
};
|
||||
|
||||
struct tps68470_clk_platform_data {
|
||||
const char *consumer_dev_name;
|
||||
const char *consumer_con_id;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue