Merge tag 'i2c-for-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa...
[platform/kernel/linux-starfive.git] / drivers / platform / x86 / intel / int3472 / tps68470.c
index 5dd81bb..f83e9c3 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Author: Dan Scally <djrscally@gmail.com> */
 
+#include <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/kernel.h>
 #include <linux/mfd/core.h>
@@ -95,20 +96,65 @@ static int skl_int3472_tps68470_calc_type(struct acpi_device *adev)
        return DESIGNED_FOR_WINDOWS;
 }
 
+/*
+ * Return the size of the flexible array member, because we'll need that later
+ * on to pass .pdata_size to cells.
+ */
+static int
+skl_int3472_fill_clk_pdata(struct device *dev, struct tps68470_clk_platform_data **clk_pdata)
+{
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+       struct acpi_device *consumer;
+       unsigned int n_consumers = 0;
+       const char *sensor_name;
+       unsigned int i = 0;
+
+       for_each_acpi_consumer_dev(adev, consumer)
+               n_consumers++;
+
+       if (!n_consumers) {
+               dev_err(dev, "INT3472 seems to have no dependents\n");
+               return -ENODEV;
+       }
+
+       *clk_pdata = devm_kzalloc(dev, struct_size(*clk_pdata, consumers, n_consumers),
+                                 GFP_KERNEL);
+       if (!*clk_pdata)
+               return -ENOMEM;
+
+       (*clk_pdata)->n_consumers = n_consumers;
+       i = 0;
+
+       for_each_acpi_consumer_dev(adev, consumer) {
+               sensor_name = devm_kasprintf(dev, GFP_KERNEL, I2C_DEV_NAME_FORMAT,
+                                            acpi_dev_name(consumer));
+               if (!sensor_name)
+                       return -ENOMEM;
+
+               (*clk_pdata)->consumers[i].consumer_dev_name = sensor_name;
+               i++;
+       }
+
+       acpi_dev_put(consumer);
+
+       return n_consumers;
+}
+
 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 tps68470_clk_platform_data *clk_pdata;
        struct mfd_cell *cells;
        struct regmap *regmap;
+       int n_consumers;
        int device_type;
        int ret;
+       int i;
 
-       ret = skl_int3472_get_sensor_adev_and_name(&client->dev, NULL,
-                                                  &clk_pdata.consumer_dev_name);
-       if (ret)
-               return ret;
+       n_consumers = skl_int3472_fill_clk_pdata(&client->dev, &clk_pdata);
+       if (n_consumers < 0)
+               return n_consumers;
 
        regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
        if (IS_ERR(regmap)) {
@@ -142,22 +188,25 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client)
                 * 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[0].platform_data = clk_pdata;
+               cells[0].pdata_size = struct_size(clk_pdata, consumers, n_consumers);
                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);
+               for (i = 0; i < board_data->n_gpiod_lookups; i++)
+                       gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]);
 
                ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
                                           cells, TPS68470_WIN_MFD_CELL_COUNT,
                                           NULL, 0, NULL);
                kfree(cells);
 
-               if (ret)
-                       gpiod_remove_lookup_table(board_data->tps68470_gpio_lookup_table);
+               if (ret) {
+                       for (i = 0; i < board_data->n_gpiod_lookups; i++)
+                               gpiod_remove_lookup_table(board_data->tps68470_gpio_lookup_tables[i]);
+               }
 
                break;
        case DESIGNED_FOR_CHROMEOS:
@@ -181,10 +230,13 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client)
 static void skl_int3472_tps68470_remove(struct i2c_client *client)
 {
        const struct int3472_tps68470_board_data *board_data;
+       int i;
 
        board_data = int3472_tps68470_get_board_data(dev_name(&client->dev));
-       if (board_data)
-               gpiod_remove_lookup_table(board_data->tps68470_gpio_lookup_table);
+       if (board_data) {
+               for (i = 0; i < board_data->n_gpiod_lookups; i++)
+                       gpiod_remove_lookup_table(board_data->tps68470_gpio_lookup_tables[i]);
+       }
 }
 
 static const struct acpi_device_id int3472_device_id[] = {