diff options
Diffstat (limited to 'drivers/auxdisplay/ht16k33.c')
-rw-r--r-- | drivers/auxdisplay/ht16k33.c | 510 |
1 files changed, 401 insertions, 109 deletions
diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c index 9c0bb771751d..4fab3b2c7023 100644 --- a/drivers/auxdisplay/ht16k33.c +++ b/drivers/auxdisplay/ht16k33.c @@ -5,27 +5,39 @@ * Author: Robin van der Gracht <robin@protonic.nl> * * Copyright: (C) 2016 Protonic Holland. + * Copyright (C) 2021 Glider bv */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/i2c.h> -#include <linux/of.h> +#include <linux/property.h> #include <linux/fb.h> -#include <linux/slab.h> #include <linux/backlight.h> #include <linux/input.h> #include <linux/input/matrix_keypad.h> +#include <linux/leds.h> #include <linux/workqueue.h> #include <linux/mm.h> +#include <linux/map_to_7segment.h> +#include <linux/map_to_14segment.h> + +#include <asm/unaligned.h> + +#include "line-display.h" + /* Registers */ #define REG_SYSTEM_SETUP 0x20 #define REG_SYSTEM_SETUP_OSC_ON BIT(0) #define REG_DISPLAY_SETUP 0x80 #define REG_DISPLAY_SETUP_ON BIT(0) +#define REG_DISPLAY_SETUP_BLINK_OFF (0 << 1) +#define REG_DISPLAY_SETUP_BLINK_2HZ (1 << 1) +#define REG_DISPLAY_SETUP_BLINK_1HZ (2 << 1) +#define REG_DISPLAY_SETUP_BLINK_0HZ5 (3 << 1) #define REG_ROWINT_SET 0xA0 #define REG_ROWINT_SET_INT_EN BIT(0) @@ -47,6 +59,12 @@ #define BYTES_PER_ROW (HT16K33_MATRIX_LED_MAX_ROWS / 8) #define HT16K33_FB_SIZE (HT16K33_MATRIX_LED_MAX_COLS * BYTES_PER_ROW) +enum display_type { + DISP_MATRIX = 0, + DISP_QUAD_7SEG, + DISP_QUAD_14SEG, +}; + struct ht16k33_keypad { struct i2c_client *client; struct input_dev *dev; @@ -65,16 +83,32 @@ struct ht16k33_fbdev { uint32_t refresh_rate; uint8_t *buffer; uint8_t *cache; - struct delayed_work work; +}; + +struct ht16k33_seg { + struct linedisp linedisp; + union { + struct seg7_conversion_map seg7; + struct seg14_conversion_map seg14; + } map; + unsigned int map_size; + char curr[4]; }; struct ht16k33_priv { struct i2c_client *client; + struct delayed_work work; + struct led_classdev led; struct ht16k33_keypad keypad; - struct ht16k33_fbdev fbdev; + union { + struct ht16k33_fbdev fbdev; + struct ht16k33_seg seg; + }; + enum display_type type; + uint8_t blink; }; -static struct fb_fix_screeninfo ht16k33_fb_fix = { +static const struct fb_fix_screeninfo ht16k33_fb_fix = { .id = DRIVER_NAME, .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_MONO10, @@ -85,7 +119,7 @@ static struct fb_fix_screeninfo ht16k33_fb_fix = { .accel = FB_ACCEL_NONE, }; -static struct fb_var_screeninfo ht16k33_fb_var = { +static const struct fb_var_screeninfo ht16k33_fb_var = { .xres = HT16K33_MATRIX_LED_MAX_ROWS, .yres = HT16K33_MATRIX_LED_MAX_COLS, .xres_virtual = HT16K33_MATRIX_LED_MAX_ROWS, @@ -101,9 +135,36 @@ static struct fb_var_screeninfo ht16k33_fb_var = { .vmode = FB_VMODE_NONINTERLACED, }; +static const SEG7_DEFAULT_MAP(initial_map_seg7); +static const SEG14_DEFAULT_MAP(initial_map_seg14); + +static ssize_t map_seg_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ht16k33_priv *priv = dev_get_drvdata(dev); + + memcpy(buf, &priv->seg.map, priv->seg.map_size); + return priv->seg.map_size; +} + +static ssize_t map_seg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t cnt) +{ + struct ht16k33_priv *priv = dev_get_drvdata(dev); + + if (cnt != priv->seg.map_size) + return -EINVAL; + + memcpy(&priv->seg.map, buf, cnt); + return cnt; +} + +static DEVICE_ATTR(map_seg7, 0644, map_seg_show, map_seg_store); +static DEVICE_ATTR(map_seg14, 0644, map_seg_show, map_seg_store); + static int ht16k33_display_on(struct ht16k33_priv *priv) { - uint8_t data = REG_DISPLAY_SETUP | REG_DISPLAY_SETUP_ON; + uint8_t data = REG_DISPLAY_SETUP | REG_DISPLAY_SETUP_ON | priv->blink; return i2c_smbus_write_byte(priv->client, data); } @@ -113,12 +174,72 @@ static int ht16k33_display_off(struct ht16k33_priv *priv) return i2c_smbus_write_byte(priv->client, REG_DISPLAY_SETUP); } +static int ht16k33_brightness_set(struct ht16k33_priv *priv, + unsigned int brightness) +{ + int err; + + if (brightness == 0) { + priv->blink = REG_DISPLAY_SETUP_BLINK_OFF; + return ht16k33_display_off(priv); + } + + err = ht16k33_display_on(priv); + if (err) + return err; + + return i2c_smbus_write_byte(priv->client, + REG_BRIGHTNESS | (brightness - 1)); +} + +static int ht16k33_brightness_set_blocking(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct ht16k33_priv *priv = container_of(led_cdev, struct ht16k33_priv, + led); + + return ht16k33_brightness_set(priv, brightness); +} + +static int ht16k33_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, unsigned long *delay_off) +{ + struct ht16k33_priv *priv = container_of(led_cdev, struct ht16k33_priv, + led); + unsigned int delay; + uint8_t blink; + int err; + + if (!*delay_on && !*delay_off) { + blink = REG_DISPLAY_SETUP_BLINK_1HZ; + delay = 1000; + } else if (*delay_on <= 750) { + blink = REG_DISPLAY_SETUP_BLINK_2HZ; + delay = 500; + } else if (*delay_on <= 1500) { + blink = REG_DISPLAY_SETUP_BLINK_1HZ; + delay = 1000; + } else { + blink = REG_DISPLAY_SETUP_BLINK_0HZ5; + delay = 2000; + } + + err = i2c_smbus_write_byte(priv->client, + REG_DISPLAY_SETUP | REG_DISPLAY_SETUP_ON | + blink); + if (err) + return err; + + priv->blink = blink; + *delay_on = *delay_off = delay; + return 0; +} + static void ht16k33_fb_queue(struct ht16k33_priv *priv) { struct ht16k33_fbdev *fbdev = &priv->fbdev; - schedule_delayed_work(&fbdev->work, - msecs_to_jiffies(HZ / fbdev->refresh_rate)); + schedule_delayed_work(&priv->work, HZ / fbdev->refresh_rate); } /* @@ -126,10 +247,9 @@ static void ht16k33_fb_queue(struct ht16k33_priv *priv) */ static void ht16k33_fb_update(struct work_struct *work) { - struct ht16k33_fbdev *fbdev = - container_of(work, struct ht16k33_fbdev, work.work); - struct ht16k33_priv *priv = - container_of(fbdev, struct ht16k33_priv, fbdev); + struct ht16k33_priv *priv = container_of(work, struct ht16k33_priv, + work.work); + struct ht16k33_fbdev *fbdev = &priv->fbdev; uint8_t *p1, *p2; int len, pos = 0, first = -1; @@ -169,9 +289,9 @@ requeue: static int ht16k33_initialize(struct ht16k33_priv *priv) { + uint8_t data[HT16K33_FB_SIZE]; uint8_t byte; int err; - uint8_t data[HT16K33_MATRIX_LED_MAX_COLS * 2]; /* Clear RAM (8 * 16 bits) */ memset(data, 0, sizeof(data)); @@ -199,13 +319,10 @@ static int ht16k33_bl_update_status(struct backlight_device *bl) if (bl->props.power != FB_BLANK_UNBLANK || bl->props.fb_blank != FB_BLANK_UNBLANK || - bl->props.state & BL_CORE_FBBLANK || brightness == 0) { - return ht16k33_display_off(priv); - } + bl->props.state & BL_CORE_FBBLANK) + brightness = 0; - ht16k33_display_on(priv); - return i2c_smbus_write_byte(priv->client, - REG_BRIGHTNESS | (brightness - 1)); + return ht16k33_brightness_set(priv, brightness); } static int ht16k33_bl_check_fb(struct backlight_device *bl, struct fb_info *fi) @@ -220,6 +337,15 @@ static const struct backlight_ops ht16k33_bl_ops = { .check_fb = ht16k33_bl_check_fb, }; +/* + * Blank events will be passed to the actual device handling the backlight when + * we return zero here. + */ +static int ht16k33_blank(int blank, struct fb_info *info) +{ + return 0; +} + static int ht16k33_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct ht16k33_priv *priv = info->par; @@ -228,10 +354,11 @@ static int ht16k33_mmap(struct fb_info *info, struct vm_area_struct *vma) return vm_map_pages_zero(vma, &pages, 1); } -static struct fb_ops ht16k33_fb_ops = { +static const struct fb_ops ht16k33_fb_ops = { .owner = THIS_MODULE, .fb_read = fb_sys_read, .fb_write = fb_sys_write, + .fb_blank = ht16k33_blank, .fb_fillrect = sys_fillrect, .fb_copyarea = sys_copyarea, .fb_imageblit = sys_imageblit, @@ -314,10 +441,82 @@ static void ht16k33_keypad_stop(struct input_dev *dev) disable_irq(keypad->client->irq); } +static void ht16k33_linedisp_update(struct linedisp *linedisp) +{ + struct ht16k33_priv *priv = container_of(linedisp, struct ht16k33_priv, + seg.linedisp); + + schedule_delayed_work(&priv->work, 0); +} + +static void ht16k33_seg7_update(struct work_struct *work) +{ + struct ht16k33_priv *priv = container_of(work, struct ht16k33_priv, + work.work); + struct ht16k33_seg *seg = &priv->seg; + char *s = seg->curr; + uint8_t buf[9]; + + buf[0] = map_to_seg7(&seg->map.seg7, *s++); + buf[1] = 0; + buf[2] = map_to_seg7(&seg->map.seg7, *s++); + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = map_to_seg7(&seg->map.seg7, *s++); + buf[7] = 0; + buf[8] = map_to_seg7(&seg->map.seg7, *s++); + + i2c_smbus_write_i2c_block_data(priv->client, 0, ARRAY_SIZE(buf), buf); +} + +static void ht16k33_seg14_update(struct work_struct *work) +{ + struct ht16k33_priv *priv = container_of(work, struct ht16k33_priv, + work.work); + struct ht16k33_seg *seg = &priv->seg; + char *s = seg->curr; + uint8_t buf[8]; + + put_unaligned_le16(map_to_seg14(&seg->map.seg14, *s++), buf); + put_unaligned_le16(map_to_seg14(&seg->map.seg14, *s++), buf + 2); + put_unaligned_le16(map_to_seg14(&seg->map.seg14, *s++), buf + 4); + put_unaligned_le16(map_to_seg14(&seg->map.seg14, *s++), buf + 6); + + i2c_smbus_write_i2c_block_data(priv->client, 0, ARRAY_SIZE(buf), buf); +} + +static int ht16k33_led_probe(struct device *dev, struct led_classdev *led, + unsigned int brightness) +{ + struct led_init_data init_data = {}; + int err; + + /* The LED is optional */ + init_data.fwnode = device_get_named_child_node(dev, "led"); + if (!init_data.fwnode) + return 0; + + init_data.devicename = "auxdisplay"; + init_data.devname_mandatory = true; + + led->brightness_set_blocking = ht16k33_brightness_set_blocking; + led->blink_set = ht16k33_blink_set; + led->flags = LED_CORE_SUSPENDRESUME; + led->brightness = brightness; + led->max_brightness = MAX_BRIGHTNESS; + + err = devm_led_classdev_register_ext(dev, led, &init_data); + if (err) + dev_err(dev, "Failed to register LED\n"); + + return err; +} + static int ht16k33_keypad_probe(struct i2c_client *client, struct ht16k33_keypad *keypad) { - struct device_node *node = client->dev.of_node; + struct device *dev = &client->dev; u32 rows = HT16K33_MATRIX_KEYPAD_MAX_ROWS; u32 cols = HT16K33_MATRIX_KEYPAD_MAX_COLS; int err; @@ -325,7 +524,7 @@ static int ht16k33_keypad_probe(struct i2c_client *client, keypad->client = client; init_waitqueue_head(&keypad->wait); - keypad->dev = devm_input_allocate_device(&client->dev); + keypad->dev = devm_input_allocate_device(dev); if (!keypad->dev) return -ENOMEM; @@ -336,23 +535,23 @@ static int ht16k33_keypad_probe(struct i2c_client *client, keypad->dev->open = ht16k33_keypad_start; keypad->dev->close = ht16k33_keypad_stop; - if (!of_get_property(node, "linux,no-autorepeat", NULL)) + if (!device_property_read_bool(dev, "linux,no-autorepeat")) __set_bit(EV_REP, keypad->dev->evbit); - err = of_property_read_u32(node, "debounce-delay-ms", - &keypad->debounce_ms); + err = device_property_read_u32(dev, "debounce-delay-ms", + &keypad->debounce_ms); if (err) { - dev_err(&client->dev, "key debounce delay not specified\n"); + dev_err(dev, "key debounce delay not specified\n"); return err; } - err = matrix_keypad_parse_of_params(&client->dev, &rows, &cols); + err = matrix_keypad_parse_properties(dev, &rows, &cols); if (err) return err; if (rows > HT16K33_MATRIX_KEYPAD_MAX_ROWS || cols > HT16K33_MATRIX_KEYPAD_MAX_COLS) { - dev_err(&client->dev, "%u rows or %u cols out of range in DT\n", - rows, cols); + dev_err(dev, "%u rows or %u cols out of range in DT\n", rows, + cols); return -ERANGE; } @@ -363,94 +562,89 @@ static int ht16k33_keypad_probe(struct i2c_client *client, err = matrix_keypad_build_keymap(NULL, NULL, rows, cols, NULL, keypad->dev); if (err) { - dev_err(&client->dev, "failed to build keymap\n"); + dev_err(dev, "failed to build keymap\n"); return err; } - err = devm_request_threaded_irq(&client->dev, client->irq, - NULL, ht16k33_keypad_irq_thread, + err = devm_request_threaded_irq(dev, client->irq, NULL, + ht16k33_keypad_irq_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DRIVER_NAME, keypad); if (err) { - dev_err(&client->dev, "irq request failed %d, error %d\n", - client->irq, err); + dev_err(dev, "irq request failed %d, error %d\n", client->irq, + err); return err; } ht16k33_keypad_stop(keypad->dev); - err = input_register_device(keypad->dev); - if (err) - return err; - - return 0; + return input_register_device(keypad->dev); } -static int ht16k33_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ht16k33_fbdev_probe(struct device *dev, struct ht16k33_priv *priv, + uint32_t brightness) { + struct ht16k33_fbdev *fbdev = &priv->fbdev; + struct backlight_device *bl = NULL; int err; - uint32_t dft_brightness; - struct backlight_device *bl; - struct backlight_properties bl_props; - struct ht16k33_priv *priv; - struct ht16k33_fbdev *fbdev; - struct device_node *node = client->dev.of_node; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - dev_err(&client->dev, "i2c_check_functionality error\n"); - return -EIO; - } + if (priv->led.dev) { + err = ht16k33_brightness_set(priv, brightness); + if (err) + return err; + } else { + /* backwards compatibility with DT lacking an led subnode */ + struct backlight_properties bl_props; + + memset(&bl_props, 0, sizeof(struct backlight_properties)); + bl_props.type = BACKLIGHT_RAW; + bl_props.max_brightness = MAX_BRIGHTNESS; + + bl = devm_backlight_device_register(dev, DRIVER_NAME"-bl", dev, + priv, &ht16k33_bl_ops, + &bl_props); + if (IS_ERR(bl)) { + dev_err(dev, "failed to register backlight\n"); + return PTR_ERR(bl); + } - if (client->irq <= 0) { - dev_err(&client->dev, "No IRQ specified\n"); - return -EINVAL; + bl->props.brightness = brightness; + ht16k33_bl_update_status(bl); } - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->client = client; - i2c_set_clientdata(client, priv); - fbdev = &priv->fbdev; - - err = ht16k33_initialize(priv); - if (err) - return err; - /* Framebuffer (2 bytes per column) */ BUILD_BUG_ON(PAGE_SIZE < HT16K33_FB_SIZE); fbdev->buffer = (unsigned char *) get_zeroed_page(GFP_KERNEL); if (!fbdev->buffer) return -ENOMEM; - fbdev->cache = devm_kmalloc(&client->dev, HT16K33_FB_SIZE, GFP_KERNEL); + fbdev->cache = devm_kmalloc(dev, HT16K33_FB_SIZE, GFP_KERNEL); if (!fbdev->cache) { err = -ENOMEM; goto err_fbdev_buffer; } - fbdev->info = framebuffer_alloc(0, &client->dev); + fbdev->info = framebuffer_alloc(0, dev); if (!fbdev->info) { err = -ENOMEM; goto err_fbdev_buffer; } - err = of_property_read_u32(node, "refresh-rate-hz", - &fbdev->refresh_rate); + err = device_property_read_u32(dev, "refresh-rate-hz", + &fbdev->refresh_rate); if (err) { - dev_err(&client->dev, "refresh rate not specified\n"); + dev_err(dev, "refresh rate not specified\n"); goto err_fbdev_info; } fb_bl_default_curve(fbdev->info, 0, MIN_BRIGHTNESS, MAX_BRIGHTNESS); - INIT_DELAYED_WORK(&fbdev->work, ht16k33_fb_update); + INIT_DELAYED_WORK(&priv->work, ht16k33_fb_update); fbdev->info->fbops = &ht16k33_fb_ops; fbdev->info->screen_base = (char __iomem *) fbdev->buffer; fbdev->info->screen_size = HT16K33_FB_SIZE; fbdev->info->fix = ht16k33_fb_fix; fbdev->info->var = ht16k33_fb_var; + fbdev->info->bl_dev = bl; fbdev->info->pseudo_palette = NULL; fbdev->info->flags = FBINFO_FLAG_DEFAULT; fbdev->info->par = priv; @@ -459,48 +653,125 @@ static int ht16k33_probe(struct i2c_client *client, if (err) goto err_fbdev_info; - err = ht16k33_keypad_probe(client, &priv->keypad); + ht16k33_fb_queue(priv); + return 0; + +err_fbdev_info: + framebuffer_release(fbdev->info); +err_fbdev_buffer: + free_page((unsigned long) fbdev->buffer); + + return err; +} + +static int ht16k33_seg_probe(struct device *dev, struct ht16k33_priv *priv, + uint32_t brightness) +{ + struct ht16k33_seg *seg = &priv->seg; + int err; + + err = ht16k33_brightness_set(priv, brightness); if (err) - goto err_fbdev_unregister; - - /* Backlight */ - memset(&bl_props, 0, sizeof(struct backlight_properties)); - bl_props.type = BACKLIGHT_RAW; - bl_props.max_brightness = MAX_BRIGHTNESS; - - bl = devm_backlight_device_register(&client->dev, DRIVER_NAME"-bl", - &client->dev, priv, - &ht16k33_bl_ops, &bl_props); - if (IS_ERR(bl)) { - dev_err(&client->dev, "failed to register backlight\n"); - err = PTR_ERR(bl); - goto err_fbdev_unregister; + return err; + + switch (priv->type) { + case DISP_MATRIX: + /* not handled here */ + err = -EINVAL; + break; + + case DISP_QUAD_7SEG: + INIT_DELAYED_WORK(&priv->work, ht16k33_seg7_update); + seg->map.seg7 = initial_map_seg7; + seg->map_size = sizeof(seg->map.seg7); + err = device_create_file(dev, &dev_attr_map_seg7); + break; + + case DISP_QUAD_14SEG: + INIT_DELAYED_WORK(&priv->work, ht16k33_seg14_update); + seg->map.seg14 = initial_map_seg14; + seg->map_size = sizeof(seg->map.seg14); + err = device_create_file(dev, &dev_attr_map_seg14); + break; } + if (err) + return err; - err = of_property_read_u32(node, "default-brightness-level", - &dft_brightness); + err = linedisp_register(&seg->linedisp, dev, 4, seg->curr, + ht16k33_linedisp_update); + if (err) + goto err_remove_map_file; + + return 0; + +err_remove_map_file: + device_remove_file(dev, &dev_attr_map_seg7); + device_remove_file(dev, &dev_attr_map_seg14); + return err; +} + +static int ht16k33_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + const struct of_device_id *id; + struct ht16k33_priv *priv; + uint32_t dft_brightness; + int err; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(dev, "i2c_check_functionality error\n"); + return -EIO; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->client = client; + id = i2c_of_match_device(dev->driver->of_match_table, client); + if (id) + priv->type = (uintptr_t)id->data; + i2c_set_clientdata(client, priv); + + err = ht16k33_initialize(priv); + if (err) + return err; + + err = device_property_read_u32(dev, "default-brightness-level", + &dft_brightness); if (err) { dft_brightness = MAX_BRIGHTNESS; } else if (dft_brightness > MAX_BRIGHTNESS) { - dev_warn(&client->dev, + dev_warn(dev, "invalid default brightness level: %u, using %u\n", dft_brightness, MAX_BRIGHTNESS); dft_brightness = MAX_BRIGHTNESS; } - bl->props.brightness = dft_brightness; - ht16k33_bl_update_status(bl); - - ht16k33_fb_queue(priv); - return 0; + /* LED */ + err = ht16k33_led_probe(dev, &priv->led, dft_brightness); + if (err) + return err; -err_fbdev_unregister: - unregister_framebuffer(fbdev->info); -err_fbdev_info: - framebuffer_release(fbdev->info); -err_fbdev_buffer: - free_page((unsigned long) fbdev->buffer); + /* Keypad */ + if (client->irq > 0) { + err = ht16k33_keypad_probe(client, &priv->keypad); + if (err) + return err; + } + switch (priv->type) { + case DISP_MATRIX: + /* Frame Buffer Display */ + err = ht16k33_fbdev_probe(dev, priv, dft_brightness); + break; + + case DISP_QUAD_7SEG: + case DISP_QUAD_14SEG: + /* Segment Display */ + err = ht16k33_seg_probe(dev, priv, dft_brightness); + break; + } return err; } @@ -509,10 +780,22 @@ static int ht16k33_remove(struct i2c_client *client) struct ht16k33_priv *priv = i2c_get_clientdata(client); struct ht16k33_fbdev *fbdev = &priv->fbdev; - cancel_delayed_work_sync(&fbdev->work); - unregister_framebuffer(fbdev->info); - framebuffer_release(fbdev->info); - free_page((unsigned long) fbdev->buffer); + cancel_delayed_work_sync(&priv->work); + + switch (priv->type) { + case DISP_MATRIX: + unregister_framebuffer(fbdev->info); + framebuffer_release(fbdev->info); + free_page((unsigned long)fbdev->buffer); + break; + + case DISP_QUAD_7SEG: + case DISP_QUAD_14SEG: + linedisp_unregister(&priv->seg.linedisp); + device_remove_file(&client->dev, &dev_attr_map_seg7); + device_remove_file(&client->dev, &dev_attr_map_seg14); + break; + } return 0; } @@ -524,17 +807,26 @@ static const struct i2c_device_id ht16k33_i2c_match[] = { MODULE_DEVICE_TABLE(i2c, ht16k33_i2c_match); static const struct of_device_id ht16k33_of_match[] = { - { .compatible = "holtek,ht16k33", }, + { + /* 0.56" 4-Digit 7-Segment FeatherWing Display (Red) */ + .compatible = "adafruit,3108", .data = (void *)DISP_QUAD_7SEG, + }, { + /* 0.54" Quad Alphanumeric FeatherWing Display (Red) */ + .compatible = "adafruit,3130", .data = (void *)DISP_QUAD_14SEG, + }, { + /* Generic, assumed Dot-Matrix Display */ + .compatible = "holtek,ht16k33", .data = (void *)DISP_MATRIX, + }, { } }; MODULE_DEVICE_TABLE(of, ht16k33_of_match); static struct i2c_driver ht16k33_driver = { - .probe = ht16k33_probe, + .probe_new = ht16k33_probe, .remove = ht16k33_remove, .driver = { .name = DRIVER_NAME, - .of_match_table = of_match_ptr(ht16k33_of_match), + .of_match_table = ht16k33_of_match, }, .id_table = ht16k33_i2c_match, }; |