Linux reset子系统

文章代码分析基于linux-5.19.13,架构基于aarch64(ARM64)。

1. 前言

复杂IC内部有很多具有独立功能的硬件模块,例如CPU cores、GPU cores、USB控制器、MMC控制器、等等,出于功耗、稳定性等方面的考虑,有些IC在内部为这些硬件模块设计了复位信号(reset signals),软件可通过寄存器(一般1个bit控制1个硬件)控制这些硬件模块的复位状态。
Linux kernel为了方便设备驱动的编写,抽象出一个简单的软件框架—-reset framework,为reset的provider提供统一的reset资源管理手段,并为reset的consumer(各个硬件模块)提供便捷、统一的复位控制API。

2. 前言

reset子系统也分为了consumer和provider,结构体关系如下:

3. consumer

对于一个具体的硬件模块,它的要求很简单:复位我的硬件模块,而不必关注具体复位的手段(例如控制哪个寄存器的哪个bit位,等等)。

Linux kernel基于device tree提供了对应的reset framework:

  1. 首先,提供描述系统中reset资源的方法(参考provider的介绍),这样consumer可以基于这种描述,在自己的dts node中引用所需的reset信号。

  2. 然后,consumer设备在自己的dts node中使用“resets”、“reset-names”等关键字声明所需的reset的资源,例如(“resets”字段的具体格式由reset provider决定):

device { resets = <&rst 20>; reset-names = "reset"; };This represents a device with a single reset signal named "reset". bus { resets = <&rst 10> <&rst 11> <&rst 12> <&rst 11>; reset-names = "i2s1", "i2s2", "dma", "mixer"; };This represents a bus that controls the reset signal of each of four sub- ordinate devices. Consider for example a bus that fails to operate unless no child device has reset asserted.
device {  resets = <&rst 20>;  reset-names = "reset"; };This represents a device with a single reset signal named "reset". bus {   resets = <&rst 10> <&rst 11> <&rst 12> <&rst 11>;  reset-names = "i2s1", "i2s2", "dma", "mixer"; };This represents a bus that controls the reset signal of each of four sub- ordinate devices. Consider for example a bus that fails to operate unless no child device has reset asserted. 
device { resets = <&rst 20>; reset-names = "reset"; };This represents a device with a single reset signal named "reset". bus { resets = <&rst 10> <&rst 11> <&rst 12> <&rst 11>; reset-names = "i2s1", "i2s2", "dma", "mixer"; };This represents a bus that controls the reset signal of each of four sub- ordinate devices. Consider for example a bus that fails to operate unless no child device has reset asserted.
  1. 最后,consumer driver在需要的时候,可以调用下面的API复位自己(具体可参考”include\linux\reset.h”):
  • 只有一个reset信号的话,可以使用最简单的device_reset API
static inline int __must_check device_reset(struct device *dev)
static inline int __must_check device_reset(struct device *dev)
static inline int __must_check device_reset(struct device *dev)
  • 如果需要更为复杂的控制(例如有多个reset信号、需要控制处于reset状态的长度的等),可以使用稍微复杂的API
/* 通过reset_control_get或者devm_reset_control_get获得reset句柄 */struct reset_control *reset_control_get(struct device *dev, const char *id); struct reset_control *devm_reset_control_get(struct device *dev, const char *id); /* 通过reset_control_put释放reset句柄 */void reset_control_put(struct reset_control *rstc); /* 通过reset_control_reset进行复位,或者通过reset_control_assert使设备处于复位生效状态,通过reset_control_deassert使复位失效 */int reset_control_reset(struct reset_control *rstc); /先复位,延迟一会,然后解复位 int reset_control_assert(struct reset_control *rstc); //复位 int reset_control_deassert(struct reset_control *rstc);//解复位
/* 通过reset_control_get或者devm_reset_control_get获得reset句柄 */struct reset_control *reset_control_get(struct device *dev, const char *id);                             struct reset_control *devm_reset_control_get(struct device *dev, const char *id); /* 通过reset_control_put释放reset句柄 */void reset_control_put(struct reset_control *rstc);   /* 通过reset_control_reset进行复位,或者通过reset_control_assert使设备处于复位生效状态,通过reset_control_deassert使复位失效 */int reset_control_reset(struct reset_control *rstc);   /先复位,延迟一会,然后解复位                        int reset_control_assert(struct reset_control *rstc);  //复位                       int reset_control_deassert(struct reset_control *rstc);//解复位
/* 通过reset_control_get或者devm_reset_control_get获得reset句柄 */struct reset_control *reset_control_get(struct device *dev, const char *id); struct reset_control *devm_reset_control_get(struct device *dev, const char *id); /* 通过reset_control_put释放reset句柄 */void reset_control_put(struct reset_control *rstc); /* 通过reset_control_reset进行复位,或者通过reset_control_assert使设备处于复位生效状态,通过reset_control_deassert使复位失效 */int reset_control_reset(struct reset_control *rstc); /先复位,延迟一会,然后解复位 int reset_control_assert(struct reset_control *rstc); //复位 int reset_control_deassert(struct reset_control *rstc);//解复位

