LoongArch: Parse MADT to get multi-processor information
[linux-2.6-microblaze.git] / drivers / leds / leds-pca963x.c
index d288acb..00aecd6 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/property.h>
 #include <linux/slab.h>
 #include <linux/of.h>
-#include <linux/platform_data/leds-pca963x.h>
 
 /* LED select registers determine the source that drives LED outputs */
 #define PCA963X_LED_OFF                0x0     /* LED driver off */
@@ -96,142 +95,148 @@ static const struct i2c_device_id pca963x_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, pca963x_id);
 
-struct pca963x_led;
-
-struct pca963x {
-       struct pca963x_chipdef *chipdef;
-       struct mutex mutex;
-       struct i2c_client *client;
-       struct pca963x_led *leds;
-       unsigned long leds_on;
-};
+struct pca963x;
 
 struct pca963x_led {
        struct pca963x *chip;
        struct led_classdev led_cdev;
        int led_num; /* 0 .. 15 potentially */
-       char name[32];
        u8 gdc;
        u8 gfrq;
 };
 
-static int pca963x_brightness(struct pca963x_led *pca963x,
-                              enum led_brightness brightness)
+struct pca963x {
+       struct pca963x_chipdef *chipdef;
+       struct mutex mutex;
+       struct i2c_client *client;
+       unsigned long leds_on;
+       struct pca963x_led leds[];
+};
+
+static int pca963x_brightness(struct pca963x_led *led,
+                             enum led_brightness brightness)
 {
-       u8 ledout_addr = pca963x->chip->chipdef->ledout_base
-               + (pca963x->led_num / 4);
-       u8 ledout;
-       int shift = 2 * (pca963x->led_num % 4);
-       u8 mask = 0x3 << shift;
+       struct i2c_client *client = led->chip->client;
+       struct pca963x_chipdef *chipdef = led->chip->chipdef;
+       u8 ledout_addr, ledout, mask, val;
+       int shift;
        int ret;
 
-       ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr);
+       ledout_addr = chipdef->ledout_base + (led->led_num / 4);
+       shift = 2 * (led->led_num % 4);
+       mask = 0x3 << shift;
+       ledout = i2c_smbus_read_byte_data(client, ledout_addr);
+
        switch (brightness) {
        case LED_FULL:
-               ret = i2c_smbus_write_byte_data(pca963x->chip->client,
-                       ledout_addr,
-                       (ledout & ~mask) | (PCA963X_LED_ON << shift));
+               val = (ledout & ~mask) | (PCA963X_LED_ON << shift);
+               ret = i2c_smbus_write_byte_data(client, ledout_addr, val);
                break;
        case LED_OFF:
-               ret = i2c_smbus_write_byte_data(pca963x->chip->client,
-                       ledout_addr, ledout & ~mask);
+               val = ledout & ~mask;
+               ret = i2c_smbus_write_byte_data(client, ledout_addr, val);
                break;
        default:
-               ret = i2c_smbus_write_byte_data(pca963x->chip->client,
-                       PCA963X_PWM_BASE + pca963x->led_num,
-                       brightness);
+               ret = i2c_smbus_write_byte_data(client,
+                                               PCA963X_PWM_BASE +
+                                               led->led_num,
+                                               brightness);
                if (ret < 0)
                        return ret;
-               ret = i2c_smbus_write_byte_data(pca963x->chip->client,
-                       ledout_addr,
-                       (ledout & ~mask) | (PCA963X_LED_PWM << shift));
+
+               val = (ledout & ~mask) | (PCA963X_LED_PWM << shift);
+               ret = i2c_smbus_write_byte_data(client, ledout_addr, val);
                break;
        }
 
        return ret;
 }
 
-static void pca963x_blink(struct pca963x_led *pca963x)
+static void pca963x_blink(struct pca963x_led *led)
 {
-       u8 ledout_addr = pca963x->chip->chipdef->ledout_base +
-               (pca963x->led_num / 4);
-       u8 ledout;
-       u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client,
-                                                       PCA963X_MODE2);
-       int shift = 2 * (pca963x->led_num % 4);
-       u8 mask = 0x3 << shift;
+       struct i2c_client *client = led->chip->client;
+       struct pca963x_chipdef *chipdef = led->chip->chipdef;
+       u8 ledout_addr, ledout, mask, val, mode2;
+       int shift;
+
+       ledout_addr = chipdef->ledout_base + (led->led_num / 4);
+       shift = 2 * (led->led_num % 4);
+       mask = 0x3 << shift;
+       mode2 = i2c_smbus_read_byte_data(client, PCA963X_MODE2);
 
