| .. | .. |
|---|
| 20 | 20 | #include <linux/dma-mapping.h> |
|---|
| 21 | 21 | #include <linux/sched.h> |
|---|
| 22 | 22 | #include <linux/kthread.h> |
|---|
| 23 | | - |
|---|
| 24 | | -#include "most/core.h" |
|---|
| 23 | +#include <linux/most.h> |
|---|
| 25 | 24 | #include "hal.h" |
|---|
| 26 | 25 | #include "errors.h" |
|---|
| 27 | 26 | #include "sysfs.h" |
|---|
| .. | .. |
|---|
| 47 | 46 | static DEFINE_SPINLOCK(dim_lock); |
|---|
| 48 | 47 | |
|---|
| 49 | 48 | static void dim2_tasklet_fn(unsigned long data); |
|---|
| 50 | | -static DECLARE_TASKLET(dim2_tasklet, dim2_tasklet_fn, 0); |
|---|
| 49 | +static DECLARE_TASKLET_OLD(dim2_tasklet, dim2_tasklet_fn); |
|---|
| 51 | 50 | |
|---|
| 52 | 51 | /** |
|---|
| 53 | 52 | * struct hdm_channel - private structure to keep channel specific data |
|---|
| .. | .. |
|---|
| 101 | 100 | struct medialb_bus bus; |
|---|
| 102 | 101 | void (*on_netinfo)(struct most_interface *most_iface, |
|---|
| 103 | 102 | unsigned char link_state, unsigned char *addrs); |
|---|
| 104 | | - void (*disable_platform)(struct platform_device *); |
|---|
| 103 | + void (*disable_platform)(struct platform_device *pdev); |
|---|
| 105 | 104 | }; |
|---|
| 106 | 105 | |
|---|
| 107 | 106 | struct dim2_platform_data { |
|---|
| 108 | | - int (*enable)(struct platform_device *); |
|---|
| 109 | | - void (*disable)(struct platform_device *); |
|---|
| 107 | + int (*enable)(struct platform_device *pdev); |
|---|
| 108 | + void (*disable)(struct platform_device *pdev); |
|---|
| 110 | 109 | }; |
|---|
| 111 | 110 | |
|---|
| 112 | 111 | #define iface_to_hdm(iface) container_of(iface, struct dim2_hdm, most_iface) |
|---|
| .. | .. |
|---|
| 116 | 115 | (((p)[1] == 0x18) && ((p)[2] == 0x05) && ((p)[3] == 0x0C) && \ |
|---|
| 117 | 116 | ((p)[13] == 0x3C) && ((p)[14] == 0x00) && ((p)[15] == 0x0A)) |
|---|
| 118 | 117 | |
|---|
| 119 | | -bool dim2_sysfs_get_state_cb(void) |
|---|
| 118 | +static ssize_t state_show(struct device *dev, struct device_attribute *attr, |
|---|
| 119 | + char *buf) |
|---|
| 120 | 120 | { |
|---|
| 121 | 121 | bool state; |
|---|
| 122 | 122 | unsigned long flags; |
|---|
| .. | .. |
|---|
| 125 | 125 | state = dim_get_lock_state(); |
|---|
| 126 | 126 | spin_unlock_irqrestore(&dim_lock, flags); |
|---|
| 127 | 127 | |
|---|
| 128 | | - return state; |
|---|
| 128 | + return sysfs_emit(buf, "%s\n", state ? "locked" : ""); |
|---|
| 129 | 129 | } |
|---|
| 130 | 130 | |
|---|
| 131 | | -/** |
|---|
| 132 | | - * dimcb_io_read - callback from HAL to read an I/O register |
|---|
| 133 | | - * @ptr32: register address |
|---|
| 134 | | - */ |
|---|
| 135 | | -u32 dimcb_io_read(u32 __iomem *ptr32) |
|---|
| 136 | | -{ |
|---|
| 137 | | - return readl(ptr32); |
|---|
| 138 | | -} |
|---|
| 131 | +static DEVICE_ATTR_RO(state); |
|---|
| 139 | 132 | |
|---|
| 140 | | -/** |
|---|
| 141 | | - * dimcb_io_write - callback from HAL to write value to an I/O register |
|---|
| 142 | | - * @ptr32: register address |
|---|
| 143 | | - * @value: value to write |
|---|
| 144 | | - */ |
|---|
| 145 | | -void dimcb_io_write(u32 __iomem *ptr32, u32 value) |
|---|
| 146 | | -{ |
|---|
| 147 | | - writel(value, ptr32); |
|---|
| 148 | | -} |
|---|
| 133 | +static struct attribute *dim2_attrs[] = { |
|---|
| 134 | + &dev_attr_state.attr, |
|---|
| 135 | + NULL, |
|---|
| 136 | +}; |
|---|
| 137 | + |
|---|
| 138 | +ATTRIBUTE_GROUPS(dim2); |
|---|
| 149 | 139 | |
|---|
| 150 | 140 | /** |
|---|
| 151 | 141 | * dimcb_on_error - callback from HAL to report miscommunication between |
|---|
| .. | .. |
|---|
| 733 | 723 | return -EINVAL; |
|---|
| 734 | 724 | } |
|---|
| 735 | 725 | |
|---|
| 726 | +static void dim2_release(struct device *d) |
|---|
| 727 | +{ |
|---|
| 728 | + struct dim2_hdm *dev = container_of(d, struct dim2_hdm, dev); |
|---|
| 729 | + unsigned long flags; |
|---|
| 730 | + |
|---|
| 731 | + kthread_stop(dev->netinfo_task); |
|---|
| 732 | + |
|---|
| 733 | + spin_lock_irqsave(&dim_lock, flags); |
|---|
| 734 | + dim_shutdown(); |
|---|
| 735 | + spin_unlock_irqrestore(&dim_lock, flags); |
|---|
| 736 | + |
|---|
| 737 | + if (dev->disable_platform) |
|---|
| 738 | + dev->disable_platform(to_platform_device(d->parent)); |
|---|
| 739 | + |
|---|
| 740 | + kfree(dev); |
|---|
| 741 | +} |
|---|
| 742 | + |
|---|
| 736 | 743 | /* |
|---|
| 737 | 744 | * dim2_probe - dim2 probe handler |
|---|
| 738 | 745 | * @pdev: platform device structure |
|---|
| .. | .. |
|---|
| 753 | 760 | |
|---|
| 754 | 761 | enum { MLB_INT_IDX, AHB0_INT_IDX }; |
|---|
| 755 | 762 | |
|---|
| 756 | | - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); |
|---|
| 763 | + dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
|---|
| 757 | 764 | if (!dev) |
|---|
| 758 | 765 | return -ENOMEM; |
|---|
| 759 | 766 | |
|---|
| .. | .. |
|---|
| 765 | 772 | "microchip,clock-speed", &clock_speed); |
|---|
| 766 | 773 | if (ret) { |
|---|
| 767 | 774 | dev_err(&pdev->dev, "missing dt property clock-speed\n"); |
|---|
| 768 | | - return ret; |
|---|
| 775 | + goto err_free_dev; |
|---|
| 769 | 776 | } |
|---|
| 770 | 777 | |
|---|
| 771 | 778 | ret = get_dim2_clk_speed(clock_speed, &dev->clk_speed); |
|---|
| 772 | 779 | if (ret) { |
|---|
| 773 | 780 | dev_err(&pdev->dev, "bad dt property clock-speed\n"); |
|---|
| 774 | | - return ret; |
|---|
| 781 | + goto err_free_dev; |
|---|
| 775 | 782 | } |
|---|
| 776 | 783 | |
|---|
| 777 | 784 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 778 | 785 | dev->io_base = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 779 | | - if (IS_ERR(dev->io_base)) |
|---|
| 780 | | - return PTR_ERR(dev->io_base); |
|---|
| 786 | + if (IS_ERR(dev->io_base)) { |
|---|
| 787 | + ret = PTR_ERR(dev->io_base); |
|---|
| 788 | + goto err_free_dev; |
|---|
| 789 | + } |
|---|
| 781 | 790 | |
|---|
| 782 | 791 | of_id = of_match_node(dim2_of_match, pdev->dev.of_node); |
|---|
| 783 | 792 | pdata = of_id->data; |
|---|
| 784 | 793 | ret = pdata && pdata->enable ? pdata->enable(pdev) : 0; |
|---|
| 785 | 794 | if (ret) |
|---|
| 786 | | - return ret; |
|---|
| 795 | + goto err_free_dev; |
|---|
| 787 | 796 | |
|---|
| 788 | 797 | dev->disable_platform = pdata ? pdata->disable : NULL; |
|---|
| 789 | 798 | |
|---|
| .. | .. |
|---|
| 797 | 806 | |
|---|
| 798 | 807 | irq = platform_get_irq(pdev, AHB0_INT_IDX); |
|---|
| 799 | 808 | if (irq < 0) { |
|---|
| 800 | | - dev_err(&pdev->dev, "failed to get ahb0_int irq: %d\n", irq); |
|---|
| 801 | 809 | ret = irq; |
|---|
| 802 | 810 | goto err_shutdown_dim; |
|---|
| 803 | 811 | } |
|---|
| .. | .. |
|---|
| 811 | 819 | |
|---|
| 812 | 820 | irq = platform_get_irq(pdev, MLB_INT_IDX); |
|---|
| 813 | 821 | if (irq < 0) { |
|---|
| 814 | | - dev_err(&pdev->dev, "failed to get mlb_int irq: %d\n", irq); |
|---|
| 815 | 822 | ret = irq; |
|---|
| 816 | 823 | goto err_shutdown_dim; |
|---|
| 817 | 824 | } |
|---|
| .. | .. |
|---|
| 875 | 882 | dev->most_iface.poison_channel = poison_channel; |
|---|
| 876 | 883 | dev->most_iface.request_netinfo = request_netinfo; |
|---|
| 877 | 884 | dev->most_iface.driver_dev = &pdev->dev; |
|---|
| 878 | | - dev->dev.init_name = "dim2_state"; |
|---|
| 879 | | - dev->dev.parent = &dev->most_iface.dev; |
|---|
| 885 | + dev->most_iface.dev = &dev->dev; |
|---|
| 886 | + dev->dev.init_name = dev->name; |
|---|
| 887 | + dev->dev.parent = &pdev->dev; |
|---|
| 888 | + dev->dev.release = dim2_release; |
|---|
| 880 | 889 | |
|---|
| 881 | | - ret = most_register_interface(&dev->most_iface); |
|---|
| 882 | | - if (ret) { |
|---|
| 883 | | - dev_err(&pdev->dev, "failed to register MOST interface\n"); |
|---|
| 884 | | - goto err_stop_thread; |
|---|
| 885 | | - } |
|---|
| 890 | + return most_register_interface(&dev->most_iface); |
|---|
| 886 | 891 | |
|---|
| 887 | | - ret = dim2_sysfs_probe(&dev->dev); |
|---|
| 888 | | - if (ret) { |
|---|
| 889 | | - dev_err(&pdev->dev, "failed to create sysfs attribute\n"); |
|---|
| 890 | | - goto err_unreg_iface; |
|---|
| 891 | | - } |
|---|
| 892 | | - |
|---|
| 893 | | - return 0; |
|---|
| 894 | | - |
|---|
| 895 | | -err_unreg_iface: |
|---|
| 896 | | - most_deregister_interface(&dev->most_iface); |
|---|
| 897 | | -err_stop_thread: |
|---|
| 898 | | - kthread_stop(dev->netinfo_task); |
|---|
| 899 | 892 | err_shutdown_dim: |
|---|
| 900 | 893 | dim_shutdown(); |
|---|
| 901 | 894 | err_disable_platform: |
|---|
| 902 | 895 | if (dev->disable_platform) |
|---|
| 903 | 896 | dev->disable_platform(pdev); |
|---|
| 897 | +err_free_dev: |
|---|
| 898 | + kfree(dev); |
|---|
| 904 | 899 | |
|---|
| 905 | 900 | return ret; |
|---|
| 906 | 901 | } |
|---|
| .. | .. |
|---|
| 914 | 909 | static int dim2_remove(struct platform_device *pdev) |
|---|
| 915 | 910 | { |
|---|
| 916 | 911 | struct dim2_hdm *dev = platform_get_drvdata(pdev); |
|---|
| 917 | | - unsigned long flags; |
|---|
| 918 | 912 | |
|---|
| 919 | | - dim2_sysfs_destroy(&dev->dev); |
|---|
| 920 | 913 | most_deregister_interface(&dev->most_iface); |
|---|
| 921 | | - kthread_stop(dev->netinfo_task); |
|---|
| 922 | | - |
|---|
| 923 | | - spin_lock_irqsave(&dim_lock, flags); |
|---|
| 924 | | - dim_shutdown(); |
|---|
| 925 | | - spin_unlock_irqrestore(&dim_lock, flags); |
|---|
| 926 | | - |
|---|
| 927 | | - if (dev->disable_platform) |
|---|
| 928 | | - dev->disable_platform(pdev); |
|---|
| 929 | 914 | |
|---|
| 930 | 915 | return 0; |
|---|
| 931 | 916 | } |
|---|
| .. | .. |
|---|
| 1100 | 1085 | .driver = { |
|---|
| 1101 | 1086 | .name = "hdm_dim2", |
|---|
| 1102 | 1087 | .of_match_table = dim2_of_match, |
|---|
| 1088 | + .dev_groups = dim2_groups, |
|---|
| 1103 | 1089 | }, |
|---|
| 1104 | 1090 | }; |
|---|
| 1105 | 1091 | |
|---|