diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/i2c_eeprom.c | 35 | ||||
-rw-r--r-- | drivers/misc/irq-uclass.c | 131 | ||||
-rw-r--r-- | drivers/misc/irq_sandbox.c | 43 |
3 files changed, 207 insertions, 2 deletions
diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c index 934f82074d5..6c0459dc555 100644 --- a/drivers/misc/i2c_eeprom.c +++ b/drivers/misc/i2c_eeprom.c @@ -15,6 +15,8 @@ struct i2c_eeprom_drv_data { u32 size; /* size in bytes */ u32 pagewidth; /* pagesize = 2^pagewidth */ + u32 addr_offset_mask; /* bits in addr used for offset overflow */ + u32 offset_len; /* size in bytes of offset */ }; int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size) @@ -140,6 +142,11 @@ static int i2c_eeprom_std_probe(struct udevice *dev) { u8 test_byte; int ret; + struct i2c_eeprom_drv_data *data = + (struct i2c_eeprom_drv_data *)dev_get_driver_data(dev); + + i2c_set_chip_offset_len(dev, data->offset_len); + i2c_set_chip_addr_offset_mask(dev, data->addr_offset_mask); /* Verify that the chip is functional */ ret = i2c_eeprom_read(dev, 0, &test_byte, 1); @@ -152,71 +159,99 @@ static int i2c_eeprom_std_probe(struct udevice *dev) static const struct i2c_eeprom_drv_data eeprom_data = { .size = 0, .pagewidth = 0, + .addr_offset_mask = 0, + .offset_len = 1, }; static const struct i2c_eeprom_drv_data mc24aa02e48_data = { .size = 256, .pagewidth = 3, + .addr_offset_mask = 0, + .offset_len = 1, }; static const struct i2c_eeprom_drv_data atmel24c01a_data = { .size = 128, .pagewidth = 3, + .addr_offset_mask = 0, + .offset_len = 1, }; static const struct i2c_eeprom_drv_data atmel24c02_data = { .size = 256, .pagewidth = 3, + .addr_offset_mask = 0, + .offset_len = 1, }; static const struct i2c_eeprom_drv_data atmel24c04_data = { .size = 512, .pagewidth = 4, + .addr_offset_mask = 0x1, + .offset_len = 1, }; static const struct i2c_eeprom_drv_data atmel24c08_data = { .size = 1024, .pagewidth = 4, + .addr_offset_mask = 0x3, + .offset_len = 1, }; static const struct i2c_eeprom_drv_data atmel24c08a_data = { .size = 1024, .pagewidth = 4, + .addr_offset_mask = 0x3, + .offset_len = 1, }; static const struct i2c_eeprom_drv_data atmel24c16a_data = { .size = 2048, .pagewidth = 4, + .addr_offset_mask = 0x7, + .offset_len = 1, }; static const struct i2c_eeprom_drv_data atmel24mac402_data = { .size = 256, .pagewidth = 4, + .addr_offset_mask = 0, + .offset_len = 1, }; static const struct i2c_eeprom_drv_data atmel24c32_data = { .size = 4096, .pagewidth = 5, + .addr_offset_mask = 0, + .offset_len = 2, }; static const struct i2c_eeprom_drv_data atmel24c64_data = { .size = 8192, .pagewidth = 5, + .addr_offset_mask = 0, + .offset_len = 2, }; static const struct i2c_eeprom_drv_data atmel24c128_data = { .size = 16384, .pagewidth = 6, + .addr_offset_mask = 0, + .offset_len = 2, }; static const struct i2c_eeprom_drv_data atmel24c256_data = { .size = 32768, .pagewidth = 6, + .addr_offset_mask = 0, + .offset_len = 2, }; static const struct i2c_eeprom_drv_data atmel24c512_data = { .size = 65536, .pagewidth = 6, + .addr_offset_mask = 0, + .offset_len = 2, }; static const struct udevice_id i2c_eeprom_std_ids[] = { diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c index d5182cf1497..61aa10e4658 100644 --- a/drivers/misc/irq-uclass.c +++ b/drivers/misc/irq-uclass.c @@ -1,11 +1,16 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> + * Copyright 2019 Google, LLC + * Written by Simon Glass <sjg@chromium.org> */ +#define LOG_CATEGORY UCLASS_IRQ + #include <common.h> #include <dm.h> +#include <dt-structs.h> #include <irq.h> +#include <dm/device-internal.h> int irq_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num) { @@ -47,6 +52,130 @@ int irq_restore_polarities(struct udevice *dev) return ops->restore_polarities(dev); } +int irq_read_and_clear(struct irq *irq) +{ + const struct irq_ops *ops = irq_get_ops(irq->dev); + + if (!ops->read_and_clear) + return -ENOSYS; + + return ops->read_and_clear(irq); +} + +#if CONFIG_IS_ENABLED(OF_PLATDATA) +int irq_get_by_index_platdata(struct udevice *dev, int index, + struct phandle_1_arg *cells, struct irq *irq) +{ + int ret; + + if (index != 0) + return -ENOSYS; + ret = uclass_get_device(UCLASS_IRQ, 0, &irq->dev); + if (ret) + return ret; + irq->id = cells[0].arg[0]; + + return 0; +} +#else +static int irq_of_xlate_default(struct irq *irq, + struct ofnode_phandle_args *args) +{ + log_debug("(irq=%p)\n", irq); + + if (args->args_count > 1) { + log_debug("Invaild args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args_count) + irq->id = args->args[0]; + else + irq->id = 0; + + return 0; +} + +static int irq_get_by_index_tail(int ret, ofnode node, + struct ofnode_phandle_args *args, + const char *list_name, int index, + struct irq *irq) +{ + struct udevice *dev_irq; + const struct irq_ops *ops; + + assert(irq); + irq->dev = NULL; + if (ret) + goto err; + + ret = uclass_get_device_by_ofnode(UCLASS_IRQ, args->node, &dev_irq); + if (ret) { + log_debug("uclass_get_device_by_ofnode failed: err=%d\n", ret); + return ret; + } + + irq->dev = dev_irq; + + ops = irq_get_ops(dev_irq); + + if (ops->of_xlate) + ret = ops->of_xlate(irq, args); + else + ret = irq_of_xlate_default(irq, args); + if (ret) { + log_debug("of_xlate() failed: %d\n", ret); + return ret; + } + + return irq_request(dev_irq, irq); +err: + log_debug("Node '%s', property '%s', failed to request IRQ index %d: %d\n", + ofnode_get_name(node), list_name, index, ret); + return ret; +} + +int irq_get_by_index(struct udevice *dev, int index, struct irq *irq) +{ + struct ofnode_phandle_args args; + int ret; + + ret = dev_read_phandle_with_args(dev, "interrupts-extended", + "#interrupt-cells", 0, index, &args); + + return irq_get_by_index_tail(ret, dev_ofnode(dev), &args, + "interrupts-extended", index > 0, irq); +} +#endif /* OF_PLATDATA */ + +int irq_request(struct udevice *dev, struct irq *irq) +{ + const struct irq_ops *ops; + + log_debug("(dev=%p, irq=%p)\n", dev, irq); + if (!irq) + return 0; + ops = irq_get_ops(dev); + + irq->dev = dev; + + if (!ops->request) + return 0; + + return ops->request(irq); +} + +int irq_first_device_type(enum irq_dev_t type, struct udevice **devp) +{ + int ret; + + ret = uclass_first_device_drvdata(UCLASS_IRQ, type, devp); + if (ret) + return log_msg_ret("find", ret); + + return 0; +} + UCLASS_DRIVER(irq) = { .id = UCLASS_IRQ, .name = "irq", diff --git a/drivers/misc/irq_sandbox.c b/drivers/misc/irq_sandbox.c index 6dda1a4c442..54bc47c8d8a 100644 --- a/drivers/misc/irq_sandbox.c +++ b/drivers/misc/irq_sandbox.c @@ -8,6 +8,18 @@ #include <common.h> #include <dm.h> #include <irq.h> +#include <asm/test.h> + +/** + * struct sandbox_irq_priv - private data for this driver + * + * @count: Counts the number calls to the read_and_clear() method + * @pending: true if an interrupt is pending, else false + */ +struct sandbox_irq_priv { + int count; + bool pending; +}; static int sandbox_set_polarity(struct udevice *dev, uint irq, bool active_low) { @@ -35,15 +47,43 @@ static int sandbox_restore_polarities(struct udevice *dev) return 0; } +static int sandbox_irq_read_and_clear(struct irq *irq) +{ + struct sandbox_irq_priv *priv = dev_get_priv(irq->dev); + + if (irq->id != SANDBOX_IRQN_PEND) + return -EINVAL; + priv->count++; + if (priv->pending) { + priv->pending = false; + return 1; + } + + if (!(priv->count % 3)) + priv->pending = true; + + return 0; +} + +static int sandbox_irq_of_xlate(struct irq *irq, + struct ofnode_phandle_args *args) +{ + irq->id = args->args[0]; + + return 0; +} + static const struct irq_ops sandbox_irq_ops = { .route_pmc_gpio_gpe = sandbox_route_pmc_gpio_gpe, .set_polarity = sandbox_set_polarity, .snapshot_polarities = sandbox_snapshot_polarities, .restore_polarities = sandbox_restore_polarities, + .read_and_clear = sandbox_irq_read_and_clear, + .of_xlate = sandbox_irq_of_xlate, }; static const struct udevice_id sandbox_irq_ids[] = { - { .compatible = "sandbox,irq"}, + { .compatible = "sandbox,irq", SANDBOX_IRQT_BASE }, { } }; @@ -52,4 +92,5 @@ U_BOOT_DRIVER(sandbox_irq_drv) = { .id = UCLASS_IRQ, .of_match = sandbox_irq_ids, .ops = &sandbox_irq_ops, + .priv_auto_alloc_size = sizeof(struct sandbox_irq_priv), }; |