linux/drivers/usb/common/ulpi.c
<<
>>
Prefs
   1/**
   2 * ulpi.c - USB ULPI PHY bus
   3 *
   4 * Copyright (C) 2015 Intel Corporation
   5 *
   6 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/ulpi/interface.h>
  14#include <linux/ulpi/driver.h>
  15#include <linux/ulpi/regs.h>
  16#include <linux/module.h>
  17#include <linux/slab.h>
  18#include <linux/acpi.h>
  19
  20/* -------------------------------------------------------------------------- */
  21
  22int ulpi_read(struct ulpi *ulpi, u8 addr)
  23{
  24        return ulpi->ops->read(ulpi->dev.parent, addr);
  25}
  26EXPORT_SYMBOL_GPL(ulpi_read);
  27
  28int ulpi_write(struct ulpi *ulpi, u8 addr, u8 val)
  29{
  30        return ulpi->ops->write(ulpi->dev.parent, addr, val);
  31}
  32EXPORT_SYMBOL_GPL(ulpi_write);
  33
  34/* -------------------------------------------------------------------------- */
  35
  36static int ulpi_match(struct device *dev, struct device_driver *driver)
  37{
  38        struct ulpi_driver *drv = to_ulpi_driver(driver);
  39        struct ulpi *ulpi = to_ulpi_dev(dev);
  40        const struct ulpi_device_id *id;
  41
  42        for (id = drv->id_table; id->vendor; id++)
  43                if (id->vendor == ulpi->id.vendor &&
  44                    id->product == ulpi->id.product)
  45                        return 1;
  46
  47        return 0;
  48}
  49
  50static int ulpi_uevent(struct device *dev, struct kobj_uevent_env *env)
  51{
  52        struct ulpi *ulpi = to_ulpi_dev(dev);
  53
  54        if (add_uevent_var(env, "MODALIAS=ulpi:v%04xp%04x",
  55                           ulpi->id.vendor, ulpi->id.product))
  56                return -ENOMEM;
  57        return 0;
  58}
  59
  60static int ulpi_probe(struct device *dev)
  61{
  62        struct ulpi_driver *drv = to_ulpi_driver(dev->driver);
  63
  64        return drv->probe(to_ulpi_dev(dev));
  65}
  66
  67static int ulpi_remove(struct device *dev)
  68{
  69        struct ulpi_driver *drv = to_ulpi_driver(dev->driver);
  70
  71        if (drv->remove)
  72                drv->remove(to_ulpi_dev(dev));
  73
  74        return 0;
  75}
  76
  77static struct bus_type ulpi_bus = {
  78        .name = "ulpi",
  79        .match = ulpi_match,
  80        .uevent = ulpi_uevent,
  81        .probe = ulpi_probe,
  82        .remove = ulpi_remove,
  83};
  84
  85/* -------------------------------------------------------------------------- */
  86
  87static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
  88                             char *buf)
  89{
  90        struct ulpi *ulpi = to_ulpi_dev(dev);
  91
  92        return sprintf(buf, "ulpi:v%04xp%04x\n",
  93                       ulpi->id.vendor, ulpi->id.product);
  94}
  95static DEVICE_ATTR_RO(modalias);
  96
  97static struct attribute *ulpi_dev_attrs[] = {
  98        &dev_attr_modalias.attr,
  99        NULL
 100};
 101
 102static struct attribute_group ulpi_dev_attr_group = {
 103        .attrs = ulpi_dev_attrs,
 104};
 105
 106static const struct attribute_group *ulpi_dev_attr_groups[] = {
 107        &ulpi_dev_attr_group,
 108        NULL
 109};
 110
 111static void ulpi_dev_release(struct device *dev)
 112{
 113        kfree(to_ulpi_dev(dev));
 114}
 115
 116static struct device_type ulpi_dev_type = {
 117        .name = "ulpi_device",
 118        .groups = ulpi_dev_attr_groups,
 119        .release = ulpi_dev_release,
 120};
 121
 122/* -------------------------------------------------------------------------- */
 123
 124/**
 125 * ulpi_register_driver - register a driver with the ULPI bus
 126 * @drv: driver being registered
 127 *
 128 * Registers a driver with the ULPI bus.
 129 */
 130int __ulpi_register_driver(struct ulpi_driver *drv, struct module *module)
 131{
 132        if (!drv->probe)
 133                return -EINVAL;
 134
 135        drv->driver.owner = module;
 136        drv->driver.bus = &ulpi_bus;
 137
 138        return driver_register(&drv->driver);
 139}
 140EXPORT_SYMBOL_GPL(__ulpi_register_driver);
 141
 142/**
 143 * ulpi_unregister_driver - unregister a driver with the ULPI bus
 144 * @drv: driver to unregister
 145 *
 146 * Unregisters a driver with the ULPI bus.
 147 */
 148void ulpi_unregister_driver(struct ulpi_driver *drv)
 149{
 150        driver_unregister(&drv->driver);
 151}
 152EXPORT_SYMBOL_GPL(ulpi_unregister_driver);
 153
 154/* -------------------------------------------------------------------------- */
 155
 156static int ulpi_register(struct device *dev, struct ulpi *ulpi)
 157{
 158        int ret;
 159
 160        ulpi->dev.parent = dev; /* needed early for ops */
 161
 162        /* Test the interface */
 163        ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa);
 164        if (ret < 0)
 165                return ret;
 166
 167        ret = ulpi_read(ulpi, ULPI_SCRATCH);
 168        if (ret < 0)
 169                return ret;
 170
 171        if (ret != 0xaa)
 172                return -ENODEV;
 173
 174        ulpi->id.vendor = ulpi_read(ulpi, ULPI_VENDOR_ID_LOW);
 175        ulpi->id.vendor |= ulpi_read(ulpi, ULPI_VENDOR_ID_HIGH) << 8;
 176
 177        ulpi->id.product = ulpi_read(ulpi, ULPI_PRODUCT_ID_LOW);
 178        ulpi->id.product |= ulpi_read(ulpi, ULPI_PRODUCT_ID_HIGH) << 8;
 179
 180        ulpi->dev.bus = &ulpi_bus;
 181        ulpi->dev.type = &ulpi_dev_type;
 182        dev_set_name(&ulpi->dev, "%s.ulpi", dev_name(dev));
 183
 184        ACPI_COMPANION_SET(&ulpi->dev, ACPI_COMPANION(dev));
 185
 186        request_module("ulpi:v%04xp%04x", ulpi->id.vendor, ulpi->id.product);
 187
 188        ret = device_register(&ulpi->dev);
 189        if (ret)
 190                return ret;
 191
 192        dev_dbg(&ulpi->dev, "registered ULPI PHY: vendor %04x, product %04x\n",
 193                ulpi->id.vendor, ulpi->id.product);
 194
 195        return 0;
 196}
 197
 198/**
 199 * ulpi_register_interface - instantiate new ULPI device
 200 * @dev: USB controller's device interface
 201 * @ops: ULPI register access
 202 *
 203 * Allocates and registers a ULPI device and an interface for it. Called from
 204 * the USB controller that provides the ULPI interface.
 205 */
 206struct ulpi *ulpi_register_interface(struct device *dev,
 207                                     const struct ulpi_ops *ops)
 208{
 209        struct ulpi *ulpi;
 210        int ret;
 211
 212        ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL);
 213        if (!ulpi)
 214                return ERR_PTR(-ENOMEM);
 215
 216        ulpi->ops = ops;
 217
 218        ret = ulpi_register(dev, ulpi);
 219        if (ret) {
 220                kfree(ulpi);
 221                return ERR_PTR(ret);
 222        }
 223
 224        return ulpi;
 225}
 226EXPORT_SYMBOL_GPL(ulpi_register_interface);
 227
 228/**
 229 * ulpi_unregister_interface - unregister ULPI interface
 230 * @intrf: struct ulpi_interface
 231 *
 232 * Unregisters a ULPI device and it's interface that was created with
 233 * ulpi_create_interface().
 234 */
 235void ulpi_unregister_interface(struct ulpi *ulpi)
 236{
 237        device_unregister(&ulpi->dev);
 238}
 239EXPORT_SYMBOL_GPL(ulpi_unregister_interface);
 240
 241/* -------------------------------------------------------------------------- */
 242
 243static int __init ulpi_init(void)
 244{
 245        return bus_register(&ulpi_bus);
 246}
 247subsys_initcall(ulpi_init);
 248
 249static void __exit ulpi_exit(void)
 250{
 251        bus_unregister(&ulpi_bus);
 252}
 253module_exit(ulpi_exit);
 254
 255MODULE_AUTHOR("Intel Corporation");
 256MODULE_LICENSE("GPL v2");
 257MODULE_DESCRIPTION("USB ULPI PHY bus");
 258