|
8 | 8 | #include <linux/atomic.h> |
9 | 9 | #include <linux/bug.h> |
10 | 10 | #include <linux/device.h> |
| 11 | +#include <linux/dma-mapping.h> |
11 | 12 | #include <linux/err.h> |
12 | 13 | #include <linux/export.h> |
13 | 14 | #include <linux/kernel.h> |
@@ -1727,6 +1728,79 @@ int i3c_master_do_daa(struct i3c_master_controller *master) |
1727 | 1728 | } |
1728 | 1729 | EXPORT_SYMBOL_GPL(i3c_master_do_daa); |
1729 | 1730 |
|
| 1731 | +/** |
| 1732 | + * i3c_master_dma_map_single() - Map buffer for single DMA transfer |
| 1733 | + * @dev: device object of a device doing DMA |
| 1734 | + * @buf: destination/source buffer for DMA |
| 1735 | + * @len: length of transfer |
| 1736 | + * @force_bounce: true, force to use a bounce buffer, |
| 1737 | + * false, function will auto check is a bounce buffer required |
| 1738 | + * @dir: DMA direction |
| 1739 | + * |
| 1740 | + * Map buffer for a DMA transfer and allocate a bounce buffer if required. |
| 1741 | + * |
| 1742 | + * Return: I3C DMA transfer descriptor or NULL in case of error. |
| 1743 | + */ |
| 1744 | +struct i3c_dma *i3c_master_dma_map_single(struct device *dev, void *buf, |
| 1745 | + size_t len, bool force_bounce, enum dma_data_direction dir) |
| 1746 | +{ |
| 1747 | + struct i3c_dma *dma_xfer __free(kfree) = NULL; |
| 1748 | + void *bounce __free(kfree) = NULL; |
| 1749 | + void *dma_buf = buf; |
| 1750 | + |
| 1751 | + dma_xfer = kzalloc(sizeof(*dma_xfer), GFP_KERNEL); |
| 1752 | + if (!dma_xfer) |
| 1753 | + return NULL; |
| 1754 | + |
| 1755 | + dma_xfer->dev = dev; |
| 1756 | + dma_xfer->buf = buf; |
| 1757 | + dma_xfer->dir = dir; |
| 1758 | + dma_xfer->len = len; |
| 1759 | + dma_xfer->map_len = len; |
| 1760 | + |
| 1761 | + if (is_vmalloc_addr(buf)) |
| 1762 | + force_bounce = true; |
| 1763 | + |
| 1764 | + if (force_bounce) { |
| 1765 | + dma_xfer->map_len = ALIGN(len, cache_line_size()); |
| 1766 | + if (dir == DMA_FROM_DEVICE) |
| 1767 | + bounce = kzalloc(dma_xfer->map_len, GFP_KERNEL); |
| 1768 | + else |
| 1769 | + bounce = kmemdup(buf, dma_xfer->map_len, GFP_KERNEL); |
| 1770 | + if (!bounce) |
| 1771 | + return NULL; |
| 1772 | + dma_buf = bounce; |
| 1773 | + } |
| 1774 | + |
| 1775 | + dma_xfer->addr = dma_map_single(dev, dma_buf, dma_xfer->map_len, dir); |
| 1776 | + if (dma_mapping_error(dev, dma_xfer->addr)) |
| 1777 | + return NULL; |
| 1778 | + |
| 1779 | + dma_xfer->bounce_buf = no_free_ptr(bounce); |
| 1780 | + return no_free_ptr(dma_xfer); |
| 1781 | +} |
| 1782 | +EXPORT_SYMBOL_GPL(i3c_master_dma_map_single); |
| 1783 | + |
| 1784 | +/** |
| 1785 | + * i3c_master_dma_unmap_single() - Unmap buffer after DMA |
| 1786 | + * @dma_xfer: DMA transfer and mapping descriptor |
| 1787 | + * |
| 1788 | + * Unmap buffer and cleanup DMA transfer descriptor. |
| 1789 | + */ |
| 1790 | +void i3c_master_dma_unmap_single(struct i3c_dma *dma_xfer) |
| 1791 | +{ |
| 1792 | + dma_unmap_single(dma_xfer->dev, dma_xfer->addr, |
| 1793 | + dma_xfer->map_len, dma_xfer->dir); |
| 1794 | + if (dma_xfer->bounce_buf) { |
| 1795 | + if (dma_xfer->dir == DMA_FROM_DEVICE) |
| 1796 | + memcpy(dma_xfer->buf, dma_xfer->bounce_buf, |
| 1797 | + dma_xfer->len); |
| 1798 | + kfree(dma_xfer->bounce_buf); |
| 1799 | + } |
| 1800 | + kfree(dma_xfer); |
| 1801 | +} |
| 1802 | +EXPORT_SYMBOL_GPL(i3c_master_dma_unmap_single); |
| 1803 | + |
1730 | 1804 | /** |
1731 | 1805 | * i3c_master_set_info() - set master device information |
1732 | 1806 | * @master: master used to send frames on the bus |
@@ -2490,9 +2564,7 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master) |
2490 | 2564 | adap->owner = master->dev.parent->driver->owner; |
2491 | 2565 | adap->algo = &i3c_master_i2c_algo; |
2492 | 2566 | strscpy(adap->name, dev_name(master->dev.parent), sizeof(adap->name)); |
2493 | | - |
2494 | | - /* FIXME: Should we allow i3c masters to override these values? */ |
2495 | | - adap->timeout = 1000; |
| 2567 | + adap->timeout = HZ; |
2496 | 2568 | adap->retries = 3; |
2497 | 2569 |
|
2498 | 2570 | id = of_alias_get_id(master->dev.of_node, "i2c"); |
|
0 commit comments