root/drivers/video/backlight/tps65217_bl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tps65217_bl_enable
  2. tps65217_bl_disable
  3. tps65217_bl_update_status
  4. tps65217_bl_hw_init
  5. tps65217_bl_parse_dt
  6. tps65217_bl_parse_dt
  7. tps65217_bl_probe

   1 /*
   2  * tps65217_bl.c
   3  *
   4  * TPS65217 backlight driver
   5  *
   6  * Copyright (C) 2012 Matthias Kaehlcke
   7  * Author: Matthias Kaehlcke <matthias@kaehlcke.net>
   8  *
   9  * This program is free software; you can redistribute it and/or
  10  * modify it under the terms of the GNU General Public License as
  11  * published by the Free Software Foundation version 2.
  12  *
  13  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  14  * kind, whether express or implied; without even the implied warranty
  15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16  * GNU General Public License for more details.
  17  */
  18 
  19 #include <linux/kernel.h>
  20 #include <linux/backlight.h>
  21 #include <linux/err.h>
  22 #include <linux/fb.h>
  23 #include <linux/mfd/tps65217.h>
  24 #include <linux/module.h>
  25 #include <linux/platform_device.h>
  26 #include <linux/slab.h>
  27 
  28 struct tps65217_bl {
  29         struct tps65217 *tps;
  30         struct device *dev;
  31         struct backlight_device *bl;
  32         bool is_enabled;
  33 };
  34 
  35 static int tps65217_bl_enable(struct tps65217_bl *tps65217_bl)
  36 {
  37         int rc;
  38 
  39         rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1,
  40                         TPS65217_WLEDCTRL1_ISINK_ENABLE,
  41                         TPS65217_WLEDCTRL1_ISINK_ENABLE, TPS65217_PROTECT_NONE);
  42         if (rc) {
  43                 dev_err(tps65217_bl->dev,
  44                         "failed to enable backlight: %d\n", rc);
  45                 return rc;
  46         }
  47 
  48         tps65217_bl->is_enabled = true;
  49 
  50         dev_dbg(tps65217_bl->dev, "backlight enabled\n");
  51 
  52         return 0;
  53 }
  54 
  55 static int tps65217_bl_disable(struct tps65217_bl *tps65217_bl)
  56 {
  57         int rc;
  58 
  59         rc = tps65217_clear_bits(tps65217_bl->tps,
  60                                 TPS65217_REG_WLEDCTRL1,
  61                                 TPS65217_WLEDCTRL1_ISINK_ENABLE,
  62                                 TPS65217_PROTECT_NONE);
  63         if (rc) {
  64                 dev_err(tps65217_bl->dev,
  65                         "failed to disable backlight: %d\n", rc);
  66                 return rc;
  67         }
  68 
  69         tps65217_bl->is_enabled = false;
  70 
  71         dev_dbg(tps65217_bl->dev, "backlight disabled\n");
  72 
  73         return 0;
  74 }
  75 
  76 static int tps65217_bl_update_status(struct backlight_device *bl)
  77 {
  78         struct tps65217_bl *tps65217_bl = bl_get_data(bl);
  79         int rc;
  80         int brightness = bl->props.brightness;
  81 
  82         if (bl->props.state & BL_CORE_SUSPENDED)
  83                 brightness = 0;
  84 
  85         if ((bl->props.power != FB_BLANK_UNBLANK) ||
  86                 (bl->props.fb_blank != FB_BLANK_UNBLANK))
  87                 /* framebuffer in low power mode or blanking active */
  88                 brightness = 0;
  89 
  90         if (brightness > 0) {
  91                 rc = tps65217_reg_write(tps65217_bl->tps,
  92                                         TPS65217_REG_WLEDCTRL2,
  93                                         brightness - 1,
  94                                         TPS65217_PROTECT_NONE);
  95                 if (rc) {
  96                         dev_err(tps65217_bl->dev,
  97                                 "failed to set brightness level: %d\n", rc);
  98                         return rc;
  99                 }
 100 
 101                 dev_dbg(tps65217_bl->dev, "brightness set to %d\n", brightness);
 102 
 103                 if (!tps65217_bl->is_enabled)
 104                         rc = tps65217_bl_enable(tps65217_bl);
 105         } else {
 106                 rc = tps65217_bl_disable(tps65217_bl);
 107         }
 108 
 109         return rc;
 110 }
 111 
 112 static const struct backlight_ops tps65217_bl_ops = {
 113         .options        = BL_CORE_SUSPENDRESUME,
 114         .update_status  = tps65217_bl_update_status,
 115 };
 116 
 117 static int tps65217_bl_hw_init(struct tps65217_bl *tps65217_bl,
 118                         struct tps65217_bl_pdata *pdata)
 119 {
 120         int rc;
 121 
 122         rc = tps65217_bl_disable(tps65217_bl);
 123         if (rc)
 124                 return rc;
 125 
 126         switch (pdata->isel) {
 127         case TPS65217_BL_ISET1:
 128                 /* select ISET_1 current level */
 129                 rc = tps65217_clear_bits(tps65217_bl->tps,
 130                                         TPS65217_REG_WLEDCTRL1,
 131                                         TPS65217_WLEDCTRL1_ISEL,
 132                                         TPS65217_PROTECT_NONE);
 133                 if (rc) {
 134                         dev_err(tps65217_bl->dev,
 135                                 "failed to select ISET1 current level: %d)\n",
 136                                 rc);
 137                         return rc;
 138                 }
 139 
 140                 dev_dbg(tps65217_bl->dev, "selected ISET1 current level\n");
 141 
 142                 break;
 143 
 144         case TPS65217_BL_ISET2:
 145                 /* select ISET2 current level */
 146                 rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1,
 147                                 TPS65217_WLEDCTRL1_ISEL,
 148                                 TPS65217_WLEDCTRL1_ISEL, TPS65217_PROTECT_NONE);
 149                 if (rc) {
 150                         dev_err(tps65217_bl->dev,
 151                                 "failed to select ISET2 current level: %d\n",
 152                                 rc);
 153                         return rc;
 154                 }
 155 
 156                 dev_dbg(tps65217_bl->dev, "selected ISET2 current level\n");
 157 
 158                 break;
 159 
 160         default:
 161                 dev_err(tps65217_bl->dev,
 162                         "invalid value for current level: %d\n", pdata->isel);
 163                 return -EINVAL;
 164         }
 165 
 166         /* set PWM frequency */
 167         rc = tps65217_set_bits(tps65217_bl->tps,
 168                         TPS65217_REG_WLEDCTRL1,
 169                         TPS65217_WLEDCTRL1_FDIM_MASK,
 170                         pdata->fdim,
 171                         TPS65217_PROTECT_NONE);
 172         if (rc) {
 173                 dev_err(tps65217_bl->dev,
 174                         "failed to select PWM dimming frequency: %d\n",
 175                         rc);
 176                 return rc;
 177         }
 178 
 179         return 0;
 180 }
 181 
 182 #ifdef CONFIG_OF
 183 static struct tps65217_bl_pdata *
 184 tps65217_bl_parse_dt(struct platform_device *pdev)
 185 {
 186         struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
 187         struct device_node *node;
 188         struct tps65217_bl_pdata *pdata, *err;
 189         u32 val;
 190 
 191         node = of_get_child_by_name(tps->dev->of_node, "backlight");
 192         if (!node)
 193                 return ERR_PTR(-ENODEV);
 194 
 195         pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 196         if (!pdata) {
 197                 err = ERR_PTR(-ENOMEM);
 198                 goto err;
 199         }
 200 
 201         pdata->isel = TPS65217_BL_ISET1;
 202         if (!of_property_read_u32(node, "isel", &val)) {
 203                 if (val < TPS65217_BL_ISET1 ||
 204                         val > TPS65217_BL_ISET2) {
 205                         dev_err(&pdev->dev,
 206                                 "invalid 'isel' value in the device tree\n");
 207                         err = ERR_PTR(-EINVAL);
 208                         goto err;
 209                 }
 210 
 211                 pdata->isel = val;
 212         }
 213 
 214         pdata->fdim = TPS65217_BL_FDIM_200HZ;
 215         if (!of_property_read_u32(node, "fdim", &val)) {
 216                 switch (val) {
 217                 case 100:
 218                         pdata->fdim = TPS65217_BL_FDIM_100HZ;
 219                         break;
 220 
 221                 case 200:
 222                         pdata->fdim = TPS65217_BL_FDIM_200HZ;
 223                         break;
 224 
 225                 case 500:
 226                         pdata->fdim = TPS65217_BL_FDIM_500HZ;
 227                         break;
 228 
 229                 case 1000:
 230                         pdata->fdim = TPS65217_BL_FDIM_1000HZ;
 231                         break;
 232 
 233                 default:
 234                         dev_err(&pdev->dev,
 235                                 "invalid 'fdim' value in the device tree\n");
 236                         err = ERR_PTR(-EINVAL);
 237                         goto err;
 238                 }
 239         }
 240 
 241         if (!of_property_read_u32(node, "default-brightness", &val)) {
 242                 if (val > 100) {
 243                         dev_err(&pdev->dev,
 244                                 "invalid 'default-brightness' value in the device tree\n");
 245                         err = ERR_PTR(-EINVAL);
 246                         goto err;
 247                 }
 248 
 249                 pdata->dft_brightness = val;
 250         }
 251 
 252         of_node_put(node);
 253 
 254         return pdata;
 255 
 256 err:
 257         of_node_put(node);
 258 
 259         return err;
 260 }
 261 #else
 262 static struct tps65217_bl_pdata *
 263 tps65217_bl_parse_dt(struct platform_device *pdev)
 264 {
 265         return NULL;
 266 }
 267 #endif
 268 
 269 static int tps65217_bl_probe(struct platform_device *pdev)
 270 {
 271         int rc;
 272         struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
 273         struct tps65217_bl *tps65217_bl;
 274         struct tps65217_bl_pdata *pdata;
 275         struct backlight_properties bl_props;
 276 
 277         pdata = tps65217_bl_parse_dt(pdev);
 278         if (IS_ERR(pdata))
 279                 return PTR_ERR(pdata);
 280 
 281         tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl),
 282                                 GFP_KERNEL);
 283         if (tps65217_bl == NULL)
 284                 return -ENOMEM;
 285 
 286         tps65217_bl->tps = tps;
 287         tps65217_bl->dev = &pdev->dev;
 288         tps65217_bl->is_enabled = false;
 289 
 290         rc = tps65217_bl_hw_init(tps65217_bl, pdata);
 291         if (rc)
 292                 return rc;
 293 
 294         memset(&bl_props, 0, sizeof(struct backlight_properties));
 295         bl_props.type = BACKLIGHT_RAW;
 296         bl_props.max_brightness = 100;
 297 
 298         tps65217_bl->bl = devm_backlight_device_register(&pdev->dev, pdev->name,
 299                                                 tps65217_bl->dev, tps65217_bl,
 300                                                 &tps65217_bl_ops, &bl_props);
 301         if (IS_ERR(tps65217_bl->bl)) {
 302                 dev_err(tps65217_bl->dev,
 303                         "registration of backlight device failed: %d\n", rc);
 304                 return PTR_ERR(tps65217_bl->bl);
 305         }
 306 
 307         tps65217_bl->bl->props.brightness = pdata->dft_brightness;
 308         backlight_update_status(tps65217_bl->bl);
 309         platform_set_drvdata(pdev, tps65217_bl);
 310 
 311         return 0;
 312 }
 313 
 314 #ifdef CONFIG_OF
 315 static const struct of_device_id tps65217_bl_of_match[] = {
 316         { .compatible = "ti,tps65217-bl", },
 317         { /* sentinel */ },
 318 };
 319 MODULE_DEVICE_TABLE(of, tps65217_bl_of_match);
 320 #endif
 321 
 322 static struct platform_driver tps65217_bl_driver = {
 323         .probe          = tps65217_bl_probe,
 324         .driver         = {
 325                 .name   = "tps65217-bl",
 326                 .of_match_table = of_match_ptr(tps65217_bl_of_match),
 327         },
 328 };
 329 
 330 module_platform_driver(tps65217_bl_driver);
 331 
 332 MODULE_DESCRIPTION("TPS65217 Backlight driver");
 333 MODULE_LICENSE("GPL v2");
 334 MODULE_AUTHOR("Matthias Kaehlcke <matthias@kaehlcke.net>");

/* [<][>][^][v][top][bottom][index][help] */