0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/delay.h>
0012 #include <linux/err.h>
0013 #include <linux/fb.h>
0014 #include <linux/init.h>
0015 #include <linux/lcd.h>
0016 #include <linux/module.h>
0017 #include <linux/slab.h>
0018
0019 #include <linux/spi/spi.h>
0020
0021 #include <video/ili9320.h>
0022
0023 #include "ili9320.h"
0024
0025
0026 static inline int ili9320_write_spi(struct ili9320 *ili,
0027 unsigned int reg,
0028 unsigned int value)
0029 {
0030 struct ili9320_spi *spi = &ili->access.spi;
0031 unsigned char *addr = spi->buffer_addr;
0032 unsigned char *data = spi->buffer_data;
0033
0034
0035
0036
0037
0038 addr[0] = spi->id | ILI9320_SPI_INDEX | ILI9320_SPI_WRITE;
0039 addr[1] = reg >> 8;
0040 addr[2] = reg;
0041
0042
0043
0044 data[0] = spi->id | ILI9320_SPI_DATA | ILI9320_SPI_WRITE;
0045 data[1] = value >> 8;
0046 data[2] = value;
0047
0048 return spi_sync(spi->dev, &spi->message);
0049 }
0050
0051 int ili9320_write(struct ili9320 *ili, unsigned int reg, unsigned int value)
0052 {
0053 dev_dbg(ili->dev, "write: reg=%02x, val=%04x\n", reg, value);
0054 return ili->write(ili, reg, value);
0055 }
0056 EXPORT_SYMBOL_GPL(ili9320_write);
0057
0058 int ili9320_write_regs(struct ili9320 *ili,
0059 const struct ili9320_reg *values,
0060 int nr_values)
0061 {
0062 int index;
0063 int ret;
0064
0065 for (index = 0; index < nr_values; index++, values++) {
0066 ret = ili9320_write(ili, values->address, values->value);
0067 if (ret != 0)
0068 return ret;
0069 }
0070
0071 return 0;
0072 }
0073 EXPORT_SYMBOL_GPL(ili9320_write_regs);
0074
0075 static void ili9320_reset(struct ili9320 *lcd)
0076 {
0077 struct ili9320_platdata *cfg = lcd->platdata;
0078
0079 cfg->reset(1);
0080 mdelay(50);
0081
0082 cfg->reset(0);
0083 mdelay(50);
0084
0085 cfg->reset(1);
0086 mdelay(100);
0087 }
0088
0089 static inline int ili9320_init_chip(struct ili9320 *lcd)
0090 {
0091 int ret;
0092
0093 ili9320_reset(lcd);
0094
0095 ret = lcd->client->init(lcd, lcd->platdata);
0096 if (ret != 0) {
0097 dev_err(lcd->dev, "failed to initialise display\n");
0098 return ret;
0099 }
0100
0101 lcd->initialised = 1;
0102 return 0;
0103 }
0104
0105 static inline int ili9320_power_on(struct ili9320 *lcd)
0106 {
0107 if (!lcd->initialised)
0108 ili9320_init_chip(lcd);
0109
0110 lcd->display1 |= (ILI9320_DISPLAY1_D(3) | ILI9320_DISPLAY1_BASEE);
0111 ili9320_write(lcd, ILI9320_DISPLAY1, lcd->display1);
0112
0113 return 0;
0114 }
0115
0116 static inline int ili9320_power_off(struct ili9320 *lcd)
0117 {
0118 lcd->display1 &= ~(ILI9320_DISPLAY1_D(3) | ILI9320_DISPLAY1_BASEE);
0119 ili9320_write(lcd, ILI9320_DISPLAY1, lcd->display1);
0120
0121 return 0;
0122 }
0123
0124 #define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
0125
0126 static int ili9320_power(struct ili9320 *lcd, int power)
0127 {
0128 int ret = 0;
0129
0130 dev_dbg(lcd->dev, "power %d => %d\n", lcd->power, power);
0131
0132 if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
0133 ret = ili9320_power_on(lcd);
0134 else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
0135 ret = ili9320_power_off(lcd);
0136
0137 if (ret == 0)
0138 lcd->power = power;
0139 else
0140 dev_warn(lcd->dev, "failed to set power mode %d\n", power);
0141
0142 return ret;
0143 }
0144
0145 static inline struct ili9320 *to_our_lcd(struct lcd_device *lcd)
0146 {
0147 return lcd_get_data(lcd);
0148 }
0149
0150 static int ili9320_set_power(struct lcd_device *ld, int power)
0151 {
0152 struct ili9320 *lcd = to_our_lcd(ld);
0153
0154 return ili9320_power(lcd, power);
0155 }
0156
0157 static int ili9320_get_power(struct lcd_device *ld)
0158 {
0159 struct ili9320 *lcd = to_our_lcd(ld);
0160
0161 return lcd->power;
0162 }
0163
0164 static struct lcd_ops ili9320_ops = {
0165 .get_power = ili9320_get_power,
0166 .set_power = ili9320_set_power,
0167 };
0168
0169 static void ili9320_setup_spi(struct ili9320 *ili,
0170 struct spi_device *dev)
0171 {
0172 struct ili9320_spi *spi = &ili->access.spi;
0173
0174 ili->write = ili9320_write_spi;
0175 spi->dev = dev;
0176
0177
0178
0179
0180
0181
0182 spi->xfer[0].tx_buf = spi->buffer_addr;
0183 spi->xfer[1].tx_buf = spi->buffer_data;
0184 spi->xfer[0].len = 3;
0185 spi->xfer[1].len = 3;
0186 spi->xfer[0].bits_per_word = 8;
0187 spi->xfer[1].bits_per_word = 8;
0188 spi->xfer[0].cs_change = 1;
0189
0190 spi_message_init(&spi->message);
0191 spi_message_add_tail(&spi->xfer[0], &spi->message);
0192 spi_message_add_tail(&spi->xfer[1], &spi->message);
0193 }
0194
0195 int ili9320_probe_spi(struct spi_device *spi,
0196 struct ili9320_client *client)
0197 {
0198 struct ili9320_platdata *cfg = dev_get_platdata(&spi->dev);
0199 struct device *dev = &spi->dev;
0200 struct ili9320 *ili;
0201 struct lcd_device *lcd;
0202 int ret = 0;
0203
0204
0205
0206 if (cfg == NULL) {
0207 dev_err(dev, "no platform data supplied\n");
0208 return -EINVAL;
0209 }
0210
0211 if (cfg->hsize <= 0 || cfg->vsize <= 0 || cfg->reset == NULL) {
0212 dev_err(dev, "invalid platform data supplied\n");
0213 return -EINVAL;
0214 }
0215
0216
0217
0218 ili = devm_kzalloc(&spi->dev, sizeof(struct ili9320), GFP_KERNEL);
0219 if (ili == NULL)
0220 return -ENOMEM;
0221
0222 ili->access.spi.id = ILI9320_SPI_IDCODE | ILI9320_SPI_ID(1);
0223
0224 ili->dev = dev;
0225 ili->client = client;
0226 ili->power = FB_BLANK_POWERDOWN;
0227 ili->platdata = cfg;
0228
0229 spi_set_drvdata(spi, ili);
0230
0231 ili9320_setup_spi(ili, spi);
0232
0233 lcd = devm_lcd_device_register(&spi->dev, "ili9320", dev, ili,
0234 &ili9320_ops);
0235 if (IS_ERR(lcd)) {
0236 dev_err(dev, "failed to register lcd device\n");
0237 return PTR_ERR(lcd);
0238 }
0239
0240 ili->lcd = lcd;
0241
0242 dev_info(dev, "initialising %s\n", client->name);
0243
0244 ret = ili9320_power(ili, FB_BLANK_UNBLANK);
0245 if (ret != 0) {
0246 dev_err(dev, "failed to set lcd power state\n");
0247 return ret;
0248 }
0249
0250 return 0;
0251 }
0252 EXPORT_SYMBOL_GPL(ili9320_probe_spi);
0253
0254 void ili9320_remove(struct ili9320 *ili)
0255 {
0256 ili9320_power(ili, FB_BLANK_POWERDOWN);
0257 }
0258 EXPORT_SYMBOL_GPL(ili9320_remove);
0259
0260 #ifdef CONFIG_PM_SLEEP
0261 int ili9320_suspend(struct ili9320 *lcd)
0262 {
0263 int ret;
0264
0265 ret = ili9320_power(lcd, FB_BLANK_POWERDOWN);
0266
0267 if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP) {
0268 ili9320_write(lcd, ILI9320_POWER1, lcd->power1 |
0269 ILI9320_POWER1_SLP |
0270 ILI9320_POWER1_DSTB);
0271 lcd->initialised = 0;
0272 }
0273
0274 return ret;
0275 }
0276 EXPORT_SYMBOL_GPL(ili9320_suspend);
0277
0278 int ili9320_resume(struct ili9320 *lcd)
0279 {
0280 dev_info(lcd->dev, "resuming from power state %d\n", lcd->power);
0281
0282 if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP)
0283 ili9320_write(lcd, ILI9320_POWER1, 0x00);
0284
0285 return ili9320_power(lcd, FB_BLANK_UNBLANK);
0286 }
0287 EXPORT_SYMBOL_GPL(ili9320_resume);
0288 #endif
0289
0290
0291 void ili9320_shutdown(struct ili9320 *lcd)
0292 {
0293 ili9320_power(lcd, FB_BLANK_POWERDOWN);
0294 }
0295 EXPORT_SYMBOL_GPL(ili9320_shutdown);
0296
0297 MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
0298 MODULE_DESCRIPTION("ILI9320 LCD Driver");
0299 MODULE_LICENSE("GPL v2");