blob: bcabf2cb949ac1d20a27fa86db11857038eea243 [file] [log] [blame]
Milo(Woogyom) Kimc93d08f2013-02-05 18:01:23 +09001/*
2 * LP5521/LP5523/LP55231 Common Driver
3 *
4 * Copyright 2012 Texas Instruments
5 *
6 * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Derived from leds-lp5521.c, leds-lp5523.c
13 */
14
Milo(Woogyom) Kima85908d2013-02-05 18:07:20 +090015#include <linux/delay.h>
Milo(Woogyom) Kimc93d08f2013-02-05 18:01:23 +090016#include <linux/i2c.h>
17#include <linux/leds.h>
18#include <linux/module.h>
19#include <linux/platform_data/leds-lp55xx.h>
20
21#include "leds-lp55xx-common.h"
22
Milo(Woogyom) Kim48068d52013-02-05 18:08:49 +090023static void lp55xx_reset_device(struct lp55xx_chip *chip)
24{
25 struct lp55xx_device_config *cfg = chip->cfg;
26 u8 addr = cfg->reset.addr;
27 u8 val = cfg->reset.val;
28
29 /* no error checking here because no ACK from the device after reset */
30 lp55xx_write(chip, addr, val);
31}
32
Milo(Woogyom) Kime3a700d2013-02-05 18:09:56 +090033static int lp55xx_detect_device(struct lp55xx_chip *chip)
34{
35 struct lp55xx_device_config *cfg = chip->cfg;
36 u8 addr = cfg->enable.addr;
37 u8 val = cfg->enable.val;
38 int ret;
39
40 ret = lp55xx_write(chip, addr, val);
41 if (ret)
42 return ret;
43
44 usleep_range(1000, 2000);
45
46 ret = lp55xx_read(chip, addr, &val);
47 if (ret)
48 return ret;
49
50 if (val != cfg->enable.val)
51 return -ENODEV;
52
53 return 0;
54}
55
Milo(Woogyom) Kimffbdccd2013-02-05 18:57:36 +090056static int lp55xx_post_init_device(struct lp55xx_chip *chip)
57{
58 struct lp55xx_device_config *cfg = chip->cfg;
59
60 if (!cfg->post_init_device)
61 return 0;
62
63 return cfg->post_init_device(chip);
64}
65
Milo(Woogyom) Kimc93d08f2013-02-05 18:01:23 +090066int lp55xx_write(struct lp55xx_chip *chip, u8 reg, u8 val)
67{
68 return i2c_smbus_write_byte_data(chip->cl, reg, val);
69}
70EXPORT_SYMBOL_GPL(lp55xx_write);
71
72int lp55xx_read(struct lp55xx_chip *chip, u8 reg, u8 *val)
73{
74 s32 ret;
75
76 ret = i2c_smbus_read_byte_data(chip->cl, reg);
77 if (ret < 0)
78 return ret;
79
80 *val = ret;
81 return 0;
82}
83EXPORT_SYMBOL_GPL(lp55xx_read);
84
85int lp55xx_update_bits(struct lp55xx_chip *chip, u8 reg, u8 mask, u8 val)
86{
87 int ret;
88 u8 tmp;
89
90 ret = lp55xx_read(chip, reg, &tmp);
91 if (ret)
92 return ret;
93
94 tmp &= ~mask;
95 tmp |= val & mask;
96
97 return lp55xx_write(chip, reg, tmp);
98}
99EXPORT_SYMBOL_GPL(lp55xx_update_bits);
100
Milo(Woogyom) Kima85908d2013-02-05 18:07:20 +0900101int lp55xx_init_device(struct lp55xx_chip *chip)
102{
103 struct lp55xx_platform_data *pdata;
Milo(Woogyom) Kim48068d52013-02-05 18:08:49 +0900104 struct lp55xx_device_config *cfg;
Milo(Woogyom) Kima85908d2013-02-05 18:07:20 +0900105 struct device *dev = &chip->cl->dev;
106 int ret = 0;
107
108 WARN_ON(!chip);
109
110 pdata = chip->pdata;
Milo(Woogyom) Kim48068d52013-02-05 18:08:49 +0900111 cfg = chip->cfg;
Milo(Woogyom) Kima85908d2013-02-05 18:07:20 +0900112
Milo(Woogyom) Kim48068d52013-02-05 18:08:49 +0900113 if (!pdata || !cfg)
Milo(Woogyom) Kima85908d2013-02-05 18:07:20 +0900114 return -EINVAL;
115
116 if (pdata->setup_resources) {
117 ret = pdata->setup_resources();
118 if (ret < 0) {
119 dev_err(dev, "setup resoure err: %d\n", ret);
120 goto err;
121 }
122 }
123
124 if (pdata->enable) {
125 pdata->enable(0);
126 usleep_range(1000, 2000); /* Keep enable down at least 1ms */
127 pdata->enable(1);
128 usleep_range(1000, 2000); /* 500us abs min. */
129 }
130
Milo(Woogyom) Kim48068d52013-02-05 18:08:49 +0900131 lp55xx_reset_device(chip);
132
133 /*
134 * Exact value is not available. 10 - 20ms
135 * appears to be enough for reset.
136 */
137 usleep_range(10000, 20000);
138
Milo(Woogyom) Kime3a700d2013-02-05 18:09:56 +0900139 ret = lp55xx_detect_device(chip);
140 if (ret) {
141 dev_err(dev, "device detection err: %d\n", ret);
142 goto err;
143 }
144
Milo(Woogyom) Kimffbdccd2013-02-05 18:57:36 +0900145 /* chip specific initialization */
146 ret = lp55xx_post_init_device(chip);
Milo(Woogyom) Kim22ebeb42013-02-05 18:58:35 +0900147 if (ret) {
148 dev_err(dev, "post init device err: %d\n", ret);
149 goto err_post_init;
150 }
Milo(Woogyom) Kimffbdccd2013-02-05 18:57:36 +0900151
152 return 0;
153
Milo(Woogyom) Kim22ebeb42013-02-05 18:58:35 +0900154err_post_init:
Milo(Woogyom) Kim6ce61762013-02-05 19:03:02 +0900155 lp55xx_deinit_device(chip);
Milo(Woogyom) Kima85908d2013-02-05 18:07:20 +0900156err:
157 return ret;
158}
159EXPORT_SYMBOL_GPL(lp55xx_init_device);
160
Milo(Woogyom) Kim6ce61762013-02-05 19:03:02 +0900161void lp55xx_deinit_device(struct lp55xx_chip *chip)
162{
163 struct lp55xx_platform_data *pdata = chip->pdata;
164
165 if (pdata->enable)
166 pdata->enable(0);
167
168 if (pdata->release_resources)
169 pdata->release_resources();
170}
171EXPORT_SYMBOL_GPL(lp55xx_deinit_device);
172
Milo(Woogyom) Kimc93d08f2013-02-05 18:01:23 +0900173MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
174MODULE_DESCRIPTION("LP55xx Common Driver");
175MODULE_LICENSE("GPL");