4. provider

kernel为reset provider提供的API位于”include/linux/reset-controller.h”中,很简单,无非就是:创建并填充reset controller设备(struct reset_controller_dev),并调用相应的接口:

  • reset_controller_register //注册reset_controller
  • reset_controller_unregister //注销reset_controller

reset controller的抽象也很简单:

/** * struct reset_controller_dev - reset controller entity that might * provide multiple reset controls * @ops: a pointer to device specific struct reset_control_ops * @owner: kernel module of the reset controller driver * @list: internal list of reset controller devices * @reset_control_head: head of internal list of requested reset controls * @dev: corresponding driver model device struct * @of_node: corresponding device tree node as phandle target * @of_reset_n_cells: number of cells in reset line specifiers * @of_xlate: translation function to translate from specifier as found in the * device tree to id as given to the reset control ops, defaults * to :c:func:`of_reset_simple_xlate`. * @nr_resets: number of reset controls in this reset controller device */struct reset_controller_dev { const struct reset_control_ops *ops;//ops提供reset操作的实现,基本上是reset provider的所有工作量。 struct module *owner; struct list_head list;////全局链表,复位控制器注册后挂载到全局链表 struct list_head reset_control_head;////各个模块复位的链表头 struct device *dev; struct device_node *of_node; int of_reset_n_cells;////用于解析consumer device dts node中的“resets = <>; ”节点,指示dts中引用时,需要几个参数 int (*of_xlate)(struct reset_controller_dev *rcdev, const struct of_phandle_args *reset_spec);//用于解析consumer device dts node中的“resets = <>; ”节点 unsigned int nr_resets;//该reset controller所控制的reset信号的个数};
/** * struct reset_controller_dev - reset controller entity that might *                               provide multiple reset controls * @ops: a pointer to device specific struct reset_control_ops * @owner: kernel module of the reset controller driver * @list: internal list of reset controller devices * @reset_control_head: head of internal list of requested reset controls * @dev: corresponding driver model device struct * @of_node: corresponding device tree node as phandle target * @of_reset_n_cells: number of cells in reset line specifiers * @of_xlate: translation function to translate from specifier as found in the *            device tree to id as given to the reset control ops, defaults *            to :c:func:`of_reset_simple_xlate`. * @nr_resets: number of reset controls in this reset controller device */struct reset_controller_dev {  const struct reset_control_ops *ops;//ops提供reset操作的实现,基本上是reset provider的所有工作量。  struct module *owner;  struct list_head list;////全局链表,复位控制器注册后挂载到全局链表  struct list_head reset_control_head;////各个模块复位的链表头  struct device *dev;  struct device_node *of_node;  int of_reset_n_cells;////用于解析consumer device dts node中的“resets = <>; ”节点,指示dts中引用时,需要几个参数  int (*of_xlate)(struct reset_controller_dev *rcdev,      const struct of_phandle_args *reset_spec);//用于解析consumer device dts node中的“resets = <>; ”节点  unsigned int nr_resets;//该reset controller所控制的reset信号的个数};
/** * struct reset_controller_dev - reset controller entity that might * provide multiple reset controls * @ops: a pointer to device specific struct reset_control_ops * @owner: kernel module of the reset controller driver * @list: internal list of reset controller devices * @reset_control_head: head of internal list of requested reset controls * @dev: corresponding driver model device struct * @of_node: corresponding device tree node as phandle target * @of_reset_n_cells: number of cells in reset line specifiers * @of_xlate: translation function to translate from specifier as found in the * device tree to id as given to the reset control ops, defaults * to :c:func:`of_reset_simple_xlate`. * @nr_resets: number of reset controls in this reset controller device */struct reset_controller_dev { const struct reset_control_ops *ops;//ops提供reset操作的实现,基本上是reset provider的所有工作量。 struct module *owner; struct list_head list;////全局链表,复位控制器注册后挂载到全局链表 struct list_head reset_control_head;////各个模块复位的链表头 struct device *dev; struct device_node *of_node; int of_reset_n_cells;////用于解析consumer device dts node中的“resets = <>; ”节点,指示dts中引用时,需要几个参数 int (*of_xlate)(struct reset_controller_dev *rcdev, const struct of_phandle_args *reset_spec);//用于解析consumer device dts node中的“resets = <>; ”节点 unsigned int nr_resets;//该reset controller所控制的reset信号的个数};

struct reset_control_ops也比较单纯,如下:

/** * struct reset_control_ops - reset controller driver callbacks * * @reset: for self-deasserting resets, does all necessary * things to reset the device * @assert: manually assert the reset line, if supported * @deassert: manually deassert the reset line, if supported * @status: return the status of the reset line, if supported */struct reset_control_ops { int (*reset)(struct reset_controller_dev *rcdev, unsigned long id); //控制设备完成一次完整的复位过程 int (*assert)(struct reset_controller_dev *rcdev, unsigned long id); //控制设备reset状态的生效 int (*deassert)(struct reset_controller_dev *rcdev, unsigned long id);//控制设备reset状态的失效。 int (*status)(struct reset_controller_dev *rcdev, unsigned long id); //复位状态查询};
/** * struct reset_control_ops - reset controller driver callbacks * * @reset: for self-deasserting resets, does all necessary *         things to reset the device * @assert: manually assert the reset line, if supported * @deassert: manually deassert the reset line, if supported * @status: return the status of the reset line, if supported */struct reset_control_ops {  int (*reset)(struct reset_controller_dev *rcdev, unsigned long id);   //控制设备完成一次完整的复位过程  int (*assert)(struct reset_controller_dev *rcdev, unsigned long id);  //控制设备reset状态的生效  int (*deassert)(struct reset_controller_dev *rcdev, unsigned long id);//控制设备reset状态的失效。  int (*status)(struct reset_controller_dev *rcdev, unsigned long id);  //复位状态查询};
/** * struct reset_control_ops - reset controller driver callbacks * * @reset: for self-deasserting resets, does all necessary * things to reset the device * @assert: manually assert the reset line, if supported * @deassert: manually deassert the reset line, if supported * @status: return the status of the reset line, if supported */struct reset_control_ops { int (*reset)(struct reset_controller_dev *rcdev, unsigned long id); //控制设备完成一次完整的复位过程 int (*assert)(struct reset_controller_dev *rcdev, unsigned long id); //控制设备reset状态的生效 int (*deassert)(struct reset_controller_dev *rcdev, unsigned long id);//控制设备reset状态的失效。 int (*status)(struct reset_controller_dev *rcdev, unsigned long id); //复位状态查询};

5. reset驱动的设备树描述总结

5.1 对于provider

reset:reset-controller{ compatible = "xx,xx-reset"; reg = <0x0 0x30390000 0x0 0x10000>; #reset-cells = <1>;};
reset:reset-controller{  compatible = "xx,xx-reset";  reg = <0x0 0x30390000 0x0 0x10000>;  #reset-cells = <1>;};
reset:reset-controller{ compatible = "xx,xx-reset"; reg = <0x0 0x30390000 0x0 0x10000>; #reset-cells = <1>;};

上述是一个reset控制器的节点,0x30390000 是寄存器基址,0x1000是映射大小。”#reset-cells”代表引用该reset时需要的cells个数。

5.2 对于consumer

例如,#reset-cells = <1>; 则正确引用为:

mmc:mmc@0x12345678{ ...... resets = <&reset 0>;//0代表reset设备id,id是自定义的,但是不能超过reset驱动中指定的设备个数 ......};
mmc:mmc@0x12345678{    ......    resets = <&reset  0>;//0代表reset设备id,id是自定义的,但是不能超过reset驱动中指定的设备个数    ......};
mmc:mmc@0x12345678{ ...... resets = <&reset 0>;//0代表reset设备id,id是自定义的,但是不能超过reset驱动中指定的设备个数 ......};

6. 开源reset驱动实例

6.1 实例1(比较容易理解)

设备树: arch/arm/boot/dts/imx7d.dtsi

pcie: pcie@0x33800000 { compatible = "fsl,imx7d-pcie", "snps,dw-pcie"; .... resets = <&src IMX7_RESET_PCIEPHY>, <&src IMX7_RESET_PCIE_CTRL_APPS_EN>; reset-names = "pciephy", "apps"; status = "disabled"; };
  pcie: pcie@0x33800000 {    compatible = "fsl,imx7d-pcie", "snps,dw-pcie";     ....     resets = <&src IMX7_RESET_PCIEPHY>,       <&src IMX7_RESET_PCIE_CTRL_APPS_EN>;    reset-names = "pciephy", "apps";    status = "disabled";  };
pcie: pcie@0x33800000 { compatible = "fsl,imx7d-pcie", "snps,dw-pcie"; .... resets = <&src IMX7_RESET_PCIEPHY>, <&src IMX7_RESET_PCIE_CTRL_APPS_EN>; reset-names = "pciephy", "apps"; status = "disabled"; };

驱动代码: drivers/reset/reset-imx7.c

... struct imx7_src { struct reset_controller_dev rcdev; struct regmap *regmap;}; enum imx7_src_registers { SRC_A7RCR0 = 0x0004, SRC_M4RCR = 0x000c, SRC_ERCR = 0x0014, SRC_HSICPHY_RCR = 0x001c, SRC_USBOPHY1_RCR = 0x0020, SRC_USBOPHY2_RCR = 0x0024, SRC_MIPIPHY_RCR = 0x0028, SRC_PCIEPHY_RCR = 0x002c, SRC_DDRC_RCR = 0x1000,}; struct imx7_src_signal { unsigned int offset, bit;}; static const struct imx7_src_signal imx7_src_signals[IMX7_RESET_NUM] = { [IMX7_RESET_A7_CORE_POR_RESET0] = { SRC_A7RCR0, BIT(0) }, [IMX7_RESET_A7_CORE_POR_RESET1] = { SRC_A7RCR0, BIT(1) }, [IMX7_RESET_A7_CORE_RESET0] = { SRC_A7RCR0, BIT(4) }, [IMX7_RESET_A7_CORE_RESET1] = { SRC_A7RCR0, BIT(5) }, [IMX7_RESET_A7_DBG_RESET0] = { SRC_A7RCR0, BIT(8) }, [IMX7_RESET_A7_DBG_RESET1] = { SRC_A7RCR0, BIT(9) }, ...}; static struct imx7_src *to_imx7_src(struct reset_controller_dev *rcdev){ return container_of(rcdev, struct imx7_src, rcdev);} static int imx7_reset_set(struct reset_controller_dev *rcdev, unsigned long id, bool assert){ struct imx7_src *imx7src = to_imx7_src(rcdev); const struct imx7_src_signal *signal = &imx7_src_signals[id]; unsigned int value = assert ? signal->bit : 0; switch (id) { case IMX7_RESET_PCIEPHY: /* * wait for more than 10us to release phy g_rst and * btnrst */ if (!assert) udelay(10); break; case IMX7_RESET_PCIE_CTRL_APPS_EN: value = (assert) ? 0 : signal->bit; break; } return regmap_update_bits(imx7src->regmap, signal->offset, signal->bit, value);} static int imx7_reset_assert(struct reset_controller_dev *rcdev, unsigned long id){ return imx7_reset_set(rcdev, id, true);} static int imx7_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id){ return imx7_reset_set(rcdev, id, false);} static const struct reset_control_ops imx7_reset_ops = { .assert = imx7_reset_assert, .deassert = imx7_reset_deassert,}; static int imx7_reset_probe(struct platform_device *pdev){ struct imx7_src *imx7src; struct device *dev = &pdev->dev; struct regmap_config config = { .name = "src" }; imx7src = devm_kzalloc(dev, sizeof(*imx7src), GFP_KERNEL); if (!imx7src) return -ENOMEM; imx7src->regmap = syscon_node_to_regmap(dev->of_node); if (IS_ERR(imx7src->regmap)) { dev_err(dev, "Unable to get imx7-src regmap"); return PTR_ERR(imx7src->regmap); } regmap_attach_dev(dev, imx7src->regmap, &config); imx7src->rcdev.owner = THIS_MODULE; imx7src->rcdev.nr_resets = IMX7_RESET_NUM; imx7src->rcdev.ops = &imx7_reset_ops; imx7src->rcdev.of_node = dev->of_node; return devm_reset_controller_register(dev, &imx7src->rcdev);} static const struct of_device_id imx7_reset_dt_ids[] = { { .compatible = "fsl,imx7d-src", }, { /* sentinel */ },}; static struct platform_driver imx7_reset_driver = { .probe = imx7_reset_probe, .driver = { .name = KBUILD_MODNAME, .of_match_table = imx7_reset_dt_ids, },};builtin_platform_driver(imx7_reset_driver);
... struct imx7_src {  struct reset_controller_dev rcdev;  struct regmap *regmap;}; enum imx7_src_registers {  SRC_A7RCR0    = 0x0004,  SRC_M4RCR    = 0x000c,  SRC_ERCR    = 0x0014,  SRC_HSICPHY_RCR    = 0x001c,  SRC_USBOPHY1_RCR  = 0x0020,  SRC_USBOPHY2_RCR  = 0x0024,  SRC_MIPIPHY_RCR    = 0x0028,  SRC_PCIEPHY_RCR    = 0x002c,  SRC_DDRC_RCR    = 0x1000,}; struct imx7_src_signal {  unsigned int offset, bit;}; static const struct imx7_src_signal imx7_src_signals[IMX7_RESET_NUM] = {  [IMX7_RESET_A7_CORE_POR_RESET0] = { SRC_A7RCR0, BIT(0) },  [IMX7_RESET_A7_CORE_POR_RESET1] = { SRC_A7RCR0, BIT(1) },  [IMX7_RESET_A7_CORE_RESET0]     = { SRC_A7RCR0, BIT(4) },  [IMX7_RESET_A7_CORE_RESET1]  = { SRC_A7RCR0, BIT(5) },  [IMX7_RESET_A7_DBG_RESET0]  = { SRC_A7RCR0, BIT(8) },  [IMX7_RESET_A7_DBG_RESET1]  = { SRC_A7RCR0, BIT(9) },  ...}; static struct imx7_src *to_imx7_src(struct reset_controller_dev *rcdev){  return container_of(rcdev, struct imx7_src, rcdev);} static int imx7_reset_set(struct reset_controller_dev *rcdev,        unsigned long id, bool assert){  struct imx7_src *imx7src = to_imx7_src(rcdev);  const struct imx7_src_signal *signal = &imx7_src_signals[id];  unsigned int value = assert ? signal->bit : 0;   switch (id) {  case IMX7_RESET_PCIEPHY:    /*     * wait for more than 10us to release phy g_rst and     * btnrst     */    if (!assert)      udelay(10);    break;   case IMX7_RESET_PCIE_CTRL_APPS_EN:    value = (assert) ? 0 : signal->bit;    break;  }   return regmap_update_bits(imx7src->regmap,          signal->offset, signal->bit, value);} static int imx7_reset_assert(struct reset_controller_dev *rcdev,           unsigned long id){  return imx7_reset_set(rcdev, id, true);} static int imx7_reset_deassert(struct reset_controller_dev *rcdev,             unsigned long id){  return imx7_reset_set(rcdev, id, false);} static const struct reset_control_ops imx7_reset_ops = {  .assert    = imx7_reset_assert,  .deassert  = imx7_reset_deassert,}; static int imx7_reset_probe(struct platform_device *pdev){  struct imx7_src *imx7src;  struct device *dev = &pdev->dev;  struct regmap_config config = { .name = "src" };   imx7src = devm_kzalloc(dev, sizeof(*imx7src), GFP_KERNEL);  if (!imx7src)    return -ENOMEM;   imx7src->regmap = syscon_node_to_regmap(dev->of_node);  if (IS_ERR(imx7src->regmap)) {    dev_err(dev, "Unable to get imx7-src regmap");    return PTR_ERR(imx7src->regmap);  }  regmap_attach_dev(dev, imx7src->regmap, &config);   imx7src->rcdev.owner     = THIS_MODULE;  imx7src->rcdev.nr_resets = IMX7_RESET_NUM;  imx7src->rcdev.ops       = &imx7_reset_ops;  imx7src->rcdev.of_node   = dev->of_node;   return devm_reset_controller_register(dev, &imx7src->rcdev);} static const struct of_device_id imx7_reset_dt_ids[] = {  { .compatible = "fsl,imx7d-src", },  { /* sentinel */ },}; static struct platform_driver imx7_reset_driver = {  .probe  = imx7_reset_probe,  .driver = {    .name    = KBUILD_MODNAME,    .of_match_table  = imx7_reset_dt_ids,  },};builtin_platform_driver(imx7_reset_driver); 
... struct imx7_src { struct reset_controller_dev rcdev; struct regmap *regmap;}; enum imx7_src_registers { SRC_A7RCR0 = 0x0004, SRC_M4RCR = 0x000c, SRC_ERCR = 0x0014, SRC_HSICPHY_RCR = 0x001c, SRC_USBOPHY1_RCR = 0x0020, SRC_USBOPHY2_RCR = 0x0024, SRC_MIPIPHY_RCR = 0x0028, SRC_PCIEPHY_RCR = 0x002c, SRC_DDRC_RCR = 0x1000,}; struct imx7_src_signal { unsigned int offset, bit;}; static const struct imx7_src_signal imx7_src_signals[IMX7_RESET_NUM] = { [IMX7_RESET_A7_CORE_POR_RESET0] = { SRC_A7RCR0, BIT(0) }, [IMX7_RESET_A7_CORE_POR_RESET1] = { SRC_A7RCR0, BIT(1) }, [IMX7_RESET_A7_CORE_RESET0] = { SRC_A7RCR0, BIT(4) }, [IMX7_RESET_A7_CORE_RESET1] = { SRC_A7RCR0, BIT(5) }, [IMX7_RESET_A7_DBG_RESET0] = { SRC_A7RCR0, BIT(8) }, [IMX7_RESET_A7_DBG_RESET1] = { SRC_A7RCR0, BIT(9) }, ...}; static struct imx7_src *to_imx7_src(struct reset_controller_dev *rcdev){ return container_of(rcdev, struct imx7_src, rcdev);} static int imx7_reset_set(struct reset_controller_dev *rcdev, unsigned long id, bool assert){ struct imx7_src *imx7src = to_imx7_src(rcdev); const struct imx7_src_signal *signal = &imx7_src_signals[id]; unsigned int value = assert ? signal->bit : 0; switch (id) { case IMX7_RESET_PCIEPHY: /* * wait for more than 10us to release phy g_rst and * btnrst */ if (!assert) udelay(10); break; case IMX7_RESET_PCIE_CTRL_APPS_EN: value = (assert) ? 0 : signal->bit; break; } return regmap_update_bits(imx7src->regmap, signal->offset, signal->bit, value);} static int imx7_reset_assert(struct reset_controller_dev *rcdev, unsigned long id){ return imx7_reset_set(rcdev, id, true);} static int imx7_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id){ return imx7_reset_set(rcdev, id, false);} static const struct reset_control_ops imx7_reset_ops = { .assert = imx7_reset_assert, .deassert = imx7_reset_deassert,}; static int imx7_reset_probe(struct platform_device *pdev){ struct imx7_src *imx7src; struct device *dev = &pdev->dev; struct regmap_config config = { .name = "src" }; imx7src = devm_kzalloc(dev, sizeof(*imx7src), GFP_KERNEL); if (!imx7src) return -ENOMEM; imx7src->regmap = syscon_node_to_regmap(dev->of_node); if (IS_ERR(imx7src->regmap)) { dev_err(dev, "Unable to get imx7-src regmap"); return PTR_ERR(imx7src->regmap); } regmap_attach_dev(dev, imx7src->regmap, &config); imx7src->rcdev.owner = THIS_MODULE; imx7src->rcdev.nr_resets = IMX7_RESET_NUM; imx7src->rcdev.ops = &imx7_reset_ops; imx7src->rcdev.of_node = dev->of_node; return devm_reset_controller_register(dev, &imx7src->rcdev);} static const struct of_device_id imx7_reset_dt_ids[] = { { .compatible = "fsl,imx7d-src", }, { /* sentinel */ },}; static struct platform_driver imx7_reset_driver = { .probe = imx7_reset_probe, .driver = { .name = KBUILD_MODNAME, .of_match_table = imx7_reset_dt_ids, },};builtin_platform_driver(imx7_reset_driver);

6.2 实例2(在gpio子系统中嵌套reset子系统)

设备树: arc/arm64/boot/dts/myzr/myimx8mm.dts

&pcie0{ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c4_pcieclk>, <&pinctrl_gpio1_pciendis>, <&pinctrl_sd2_pciewake>, <&pinctrl_sai2_pcienrst>; disable-gpio = <&gpio1 5 GPIO_ACTIVE_LOW>; reset-gpio = <&gpio4 21 GPIO_ACTIVE_LOW>; ext_osc = <1>; status = "okay";};
&pcie0{  pinctrl-names = "default";  pinctrl-0 = <&pinctrl_i2c4_pcieclk>, <&pinctrl_gpio1_pciendis>, <&pinctrl_sd2_pciewake>, <&pinctrl_sai2_pcienrst>;  disable-gpio = <&gpio1 5 GPIO_ACTIVE_LOW>;  reset-gpio = <&gpio4 21 GPIO_ACTIVE_LOW>;  ext_osc = <1>;  status = "okay";};
&pcie0{ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c4_pcieclk>, <&pinctrl_gpio1_pciendis>, <&pinctrl_sd2_pciewake>, <&pinctrl_sai2_pcienrst>; disable-gpio = <&gpio1 5 GPIO_ACTIVE_LOW>; reset-gpio = <&gpio4 21 GPIO_ACTIVE_LOW>; ext_osc = <1>; status = "okay";};

驱动代码: drivers/reset/gpio-reset.c

... struct gpio_reset_data { struct reset_controller_dev rcdev; unsigned int gpio; bool active_low; s32 delay_us; s32 post_delay_ms;}; static void gpio_reset_set(struct reset_controller_dev *rcdev, int asserted){ struct gpio_reset_data *drvdata = container_of(rcdev, struct gpio_reset_data, rcdev); int value = asserted; if (drvdata->active_low) value = !value; gpio_set_value_cansleep(drvdata->gpio, value);} static int gpio_reset(struct reset_controller_dev *rcdev, unsigned long id){ struct gpio_reset_data *drvdata = container_of(rcdev, struct gpio_reset_data, rcdev); if (drvdata->delay_us < 0) return -ENOSYS; gpio_reset_set(rcdev, 1); udelay(drvdata->delay_us); gpio_reset_set(rcdev, 0); if (drvdata->post_delay_ms < 0) return 0; msleep(drvdata->post_delay_ms); return 0;} static int gpio_reset_assert(struct reset_controller_dev *rcdev, unsigned long id){ gpio_reset_set(rcdev, 1); return 0;} static int gpio_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id){ gpio_reset_set(rcdev, 0); return 0;} static struct reset_control_ops gpio_reset_ops = { .reset = gpio_reset, .assert = gpio_reset_assert, .deassert = gpio_reset_deassert,}; static int of_gpio_reset_xlate(struct reset_controller_dev *rcdev, const struct of_phandle_args *reset_spec){ if (WARN_ON(reset_spec->args_count != 0)) return -EINVAL; return 0;} static int gpio_reset_probe(struct platform_device *pdev){ ... drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); ... drvdata->rcdev.of_node = np; drvdata->rcdev.owner = THIS_MODULE; drvdata->rcdev.nr_resets = 1; ////该reset controller所控制的reset信号的个数 drvdata->rcdev.ops = &gpio_reset_ops; //ops提供reset操作的实现。 drvdata->rcdev.of_xlate = of_gpio_reset_xlate; reset_controller_register(&drvdata->rcdev); //注册reset controller return 0;} static int gpio_reset_remove(struct platform_device *pdev){ struct gpio_reset_data *drvdata = platform_get_drvdata(pdev); reset_controller_unregister(&drvdata->rcdev); return 0;} static struct of_device_id gpio_reset_dt_ids[] = { { .compatible = "gpio-reset" }, { }}; #ifdef CONFIG_PM_SLEEPstatic int gpio_reset_suspend(struct device *dev){ pinctrl_pm_select_sleep_state(dev); return 0;}static int gpio_reset_resume(struct device *dev){ pinctrl_pm_select_default_state(dev); return 0;}#endif static const struct dev_pm_ops gpio_reset_pm_ops = { SET_LATE_SYSTEM_SLEEP_PM_OPS(gpio_reset_suspend, gpio_reset_resume)}; static struct platform_driver gpio_reset_driver = { .probe = gpio_reset_probe, .remove = gpio_reset_remove, .driver = { .name = "gpio-reset", .owner = THIS_MODULE, .of_match_table = of_match_ptr(gpio_reset_dt_ids), .pm = &gpio_reset_pm_ops, },}; static int __init gpio_reset_init(void){ return platform_driver_register(&gpio_reset_driver);}arch_initcall(gpio_reset_init); static void __exit gpio_reset_exit(void){ platform_driver_unregister(&gpio_reset_driver);}...
... struct gpio_reset_data {  struct reset_controller_dev rcdev;  unsigned int gpio;  bool active_low;  s32 delay_us;  s32 post_delay_ms;}; static void gpio_reset_set(struct reset_controller_dev *rcdev, int asserted){  struct gpio_reset_data *drvdata = container_of(rcdev,      struct gpio_reset_data, rcdev);  int value = asserted;   if (drvdata->active_low)    value = !value;   gpio_set_value_cansleep(drvdata->gpio, value);} static int gpio_reset(struct reset_controller_dev *rcdev, unsigned long id){  struct gpio_reset_data *drvdata = container_of(rcdev,      struct gpio_reset_data, rcdev);   if (drvdata->delay_us < 0)    return -ENOSYS;   gpio_reset_set(rcdev, 1);  udelay(drvdata->delay_us);  gpio_reset_set(rcdev, 0);   if (drvdata->post_delay_ms < 0)    return 0;   msleep(drvdata->post_delay_ms);  return 0;} static int gpio_reset_assert(struct reset_controller_dev *rcdev,    unsigned long id){  gpio_reset_set(rcdev, 1);   return 0;} static int gpio_reset_deassert(struct reset_controller_dev *rcdev,    unsigned long id){  gpio_reset_set(rcdev, 0);   return 0;} static struct reset_control_ops gpio_reset_ops = {  .reset = gpio_reset,  .assert = gpio_reset_assert,  .deassert = gpio_reset_deassert,}; static int of_gpio_reset_xlate(struct reset_controller_dev *rcdev,             const struct of_phandle_args *reset_spec){  if (WARN_ON(reset_spec->args_count != 0))    return -EINVAL;   return 0;} static int gpio_reset_probe(struct platform_device *pdev){  ...   drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);   ...   drvdata->rcdev.of_node = np;  drvdata->rcdev.owner = THIS_MODULE;  drvdata->rcdev.nr_resets = 1;                  ////该reset controller所控制的reset信号的个数  drvdata->rcdev.ops = &gpio_reset_ops;          //ops提供reset操作的实现。  drvdata->rcdev.of_xlate = of_gpio_reset_xlate;   reset_controller_register(&drvdata->rcdev);    //注册reset controller   return 0;} static int gpio_reset_remove(struct platform_device *pdev){  struct gpio_reset_data *drvdata = platform_get_drvdata(pdev);   reset_controller_unregister(&drvdata->rcdev);   return 0;} static struct of_device_id gpio_reset_dt_ids[] = {  { .compatible = "gpio-reset" },  { }}; #ifdef CONFIG_PM_SLEEPstatic int gpio_reset_suspend(struct device *dev){  pinctrl_pm_select_sleep_state(dev);   return 0;}static int gpio_reset_resume(struct device *dev){  pinctrl_pm_select_default_state(dev);   return 0;}#endif static const struct dev_pm_ops gpio_reset_pm_ops = {  SET_LATE_SYSTEM_SLEEP_PM_OPS(gpio_reset_suspend, gpio_reset_resume)}; static struct platform_driver gpio_reset_driver = {  .probe = gpio_reset_probe,  .remove = gpio_reset_remove,  .driver = {    .name = "gpio-reset",    .owner = THIS_MODULE,    .of_match_table = of_match_ptr(gpio_reset_dt_ids),    .pm = &gpio_reset_pm_ops,  },}; static int __init gpio_reset_init(void){  return platform_driver_register(&gpio_reset_driver);}arch_initcall(gpio_reset_init); static void __exit gpio_reset_exit(void){  platform_driver_unregister(&gpio_reset_driver);}...
... struct gpio_reset_data { struct reset_controller_dev rcdev; unsigned int gpio; bool active_low; s32 delay_us; s32 post_delay_ms;}; static void gpio_reset_set(struct reset_controller_dev *rcdev, int asserted){ struct gpio_reset_data *drvdata = container_of(rcdev, struct gpio_reset_data, rcdev); int value = asserted; if (drvdata->active_low) value = !value; gpio_set_value_cansleep(drvdata->gpio, value);} static int gpio_reset(struct reset_controller_dev *rcdev, unsigned long id){ struct gpio_reset_data *drvdata = container_of(rcdev, struct gpio_reset_data, rcdev); if (drvdata->delay_us < 0) return -ENOSYS; gpio_reset_set(rcdev, 1); udelay(drvdata->delay_us); gpio_reset_set(rcdev, 0); if (drvdata->post_delay_ms < 0) return 0; msleep(drvdata->post_delay_ms); return 0;} static int gpio_reset_assert(struct reset_controller_dev *rcdev, unsigned long id){ gpio_reset_set(rcdev, 1); return 0;} static int gpio_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id){ gpio_reset_set(rcdev, 0); return 0;} static struct reset_control_ops gpio_reset_ops = { .reset = gpio_reset, .assert = gpio_reset_assert, .deassert = gpio_reset_deassert,}; static int of_gpio_reset_xlate(struct reset_controller_dev *rcdev, const struct of_phandle_args *reset_spec){ if (WARN_ON(reset_spec->args_count != 0)) return -EINVAL; return 0;} static int gpio_reset_probe(struct platform_device *pdev){ ... drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); ... drvdata->rcdev.of_node = np; drvdata->rcdev.owner = THIS_MODULE; drvdata->rcdev.nr_resets = 1; ////该reset controller所控制的reset信号的个数 drvdata->rcdev.ops = &gpio_reset_ops; //ops提供reset操作的实现。 drvdata->rcdev.of_xlate = of_gpio_reset_xlate; reset_controller_register(&drvdata->rcdev); //注册reset controller return 0;} static int gpio_reset_remove(struct platform_device *pdev){ struct gpio_reset_data *drvdata = platform_get_drvdata(pdev); reset_controller_unregister(&drvdata->rcdev); return 0;} static struct of_device_id gpio_reset_dt_ids[] = { { .compatible = "gpio-reset" }, { }}; #ifdef CONFIG_PM_SLEEPstatic int gpio_reset_suspend(struct device *dev){ pinctrl_pm_select_sleep_state(dev); return 0;}static int gpio_reset_resume(struct device *dev){ pinctrl_pm_select_default_state(dev); return 0;}#endif static const struct dev_pm_ops gpio_reset_pm_ops = { SET_LATE_SYSTEM_SLEEP_PM_OPS(gpio_reset_suspend, gpio_reset_resume)}; static struct platform_driver gpio_reset_driver = { .probe = gpio_reset_probe, .remove = gpio_reset_remove, .driver = { .name = "gpio-reset", .owner = THIS_MODULE, .of_match_table = of_match_ptr(gpio_reset_dt_ids), .pm = &gpio_reset_pm_ops, },}; static int __init gpio_reset_init(void){ return platform_driver_register(&gpio_reset_driver);}arch_initcall(gpio_reset_init); static void __exit gpio_reset_exit(void){ platform_driver_unregister(&gpio_reset_driver);}...

7. reset驱动的实质

操作soc对应的reset寄存器,以实现内核IP的复位,或者操作gpio管脚的电平,间接复位接到该pin脚的从设备。

参考

[1] Documentation/devicetree/bindings/reset/reset.txt
[2] Linux reset framework
[2] Linux reset子系统及驱动实例

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYdeYhoj' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片