Kamil Debski | 06fb013 | 2014-03-06 12:16:48 +0100 | [diff] [blame] | 1 | .------------------------------------------------------------------------------+ |
| 2 | | Samsung USB 2.0 PHY adaptation layer | |
| 3 | +-----------------------------------------------------------------------------+' |
| 4 | |
| 5 | | 1. Description |
| 6 | +---------------- |
| 7 | |
| 8 | The architecture of the USB 2.0 PHY module in Samsung SoCs is similar |
| 9 | among many SoCs. In spite of the similarities it proved difficult to |
| 10 | create a one driver that would fit all these PHY controllers. Often |
| 11 | the differences were minor and were found in particular bits of the |
| 12 | registers of the PHY. In some rare cases the order of register writes or |
| 13 | the PHY powering up process had to be altered. This adaptation layer is |
| 14 | a compromise between having separate drivers and having a single driver |
| 15 | with added support for many special cases. |
| 16 | |
| 17 | | 2. Files description |
| 18 | +---------------------- |
| 19 | |
| 20 | - phy-samsung-usb2.c |
| 21 | This is the main file of the adaptation layer. This file contains |
| 22 | the probe function and provides two callbacks to the Generic PHY |
| 23 | Framework. This two callbacks are used to power on and power off the |
| 24 | phy. They carry out the common work that has to be done on all version |
| 25 | of the PHY module. Depending on which SoC was chosen they execute SoC |
| 26 | specific callbacks. The specific SoC version is selected by choosing |
| 27 | the appropriate compatible string. In addition, this file contains |
| 28 | struct of_device_id definitions for particular SoCs. |
| 29 | |
| 30 | - phy-samsung-usb2.h |
| 31 | This is the include file. It declares the structures used by this |
| 32 | driver. In addition it should contain extern declarations for |
| 33 | structures that describe particular SoCs. |
| 34 | |
| 35 | | 3. Supporting SoCs |
| 36 | +-------------------- |
| 37 | |
| 38 | To support a new SoC a new file should be added to the drivers/phy |
| 39 | directory. Each SoC's configuration is stored in an instance of the |
| 40 | struct samsung_usb2_phy_config. |
| 41 | |
| 42 | struct samsung_usb2_phy_config { |
| 43 | const struct samsung_usb2_common_phy *phys; |
| 44 | int (*rate_to_clk)(unsigned long, u32 *); |
| 45 | unsigned int num_phys; |
| 46 | bool has_mode_switch; |
| 47 | }; |
| 48 | |
| 49 | The num_phys is the number of phys handled by the driver. *phys is an |
| 50 | array that contains the configuration for each phy. The has_mode_switch |
| 51 | property is a boolean flag that determines whether the SoC has USB host |
| 52 | and device on a single pair of pins. If so, a special register has to |
| 53 | be modified to change the internal routing of these pins between a USB |
| 54 | device or host module. |
| 55 | |
| 56 | For example the configuration for Exynos 4210 is following: |
| 57 | |
| 58 | const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = { |
| 59 | .has_mode_switch = 0, |
| 60 | .num_phys = EXYNOS4210_NUM_PHYS, |
| 61 | .phys = exynos4210_phys, |
| 62 | .rate_to_clk = exynos4210_rate_to_clk, |
| 63 | } |
| 64 | |
| 65 | - int (*rate_to_clk)(unsigned long, u32 *) |
| 66 | The rate_to_clk callback is to convert the rate of the clock |
| 67 | used as the reference clock for the PHY module to the value |
| 68 | that should be written in the hardware register. |
| 69 | |
| 70 | The exynos4210_phys configuration array is as follows: |
| 71 | |
| 72 | static const struct samsung_usb2_common_phy exynos4210_phys[] = { |
| 73 | { |
| 74 | .label = "device", |
| 75 | .id = EXYNOS4210_DEVICE, |
| 76 | .power_on = exynos4210_power_on, |
| 77 | .power_off = exynos4210_power_off, |
| 78 | }, |
| 79 | { |
| 80 | .label = "host", |
| 81 | .id = EXYNOS4210_HOST, |
| 82 | .power_on = exynos4210_power_on, |
| 83 | .power_off = exynos4210_power_off, |
| 84 | }, |
| 85 | { |
| 86 | .label = "hsic0", |
| 87 | .id = EXYNOS4210_HSIC0, |
| 88 | .power_on = exynos4210_power_on, |
| 89 | .power_off = exynos4210_power_off, |
| 90 | }, |
| 91 | { |
| 92 | .label = "hsic1", |
| 93 | .id = EXYNOS4210_HSIC1, |
| 94 | .power_on = exynos4210_power_on, |
| 95 | .power_off = exynos4210_power_off, |
| 96 | }, |
| 97 | {}, |
| 98 | }; |
| 99 | |
| 100 | - int (*power_on)(struct samsung_usb2_phy_instance *); |
| 101 | - int (*power_off)(struct samsung_usb2_phy_instance *); |
| 102 | These two callbacks are used to power on and power off the phy |
| 103 | by modifying appropriate registers. |
| 104 | |
| 105 | Final change to the driver is adding appropriate compatible value to the |
| 106 | phy-samsung-usb2.c file. In case of Exynos 4210 the following lines were |
| 107 | added to the struct of_device_id samsung_usb2_phy_of_match[] array: |
| 108 | |
| 109 | #ifdef CONFIG_PHY_EXYNOS4210_USB2 |
| 110 | { |
| 111 | .compatible = "samsung,exynos4210-usb2-phy", |
| 112 | .data = &exynos4210_usb2_phy_config, |
| 113 | }, |
| 114 | #endif |
| 115 | |
| 116 | To add further flexibility to the driver the Kconfig file enables to |
| 117 | include support for selected SoCs in the compiled driver. The Kconfig |
| 118 | entry for Exynos 4210 is following: |
| 119 | |
| 120 | config PHY_EXYNOS4210_USB2 |
| 121 | bool "Support for Exynos 4210" |
| 122 | depends on PHY_SAMSUNG_USB2 |
| 123 | depends on CPU_EXYNOS4210 |
| 124 | help |
| 125 | Enable USB PHY support for Exynos 4210. This option requires that |
| 126 | Samsung USB 2.0 PHY driver is enabled and means that support for this |
| 127 | particular SoC is compiled in the driver. In case of Exynos 4210 four |
| 128 | phys are available - device, host, HSCI0 and HSCI1. |
| 129 | |
| 130 | The newly created file that supports the new SoC has to be also added to the |
| 131 | Makefile. In case of Exynos 4210 the added line is following: |
| 132 | |
| 133 | obj-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o |
| 134 | |
| 135 | After completing these steps the support for the new SoC should be ready. |