-       i2c_smbus_write_byte_data(pca963x->chip->client,
-                       pca963x->chip->chipdef->grppwm, pca963x->gdc);
+       i2c_smbus_write_byte_data(client, chipdef->grppwm, led->gdc);
 
-       i2c_smbus_write_byte_data(pca963x->chip->client,
-                       pca963x->chip->chipdef->grpfreq, pca963x->gfrq);
+       i2c_smbus_write_byte_data(client, chipdef->grpfreq, led->gfrq);
 
        if (!(mode2 & PCA963X_MODE2_DMBLNK))
-               i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2,
-                       mode2 | PCA963X_MODE2_DMBLNK);
-
-       mutex_lock(&pca963x->chip->mutex);
-       ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr);
-       if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift))
-               i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
-                       (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift));
-       mutex_unlock(&pca963x->chip->mutex);
+               i2c_smbus_write_byte_data(client, PCA963X_MODE2,
+                                         mode2 | PCA963X_MODE2_DMBLNK);
+
+       mutex_lock(&led->chip->mutex);
+
+       ledout = i2c_smbus_read_byte_data(client, ledout_addr);
+       if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift)) {
+               val = (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift);
+               i2c_smbus_write_byte_data(client, ledout_addr, val);
+       }
+
+       mutex_unlock(&led->chip->mutex);
 }
 
-static int pca963x_power_state(struct pca963x_led *pca963x)
+static int pca963x_power_state(struct pca963x_led *led)
 {
-       unsigned long *leds_on = &pca963x->chip->leds_on;
-       unsigned long cached_leds = pca963x->chip->leds_on;
+       struct i2c_client *client = led->chip->client;
+       unsigned long *leds_on = &led->chip->leds_on;
+       unsigned long cached_leds = *leds_on;
 
-       if (pca963x->led_cdev.brightness)
-               set_bit(pca963x->led_num, leds_on);
+       if (led->led_cdev.brightness)
+               set_bit(led->led_num, leds_on);
        else
-               clear_bit(pca963x->led_num, leds_on);
+               clear_bit(led->led_num, leds_on);
 
        if (!(*leds_on) != !cached_leds)
-               return i2c_smbus_write_byte_data(pca963x->chip->client,
-                       PCA963X_MODE1, *leds_on ? 0 : BIT(4));
+               return i2c_smbus_write_byte_data(client, PCA963X_MODE1,
+                                                *leds_on ? 0 : BIT(4));
 
        return 0;
 }
 
 static int pca963x_led_set(struct led_classdev *led_cdev,
-       enum led_brightness value)
+                          enum led_brightness value)
 {
-       struct pca963x_led *pca963x;
+       struct pca963x_led *led;
        int ret;
 
-       pca963x = container_of(led_cdev, struct pca963x_led, led_cdev);
+       led = container_of(led_cdev, struct pca963x_led, led_cdev);
 
-       mutex_lock(&pca963x->chip->mutex);
+       mutex_lock(&led->chip->mutex);
 
-       ret = pca963x_brightness(pca963x, value);
+       ret = pca963x_brightness(led, value);
        if (ret < 0)
                goto unlock;
-       ret = pca963x_power_state(pca963x);
+       ret = pca963x_power_state(led);
 
 unlock:
-       mutex_unlock(&pca963x->chip->mutex);
+       mutex_unlock(&led->chip->mutex);
        return ret;
 }
 
-static unsigned int pca963x_period_scale(struct pca963x_led *pca963x,
-       unsigned int val)
+static unsigned int pca963x_period_scale(struct pca963x_led *led,
+                                        unsigned int val)
 {
-       unsigned int scaling = pca963x->chip->chipdef->scaling;
+       unsigned int scaling = led->chip->chipdef->scaling;
 
        return scaling ? DIV_ROUND_CLOSEST(val * scaling, 1000) : val;
 }
 
 static int pca963x_blink_set(struct led_classdev *led_cdev,
-               unsigned long *delay_on, unsigned long *delay_off)
+                            unsigned long *delay_on, unsigned long *delay_off)
 {
-       struct pca963x_led *pca963x;
        unsigned long time_on, time_off, period;
+       struct pca963x_led *led;
        u8 gdc, gfrq;
 
-       pca963x = container_of(led_cdev, struct pca963x_led, led_cdev);
+       led = container_of(led_cdev, struct pca963x_led, led_cdev);
 
        time_on = *delay_on;
        time_off = *delay_off;
@@ -242,14 +247,14 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
                time_off = 500;
        }
 
