162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NEC NL8048HL11 Panel driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2010 Texas Instruments Inc. 662306a36Sopenharmony_ci * Author: Erik Gilling <konkers@android.com> 762306a36Sopenharmony_ci * Converted to new DSS device model: Tomi Valkeinen <tomi.valkeinen@ti.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <linux/fb.h> 1362306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/spi/spi.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <video/omapfb_dss.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct panel_drv_data { 2062306a36Sopenharmony_ci struct omap_dss_device dssdev; 2162306a36Sopenharmony_ci struct omap_dss_device *in; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci struct omap_video_timings videomode; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci int data_lines; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci struct gpio_desc *res_gpio; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci struct spi_device *spi; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define LCD_XRES 800 3362306a36Sopenharmony_ci#define LCD_YRES 480 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * NEC PIX Clock Ratings 3662306a36Sopenharmony_ci * MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci#define LCD_PIXEL_CLOCK 23800000 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic const struct { 4162306a36Sopenharmony_ci unsigned char addr; 4262306a36Sopenharmony_ci unsigned char dat; 4362306a36Sopenharmony_ci} nec_8048_init_seq[] = { 4462306a36Sopenharmony_ci { 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, { 5, 0x14 }, 4562306a36Sopenharmony_ci { 6, 0x24 }, { 16, 0xD7 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x55 }, 4662306a36Sopenharmony_ci { 20, 0x01 }, { 21, 0x70 }, { 22, 0x1E }, { 23, 0x25 }, { 24, 0x25 }, 4762306a36Sopenharmony_ci { 25, 0x02 }, { 26, 0x02 }, { 27, 0xA0 }, { 32, 0x2F }, { 33, 0x0F }, 4862306a36Sopenharmony_ci { 34, 0x0F }, { 35, 0x0F }, { 36, 0x0F }, { 37, 0x0F }, { 38, 0x0F }, 4962306a36Sopenharmony_ci { 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, { 42, 0x02 }, { 43, 0x0F }, 5062306a36Sopenharmony_ci { 44, 0x0F }, { 45, 0x0F }, { 46, 0x0F }, { 47, 0x0F }, { 48, 0x0F }, 5162306a36Sopenharmony_ci { 49, 0x0F }, { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 }, 5262306a36Sopenharmony_ci { 80, 0x0C }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, { 86, 0x14 }, 5362306a36Sopenharmony_ci { 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, { 92, 0x02 }, { 93, 0x0C }, 5462306a36Sopenharmony_ci { 94, 0x1C }, { 95, 0x27 }, { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 }, 5562306a36Sopenharmony_ci { 103, 0x27 }, { 112, 0x01 }, { 113, 0x0E }, { 114, 0x02 }, 5662306a36Sopenharmony_ci { 115, 0x0C }, { 118, 0x0C }, { 121, 0x30 }, { 130, 0x00 }, 5762306a36Sopenharmony_ci { 131, 0x00 }, { 132, 0xFC }, { 134, 0x00 }, { 136, 0x00 }, 5862306a36Sopenharmony_ci { 138, 0x00 }, { 139, 0x00 }, { 140, 0x00 }, { 141, 0xFC }, 5962306a36Sopenharmony_ci { 143, 0x00 }, { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 }, 6062306a36Sopenharmony_ci { 149, 0x00 }, { 150, 0xFC }, { 152, 0x00 }, { 154, 0x00 }, 6162306a36Sopenharmony_ci { 156, 0x00 }, { 157, 0x00 }, { 2, 0x00 }, 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic const struct omap_video_timings nec_8048_panel_timings = { 6562306a36Sopenharmony_ci .x_res = LCD_XRES, 6662306a36Sopenharmony_ci .y_res = LCD_YRES, 6762306a36Sopenharmony_ci .pixelclock = LCD_PIXEL_CLOCK, 6862306a36Sopenharmony_ci .hfp = 6, 6962306a36Sopenharmony_ci .hsw = 1, 7062306a36Sopenharmony_ci .hbp = 4, 7162306a36Sopenharmony_ci .vfp = 3, 7262306a36Sopenharmony_ci .vsw = 1, 7362306a36Sopenharmony_ci .vbp = 4, 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, 7662306a36Sopenharmony_ci .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, 7762306a36Sopenharmony_ci .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, 7862306a36Sopenharmony_ci .de_level = OMAPDSS_SIG_ACTIVE_HIGH, 7962306a36Sopenharmony_ci .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int nec_8048_spi_send(struct spi_device *spi, unsigned char reg_addr, 8562306a36Sopenharmony_ci unsigned char reg_data) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci int ret = 0; 8862306a36Sopenharmony_ci unsigned int cmd = 0, data = 0; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci cmd = 0x0000 | reg_addr; /* register address write */ 9162306a36Sopenharmony_ci data = 0x0100 | reg_data; /* register data write */ 9262306a36Sopenharmony_ci data = (cmd << 16) | data; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci ret = spi_write(spi, (unsigned char *)&data, 4); 9562306a36Sopenharmony_ci if (ret) 9662306a36Sopenharmony_ci pr_err("error in spi_write %x\n", data); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return ret; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int init_nec_8048_wvga_lcd(struct spi_device *spi) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci unsigned int i; 10462306a36Sopenharmony_ci /* Initialization Sequence */ 10562306a36Sopenharmony_ci /* nec_8048_spi_send(spi, REG, VAL) */ 10662306a36Sopenharmony_ci for (i = 0; i < (ARRAY_SIZE(nec_8048_init_seq) - 1); i++) 10762306a36Sopenharmony_ci nec_8048_spi_send(spi, nec_8048_init_seq[i].addr, 10862306a36Sopenharmony_ci nec_8048_init_seq[i].dat); 10962306a36Sopenharmony_ci udelay(20); 11062306a36Sopenharmony_ci nec_8048_spi_send(spi, nec_8048_init_seq[i].addr, 11162306a36Sopenharmony_ci nec_8048_init_seq[i].dat); 11262306a36Sopenharmony_ci return 0; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic int nec_8048_connect(struct omap_dss_device *dssdev) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci struct panel_drv_data *ddata = to_panel_data(dssdev); 11862306a36Sopenharmony_ci struct omap_dss_device *in = ddata->in; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (omapdss_device_is_connected(dssdev)) 12162306a36Sopenharmony_ci return 0; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return in->ops.dpi->connect(in, dssdev); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void nec_8048_disconnect(struct omap_dss_device *dssdev) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct panel_drv_data *ddata = to_panel_data(dssdev); 12962306a36Sopenharmony_ci struct omap_dss_device *in = ddata->in; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (!omapdss_device_is_connected(dssdev)) 13262306a36Sopenharmony_ci return; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci in->ops.dpi->disconnect(in, dssdev); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int nec_8048_enable(struct omap_dss_device *dssdev) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct panel_drv_data *ddata = to_panel_data(dssdev); 14062306a36Sopenharmony_ci struct omap_dss_device *in = ddata->in; 14162306a36Sopenharmony_ci int r; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (!omapdss_device_is_connected(dssdev)) 14462306a36Sopenharmony_ci return -ENODEV; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (omapdss_device_is_enabled(dssdev)) 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (ddata->data_lines) 15062306a36Sopenharmony_ci in->ops.dpi->set_data_lines(in, ddata->data_lines); 15162306a36Sopenharmony_ci in->ops.dpi->set_timings(in, &ddata->videomode); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci r = in->ops.dpi->enable(in); 15462306a36Sopenharmony_ci if (r) 15562306a36Sopenharmony_ci return r; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* Apparently existing DTSes use incorrect polarity (active high) */ 15862306a36Sopenharmony_ci gpiod_set_value_cansleep(ddata->res_gpio, 1); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic void nec_8048_disable(struct omap_dss_device *dssdev) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct panel_drv_data *ddata = to_panel_data(dssdev); 16862306a36Sopenharmony_ci struct omap_dss_device *in = ddata->in; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (!omapdss_device_is_enabled(dssdev)) 17162306a36Sopenharmony_ci return; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* Apparently existing DTSes use incorrect polarity (active high) */ 17462306a36Sopenharmony_ci gpiod_set_value_cansleep(ddata->res_gpio, 0); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci in->ops.dpi->disable(in); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci dssdev->state = OMAP_DSS_DISPLAY_DISABLED; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void nec_8048_set_timings(struct omap_dss_device *dssdev, 18262306a36Sopenharmony_ci struct omap_video_timings *timings) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci struct panel_drv_data *ddata = to_panel_data(dssdev); 18562306a36Sopenharmony_ci struct omap_dss_device *in = ddata->in; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci ddata->videomode = *timings; 18862306a36Sopenharmony_ci dssdev->panel.timings = *timings; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci in->ops.dpi->set_timings(in, timings); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic void nec_8048_get_timings(struct omap_dss_device *dssdev, 19462306a36Sopenharmony_ci struct omap_video_timings *timings) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct panel_drv_data *ddata = to_panel_data(dssdev); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci *timings = ddata->videomode; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic int nec_8048_check_timings(struct omap_dss_device *dssdev, 20262306a36Sopenharmony_ci struct omap_video_timings *timings) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct panel_drv_data *ddata = to_panel_data(dssdev); 20562306a36Sopenharmony_ci struct omap_dss_device *in = ddata->in; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return in->ops.dpi->check_timings(in, timings); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic struct omap_dss_driver nec_8048_ops = { 21162306a36Sopenharmony_ci .connect = nec_8048_connect, 21262306a36Sopenharmony_ci .disconnect = nec_8048_disconnect, 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci .enable = nec_8048_enable, 21562306a36Sopenharmony_ci .disable = nec_8048_disable, 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci .set_timings = nec_8048_set_timings, 21862306a36Sopenharmony_ci .get_timings = nec_8048_get_timings, 21962306a36Sopenharmony_ci .check_timings = nec_8048_check_timings, 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci .get_resolution = omapdss_default_get_resolution, 22262306a36Sopenharmony_ci}; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int nec_8048_probe(struct spi_device *spi) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct panel_drv_data *ddata; 22762306a36Sopenharmony_ci struct omap_dss_device *dssdev; 22862306a36Sopenharmony_ci int r; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci dev_dbg(&spi->dev, "%s\n", __func__); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (!spi->dev.of_node) 23362306a36Sopenharmony_ci return -ENODEV; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci spi->mode = SPI_MODE_0; 23662306a36Sopenharmony_ci spi->bits_per_word = 32; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci r = spi_setup(spi); 23962306a36Sopenharmony_ci if (r < 0) { 24062306a36Sopenharmony_ci dev_err(&spi->dev, "spi_setup failed: %d\n", r); 24162306a36Sopenharmony_ci return r; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci init_nec_8048_wvga_lcd(spi); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); 24762306a36Sopenharmony_ci if (ddata == NULL) 24862306a36Sopenharmony_ci return -ENOMEM; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci dev_set_drvdata(&spi->dev, ddata); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci ddata->spi = spi; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci ddata->in = omapdss_of_find_source_for_first_ep(spi->dev.of_node); 25562306a36Sopenharmony_ci r = PTR_ERR_OR_ZERO(ddata->in); 25662306a36Sopenharmony_ci if (r) { 25762306a36Sopenharmony_ci dev_err(&spi->dev, "failed to find video source: %d\n", r); 25862306a36Sopenharmony_ci return r; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci ddata->res_gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW); 26262306a36Sopenharmony_ci r = PTR_ERR_OR_ZERO(ddata->res_gpio); 26362306a36Sopenharmony_ci if (r) { 26462306a36Sopenharmony_ci dev_err(&spi->dev, "failed to request reset gpio: %d\n", r); 26562306a36Sopenharmony_ci goto err_gpio; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci gpiod_set_consumer_name(ddata->res_gpio, "lcd RES"); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci ddata->videomode = nec_8048_panel_timings; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci dssdev = &ddata->dssdev; 27362306a36Sopenharmony_ci dssdev->dev = &spi->dev; 27462306a36Sopenharmony_ci dssdev->driver = &nec_8048_ops; 27562306a36Sopenharmony_ci dssdev->type = OMAP_DISPLAY_TYPE_DPI; 27662306a36Sopenharmony_ci dssdev->owner = THIS_MODULE; 27762306a36Sopenharmony_ci dssdev->panel.timings = ddata->videomode; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci r = omapdss_register_display(dssdev); 28062306a36Sopenharmony_ci if (r) { 28162306a36Sopenharmony_ci dev_err(&spi->dev, "Failed to register panel\n"); 28262306a36Sopenharmony_ci goto err_reg; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cierr_reg: 28862306a36Sopenharmony_cierr_gpio: 28962306a36Sopenharmony_ci omap_dss_put_device(ddata->in); 29062306a36Sopenharmony_ci return r; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic void nec_8048_remove(struct spi_device *spi) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); 29662306a36Sopenharmony_ci struct omap_dss_device *dssdev = &ddata->dssdev; 29762306a36Sopenharmony_ci struct omap_dss_device *in = ddata->in; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci dev_dbg(&ddata->spi->dev, "%s\n", __func__); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci omapdss_unregister_display(dssdev); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci nec_8048_disable(dssdev); 30462306a36Sopenharmony_ci nec_8048_disconnect(dssdev); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci omap_dss_put_device(in); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 31062306a36Sopenharmony_cistatic int nec_8048_suspend(struct device *dev) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci nec_8048_spi_send(spi, 2, 0x01); 31562306a36Sopenharmony_ci mdelay(40); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic int nec_8048_resume(struct device *dev) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* reinitialize the panel */ 32562306a36Sopenharmony_ci spi_setup(spi); 32662306a36Sopenharmony_ci nec_8048_spi_send(spi, 2, 0x00); 32762306a36Sopenharmony_ci init_nec_8048_wvga_lcd(spi); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(nec_8048_pm_ops, nec_8048_suspend, 33262306a36Sopenharmony_ci nec_8048_resume); 33362306a36Sopenharmony_ci#define NEC_8048_PM_OPS (&nec_8048_pm_ops) 33462306a36Sopenharmony_ci#else 33562306a36Sopenharmony_ci#define NEC_8048_PM_OPS NULL 33662306a36Sopenharmony_ci#endif 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic const struct of_device_id nec_8048_of_match[] = { 33962306a36Sopenharmony_ci { .compatible = "omapdss,nec,nl8048hl11", }, 34062306a36Sopenharmony_ci {}, 34162306a36Sopenharmony_ci}; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, nec_8048_of_match); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic struct spi_driver nec_8048_driver = { 34662306a36Sopenharmony_ci .driver = { 34762306a36Sopenharmony_ci .name = "panel-nec-nl8048hl11", 34862306a36Sopenharmony_ci .pm = NEC_8048_PM_OPS, 34962306a36Sopenharmony_ci .of_match_table = nec_8048_of_match, 35062306a36Sopenharmony_ci .suppress_bind_attrs = true, 35162306a36Sopenharmony_ci }, 35262306a36Sopenharmony_ci .probe = nec_8048_probe, 35362306a36Sopenharmony_ci .remove = nec_8048_remove, 35462306a36Sopenharmony_ci}; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cimodule_spi_driver(nec_8048_driver); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ciMODULE_ALIAS("spi:nec,nl8048hl11"); 35962306a36Sopenharmony_ciMODULE_AUTHOR("Erik Gilling <konkers@android.com>"); 36062306a36Sopenharmony_ciMODULE_DESCRIPTION("NEC-NL8048HL11 Driver"); 36162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 362