clk-lpss.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. * Intel Low Power Subsystem clocks.
  3. *
  4. * Copyright (C) 2013, Intel Corporation
  5. * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
  6. * 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. #include <linux/acpi.h>
  13. #include <linux/clk.h>
  14. #include <linux/clk-provider.h>
  15. #include <linux/err.h>
  16. #include <linux/io.h>
  17. #include <linux/module.h>
  18. static int clk_lpss_is_mmio_resource(struct acpi_resource *res, void *data)
  19. {
  20. struct resource r;
  21. return !acpi_dev_resource_memory(res, &r);
  22. }
  23. static acpi_status clk_lpss_find_mmio(acpi_handle handle, u32 level,
  24. void *data, void **retval)
  25. {
  26. struct resource_list_entry *rentry;
  27. struct list_head resource_list;
  28. struct acpi_device *adev;
  29. const char *uid = data;
  30. int ret;
  31. if (acpi_bus_get_device(handle, &adev))
  32. return AE_OK;
  33. if (uid) {
  34. if (!adev->pnp.unique_id)
  35. return AE_OK;
  36. if (strcmp(uid, adev->pnp.unique_id))
  37. return AE_OK;
  38. }
  39. INIT_LIST_HEAD(&resource_list);
  40. ret = acpi_dev_get_resources(adev, &resource_list,
  41. clk_lpss_is_mmio_resource, NULL);
  42. if (ret < 0)
  43. return AE_NO_MEMORY;
  44. list_for_each_entry(rentry, &resource_list, node)
  45. if (resource_type(&rentry->res) == IORESOURCE_MEM) {
  46. *(struct resource *)retval = rentry->res;
  47. break;
  48. }
  49. acpi_dev_free_resource_list(&resource_list);
  50. return AE_OK;
  51. }
  52. /**
  53. * clk_register_lpss_gate - register LPSS clock gate
  54. * @name: name of this clock gate
  55. * @parent_name: parent clock name
  56. * @hid: ACPI _HID of the device
  57. * @uid: ACPI _UID of the device (optional)
  58. * @offset: LPSS PRV_CLOCK_PARAMS offset
  59. *
  60. * Creates and registers LPSS clock gate.
  61. */
  62. struct clk *clk_register_lpss_gate(const char *name, const char *parent_name,
  63. const char *hid, const char *uid,
  64. unsigned offset)
  65. {
  66. struct resource res = { };
  67. void __iomem *mmio_base;
  68. acpi_status status;
  69. struct clk *clk;
  70. /*
  71. * First try to look the device and its mmio resource from the
  72. * ACPI namespace.
  73. */
  74. status = acpi_get_devices(hid, clk_lpss_find_mmio, (void *)uid,
  75. (void **)&res);
  76. if (ACPI_FAILURE(status) || !res.start)
  77. return ERR_PTR(-ENODEV);
  78. mmio_base = ioremap(res.start, resource_size(&res));
  79. if (!mmio_base)
  80. return ERR_PTR(-ENOMEM);
  81. clk = clk_register_gate(NULL, name, parent_name, 0, mmio_base + offset,
  82. 0, 0, NULL);
  83. if (IS_ERR(clk))
  84. iounmap(mmio_base);
  85. return clk;
  86. }