-       period = pca963x_period_scale(pca963x, time_on + time_off);
+       period = pca963x_period_scale(led, time_on + time_off);
 
        /* If period not supported by hardware, default to someting sane. */
        if ((period < PCA963X_BLINK_PERIOD_MIN) ||
            (period > PCA963X_BLINK_PERIOD_MAX)) {
                time_on = 500;
                time_off = 500;
-               period = pca963x_period_scale(pca963x, 1000);
+               period = pca963x_period_scale(led, 1000);
        }
 
        /*
@@ -257,7 +262,7 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
         *      (time_on / period) = (GDC / 256) ->
         *              GDC = ((time_on * 256) / period)
         */
-       gdc = (pca963x_period_scale(pca963x, time_on) * 256) / period;
+       gdc = (pca963x_period_scale(led, time_on) * 256) / period;
 
        /*
         * From manual: period = ((GFRQ + 1) / 24) in seconds.
@@ -266,10 +271,10 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
         */
        gfrq = (period * 24 / 1000) - 1;
 
-       pca963x->gdc = gdc;
-       pca963x->gfrq = gfrq;
+       led->gdc = gdc;
+       led->gfrq = gfrq;
 
-       pca963x_blink(pca963x);
+       pca963x_blink(led);
 
        *delay_on = time_on;
        *delay_off = time_off;
@@ -277,72 +282,84 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
        return 0;
 }
 
-static struct pca963x_platform_data *
-pca963x_get_pdata(struct i2c_client *client, struct pca963x_chipdef *chip)
+static int pca963x_register_leds(struct i2c_client *client,
+                                struct pca963x *chip)
 {
-       struct pca963x_platform_data *pdata;
-       struct led_info *pca963x_leds;
+       struct pca963x_chipdef *chipdef = chip->chipdef;
+       struct pca963x_led *led = chip->leds;
+       struct device *dev = &client->dev;
        struct fwnode_handle *child;
-       int count;
-
-       count = device_get_child_node_count(&client->dev);
-       if (!count || count > chip->n_leds)
-               return ERR_PTR(-ENODEV);
-
-       pca963x_leds = devm_kcalloc(&client->dev,
-                       chip->n_leds, sizeof(struct led_info), GFP_KERNEL);
-       if (!pca963x_leds)
-               return ERR_PTR(-ENOMEM);
-
-       device_for_each_child_node(&client->dev, child) {
-               struct led_info led = {};
-               u32 reg;
-               int res;
-
-               res = fwnode_property_read_u32(child, "reg", &reg);
-               if ((res != 0) || (reg >= chip->n_leds))
-                       continue;
+       bool hw_blink;
+       s32 mode2;
+       u32 reg;
+       int ret;
 
-               res = fwnode_property_read_string(child, "label", &led.name);
-               if ((res != 0) && is_of_node(child))
-                       led.name = to_of_node(child)->name;
+       if (device_property_read_u32(dev, "nxp,period-scale",
+                                    &chipdef->scaling))
+               chipdef->scaling = 1000;
 
-               fwnode_property_read_string(child, "linux,default-trigger",
-                                           &led.default_trigger);
+       hw_blink = device_property_read_bool(dev, "nxp,hw-blink");
 
-               pca963x_leds[reg] = led;
-       }
-       pdata = devm_kzalloc(&client->dev,
-                            sizeof(struct pca963x_platform_data), GFP_KERNEL);
-       if (!pdata)
-               return ERR_PTR(-ENOMEM);
-
-       pdata->leds.leds = pca963x_leds;
-       pdata->leds.num_leds = chip->n_leds;
+       mode2 = i2c_smbus_read_byte_data(client, PCA963X_MODE2);
+       if (mode2 < 0)
+               return mode2;
 
        /* default to open-drain unless totem pole (push-pull) is specified */
-       if (device_property_read_bool(&client->dev, "nxp,totem-pole"))
-               pdata->outdrv = PCA963X_TOTEM_POLE;
+       if (device_property_read_bool(dev, "nxp,totem-pole"))
+               mode2 |= PCA963X_MODE2_OUTDRV;
        else
-               pdata->outdrv = PCA963X_OPEN_DRAIN;
+               mode2 &= ~PCA963X_MODE2_OUTDRV;
 
-       /* default to software blinking unless hardware blinking is specified */
-       if (device_property_read_bool(&client->dev, "nxp,hw-blink"))
-               pdata->blink_type = PCA963X_HW_BLINK;
+       /* default to non-inverted output, unless inverted is specified */
+       if (device_property_read_bool(dev, "nxp,inverted-out"))
+               mode2 |= PCA963X_MODE2_INVRT;
        else
-               pdata->blink_type = PCA963X_SW_BLINK;
+               mode2 &= ~PCA963X_MODE2_INVRT;
+
+       ret = i2c_smbus_write_byte_data(client, PCA963X_MODE2, mode2);
+       if (ret < 0)
+               return ret;
+
+       device_for_each_child_node(dev, child) {
+               struct led_init_data init_data = {};
+               char default_label[32];
+
+               ret = fwnode_property_read_u32(child, "reg", &reg);
+               if (ret || reg >= chipdef->n_leds) {
+                       dev_err(dev, "Invalid 'reg' property for node %pfw\n",
+                               child);
+                       ret = -EINVAL;
+                       goto err;
+               }
 
-       if (device_property_read_u32(&client->dev, "nxp,period-scale",
-                                    &chip->scaling))
-               chip->scaling = 1000;
+               led->led_num = reg;
+               led->chip = chip;
+               led->led_cdev.brightness_set_blocking = pca963x_led_set;
+               if (hw_blink)
+                       led->led_cdev.blink_set = pca963x_blink_set;
+
+               init_data.fwnode = child;
+               /* for backwards compatibility */
+               init_data.devicename = "pca963x";
+               snprintf(default_label, sizeof(default_label), "%d:%.2x:%u",
+                        client->adapter->nr, client->addr, reg);
+               init_data.default_label = default_label;
+
+               ret = devm_led_classdev_register_ext(dev, &led->led_cdev,
+                                                    &init_data);
+               if (ret) {
+                       dev_err(dev, "Failed to register LED for node %pfw\n",
+                               child);
+                       goto err;
+               }
 
-       /* default to non-inverted output, unless inverted is specified */
-       if (device_property_read_bool(&client->dev, "nxp,inverted-out"))
-               pdata->dir = PCA963X_INVERTED;
-       else
-               pdata->dir = PCA963X_NORMAL;
+               ++led;
+       }
 
-       return pdata;
+       return 0;
+err:
+       fwnode_handle_put(child);
+       return ret;
 }
 
 static const struct of_device_id of_pca963x_match[] = {
@@ -355,119 +372,40 @@ static const struct of_device_id of_pca963x_match[] = {
 MODULE_DEVICE_TABLE(of, of_pca963x_match);
 
 static int pca963x_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
+                        const struct i2c_device_id *id)
 {
-       struct pca963x *pca963x_chip;
-       struct pca963x_led *pca963x;
-       struct pca963x_platform_data *pdata;
-       struct pca963x_chipdef *chip;
-       int i, err;
-
-       chip = &pca963x_chipdefs[id->driver_data];
-       pdata = dev_get_platdata(&client->dev);
-
-       if (!pdata) {
-               pdata = pca963x_get_pdata(client, chip);
-               if (IS_ERR(pdata)) {
-                       dev_warn(&client->dev, "could not parse configuration\n");
-                       pdata = NULL;
-               }
-       }
+       struct device *dev = &client->dev;
+       struct pca963x_chipdef *chipdef;
+       struct pca963x *chip;
+       int i, count;
 
-       if (pdata && (pdata->leds.num_leds < 1 ||
-                                pdata->leds.num_leds > chip->n_leds)) {
-               dev_err(&client->dev, "board info must claim 1-%d LEDs",
-                                                               chip->n_leds);
+       chipdef = &pca963x_chipdefs[id->driver_data];
+
+       count = device_get_child_node_count(dev);
+       if (!count || count > chipdef->n_leds) {
+               dev_err(dev, "Node %pfw must define between 1 and %d LEDs\n",
+                       dev_fwnode(dev), chipdef->n_leds);
                return -EINVAL;
        }
 
-       pca963x_chip = devm_kzalloc(&client->dev, sizeof(*pca963x_chip),
-                                                               GFP_KERNEL);
-       if (!pca963x_chip)
-               return -ENOMEM;
-       pca963x = devm_kcalloc(&client->dev, chip->n_leds, sizeof(*pca963x),
-                                                               GFP_KERNEL);
-       if (!pca963x)
+       chip = devm_kzalloc(dev, struct_size(chip, leds, count), GFP_KERNEL);
+       if (!chip)
                return -ENOMEM;
 
-       i2c_set_clientdata(client, pca963x_chip);
+       i2c_set_clientdata(client, chip);
 
-       mutex_init(&pca963x_chip->mutex);
-       pca963x_chip->chipdef = chip;
-       pca963x_chip->client = client;
-       pca963x_chip->leds = pca963x;
+       mutex_init(&chip->mutex);
+       chip->chipdef = chipdef;
+       chip->client = client;
 
        /* Turn off LEDs by default*/
-       for (i = 0; i < chip->n_leds / 4; i++)
-               i2c_smbus_write_byte_data(client, chip->ledout_base + i, 0x00);
-
-       for (i = 0; i < chip->n_leds; i++) {
-               pca963x[i].led_num = i;
-               pca963x[i].chip = pca963x_chip;
-
-               /* Platform data can specify LED names and default triggers */
-               if (pdata && i < pdata->leds.num_leds) {
-                       if (pdata->leds.leds[i].name)
-                               snprintf(pca963x[i].name,
-                                        sizeof(pca963x[i].name), "pca963x:%s",
-                                        pdata->leds.leds[i].name);
-                       if (pdata->leds.leds[i].default_trigger)
-                               pca963x[i].led_cdev.default_trigger =
-                                       pdata->leds.leds[i].default_trigger;
-               }
-               if (!pdata || i >= pdata->leds.num_leds ||
-                                               !pdata->leds.leds[i].name)
-                       snprintf(pca963x[i].name, sizeof(pca963x[i].name),
-                                "pca963x:%d:%.2x:%d", client->adapter->nr,
-                                client->addr, i);
-
-               pca963x[i].led_cdev.name = pca963x[i].name;
-               pca963x[i].led_cdev.brightness_set_blocking = pca963x_led_set;
-
-               if (pdata && pdata->blink_type == PCA963X_HW_BLINK)
-                       pca963x[i].led_cdev.blink_set = pca963x_blink_set;
-
-               err = led_classdev_register(&client->dev, &pca963x[i].led_cdev);
-               if (err < 0)
-                       goto exit;
-       }
+       for (i = 0; i < chipdef->n_leds / 4; i++)
+               i2c_smbus_write_byte_data(client, chipdef->ledout_base + i, 0x00);
 
        /* Disable LED all-call address, and power down initially */
        i2c_smbus_write_byte_data(client, PCA963X_MODE1, BIT(4));
 
-       if (pdata) {
-               u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client,
-                                                   PCA963X_MODE2);
-               /* Configure output: open-drain or totem pole (push-pull) */
-               if (pdata->outdrv == PCA963X_OPEN_DRAIN)
-                       mode2 &= ~PCA963X_MODE2_OUTDRV;
-               else
-                       mode2 |= PCA963X_MODE2_OUTDRV;
-               /* Configure direction: normal or inverted */
-               if (pdata->dir == PCA963X_INVERTED)
-                       mode2 |= PCA963X_MODE2_INVRT;
-               i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2,
-                                         mode2);
-       }
-
-       return 0;
-
-exit:
-       while (i--)
-               led_classdev_unregister(&pca963x[i].led_cdev);
-
-       return err;
-}
-
-static int pca963x_remove(struct i2c_client *client)
-{
-       struct pca963x *pca963x = i2c_get_clientdata(client);
-       int i;
-
-       for (i = 0; i < pca963x->chipdef->n_leds; i++)
-               led_classdev_unregister(&pca963x->leds[i].led_cdev);
-
-       return 0;
+       return pca963x_register_leds(client, chip);
 }
 
 static struct i2c_driver pca963x_driver = {
@@ -476,7 +414,6 @@ static struct i2c_driver pca963x_driver = {
                .of_match_table = of_pca963x_match,
        },
        .probe  = pca963x_probe,
-       .remove = pca963x_remove,
        .id_table = pca963x_id,
 };